summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/cpu
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/cpu')
-rw-r--r--arch/powerpc/cpu/74xx_7xx/Makefile51
-rw-r--r--arch/powerpc/cpu/74xx_7xx/cache.S404
-rw-r--r--arch/powerpc/cpu/74xx_7xx/config.mk26
-rw-r--r--arch/powerpc/cpu/74xx_7xx/cpu.c316
-rw-r--r--arch/powerpc/cpu/74xx_7xx/cpu_init.c63
-rw-r--r--arch/powerpc/cpu/74xx_7xx/interrupts.c104
-rw-r--r--arch/powerpc/cpu/74xx_7xx/io.S128
-rw-r--r--arch/powerpc/cpu/74xx_7xx/kgdb.S77
-rw-r--r--arch/powerpc/cpu/74xx_7xx/speed.c181
-rw-r--r--arch/powerpc/cpu/74xx_7xx/start.S856
-rw-r--r--arch/powerpc/cpu/74xx_7xx/traps.c234
-rw-r--r--arch/powerpc/cpu/74xx_7xx/u-boot.lds94
-rw-r--r--arch/powerpc/cpu/mpc512x/Makefile63
-rw-r--r--arch/powerpc/cpu/mpc512x/asm-offsets.h15
-rw-r--r--arch/powerpc/cpu/mpc512x/cache.c33
-rw-r--r--arch/powerpc/cpu/mpc512x/config.mk26
-rw-r--r--arch/powerpc/cpu/mpc512x/cpu.c216
-rw-r--r--arch/powerpc/cpu/mpc512x/cpu_init.c212
-rw-r--r--arch/powerpc/cpu/mpc512x/diu.c60
-rw-r--r--arch/powerpc/cpu/mpc512x/fixed_sdram.c172
-rw-r--r--arch/powerpc/cpu/mpc512x/i2c.c402
-rw-r--r--arch/powerpc/cpu/mpc512x/ide.c128
-rw-r--r--arch/powerpc/cpu/mpc512x/interrupts.c61
-rw-r--r--arch/powerpc/cpu/mpc512x/iopin.c103
-rw-r--r--arch/powerpc/cpu/mpc512x/pci.c225
-rw-r--r--arch/powerpc/cpu/mpc512x/serial.c459
-rw-r--r--arch/powerpc/cpu/mpc512x/speed.c153
-rw-r--r--arch/powerpc/cpu/mpc512x/start.S708
-rw-r--r--arch/powerpc/cpu/mpc512x/traps.c204
-rw-r--r--arch/powerpc/cpu/mpc512x/u-boot.lds90
-rw-r--r--arch/powerpc/cpu/mpc5xx/Makefile59
-rw-r--r--arch/powerpc/cpu/mpc5xx/config.mk26
-rw-r--r--arch/powerpc/cpu/mpc5xx/cpu.c171
-rw-r--r--arch/powerpc/cpu/mpc5xx/cpu_init.c123
-rw-r--r--arch/powerpc/cpu/mpc5xx/interrupts.c207
-rw-r--r--arch/powerpc/cpu/mpc5xx/serial.c183
-rw-r--r--arch/powerpc/cpu/mpc5xx/speed.c67
-rw-r--r--arch/powerpc/cpu/mpc5xx/spi.c412
-rw-r--r--arch/powerpc/cpu/mpc5xx/start.S561
-rw-r--r--arch/powerpc/cpu/mpc5xx/traps.c227
-rw-r--r--arch/powerpc/cpu/mpc5xx/u-boot.lds103
-rw-r--r--arch/powerpc/cpu/mpc5xxx/Makefile64
-rw-r--r--arch/powerpc/cpu/mpc5xxx/config.mk27
-rw-r--r--arch/powerpc/cpu/mpc5xxx/cpu.c184
-rw-r--r--arch/powerpc/cpu/mpc5xxx/cpu_init.c247
-rw-r--r--arch/powerpc/cpu/mpc5xxx/firmware_sc_task_bestcomm.impl.S359
-rw-r--r--arch/powerpc/cpu/mpc5xxx/i2c.c472
-rw-r--r--arch/powerpc/cpu/mpc5xxx/ide.c99
-rw-r--r--arch/powerpc/cpu/mpc5xxx/interrupts.c346
-rw-r--r--arch/powerpc/cpu/mpc5xxx/io.S128
-rw-r--r--arch/powerpc/cpu/mpc5xxx/loadtask.c76
-rw-r--r--arch/powerpc/cpu/mpc5xxx/pci_mpc5200.c187
-rw-r--r--arch/powerpc/cpu/mpc5xxx/serial.c292
-rw-r--r--arch/powerpc/cpu/mpc5xxx/speed.c100
-rw-r--r--arch/powerpc/cpu/mpc5xxx/spl_boot.c87
-rw-r--r--arch/powerpc/cpu/mpc5xxx/start.S783
-rw-r--r--arch/powerpc/cpu/mpc5xxx/traps.c236
-rw-r--r--arch/powerpc/cpu/mpc5xxx/u-boot-customlayout.lds96
-rw-r--r--arch/powerpc/cpu/mpc5xxx/u-boot-spl.lds57
-rw-r--r--arch/powerpc/cpu/mpc5xxx/u-boot.lds92
-rw-r--r--arch/powerpc/cpu/mpc5xxx/usb.c58
-rw-r--r--arch/powerpc/cpu/mpc5xxx/usb_ohci.c1644
-rw-r--r--arch/powerpc/cpu/mpc5xxx/usb_ohci.h418
-rw-r--r--arch/powerpc/cpu/mpc824x/.gitignore1
-rw-r--r--arch/powerpc/cpu/mpc824x/Makefile55
-rw-r--r--arch/powerpc/cpu/mpc824x/config.mk26
-rw-r--r--arch/powerpc/cpu/mpc824x/cpu.c280
-rw-r--r--arch/powerpc/cpu/mpc824x/cpu_init.c417
-rw-r--r--arch/powerpc/cpu/mpc824x/drivers/epic.h1
-rw-r--r--arch/powerpc/cpu/mpc824x/drivers/epic/README102
-rw-r--r--arch/powerpc/cpu/mpc824x/drivers/epic/epic.h163
-rw-r--r--arch/powerpc/cpu/mpc824x/drivers/epic/epic1.c517
-rw-r--r--arch/powerpc/cpu/mpc824x/drivers/epic/epic2.S196
-rw-r--r--arch/powerpc/cpu/mpc824x/drivers/epic/epicutil.S57
-rw-r--r--arch/powerpc/cpu/mpc824x/drivers/errors.h212
-rw-r--r--arch/powerpc/cpu/mpc824x/drivers/i2c/i2c.c270
-rw-r--r--arch/powerpc/cpu/mpc824x/drivers/i2c_export.h103
-rw-r--r--arch/powerpc/cpu/mpc824x/interrupts.c93
-rw-r--r--arch/powerpc/cpu/mpc824x/pci.c78
-rw-r--r--arch/powerpc/cpu/mpc824x/speed.c118
-rw-r--r--arch/powerpc/cpu/mpc824x/start.S745
-rw-r--r--arch/powerpc/cpu/mpc824x/traps.c210
-rw-r--r--arch/powerpc/cpu/mpc824x/u-boot.lds92
-rw-r--r--arch/powerpc/cpu/mpc8260/Makefile53
-rw-r--r--arch/powerpc/cpu/mpc8260/bedbug_603e.c236
-rw-r--r--arch/powerpc/cpu/mpc8260/commproc.c178
-rw-r--r--arch/powerpc/cpu/mpc8260/config.mk27
-rw-r--r--arch/powerpc/cpu/mpc8260/cpu.c337
-rw-r--r--arch/powerpc/cpu/mpc8260/cpu_init.c292
-rw-r--r--arch/powerpc/cpu/mpc8260/ether_fcc.c1188
-rw-r--r--arch/powerpc/cpu/mpc8260/ether_scc.c383
-rw-r--r--arch/powerpc/cpu/mpc8260/i2c.c770
-rw-r--r--arch/powerpc/cpu/mpc8260/interrupts.c279
-rw-r--r--arch/powerpc/cpu/mpc8260/kgdb.S72
-rw-r--r--arch/powerpc/cpu/mpc8260/pci.c466
-rw-r--r--arch/powerpc/cpu/mpc8260/serial_scc.c508
-rw-r--r--arch/powerpc/cpu/mpc8260/serial_smc.c477
-rw-r--r--arch/powerpc/cpu/mpc8260/speed.c244
-rw-r--r--arch/powerpc/cpu/mpc8260/speed.h54
-rw-r--r--arch/powerpc/cpu/mpc8260/spi.c431
-rw-r--r--arch/powerpc/cpu/mpc8260/start.S1008
-rw-r--r--arch/powerpc/cpu/mpc8260/traps.c264
-rw-r--r--arch/powerpc/cpu/mpc8260/u-boot.lds91
-rw-r--r--arch/powerpc/cpu/mpc83xx/Makefile96
-rw-r--r--arch/powerpc/cpu/mpc83xx/cache.c33
-rw-r--r--arch/powerpc/cpu/mpc83xx/config.mk26
-rw-r--r--arch/powerpc/cpu/mpc83xx/cpu.c242
-rw-r--r--arch/powerpc/cpu/mpc83xx/cpu_init.c524
-rw-r--r--arch/powerpc/cpu/mpc83xx/ecc.c395
-rw-r--r--arch/powerpc/cpu/mpc83xx/fdt.c146
-rw-r--r--arch/powerpc/cpu/mpc83xx/interrupts.c97
-rw-r--r--arch/powerpc/cpu/mpc83xx/law.c61
-rw-r--r--arch/powerpc/cpu/mpc83xx/pci.c241
-rw-r--r--arch/powerpc/cpu/mpc83xx/pcie.c346
-rw-r--r--arch/powerpc/cpu/mpc83xx/qe_io.c82
-rw-r--r--arch/powerpc/cpu/mpc83xx/serdes.c154
-rw-r--r--arch/powerpc/cpu/mpc83xx/spd_sdram.c943
-rw-r--r--arch/powerpc/cpu/mpc83xx/speed.c609
-rw-r--r--arch/powerpc/cpu/mpc83xx/spl_minimal.c112
-rw-r--r--arch/powerpc/cpu/mpc83xx/start.S1211
-rw-r--r--arch/powerpc/cpu/mpc83xx/traps.c257
-rw-r--r--arch/powerpc/cpu/mpc83xx/u-boot-spl.lds55
-rw-r--r--arch/powerpc/cpu/mpc83xx/u-boot.lds91
-rw-r--r--arch/powerpc/cpu/mpc85xx/Makefile182
-rw-r--r--arch/powerpc/cpu/mpc85xx/b4860_ids.c147
-rw-r--r--arch/powerpc/cpu/mpc85xx/b4860_serdes.c222
-rw-r--r--arch/powerpc/cpu/mpc85xx/bsc9132_serdes.c96
-rw-r--r--arch/powerpc/cpu/mpc85xx/cache.c33
-rw-r--r--arch/powerpc/cpu/mpc85xx/cmd_errata.c271
-rw-r--r--arch/powerpc/cpu/mpc85xx/commproc.c186
-rw-r--r--arch/powerpc/cpu/mpc85xx/config.mk33
-rw-r--r--arch/powerpc/cpu/mpc85xx/cpu.c618
-rw-r--r--arch/powerpc/cpu/mpc85xx/cpu_init.c744
-rw-r--r--arch/powerpc/cpu/mpc85xx/cpu_init_early.c190
-rw-r--r--arch/powerpc/cpu/mpc85xx/ddr-gen1.c89
-rw-r--r--arch/powerpc/cpu/mpc85xx/ddr-gen2.c95
-rw-r--r--arch/powerpc/cpu/mpc85xx/ddr-gen3.c430
-rw-r--r--arch/powerpc/cpu/mpc85xx/ether_fcc.c468
-rw-r--r--arch/powerpc/cpu/mpc85xx/fdt.c835
-rw-r--r--arch/powerpc/cpu/mpc85xx/fixed_ivor.S79
-rw-r--r--arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c203
-rw-r--r--arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.h26
-rw-r--r--arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c876
-rw-r--r--arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.h41
-rw-r--r--arch/powerpc/cpu/mpc85xx/interrupts.c126
-rw-r--r--arch/powerpc/cpu/mpc85xx/liodn.c358
-rw-r--r--arch/powerpc/cpu/mpc85xx/mp.c488
-rw-r--r--arch/powerpc/cpu/mpc85xx/mp.h21
-rw-r--r--arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c249
-rw-r--r--arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c95
-rw-r--r--arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c65
-rw-r--r--arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c65
-rw-r--r--arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c74
-rw-r--r--arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c81
-rw-r--r--arch/powerpc/cpu/mpc85xx/p1010_serdes.c75
-rw-r--r--arch/powerpc/cpu/mpc85xx/p1021_serdes.c111
-rw-r--r--arch/powerpc/cpu/mpc85xx/p1022_serdes.c114
-rw-r--r--arch/powerpc/cpu/mpc85xx/p1023_serdes.c53
-rw-r--r--arch/powerpc/cpu/mpc85xx/p2020_serdes.c73
-rw-r--r--arch/powerpc/cpu/mpc85xx/p2041_ids.c129
-rw-r--r--arch/powerpc/cpu/mpc85xx/p2041_serdes.c106
-rw-r--r--arch/powerpc/cpu/mpc85xx/p3041_ids.c128
-rw-r--r--arch/powerpc/cpu/mpc85xx/p3041_serdes.c151
-rw-r--r--arch/powerpc/cpu/mpc85xx/p4080_ids.c128
-rw-r--r--arch/powerpc/cpu/mpc85xx/p4080_serdes.c98
-rw-r--r--arch/powerpc/cpu/mpc85xx/p5020_ids.c141
-rw-r--r--arch/powerpc/cpu/mpc85xx/p5020_serdes.c151
-rw-r--r--arch/powerpc/cpu/mpc85xx/p5040_ids.c127
-rw-r--r--arch/powerpc/cpu/mpc85xx/p5040_serdes.c117
-rw-r--r--arch/powerpc/cpu/mpc85xx/pci.c230
-rw-r--r--arch/powerpc/cpu/mpc85xx/portals.c324
-rw-r--r--arch/powerpc/cpu/mpc85xx/qe_io.c85
-rw-r--r--arch/powerpc/cpu/mpc85xx/release.S493
-rw-r--r--arch/powerpc/cpu/mpc85xx/resetvec.S2
-rw-r--r--arch/powerpc/cpu/mpc85xx/serial_scc.c278
-rw-r--r--arch/powerpc/cpu/mpc85xx/speed.c475
-rw-r--r--arch/powerpc/cpu/mpc85xx/spl_minimal.c59
-rw-r--r--arch/powerpc/cpu/mpc85xx/start.S1979
-rw-r--r--arch/powerpc/cpu/mpc85xx/t1040_ids.c135
-rw-r--r--arch/powerpc/cpu/mpc85xx/t1040_serdes.c93
-rw-r--r--arch/powerpc/cpu/mpc85xx/t4240_ids.c203
-rw-r--r--arch/powerpc/cpu/mpc85xx/t4240_serdes.c369
-rw-r--r--arch/powerpc/cpu/mpc85xx/tlb.c344
-rw-r--r--arch/powerpc/cpu/mpc85xx/traps.c313
-rw-r--r--arch/powerpc/cpu/mpc85xx/u-boot-nand.lds108
-rw-r--r--arch/powerpc/cpu/mpc85xx/u-boot-nand_spl.lds85
-rw-r--r--arch/powerpc/cpu/mpc85xx/u-boot-spl.lds103
-rw-r--r--arch/powerpc/cpu/mpc85xx/u-boot.lds140
-rw-r--r--arch/powerpc/cpu/mpc86xx/Makefile65
-rw-r--r--arch/powerpc/cpu/mpc86xx/cache.S378
-rw-r--r--arch/powerpc/cpu/mpc86xx/config.mk27
-rw-r--r--arch/powerpc/cpu/mpc86xx/cpu.c218
-rw-r--r--arch/powerpc/cpu/mpc86xx/cpu_init.c118
-rw-r--r--arch/powerpc/cpu/mpc86xx/ddr-8641.c85
-rw-r--r--arch/powerpc/cpu/mpc86xx/fdt.c66
-rw-r--r--arch/powerpc/cpu/mpc86xx/interrupts.c131
-rw-r--r--arch/powerpc/cpu/mpc86xx/mp.c145
-rw-r--r--arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c85
-rw-r--r--arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c94
-rw-r--r--arch/powerpc/cpu/mpc86xx/release.S167
-rw-r--r--arch/powerpc/cpu/mpc86xx/speed.c160
-rw-r--r--arch/powerpc/cpu/mpc86xx/start.S1008
-rw-r--r--arch/powerpc/cpu/mpc86xx/traps.c224
-rw-r--r--arch/powerpc/cpu/mpc86xx/u-boot.lds95
-rw-r--r--arch/powerpc/cpu/mpc8xx/Makefile65
-rw-r--r--arch/powerpc/cpu/mpc8xx/bedbug_860.c314
-rw-r--r--arch/powerpc/cpu/mpc8xx/commproc.c85
-rw-r--r--arch/powerpc/cpu/mpc8xx/config.mk26
-rw-r--r--arch/powerpc/cpu/mpc8xx/cpu.c659
-rw-r--r--arch/powerpc/cpu/mpc8xx/cpu_init.c283
-rw-r--r--arch/powerpc/cpu/mpc8xx/fdt.c46
-rw-r--r--arch/powerpc/cpu/mpc8xx/fec.c1029
-rw-r--r--arch/powerpc/cpu/mpc8xx/fec.h28
-rw-r--r--arch/powerpc/cpu/mpc8xx/i2c.c704
-rw-r--r--arch/powerpc/cpu/mpc8xx/interrupts.c294
-rw-r--r--arch/powerpc/cpu/mpc8xx/kgdb.S74
-rw-r--r--arch/powerpc/cpu/mpc8xx/plprcr_write.S135
-rw-r--r--arch/powerpc/cpu/mpc8xx/scc.c558
-rw-r--r--arch/powerpc/cpu/mpc8xx/serial.c766
-rw-r--r--arch/powerpc/cpu/mpc8xx/speed.c416
-rw-r--r--arch/powerpc/cpu/mpc8xx/spi.c556
-rw-r--r--arch/powerpc/cpu/mpc8xx/start.S669
-rw-r--r--arch/powerpc/cpu/mpc8xx/traps.c232
-rw-r--r--arch/powerpc/cpu/mpc8xx/upatch.c194
-rw-r--r--arch/powerpc/cpu/mpc8xx/video.c1331
-rw-r--r--arch/powerpc/cpu/mpc8xx/wlkbd.c36
-rw-r--r--arch/powerpc/cpu/mpc8xxx/Makefile49
-rw-r--r--arch/powerpc/cpu/mpc8xxx/cpu.c281
-rw-r--r--arch/powerpc/cpu/mpc8xxx/ddr/Makefile45
-rw-r--r--arch/powerpc/cpu/mpc8xxx/ddr/common_timing_params.h56
-rw-r--r--arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c1645
-rw-r--r--arch/powerpc/cpu/mpc8xxx/ddr/ddr.h105
-rw-r--r--arch/powerpc/cpu/mpc8xxx/ddr/ddr1_dimm_params.c343
-rw-r--r--arch/powerpc/cpu/mpc8xxx/ddr/ddr2_dimm_params.c342
-rw-r--r--arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c336
-rw-r--r--arch/powerpc/cpu/mpc8xxx/ddr/interactive.c1868
-rw-r--r--arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c517
-rw-r--r--arch/powerpc/cpu/mpc8xxx/ddr/main.c667
-rw-r--r--arch/powerpc/cpu/mpc8xxx/ddr/options.c1148
-rw-r--r--arch/powerpc/cpu/mpc8xxx/ddr/util.c264
-rw-r--r--arch/powerpc/cpu/mpc8xxx/fdt.c464
-rw-r--r--arch/powerpc/cpu/mpc8xxx/fsl_ifc.c153
-rw-r--r--arch/powerpc/cpu/mpc8xxx/fsl_lbc.c153
-rw-r--r--arch/powerpc/cpu/mpc8xxx/law.c334
-rw-r--r--arch/powerpc/cpu/mpc8xxx/srio.c459
-rw-r--r--arch/powerpc/cpu/ppc4xx/40x_spd_sdram.c464
-rw-r--r--arch/powerpc/cpu/ppc4xx/44x_spd_ddr.c1244
-rw-r--r--arch/powerpc/cpu/ppc4xx/44x_spd_ddr2.c3167
-rw-r--r--arch/powerpc/cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c1256
-rw-r--r--arch/powerpc/cpu/ppc4xx/4xx_pci.c885
-rw-r--r--arch/powerpc/cpu/ppc4xx/4xx_pcie.c1292
-rw-r--r--arch/powerpc/cpu/ppc4xx/4xx_uart.c307
-rw-r--r--arch/powerpc/cpu/ppc4xx/Makefile91
-rw-r--r--arch/powerpc/cpu/ppc4xx/bedbug_405.c308
-rw-r--r--arch/powerpc/cpu/ppc4xx/cache.S235
-rw-r--r--arch/powerpc/cpu/ppc4xx/cmd_chip_config.c148
-rw-r--r--arch/powerpc/cpu/ppc4xx/cmd_ecctest.c279
-rw-r--r--arch/powerpc/cpu/ppc4xx/config.mk34
-rw-r--r--arch/powerpc/cpu/ppc4xx/cpu.c751
-rw-r--r--arch/powerpc/cpu/ppc4xx/cpu_init.c559
-rw-r--r--arch/powerpc/cpu/ppc4xx/dcr.S198
-rw-r--r--arch/powerpc/cpu/ppc4xx/denali_data_eye.c389
-rw-r--r--arch/powerpc/cpu/ppc4xx/denali_spd_ddr2.c1249
-rw-r--r--arch/powerpc/cpu/ppc4xx/ecc.c204
-rw-r--r--arch/powerpc/cpu/ppc4xx/ecc.h75
-rw-r--r--arch/powerpc/cpu/ppc4xx/fdt.c176
-rw-r--r--arch/powerpc/cpu/ppc4xx/gpio.c260
-rw-r--r--arch/powerpc/cpu/ppc4xx/interrupts.c209
-rw-r--r--arch/powerpc/cpu/ppc4xx/kgdb.S78
-rw-r--r--arch/powerpc/cpu/ppc4xx/miiphy.c365
-rw-r--r--arch/powerpc/cpu/ppc4xx/reginfo.c370
-rw-r--r--arch/powerpc/cpu/ppc4xx/resetvec.S12
-rw-r--r--arch/powerpc/cpu/ppc4xx/sdram.c468
-rw-r--r--arch/powerpc/cpu/ppc4xx/sdram.h76
-rw-r--r--arch/powerpc/cpu/ppc4xx/speed.c1225
-rw-r--r--arch/powerpc/cpu/ppc4xx/spl_boot.c72
-rw-r--r--arch/powerpc/cpu/ppc4xx/start.S2096
-rw-r--r--arch/powerpc/cpu/ppc4xx/tlb.c352
-rw-r--r--arch/powerpc/cpu/ppc4xx/traps.c408
-rw-r--r--arch/powerpc/cpu/ppc4xx/u-boot-spl.lds74
-rw-r--r--arch/powerpc/cpu/ppc4xx/u-boot.lds149
-rw-r--r--arch/powerpc/cpu/ppc4xx/uic.c180
-rw-r--r--arch/powerpc/cpu/ppc4xx/usb.c61
-rw-r--r--arch/powerpc/cpu/ppc4xx/usb_ohci.c1639
-rw-r--r--arch/powerpc/cpu/ppc4xx/usb_ohci.h410
-rw-r--r--arch/powerpc/cpu/ppc4xx/xilinx_irq.c100
286 files changed, 88586 insertions, 0 deletions
diff --git a/arch/powerpc/cpu/74xx_7xx/Makefile b/arch/powerpc/cpu/74xx_7xx/Makefile
new file mode 100644
index 0000000..8c2800b
--- /dev/null
+++ b/arch/powerpc/cpu/74xx_7xx/Makefile
@@ -0,0 +1,51 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# (C) Copyright 2001
+# Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(CPU).o
+
+START = start.o
+SOBJS = cache.o kgdb.o io.o
+COBJS = traps.o cpu.o cpu_init.o speed.o interrupts.o
+
+SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
+START := $(addprefix $(obj),$(START))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/powerpc/cpu/74xx_7xx/cache.S b/arch/powerpc/cpu/74xx_7xx/cache.S
new file mode 100644
index 0000000..66c7298
--- /dev/null
+++ b/arch/powerpc/cpu/74xx_7xx/cache.S
@@ -0,0 +1,404 @@
+#include <config.h>
+#include <74xx_7xx.h>
+#include <version.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#ifndef CACHE_LINE_SIZE
+# define CACHE_LINE_SIZE L1_CACHE_BYTES
+#endif
+
+#if CACHE_LINE_SIZE == 128
+#define LG_CACHE_LINE_SIZE 7
+#elif CACHE_LINE_SIZE == 32
+#define LG_CACHE_LINE_SIZE 5
+#elif CACHE_LINE_SIZE == 16
+#define LG_CACHE_LINE_SIZE 4
+#elif CACHE_LINE_SIZE == 8
+#define LG_CACHE_LINE_SIZE 3
+#else
+# error "Invalid cache line size!"
+#endif
+
+/*
+ * Invalidate L1 instruction cache.
+ */
+_GLOBAL(invalidate_l1_instruction_cache)
+ mfspr r3,PVR
+ rlwinm r3,r3,16,16,31
+ cmpi 0,r3,1
+ beqlr /* for 601, do nothing */
+ /* 603/604 processor - use invalidate-all bit in HID0 */
+ mfspr r3,HID0
+ ori r3,r3,HID0_ICFI
+ mtspr HID0,r3
+ isync
+ blr
+
+/*
+ * Invalidate L1 data cache.
+ */
+_GLOBAL(invalidate_l1_data_cache)
+ mfspr r3,HID0
+ ori r3,r3,HID0_DCFI
+ mtspr HID0,r3
+ isync
+ blr
+
+/*
+ * Flush data cache.
+ */
+_GLOBAL(flush_dcache)
+ lis r3,0
+ lis r5,CACHE_LINE_SIZE
+flush:
+ cmp 0,1,r3,r5
+ bge done
+ lwz r5,0(r3)
+ lis r5,CACHE_LINE_SIZE
+ addi r3,r3,0x4
+ b flush
+done:
+ blr
+/*
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
+ * This is a no-op on the 601.
+ *
+ * flush_icache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(flush_icache_range)
+ mfspr r5,PVR
+ rlwinm r5,r5,16,16,31
+ cmpi 0,r5,1
+ beqlr /* for 601, do nothing */
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,LG_CACHE_LINE_SIZE
+ beqlr
+ mtctr r4
+ mr r6,r3
+1: dcbst 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ mtctr r4
+2: icbi 0,r6
+ addi r6,r6,CACHE_LINE_SIZE
+ bdnz 2b
+ sync /* additional sync needed on g4 */
+ isync
+ blr
+/*
+ * Write any modified data cache blocks out to memory.
+ * Does not invalidate the corresponding cache lines (especially for
+ * any corresponding instruction cache).
+ *
+ * clean_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(clean_dcache_range)
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5 /* align r3 down to cache line */
+ subf r4,r3,r4 /* r4 = offset of stop from start of cache line */
+ add r4,r4,r5 /* r4 += cache_line_size-1 */
+ srwi. r4,r4,LG_CACHE_LINE_SIZE /* r4 = number of cache lines to flush */
+ beqlr /* if r4 == 0 return */
+ mtctr r4 /* ctr = r4 */
+
+ sync
+1: dcbst 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ blr
+
+/*
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
+ *
+ * flush_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(flush_dcache_range)
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,LG_CACHE_LINE_SIZE
+ beqlr
+ mtctr r4
+
+ sync
+1: dcbf 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbf's to get to ram */
+ blr
+
+/*
+ * Like above, but invalidate the D-cache. This is used by the 8xx
+ * to invalidate the cache so the PPC core doesn't get stale data
+ * from the CPM (no cache snooping here :-).
+ *
+ * invalidate_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(invalidate_dcache_range)
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,LG_CACHE_LINE_SIZE
+ beqlr
+ mtctr r4
+
+ sync
+1: dcbi 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbi's to get to ram */
+ blr
+
+/*
+ * Flush a particular page from the data cache to RAM.
+ * Note: this is necessary because the instruction cache does *not*
+ * snoop from the data cache.
+ * This is a no-op on the 601 which has a unified cache.
+ *
+ * void __flush_page_to_ram(void *page)
+ */
+_GLOBAL(__flush_page_to_ram)
+ mfspr r5,PVR
+ rlwinm r5,r5,16,16,31
+ cmpi 0,r5,1
+ beqlr /* for 601, do nothing */
+ rlwinm r3,r3,0,0,19 /* Get page base address */
+ li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
+ mtctr r4
+ mr r6,r3
+0: dcbst 0,r3 /* Write line to ram */
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 0b
+ sync
+ mtctr r4
+1: icbi 0,r6
+ addi r6,r6,CACHE_LINE_SIZE
+ bdnz 1b
+ sync
+ isync
+ blr
+
+/*
+ * Flush a particular page from the instruction cache.
+ * Note: this is necessary because the instruction cache does *not*
+ * snoop from the data cache.
+ * This is a no-op on the 601 which has a unified cache.
+ *
+ * void __flush_icache_page(void *page)
+ */
+_GLOBAL(__flush_icache_page)
+ mfspr r5,PVR
+ rlwinm r5,r5,16,16,31
+ cmpi 0,r5,1
+ beqlr /* for 601, do nothing */
+ li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
+ mtctr r4
+1: icbi 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync
+ isync
+ blr
+
+/*
+ * Clear a page using the dcbz instruction, which doesn't cause any
+ * memory traffic (except to write out any cache lines which get
+ * displaced). This only works on cacheable memory.
+ */
+_GLOBAL(clear_page)
+ li r0,4096/CACHE_LINE_SIZE
+ mtctr r0
+1: dcbz 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ blr
+
+/*
+ * Enable L1 Instruction cache
+ */
+_GLOBAL(icache_enable)
+ mfspr r3, HID0
+ li r5, HID0_ICFI|HID0_ILOCK
+ andc r3, r3, r5
+ ori r3, r3, HID0_ICE
+ ori r5, r3, HID0_ICFI
+ mtspr HID0, r5
+ mtspr HID0, r3
+ isync
+ blr
+
+/*
+ * Disable L1 Instruction cache
+ */
+_GLOBAL(icache_disable)
+ mflr r4
+ bl invalidate_l1_instruction_cache /* uses r3 */
+ sync
+ mtlr r4
+ mfspr r3, HID0
+ li r5, 0
+ ori r5, r5, HID0_ICE
+ andc r3, r3, r5
+ mtspr HID0, r3
+ isync
+ blr
+
+/*
+ * Is instruction cache enabled?
+ */
+_GLOBAL(icache_status)
+ mfspr r3, HID0
+ andi. r3, r3, HID0_ICE
+ blr
+
+
+_GLOBAL(l1dcache_enable)
+ mfspr r3, HID0
+ li r5, HID0_DCFI|HID0_DLOCK
+ andc r3, r3, r5
+ mtspr HID0, r3 /* no invalidate, unlock */
+ ori r3, r3, HID0_DCE
+ ori r5, r3, HID0_DCFI
+ mtspr HID0, r5 /* enable + invalidate */
+ mtspr HID0, r3 /* enable */
+ sync
+ blr
+
+/*
+ * Enable data cache(s) - L1 and optionally L2
+ * Calls l2cache_enable. LR saved in r5
+ */
+_GLOBAL(dcache_enable)
+ mfspr r3, HID0
+ li r5, HID0_DCFI|HID0_DLOCK
+ andc r3, r3, r5
+ mtspr HID0, r3 /* no invalidate, unlock */
+ ori r3, r3, HID0_DCE
+ ori r5, r3, HID0_DCFI
+ mtspr HID0, r5 /* enable + invalidate */
+ mtspr HID0, r3 /* enable */
+ sync
+#ifdef CONFIG_SYS_L2
+ mflr r5
+ bl l2cache_enable /* uses r3 and r4 */
+ sync
+ mtlr r5
+#endif
+ blr
+
+
+/*
+ * Disable data cache(s) - L1 and optionally L2
+ * Calls flush_dcache and l2cache_disable_no_flush.
+ * LR saved in r4
+ */
+_GLOBAL(dcache_disable)
+ mflr r4 /* save link register */
+ bl flush_dcache /* uses r3 and r5 */
+ sync
+ mfspr r3, HID0
+ li r5, HID0_DCFI|HID0_DLOCK
+ andc r3, r3, r5
+ mtspr HID0, r3 /* no invalidate, unlock */
+ li r5, HID0_DCE|HID0_DCFI
+ andc r3, r3, r5 /* no enable, no invalidate */
+ mtspr HID0, r3
+ sync
+#ifdef CONFIG_SYS_L2
+ bl l2cache_disable_no_flush /* uses r3 */
+#endif
+ mtlr r4 /* restore link register */
+ blr
+
+/*
+ * Is data cache enabled?
+ */
+_GLOBAL(dcache_status)
+ mfspr r3, HID0
+ andi. r3, r3, HID0_DCE
+ blr
+
+/*
+ * Invalidate L2 cache using L2I and polling L2IP or L2I
+ */
+_GLOBAL(l2cache_invalidate)
+ sync
+ mfspr r3, l2cr
+ oris r3, r3, L2CR_L2I@h
+ sync
+ mtspr l2cr, r3
+ sync
+ mfspr r3, PVR
+ sync
+ rlwinm r3, r3, 16,16,31
+ cmpli 0,r3,0x8000 /* 7451, 7441 */
+ beq 0,inv_7450
+ cmpli 0,r3,0x8001 /* 7455, 7445 */
+ beq 0,inv_7450
+ cmpli 0,r3,0x8002 /* 7457, 7447 */
+ beq 0,inv_7450
+ cmpli 0,r3,0x8003 /* 7447A */
+ beq 0,inv_7450
+ cmpli 0,r3,0x8004 /* 7448 */
+ beq 0,inv_7450
+invl2:
+ mfspr r3, l2cr
+ andi. r3, r3, L2CR_L2IP
+ bne invl2
+ /* turn off the global invalidate bit */
+ mfspr r3, l2cr
+ rlwinm r3, r3, 0, 11, 9
+ sync
+ mtspr l2cr, r3
+ sync
+ blr
+inv_7450:
+ mfspr r3, l2cr
+ andis. r3, r3, L2CR_L2I@h
+ bne inv_7450
+ blr
+
+/*
+ * Enable L2 cache
+ * Calls l2cache_invalidate. LR is saved in r4
+ */
+_GLOBAL(l2cache_enable)
+ mflr r4 /* save link register */
+ bl l2cache_invalidate /* uses r3 */
+ sync
+ lis r3, L2_ENABLE@h
+ ori r3, r3, L2_ENABLE@l
+ mtspr l2cr, r3
+ isync
+ mtlr r4 /* restore link register */
+ blr
+
+/*
+ * Disable L2 cache
+ * Calls flush_dcache. LR is saved in r4
+ */
+_GLOBAL(l2cache_disable)
+ mflr r4 /* save link register */
+ bl flush_dcache /* uses r3 and r5 */
+ sync
+ mtlr r4 /* restore link register */
+l2cache_disable_no_flush: /* provide way to disable L2 w/o flushing */
+ lis r3, L2_INIT@h
+ ori r3, r3, L2_INIT@l
+ mtspr l2cr, r3
+ isync
+ blr
diff --git a/arch/powerpc/cpu/74xx_7xx/config.mk b/arch/powerpc/cpu/74xx_7xx/config.mk
new file mode 100644
index 0000000..fb0c715
--- /dev/null
+++ b/arch/powerpc/cpu/74xx_7xx/config.mk
@@ -0,0 +1,26 @@
+#
+# (C) Copyright 2001
+# Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_RELFLAGS += -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_74xx_7xx -ffixed-r2 -mstring
diff --git a/arch/powerpc/cpu/74xx_7xx/cpu.c b/arch/powerpc/cpu/74xx_7xx/cpu.c
new file mode 100644
index 0000000..17694a1
--- /dev/null
+++ b/arch/powerpc/cpu/74xx_7xx/cpu.c
@@ -0,0 +1,316 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * cpu.c
+ *
+ * CPU specific code
+ *
+ * written or collected and sometimes rewritten by
+ * Magnus Damm <damm@bitsmart.com>
+ *
+ * minor modifications by
+ * Wolfgang Denk <wd@denx.de>
+ *
+ * more modifications by
+ * Josh Huber <huber@mclx.com>
+ * added support for the 74xx series of cpus
+ * added support for the 7xx series of cpus
+ * made the code a little less hard-coded, and more auto-detectish
+ */
+
+#include <common.h>
+#include <command.h>
+#include <74xx_7xx.h>
+#include <asm/cache.h>
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+cpu_t
+get_cpu_type(void)
+{
+ uint pvr = get_pvr();
+ cpu_t type;
+
+ type = CPU_UNKNOWN;
+
+ switch (PVR_VER(pvr)) {
+ case 0x000c:
+ type = CPU_7400;
+ break;
+ case 0x0008:
+ type = CPU_750;
+
+ if (((pvr >> 8) & 0xff) == 0x01) {
+ type = CPU_750CX; /* old CX (80100 and 8010x?)*/
+ } else if (((pvr >> 8) & 0xff) == 0x22) {
+ type = CPU_750CX; /* CX (82201,82202) and CXe (82214) */
+ } else if (((pvr >> 8) & 0xff) == 0x33) {
+ type = CPU_750CX; /* CXe (83311) */
+ } else if (((pvr >> 12) & 0xF) == 0x3) {
+ type = CPU_755;
+ }
+ break;
+
+ case 0x7000:
+ type = CPU_750FX;
+ break;
+
+ case 0x7002:
+ type = CPU_750GX;
+ break;
+
+ case 0x800C:
+ type = CPU_7410;
+ break;
+
+ case 0x8000:
+ type = CPU_7450;
+ break;
+
+ case 0x8001:
+ type = CPU_7455;
+ break;
+
+ case 0x8002:
+ type = CPU_7457;
+ break;
+
+ case 0x8003:
+ type = CPU_7447A;
+ break;
+
+ case 0x8004:
+ type = CPU_7448;
+ break;
+
+ default:
+ break;
+ }
+
+ return type;
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if !defined(CONFIG_BAB7xx)
+int checkcpu (void)
+{
+ uint type = get_cpu_type();
+ uint pvr = get_pvr();
+ ulong clock = gd->cpu_clk;
+ char buf[32];
+ char *str;
+
+ puts ("CPU: ");
+
+ switch (type) {
+ case CPU_750CX:
+ printf ("750CX%s v%d.%d", (pvr&0xf0)?"e":"",
+ (pvr>>8) & 0xf,
+ pvr & 0xf);
+ goto PR_CLK;
+
+ case CPU_750:
+ str = "750";
+ break;
+
+ case CPU_750FX:
+ str = "750FX";
+ break;
+
+ case CPU_750GX:
+ str = "750GX";
+ break;
+
+ case CPU_755:
+ str = "755";
+ break;
+
+ case CPU_7400:
+ str = "MPC7400";
+ break;
+
+ case CPU_7410:
+ str = "MPC7410";
+ break;
+
+ case CPU_7447A:
+ str = "MPC7447A";
+ break;
+
+ case CPU_7448:
+ str = "MPC7448";
+ break;
+
+ case CPU_7450:
+ str = "MPC7450";
+ break;
+
+ case CPU_7455:
+ str = "MPC7455";
+ break;
+
+ case CPU_7457:
+ str = "MPC7457";
+ break;
+
+ default:
+ printf("Unknown CPU -- PVR: 0x%08x\n", pvr);
+ return -1;
+ }
+
+ printf ("%s v%d.%d", str, (pvr >> 8) & 0xFF, pvr & 0xFF);
+PR_CLK:
+ printf (" @ %s MHz\n", strmhz(buf, clock));
+
+ return (0);
+}
+#endif
+/* these two functions are unimplemented currently [josh] */
+
+/* -------------------------------------------------------------------- */
+/* L1 i-cache */
+
+int
+checkicache(void)
+{
+ return 0; /* XXX */
+}
+
+/* -------------------------------------------------------------------- */
+/* L1 d-cache */
+
+int
+checkdcache(void)
+{
+ return 0; /* XXX */
+}
+
+/* -------------------------------------------------------------------- */
+
+static inline void
+soft_restart(unsigned long addr)
+{
+ /* SRR0 has system reset vector, SRR1 has default MSR value */
+ /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
+
+ __asm__ __volatile__ ("mtspr 26, %0" :: "r" (addr));
+ __asm__ __volatile__ ("li 4, (1 << 6)" ::: "r4");
+ __asm__ __volatile__ ("mtspr 27, 4");
+ __asm__ __volatile__ ("rfi");
+
+ while(1); /* not reached */
+}
+
+
+#if !defined(CONFIG_BAB7xx) && \
+ !defined(CONFIG_ELPPC) && \
+ !defined(CONFIG_PPMC7XX)
+/* no generic way to do board reset. simply call soft_reset. */
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong addr;
+ /* flush and disable I/D cache */
+ __asm__ __volatile__ ("mfspr 3, 1008" ::: "r3");
+ __asm__ __volatile__ ("ori 5, 5, 0xcc00" ::: "r5");
+ __asm__ __volatile__ ("ori 4, 3, 0xc00" ::: "r4");
+ __asm__ __volatile__ ("andc 5, 3, 5" ::: "r5");
+ __asm__ __volatile__ ("sync");
+ __asm__ __volatile__ ("mtspr 1008, 4");
+ __asm__ __volatile__ ("isync");
+ __asm__ __volatile__ ("sync");
+ __asm__ __volatile__ ("mtspr 1008, 5");
+ __asm__ __volatile__ ("isync");
+ __asm__ __volatile__ ("sync");
+
+#ifdef CONFIG_SYS_RESET_ADDRESS
+ addr = CONFIG_SYS_RESET_ADDRESS;
+#else
+ /*
+ * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address,
+ * CONFIG_SYS_MONITOR_BASE - sizeof (ulong) is usually a valid
+ * address. Better pick an address known to be invalid on your
+ * system and assign it to CONFIG_SYS_RESET_ADDRESS.
+ */
+ addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong);
+#endif
+ soft_restart(addr);
+
+ /* not reached */
+ while(1)
+ ;
+
+ return 1;
+}
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * For the 7400 the TB clock runs at 1/4 the cpu bus speed.
+ */
+#ifndef CONFIG_SYS_BUS_CLK
+#define CONFIG_SYS_BUS_CLK gd->bus_clk
+#endif
+
+unsigned long get_tbclk(void)
+{
+ return CONFIG_SYS_BUS_CLK / 4;
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if defined(CONFIG_WATCHDOG)
+#if !defined(CONFIG_BAB7xx)
+void
+watchdog_reset(void)
+{
+
+}
+#endif /* !CONFIG_BAB7xx */
+#endif /* CONFIG_WATCHDOG */
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_OF_LIBFDT
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "timebase-frequency", bd->bi_busfreq / 4, 1);
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "bus-frequency", bd->bi_busfreq, 1);
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "clock-frequency", bd->bi_intfreq, 1);
+
+ fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+
+ fdt_fixup_ethernet(blob);
+}
+#endif
+/* ------------------------------------------------------------------------- */
diff --git a/arch/powerpc/cpu/74xx_7xx/cpu_init.c b/arch/powerpc/cpu/74xx_7xx/cpu_init.c
new file mode 100644
index 0000000..1dd1b2c
--- /dev/null
+++ b/arch/powerpc/cpu/74xx_7xx/cpu_init.c
@@ -0,0 +1,63 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * cpu_init.c - low level cpu init
+ *
+ * there's really nothing going on here yet. future work area?
+ */
+
+#include <common.h>
+#include <74xx_7xx.h>
+
+/*
+ * Breath some life into the CPU...
+ *
+ * there's basically nothing to do here since the memory controller
+ * isn't on the CPU in this case.
+ */
+void
+cpu_init_f (void)
+{
+ switch (get_cpu_type()) {
+ case CPU_7450:
+ case CPU_7455:
+ case CPU_7457:
+ case CPU_7447A:
+ case CPU_7448:
+ /* enable the timebase bit in HID0 */
+ set_hid0(get_hid0() | 0x4000000);
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+}
+
+/*
+ * initialize higher level parts of CPU like timers
+ */
+int cpu_init_r (void)
+{
+ return (0);
+}
diff --git a/arch/powerpc/cpu/74xx_7xx/interrupts.c b/arch/powerpc/cpu/74xx_7xx/interrupts.c
new file mode 100644
index 0000000..7fc8a34
--- /dev/null
+++ b/arch/powerpc/cpu/74xx_7xx/interrupts.c
@@ -0,0 +1,104 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * interrupts.c - just enough support for the decrementer/timer
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <mpc8xx_irq.h>
+#include <asm/processor.h>
+#include <commproc.h>
+#include <command.h>
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+ debug("interrupt_init: GT main cause reg: %08x:%08x\n",
+ GTREGREAD(LOW_INTERRUPT_CAUSE_REGISTER),
+ GTREGREAD(HIGH_INTERRUPT_CAUSE_REGISTER));
+ debug("interrupt_init: ethernet cause regs: %08x %08x %08x\n",
+ GTREGREAD(ETHERNET0_INTERRUPT_CAUSE_REGISTER),
+ GTREGREAD(ETHERNET1_INTERRUPT_CAUSE_REGISTER),
+ GTREGREAD(ETHERNET2_INTERRUPT_CAUSE_REGISTER));
+ debug("interrupt_init: ethernet mask regs: %08x %08x %08x\n",
+ GTREGREAD(ETHERNET0_INTERRUPT_MASK_REGISTER),
+ GTREGREAD(ETHERNET1_INTERRUPT_MASK_REGISTER),
+ GTREGREAD(ETHERNET2_INTERRUPT_MASK_REGISTER));
+ debug("interrupt_init: setting decrementer_count\n");
+
+ *decrementer_count = get_tbclk() / CONFIG_SYS_HZ;
+
+ return (0);
+}
+
+/****************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void
+external_interrupt(struct pt_regs *regs)
+{
+ puts("external_interrupt (oops!)\n");
+}
+
+volatile ulong timestamp = 0;
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * Trivial implementation - no need to be really accurate.
+ */
+void
+timer_interrupt_cpu (struct pt_regs *regs)
+{
+ /* nothing to do here */
+ return;
+}
+
+/****************************************************************************/
+
+/*
+ * Install and free a interrupt handler.
+ */
+
+void
+irq_install_handler(int vec, interrupt_handler_t *handler, void *arg)
+{
+
+}
+
+void
+irq_free_handler(int vec)
+{
+
+}
+
+/****************************************************************************/
+
+void
+do_irqinfo(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char * const argv[])
+{
+ puts("IRQ related functions are unimplemented currently.\n");
+}
diff --git a/arch/powerpc/cpu/74xx_7xx/io.S b/arch/powerpc/cpu/74xx_7xx/io.S
new file mode 100644
index 0000000..af2e6d1
--- /dev/null
+++ b/arch/powerpc/cpu/74xx_7xx/io.S
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ * Copyright (C) 2002 Wolfgang Denk <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <ppc_asm.tmpl>
+
+/* ------------------------------------------------------------------------------- */
+/* Function: in8 */
+/* Description: Input 8 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl in8
+in8:
+ lbz r3,0(r3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: in16 */
+/* Description: Input 16 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl in16
+in16:
+ lhz r3,0(r3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: in16r */
+/* Description: Input 16 bits and byte reverse */
+/* ------------------------------------------------------------------------------- */
+ .globl in16r
+in16r:
+ lhbrx r3,0,r3
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: in32 */
+/* Description: Input 32 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl in32
+in32:
+ lwz 3,0(3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: in32r */
+/* Description: Input 32 bits and byte reverse */
+/* ------------------------------------------------------------------------------- */
+ .globl in32r
+in32r:
+ lwbrx r3,0,r3
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: out8 */
+/* Description: Output 8 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl out8
+out8:
+ stb r4,0(r3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: out16 */
+/* Description: Output 16 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl out16
+out16:
+ sth r4,0(r3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: out16r */
+/* Description: Byte reverse and output 16 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl out16r
+out16r:
+ sthbrx r4,0,r3
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: out32 */
+/* Description: Output 32 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl out32
+out32:
+ stw r4,0(r3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: out32r */
+/* Description: Byte reverse and output 32 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl out32r
+out32r:
+ stwbrx r4,0,r3
+ sync
+ blr
diff --git a/arch/powerpc/cpu/74xx_7xx/kgdb.S b/arch/powerpc/cpu/74xx_7xx/kgdb.S
new file mode 100644
index 0000000..ad487cd
--- /dev/null
+++ b/arch/powerpc/cpu/74xx_7xx/kgdb.S
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2000 Murray Jensen <Murray.Jensen@cmst.csiro.au>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307USA
+ */
+
+#include <config.h>
+#include <command.h>
+#include <74xx_7xx.h>
+#include <version.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#if defined(CONFIG_CMD_KGDB)
+
+ /*
+ * cache flushing routines for kgdb
+ */
+
+ .globl kgdb_flush_cache_all
+kgdb_flush_cache_all:
+ lis r3,0
+ addis r4,r0,0x0040
+kgdb_flush_loop:
+ lwz r5,0(r3)
+ addi r3,r3,CONFIG_SYS_CACHELINE_SIZE
+ cmp 0,0,r3,r4
+ bne kgdb_flush_loop
+ SYNC
+ mfspr r3,1008
+ ori r3,r3,0x8800
+ mtspr 1008,r3
+ sync
+ blr
+
+ .globl kgdb_flush_cache_range
+kgdb_flush_cache_range:
+ li r5,CONFIG_SYS_CACHELINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,CONFIG_SYS_CACHELINE_SHIFT
+ beqlr
+ mtctr r4
+ mr r6,r3
+1: dcbst 0,r3
+ addi r3,r3,CONFIG_SYS_CACHELINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ mtctr r4
+2: icbi 0,r6
+ addi r6,r6,CONFIG_SYS_CACHELINE_SIZE
+ bdnz 2b
+ SYNC
+ blr
+
+#endif
diff --git a/arch/powerpc/cpu/74xx_7xx/speed.c b/arch/powerpc/cpu/74xx_7xx/speed.c
new file mode 100644
index 0000000..6450c3c
--- /dev/null
+++ b/arch/powerpc/cpu/74xx_7xx/speed.c
@@ -0,0 +1,181 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <74xx_7xx.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+extern unsigned long get_board_bus_clk (void);
+
+static const int hid1_multipliers_x_10[] = {
+ 25, /* 0000 - 2.5x */
+ 75, /* 0001 - 7.5x */
+ 70, /* 0010 - 7x */
+ 10, /* 0011 - bypass */
+ 20, /* 0100 - 2x */
+ 65, /* 0101 - 6.5x */
+ 100, /* 0110 - 10x */
+ 45, /* 0111 - 4.5x */
+ 30, /* 1000 - 3x */
+ 55, /* 1001 - 5.5x */
+ 40, /* 1010 - 4x */
+ 50, /* 1011 - 5x */
+ 80, /* 1100 - 8x */
+ 60, /* 1101 - 6x */
+ 35, /* 1110 - 3.5x */
+ 0 /* 1111 - off */
+};
+
+/* PLL_CFG[0:4] table for cpu 7448/7447A/7455/7457 */
+static const int hid1_74xx_multipliers_x_10[] = {
+ 115, /* 00000 - 11.5x */
+ 170, /* 00001 - 17x */
+ 75, /* 00010 - 7.5x */
+ 150, /* 00011 - 15x */
+ 70, /* 00100 - 7x */
+ 180, /* 00101 - 18x */
+ 10, /* 00110 - bypass */
+ 200, /* 00111 - 20x */
+ 20, /* 01000 - 2x */
+ 210, /* 01001 - 21x */
+ 65, /* 01010 - 6.5x */
+ 130, /* 01011 - 13x */
+ 85, /* 01100 - 8.5x */
+ 240, /* 01101 - 24x */
+ 95, /* 01110 - 9.5x */
+ 90, /* 01111 - 9x */
+ 30, /* 10000 - 3x */
+ 105, /* 10001 - 10.5x */
+ 55, /* 10010 - 5.5x */
+ 110, /* 10011 - 11x */
+ 40, /* 10100 - 4x */
+ 100, /* 10101 - 10x */
+ 50, /* 10110 - 5x */
+ 120, /* 10111 - 12x */
+ 80, /* 11000 - 8x */
+ 140, /* 11001 - 14x */
+ 60, /* 11010 - 6x */
+ 160, /* 11011 - 16x */
+ 135, /* 11100 - 13.5x */
+ 280, /* 11101 - 28x */
+ 0, /* 11110 - off */
+ 125 /* 11111 - 12.5x */
+};
+
+static const int hid1_fx_multipliers_x_10[] = {
+ 00, /* 0000 - off */
+ 00, /* 0001 - off */
+ 10, /* 0010 - bypass */
+ 10, /* 0011 - bypass */
+ 20, /* 0100 - 2x */
+ 25, /* 0101 - 2.5x */
+ 30, /* 0110 - 3x */
+ 35, /* 0111 - 3.5x */
+ 40, /* 1000 - 4x */
+ 45, /* 1001 - 4.5x */
+ 50, /* 1010 - 5x */
+ 55, /* 1011 - 5.5x */
+ 60, /* 1100 - 6x */
+ 65, /* 1101 - 6.5x */
+ 70, /* 1110 - 7x */
+ 75, /* 1111 - 7.5 */
+ 80, /* 10000 - 8x */
+ 85, /* 10001 - 8.5x */
+ 90, /* 10010 - 9x */
+ 95, /* 10011 - 9.5x */
+ 100, /* 10100 - 10x */
+ 110, /* 10101 - 11x */
+ 120, /* 10110 - 12x */
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Measure CPU clock speed (core clock GCLK1, GCLK2)
+ *
+ * (Approx. GCLK frequency in Hz)
+ */
+
+int get_clocks (void)
+{
+ ulong clock = 0;
+
+#ifdef CONFIG_SYS_BUS_CLK
+ gd->bus_clk = CONFIG_SYS_BUS_CLK; /* bus clock is a fixed frequency */
+#else
+ gd->bus_clk = get_board_bus_clk (); /* bus clock is configurable */
+#endif
+
+ /* calculate the clock frequency based upon the CPU type */
+ switch (get_cpu_type()) {
+ case CPU_7447A:
+ case CPU_7448:
+ case CPU_7455:
+ case CPU_7457:
+ /*
+ * Make sure division is done before multiplication to prevent 32-bit
+ * arithmetic overflows which will cause a negative number
+ */
+ clock = (gd->bus_clk / 10) *
+ hid1_74xx_multipliers_x_10[(get_hid1 () >> 12) & 0x1F];
+ break;
+
+ case CPU_750GX:
+ case CPU_750FX:
+ clock = (gd->bus_clk / 10) *
+ hid1_fx_multipliers_x_10[get_hid1 () >> 27];
+ break;
+
+ case CPU_7450:
+ case CPU_740:
+ case CPU_740P:
+ case CPU_745:
+ case CPU_750CX:
+ case CPU_750:
+ case CPU_750P:
+ case CPU_755:
+ case CPU_7400:
+ case CPU_7410:
+ /*
+ * Make sure division is done before multiplication to prevent 32-bit
+ * arithmetic overflows which will cause a negative number
+ */
+ clock = (gd->bus_clk / 10) *
+ hid1_multipliers_x_10[get_hid1 () >> 28];
+ break;
+
+ case CPU_UNKNOWN:
+ printf ("get_gclk_freq(): unknown CPU type\n");
+ clock = 0;
+ return (1);
+ }
+
+ gd->cpu_clk = clock;
+
+ return (0);
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/arch/powerpc/cpu/74xx_7xx/start.S b/arch/powerpc/cpu/74xx_7xx/start.S
new file mode 100644
index 0000000..cd8dea8
--- /dev/null
+++ b/arch/powerpc/cpu/74xx_7xx/start.S
@@ -0,0 +1,856 @@
+/*
+ * Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2000,2001,2002 Wolfgang Denk <wd@denx.de>
+ * Copyright (C) 2001 Josh Huber <huber@mclx.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* U-Boot - Startup Code for PowerPC based Embedded Boards
+ *
+ *
+ * The processor starts at 0xfff00100 and the code is executed
+ * from flash. The code is organized to be at an other address
+ * in memory, but as long we don't jump around before relocating.
+ * board_init lies at a quite high address and when the cpu has
+ * jumped there, everything is ok.
+ */
+#include <asm-offsets.h>
+#include <config.h>
+#include <74xx_7xx.h>
+#include <version.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+#include <asm/u-boot.h>
+
+#if !defined(CONFIG_DB64360) && \
+ !defined(CONFIG_DB64460) && \
+ !defined(CONFIG_CPCI750) && \
+ !defined(CONFIG_P3Mx)
+#include <galileo/gt64260R.h>
+#endif
+
+/* We don't want the MMU yet.
+*/
+#undef MSR_KERNEL
+/* Machine Check and Recoverable Interr. */
+#define MSR_KERNEL ( MSR_ME | MSR_RI )
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+ START_GOT
+ GOT_ENTRY(_GOT2_TABLE_)
+ GOT_ENTRY(_FIXUP_TABLE_)
+
+ GOT_ENTRY(_start)
+ GOT_ENTRY(_start_of_vectors)
+ GOT_ENTRY(_end_of_vectors)
+ GOT_ENTRY(transfer_to_handler)
+
+ GOT_ENTRY(__init_end)
+ GOT_ENTRY(__bss_end)
+ GOT_ENTRY(__bss_start)
+ END_GOT
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+ .text
+ .long 0x27051956 /* U-Boot Magic Number */
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION_STRING, "\0"
+
+ . = EXC_OFF_SYS_RESET
+ .globl _start
+_start:
+ b boot_cold
+
+ /* the boot code is located below the exception table */
+
+ .globl _start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. "Never" generated on the 860. */
+ STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. "Never" generated on the 860. */
+ STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+ STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+ . = 0x600
+Alignment:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+ . = 0x700
+ProgramCheck:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+ MSR_KERNEL, COPY_EE)
+
+ /* No FPU on MPC8xx. This exception is not supposed to happen.
+ */
+ STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+ /* I guess we could implement decrementer, and may have
+ * to someday for timekeeping.
+ */
+ STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+ STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+ STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+ STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+ STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+ STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+ STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+ /*
+ * On the MPC8xx, this is a software emulation interrupt. It
+ * occurs for all unimplemented and illegal instructions.
+ */
+ STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException)
+
+ STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
+ STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
+
+ STD_EXCEPTION(0x1500, Reserved5, UnknownException)
+ STD_EXCEPTION(0x1600, Reserved6, UnknownException)
+ STD_EXCEPTION(0x1700, Reserved7, UnknownException)
+ STD_EXCEPTION(0x1800, Reserved8, UnknownException)
+ STD_EXCEPTION(0x1900, Reserved9, UnknownException)
+ STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
+ STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
+
+ STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1d00, InstructionBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
+
+ .globl _end_of_vectors
+_end_of_vectors:
+
+ . = 0x2000
+
+boot_cold:
+ /* disable everything */
+ li r0, 0
+ mtspr HID0, r0
+ sync
+ mtmsr 0
+ bl invalidate_bats
+ sync
+
+#ifdef CONFIG_SYS_L2
+ /* init the L2 cache */
+ addis r3, r0, L2_INIT@h
+ ori r3, r3, L2_INIT@l
+ sync
+ mtspr l2cr, r3
+#endif
+#if defined(CONFIG_ALTIVEC) && defined(CONFIG_74xx)
+ .long 0x7e00066c
+ /*
+ * dssall instruction, gas doesn't have it yet
+ * ...for altivec, data stream stop all this probably
+ * isn't needed unless we warm (software) reboot U-Boot
+ */
+#endif
+
+#ifdef CONFIG_SYS_L2
+ /* invalidate the L2 cache */
+ bl l2cache_invalidate
+ sync
+#endif
+#ifdef CONFIG_SYS_BOARD_ASM_INIT
+ /* do early init */
+ bl board_asm_init
+#endif
+
+ /*
+ * Calculate absolute address in FLASH and jump there
+ *------------------------------------------------------*/
+ lis r3, CONFIG_SYS_MONITOR_BASE@h
+ ori r3, r3, CONFIG_SYS_MONITOR_BASE@l
+ addi r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
+ mtlr r3
+ blr
+
+in_flash:
+ /* let the C-code set up the rest */
+ /* */
+ /* Be careful to keep code relocatable ! */
+ /*------------------------------------------------------*/
+
+ /* perform low-level init */
+ /* sdram init, galileo init, etc */
+ /* r3: NHR bit from HID0 */
+
+ /* setup the bats */
+ bl setup_bats
+ sync
+
+ /*
+ * Cache must be enabled here for stack-in-cache trick.
+ * This means we need to enable the BATS.
+ * This means:
+ * 1) for the EVB, original gt regs need to be mapped
+ * 2) need to have an IBAT for the 0xf region,
+ * we are running there!
+ * Cache should be turned on after BATs, since by default
+ * everything is write-through.
+ * The init-mem BAT can be reused after reloc. The old
+ * gt-regs BAT can be reused after board_init_f calls
+ * board_early_init_f (EVB only).
+ */
+#if !defined(CONFIG_BAB7xx) && !defined(CONFIG_ELPPC) && !defined(CONFIG_P3Mx)
+ /* enable address translation */
+ bl enable_addr_trans
+ sync
+
+ /* enable and invalidate the data cache */
+ bl l1dcache_enable
+ sync
+#endif
+#ifdef CONFIG_SYS_INIT_RAM_LOCK
+ bl lock_ram_in_cache
+ sync
+#endif
+
+ /* set up the stack pointer in our newly created
+ * cache-ram (r1) */
+ lis r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@h
+ ori r1, r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@l
+
+ li r0, 0 /* Make room for stack frame header and */
+ stwu r0, -4(r1) /* clear final stack frame so that */
+ stwu r0, -4(r1) /* stack backtraces terminate cleanly */
+
+ GET_GOT /* initialize GOT access */
+
+ /* run low-level CPU init code (from Flash) */
+ bl cpu_init_f
+ sync
+
+ /* run 1st part of board init code (from Flash) */
+ bl board_init_f
+ sync
+
+ /* NOTREACHED - board_init_f() does not return */
+
+ .globl invalidate_bats
+invalidate_bats:
+ /* invalidate BATs */
+ mtspr IBAT0U, r0
+ mtspr IBAT1U, r0
+ mtspr IBAT2U, r0
+ mtspr IBAT3U, r0
+#ifdef CONFIG_HIGH_BATS
+ mtspr IBAT4U, r0
+ mtspr IBAT5U, r0
+ mtspr IBAT6U, r0
+ mtspr IBAT7U, r0
+#endif
+ isync
+ mtspr DBAT0U, r0
+ mtspr DBAT1U, r0
+ mtspr DBAT2U, r0
+ mtspr DBAT3U, r0
+#ifdef CONFIG_HIGH_BATS
+ mtspr DBAT4U, r0
+ mtspr DBAT5U, r0
+ mtspr DBAT6U, r0
+ mtspr DBAT7U, r0
+#endif
+ isync
+ sync
+ blr
+
+ /* setup_bats - set them up to some initial state */
+ .globl setup_bats
+setup_bats:
+ addis r0, r0, 0x0000
+
+ /* IBAT 0 */
+ addis r4, r0, CONFIG_SYS_IBAT0L@h
+ ori r4, r4, CONFIG_SYS_IBAT0L@l
+ addis r3, r0, CONFIG_SYS_IBAT0U@h
+ ori r3, r3, CONFIG_SYS_IBAT0U@l
+ mtspr IBAT0L, r4
+ mtspr IBAT0U, r3
+ isync
+
+ /* DBAT 0 */
+ addis r4, r0, CONFIG_SYS_DBAT0L@h
+ ori r4, r4, CONFIG_SYS_DBAT0L@l
+ addis r3, r0, CONFIG_SYS_DBAT0U@h
+ ori r3, r3, CONFIG_SYS_DBAT0U@l
+ mtspr DBAT0L, r4
+ mtspr DBAT0U, r3
+ isync
+
+ /* IBAT 1 */
+ addis r4, r0, CONFIG_SYS_IBAT1L@h
+ ori r4, r4, CONFIG_SYS_IBAT1L@l
+ addis r3, r0, CONFIG_SYS_IBAT1U@h
+ ori r3, r3, CONFIG_SYS_IBAT1U@l
+ mtspr IBAT1L, r4
+ mtspr IBAT1U, r3
+ isync
+
+ /* DBAT 1 */
+ addis r4, r0, CONFIG_SYS_DBAT1L@h
+ ori r4, r4, CONFIG_SYS_DBAT1L@l
+ addis r3, r0, CONFIG_SYS_DBAT1U@h
+ ori r3, r3, CONFIG_SYS_DBAT1U@l
+ mtspr DBAT1L, r4
+ mtspr DBAT1U, r3
+ isync
+
+ /* IBAT 2 */
+ addis r4, r0, CONFIG_SYS_IBAT2L@h
+ ori r4, r4, CONFIG_SYS_IBAT2L@l
+ addis r3, r0, CONFIG_SYS_IBAT2U@h
+ ori r3, r3, CONFIG_SYS_IBAT2U@l
+ mtspr IBAT2L, r4
+ mtspr IBAT2U, r3
+ isync
+
+ /* DBAT 2 */
+ addis r4, r0, CONFIG_SYS_DBAT2L@h
+ ori r4, r4, CONFIG_SYS_DBAT2L@l
+ addis r3, r0, CONFIG_SYS_DBAT2U@h
+ ori r3, r3, CONFIG_SYS_DBAT2U@l
+ mtspr DBAT2L, r4
+ mtspr DBAT2U, r3
+ isync
+
+ /* IBAT 3 */
+ addis r4, r0, CONFIG_SYS_IBAT3L@h
+ ori r4, r4, CONFIG_SYS_IBAT3L@l
+ addis r3, r0, CONFIG_SYS_IBAT3U@h
+ ori r3, r3, CONFIG_SYS_IBAT3U@l
+ mtspr IBAT3L, r4
+ mtspr IBAT3U, r3
+ isync
+
+ /* DBAT 3 */
+ addis r4, r0, CONFIG_SYS_DBAT3L@h
+ ori r4, r4, CONFIG_SYS_DBAT3L@l
+ addis r3, r0, CONFIG_SYS_DBAT3U@h
+ ori r3, r3, CONFIG_SYS_DBAT3U@l
+ mtspr DBAT3L, r4
+ mtspr DBAT3U, r3
+ isync
+
+#ifdef CONFIG_HIGH_BATS
+ /* IBAT 4 */
+ addis r4, r0, CONFIG_SYS_IBAT4L@h
+ ori r4, r4, CONFIG_SYS_IBAT4L@l
+ addis r3, r0, CONFIG_SYS_IBAT4U@h
+ ori r3, r3, CONFIG_SYS_IBAT4U@l
+ mtspr IBAT4L, r4
+ mtspr IBAT4U, r3
+ isync
+
+ /* DBAT 4 */
+ addis r4, r0, CONFIG_SYS_DBAT4L@h
+ ori r4, r4, CONFIG_SYS_DBAT4L@l
+ addis r3, r0, CONFIG_SYS_DBAT4U@h
+ ori r3, r3, CONFIG_SYS_DBAT4U@l
+ mtspr DBAT4L, r4
+ mtspr DBAT4U, r3
+ isync
+
+ /* IBAT 5 */
+ addis r4, r0, CONFIG_SYS_IBAT5L@h
+ ori r4, r4, CONFIG_SYS_IBAT5L@l
+ addis r3, r0, CONFIG_SYS_IBAT5U@h
+ ori r3, r3, CONFIG_SYS_IBAT5U@l
+ mtspr IBAT5L, r4
+ mtspr IBAT5U, r3
+ isync
+
+ /* DBAT 5 */
+ addis r4, r0, CONFIG_SYS_DBAT5L@h
+ ori r4, r4, CONFIG_SYS_DBAT5L@l
+ addis r3, r0, CONFIG_SYS_DBAT5U@h
+ ori r3, r3, CONFIG_SYS_DBAT5U@l
+ mtspr DBAT5L, r4
+ mtspr DBAT5U, r3
+ isync
+
+ /* IBAT 6 */
+ addis r4, r0, CONFIG_SYS_IBAT6L@h
+ ori r4, r4, CONFIG_SYS_IBAT6L@l
+ addis r3, r0, CONFIG_SYS_IBAT6U@h
+ ori r3, r3, CONFIG_SYS_IBAT6U@l
+ mtspr IBAT6L, r4
+ mtspr IBAT6U, r3
+ isync
+
+ /* DBAT 6 */
+ addis r4, r0, CONFIG_SYS_DBAT6L@h
+ ori r4, r4, CONFIG_SYS_DBAT6L@l
+ addis r3, r0, CONFIG_SYS_DBAT6U@h
+ ori r3, r3, CONFIG_SYS_DBAT6U@l
+ mtspr DBAT6L, r4
+ mtspr DBAT6U, r3
+ isync
+
+ /* IBAT 7 */
+ addis r4, r0, CONFIG_SYS_IBAT7L@h
+ ori r4, r4, CONFIG_SYS_IBAT7L@l
+ addis r3, r0, CONFIG_SYS_IBAT7U@h
+ ori r3, r3, CONFIG_SYS_IBAT7U@l
+ mtspr IBAT7L, r4
+ mtspr IBAT7U, r3
+ isync
+
+ /* DBAT 7 */
+ addis r4, r0, CONFIG_SYS_DBAT7L@h
+ ori r4, r4, CONFIG_SYS_DBAT7L@l
+ addis r3, r0, CONFIG_SYS_DBAT7U@h
+ ori r3, r3, CONFIG_SYS_DBAT7U@l
+ mtspr DBAT7L, r4
+ mtspr DBAT7U, r3
+ isync
+#endif
+
+ /* bats are done, now invalidate the TLBs */
+
+ addis r3, 0, 0x0000
+ addis r5, 0, 0x4 /* upper bound of 0x00040000 for 7400/750 */
+
+ isync
+
+tlblp:
+ tlbie r3
+ sync
+ addi r3, r3, 0x1000
+ cmp 0, 0, r3, r5
+ blt tlblp
+
+ blr
+
+ .globl enable_addr_trans
+enable_addr_trans:
+ /* enable address translation */
+ mfmsr r5
+ ori r5, r5, (MSR_IR | MSR_DR)
+ mtmsr r5
+ isync
+ blr
+
+ .globl disable_addr_trans
+disable_addr_trans:
+ /* disable address translation */
+ mflr r4
+ mfmsr r3
+ andi. r0, r3, (MSR_IR | MSR_DR)
+ beqlr
+ andc r3, r3, r0
+ mtspr SRR0, r4
+ mtspr SRR1, r3
+ rfi
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+ .globl transfer_to_handler
+transfer_to_handler:
+ stw r22,_NIP(r21)
+ lis r22,MSR_POW@h
+ andc r23,r23,r22
+ stw r23,_MSR(r21)
+ SAVE_GPR(7, r21)
+ SAVE_4GPRS(8, r21)
+ SAVE_8GPRS(12, r21)
+ SAVE_8GPRS(24, r21)
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ mtspr SPRG2,r22 /* r1 is now kernel sp */
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
+
+int_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+
+ .globl dc_read
+dc_read:
+ blr
+
+ .globl get_pvr
+get_pvr:
+ mfspr r3, PVR
+ blr
+
+/*-----------------------------------------------------------------------*/
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+ .globl relocate_code
+relocate_code:
+ mr r1, r3 /* Set new stack pointer */
+ mr r9, r4 /* Save copy of Global Data pointer */
+ mr r10, r5 /* Save copy of Destination Address */
+
+ GET_GOT
+ mr r3, r5 /* Destination Address */
+ lis r4, CONFIG_SYS_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CONFIG_SYS_MONITOR_BASE@l
+ lwz r5, GOT(__init_end)
+ sub r5, r5, r4
+ li r6, CONFIG_SYS_CACHELINE_SIZE /* Cache Line Size */
+
+ /*
+ * Fix GOT pointer:
+ *
+ * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+ *
+ * Offset:
+ */
+ sub r15, r10, r4
+
+ /* First our own GOT */
+ add r12, r12, r15
+ /* then the one used by the C code */
+ add r30, r30, r15
+
+ /*
+ * Now relocate code
+ */
+#ifdef CONFIG_ECC
+ bl board_relocate_rom
+ sync
+ mr r3, r10 /* Destination Address */
+ lis r4, CONFIG_SYS_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CONFIG_SYS_MONITOR_BASE@l
+ lwz r5, GOT(__init_end)
+ sub r5, r5, r4
+ li r6, CONFIG_SYS_CACHELINE_SIZE /* Cache Line Size */
+#else
+ cmplw cr1,r3,r4
+ addi r0,r5,3
+ srwi. r0,r0,2
+ beq cr1,4f /* In place copy is not necessary */
+ beq 7f /* Protect against 0 count */
+ mtctr r0
+ bge cr1,2f
+
+ la r8,-4(r4)
+ la r7,-4(r3)
+1: lwzu r0,4(r8)
+ stwu r0,4(r7)
+ bdnz 1b
+ b 4f
+
+2: slwi r0,r0,2
+ add r8,r4,r0
+ add r7,r3,r0
+3: lwzu r0,-4(r8)
+ stwu r0,-4(r7)
+ bdnz 3b
+#endif
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4: cmpwi r6,0
+ add r5,r3,r5
+ beq 7f /* Always flush prefetch queue in any case */
+ subi r0,r6,1
+ andc r3,r3,r0
+ mr r4,r3
+5: dcbst 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 5b
+ sync /* Wait for all dcbst to complete on bus */
+ mr r4,r3
+6: icbi 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 6b
+7: sync /* Wait for all icbi to complete on bus */
+ isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+ addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+ mtlr r0
+ blr
+
+in_ram:
+#ifdef CONFIG_ECC
+ bl board_init_ecc
+#endif
+ /*
+ * Relocation Function, r12 point to got2+0x8000
+ *
+ * Adjust got2 pointers, no need to check for 0, this code
+ * already puts a few entries in the table.
+ */
+ li r0,__got2_entries@sectoff@l
+ la r3,GOT(_GOT2_TABLE_)
+ lwz r11,GOT(_GOT2_TABLE_)
+ mtctr r0
+ sub r11,r3,r11
+ addi r3,r3,-4
+1: lwzu r0,4(r3)
+ cmpwi r0,0
+ beq- 2f
+ add r0,r0,r11
+ stw r0,0(r3)
+2: bdnz 1b
+
+ /*
+ * Now adjust the fixups and the pointers to the fixups
+ * in case we need to move ourselves again.
+ */
+ li r0,__fixup_entries@sectoff@l
+ lwz r3,GOT(_FIXUP_TABLE_)
+ cmpwi r0,0
+ mtctr r0
+ addi r3,r3,-4
+ beq 4f
+3: lwzu r4,4(r3)
+ lwzux r0,r4,r11
+ cmpwi r0,0
+ add r0,r0,r11
+ stw r4,0(r3)
+ beq- 5f
+ stw r0,0(r4)
+5: bdnz 3b
+4:
+/* clear_bss: */
+ /*
+ * Now clear BSS segment
+ */
+ lwz r3,GOT(__bss_start)
+ lwz r4,GOT(__bss_end)
+
+ cmplw 0, r3, r4
+ beq 6f
+
+ li r0, 0
+5:
+ stw r0, 0(r3)
+ addi r3, r3, 4
+ cmplw 0, r3, r4
+ bne 5b
+6:
+ mr r3, r10 /* Destination Address */
+#if defined(CONFIG_DB64360) || \
+ defined(CONFIG_DB64460) || \
+ defined(CONFIG_CPCI750) || \
+ defined(CONFIG_PPMC7XX) || \
+ defined(CONFIG_P3Mx)
+ mr r4, r9 /* Use RAM copy of the global data */
+#endif
+ bl after_reloc
+
+ /* not reached - end relocate_code */
+/*-----------------------------------------------------------------------*/
+
+ /*
+ * Copy exception vector code to low memory
+ *
+ * r3: dest_addr
+ * r7: source address, r8: end address, r9: target address
+ */
+ .globl trap_init
+trap_init:
+ mflr r4 /* save link register */
+ GET_GOT
+ lwz r7, GOT(_start)
+ lwz r8, GOT(_end_of_vectors)
+
+ li r9, 0x100 /* reset vector always at 0x100 */
+
+ cmplw 0, r7, r8
+ bgelr /* return if r7>=r8 - just in case */
+1:
+ lwz r0, 0(r7)
+ stw r0, 0(r9)
+ addi r7, r7, 4
+ addi r9, r9, 4
+ cmplw 0, r7, r8
+ bne 1b
+
+ /*
+ * relocate `hdlr' and `int_return' entries
+ */
+ li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+ li r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 2b
+
+ li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+ li r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 3b
+
+ li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+ li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 4b
+
+ /* enable execptions from RAM vectors */
+ mfmsr r7
+ li r8,MSR_IP
+ andc r7,r7,r8
+ mtmsr r7
+
+ mtlr r4 /* restore link register */
+ blr
+
+#ifdef CONFIG_SYS_INIT_RAM_LOCK
+lock_ram_in_cache:
+ /* Allocate Initial RAM in data cache.
+ */
+ lis r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@h
+ ori r3, r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@l
+ li r4, ((CONFIG_SYS_INIT_RAM_SIZE & ~31) + \
+ (CONFIG_SYS_INIT_RAM_ADDR & 31) + 31) / 32
+ mtctr r4
+1:
+ dcbz r0, r3
+ addi r3, r3, 32
+ bdnz 1b
+
+ /* Lock the data cache */
+ mfspr r0, HID0
+ ori r0, r0, 0x1000
+ sync
+ mtspr HID0, r0
+ sync
+ blr
+
+.globl unlock_ram_in_cache
+unlock_ram_in_cache:
+ /* invalidate the INIT_RAM section */
+ lis r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@h
+ ori r3, r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@l
+ li r4, ((CONFIG_SYS_INIT_RAM_SIZE & ~31) + \
+ (CONFIG_SYS_INIT_RAM_ADDR & 31) + 31) / 32
+ mtctr r4
+1: icbi r0, r3
+ addi r3, r3, 32
+ bdnz 1b
+ sync /* Wait for all icbi to complete on bus */
+ isync
+
+ /* Unlock the data cache and invalidate it */
+ mfspr r0, HID0
+ li r3,0x1000
+ andc r0,r0,r3
+ li r3,0x0400
+ or r0,r0,r3
+ sync
+ mtspr HID0, r0
+ sync
+ blr
+#endif
diff --git a/arch/powerpc/cpu/74xx_7xx/traps.c b/arch/powerpc/cpu/74xx_7xx/traps.c
new file mode 100644
index 0000000..a33e283
--- /dev/null
+++ b/arch/powerpc/cpu/74xx_7xx/traps.c
@@ -0,0 +1,234 @@
+/*
+ * linux/arch/powerpc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM 0x02000000
+
+/*
+ * Trap & Exception support
+ */
+
+static void print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ printf("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ printf("\n");
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *)*sp;
+ }
+ printf("\n");
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ int i;
+
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS:"
+ " %p TRAP: %04lx DAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP:"
+ " %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+ regs->msr&MSR_IR ? 1 : 0,
+ regs->msr&MSR_DR ? 1 : 0);
+
+ printf("\n");
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0)
+ {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7)
+ {
+ printf("\n");
+ }
+ }
+}
+
+
+static void _exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup;
+
+ /* Probing PCI using config cycles cause this exception
+ * when a device is not present. Catch it and return to
+ * the PCI exception handler.
+ */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ return;
+ }
+
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ printf("Machine check in kernel mode.\n");
+ printf("Caused by (from msr): ");
+ printf("regs %p ",regs);
+ switch( regs->msr & 0x000F0000) {
+ case (0x80000000>>12):
+ printf("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (0x80000000>>13):
+ printf("Transfer error ack signal\n");
+ break;
+ case (0x80000000>>14):
+ printf("Data parity signal\n");
+ break;
+ case (0x80000000>>15):
+ printf("Address parity signal\n");
+ break;
+ default:
+ printf("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("machine check");
+}
+
+void AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void ProgramCheckException(struct pt_regs *regs)
+{
+ unsigned char *p = regs ? (unsigned char *)(regs->nip) : NULL;
+ int i, j;
+
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+
+ p = (unsigned char *) ((unsigned long)p & 0xFFFFFFE0);
+ p -= 32;
+ for (i = 0; i < 256; i+=16) {
+ printf("%08x: ", (unsigned int)p+i);
+ for (j = 0; j < 16; j++) {
+ printf("%02x ", p[i+j]);
+ }
+ printf("\n");
+ }
+
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void SoftEmuException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Software Emulation Exception");
+}
+
+void UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+/* Probe an address by reading. If not present, return -1, otherwise
+ * return 0.
+ */
+int addr_probe(uint *addr)
+{
+#if 0
+ int retval;
+
+ __asm__ __volatile__( \
+ "1: lwz %0,0(%1)\n" \
+ " eieio\n" \
+ " li %0,0\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,-1\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r" (retval) : "r"(addr));
+
+ return (retval);
+#endif
+ return 0;
+}
diff --git a/arch/powerpc/cpu/74xx_7xx/u-boot.lds b/arch/powerpc/cpu/74xx_7xx/u-boot.lds
new file mode 100644
index 0000000..40b89ab
--- /dev/null
+++ b/arch/powerpc/cpu/74xx_7xx/u-boot.lds
@@ -0,0 +1,94 @@
+/*
+ * (C) Copyright 2010 Wolfgang Denk <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+
+SECTIONS
+{
+ .text :
+ {
+ arch/powerpc/cpu/74xx_7xx/start.o (.text*)
+
+ *(.text*)
+ }
+ _etext = .;
+ PROVIDE (etext = .);
+ .rodata :
+ {
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ }
+
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x00FF) & 0xFFFFFF00;
+ _erotext = .;
+ PROVIDE (erotext = .);
+ .reloc :
+ {
+ _GOT2_TABLE_ = .;
+ KEEP(*(.got2))
+ KEEP(*(.got))
+ PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
+ _FIXUP_TABLE_ = .;
+ KEEP(*(.fixup))
+ }
+ __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
+ __fixup_entries = (. - _FIXUP_TABLE_)>>2;
+
+ .data :
+ {
+ *(.data*)
+ *(.sdata*)
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+
+ . = .;
+
+ . = ALIGN(4);
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+
+ . = .;
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ . = ALIGN(256);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(256);
+ __init_end = .;
+
+ __bss_start = .;
+ .bss (NOLOAD) :
+ {
+ *(.bss*)
+ *(.sbss*)
+ *(COMMON)
+ . = ALIGN(4);
+ }
+ __bss_end = . ;
+ PROVIDE (end = .);
+}
diff --git a/arch/powerpc/cpu/mpc512x/Makefile b/arch/powerpc/cpu/mpc512x/Makefile
new file mode 100644
index 0000000..4f4c9ec
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/Makefile
@@ -0,0 +1,63 @@
+#
+# (C) Copyright 2007-2009 DENX Software Engineering
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+$(shell mkdir -p $(OBJTREE)/board/freescale/common)
+
+LIB = $(obj)lib$(CPU).o
+
+START = start.o
+COBJS-y := cpu.o
+COBJS-y += traps.o
+COBJS-y += cpu_init.o
+COBJS-y += fixed_sdram.o
+COBJS-y += i2c.o
+COBJS-y += interrupts.o
+COBJS-y += iopin.o
+COBJS-y += serial.o
+COBJS-y += speed.o
+COBJS-$(CONFIG_FSL_DIU_FB) += diu.o
+COBJS-$(CONFIG_CMD_IDE) += ide.o
+COBJS-$(CONFIG_PCI) += pci.o
+
+# Stub implementations of cache management functions for USB
+COBJS-$(CONFIG_USB_EHCI) += cache.o
+
+COBJS := $(COBJS-y)
+SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
+START := $(addprefix $(obj),$(START))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/powerpc/cpu/mpc512x/asm-offsets.h b/arch/powerpc/cpu/mpc512x/asm-offsets.h
new file mode 100644
index 0000000..957d4be
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/asm-offsets.h
@@ -0,0 +1,15 @@
+/*
+ * needed for arch/powerpc/cpu/mpc512x/start.S
+ *
+ * These should be auto-generated
+ */
+#define LPCS0AW 0x0024
+#define SRAMBAR 0x00C4
+#define SWCRR 0x0904
+#define LPC_OFFSET 0x10000
+#define CS0_CONFIG 0x00000
+#define CS_CTRL 0x00020
+#define CS_CTRL_ME 0x01000000 /* CS Master Enable bit */
+
+#define EXC_OFF_SYS_RESET 0x0100
+#define _START_OFFSET EXC_OFF_SYS_RESET
diff --git a/arch/powerpc/cpu/mpc512x/cache.c b/arch/powerpc/cpu/mpc512x/cache.c
new file mode 100644
index 0000000..2a08b65
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/cache.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 Marek Vasut <marex@denx.de>
+ *
+ * This file contains stub implementation of
+ * invalidate_dcache_range()
+ * flush_dcache_range()
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+}
diff --git a/arch/powerpc/cpu/mpc512x/config.mk b/arch/powerpc/cpu/mpc512x/config.mk
new file mode 100644
index 0000000..8fceded
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/config.mk
@@ -0,0 +1,26 @@
+#
+# (C) Copyright 2007-2010 DENX Software Engineering
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_RELFLAGS += -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_MPC512X -DCONFIG_E300 \
+ -ffixed-r2 -msoft-float -mcpu=603e
diff --git a/arch/powerpc/cpu/mpc512x/cpu.c b/arch/powerpc/cpu/mpc512x/cpu.c
new file mode 100644
index 0000000..bb03c6d
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/cpu.c
@@ -0,0 +1,216 @@
+/*
+ * (C) Copyright 2007-2010 DENX Software Engineering
+ * Copyright (C) 2004-2006 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * CPU specific code for the MPC512x family.
+ *
+ * Derived from the MPC83xx code.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <netdev.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <fdt_support.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int checkcpu (void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ ulong clock = gd->cpu_clk;
+ u32 pvr = get_pvr ();
+ u32 spridr = in_be32(&immr->sysconf.spridr);
+ char buf1[32], buf2[32];
+
+ puts ("CPU: ");
+
+ switch (spridr & 0xffff0000) {
+ case SPR_5121E:
+ puts ("MPC5121e ");
+ break;
+ default:
+ printf ("Unknown part ID %08x ", spridr & 0xffff0000);
+ }
+ printf ("rev. %d.%d, Core ", SVR_MJREV (spridr), SVR_MNREV (spridr));
+
+ switch (pvr & 0xffff0000) {
+ case PVR_E300C4:
+ puts ("e300c4 ");
+ break;
+ default:
+ puts ("unknown ");
+ }
+ printf ("at %s MHz, CSB at %s MHz (RSR=0x%04lx)\n",
+ strmhz(buf1, clock),
+ strmhz(buf2, gd->arch.csb_clk),
+ gd->arch.reset_status & 0xffff);
+ return 0;
+}
+
+
+int
+do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong msr;
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+ /* Interrupts and MMU off */
+ __asm__ __volatile__ ("mfmsr %0":"=r" (msr):);
+
+ msr &= ~( MSR_EE | MSR_IR | MSR_DR);
+ __asm__ __volatile__ ("mtmsr %0"::"r" (msr));
+
+ /*
+ * Enable Reset Control Reg - "RSTE" is the magic word that let us go
+ */
+ out_be32(&immap->reset.rpr, 0x52535445);
+
+ /* Verify Reset Control Reg is enabled */
+ while (!(in_be32(&immap->reset.rcer) & RCER_CRE))
+ ;
+
+ printf ("Resetting the board.\n");
+ udelay(200);
+
+ /* Perform reset */
+ out_be32(&immap->reset.rcr, RCR_SWHR);
+
+ /* Unreached... */
+ return 1;
+}
+
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ */
+unsigned long get_tbclk (void)
+{
+ ulong tbclk;
+
+ tbclk = (gd->bus_clk + 3L) / 4L;
+
+ return tbclk;
+}
+
+
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset (void)
+{
+ int re_enable = disable_interrupts ();
+
+ /* Reset watchdog */
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ out_be32(&immr->wdt.swsrr, 0x556c);
+ out_be32(&immr->wdt.swsrr, 0xaa39);
+
+ if (re_enable)
+ enable_interrupts ();
+}
+#endif
+
+#ifdef CONFIG_OF_LIBFDT
+
+#ifdef CONFIG_OF_SUPPORT_OLD_DEVICE_TREES
+/*
+ * fdt setup for old device trees
+ * fix up
+ * cpu clocks
+ * soc clocks
+ * ethernet addresses
+ */
+static void old_ft_cpu_setup(void *blob, bd_t *bd)
+{
+ /*
+ * avoid fixing up by path because that
+ * produces scary error messages
+ */
+ uchar enetaddr[6];
+
+ /*
+ * old device trees have ethernet nodes with
+ * device_type = "network"
+ */
+ eth_getenv_enetaddr("ethaddr", enetaddr);
+ do_fixup_by_prop(blob, "device_type", "network", 8,
+ "local-mac-address", enetaddr, 6, 0);
+ do_fixup_by_prop(blob, "device_type", "network", 8,
+ "address", enetaddr, 6, 0);
+ /*
+ * old device trees have soc nodes with
+ * device_type = "soc"
+ */
+ do_fixup_by_prop_u32(blob, "device_type", "soc", 4,
+ "bus-frequency", bd->bi_ipsfreq, 0);
+}
+#endif
+
+static void ft_clock_setup(void *blob, bd_t *bd)
+{
+ char *cpu_path = "/cpus/" OF_CPU;
+
+ /*
+ * fixup cpu clocks using path
+ */
+ do_fixup_by_path_u32(blob, cpu_path,
+ "timebase-frequency", OF_TBCLK, 1);
+ do_fixup_by_path_u32(blob, cpu_path,
+ "bus-frequency", bd->bi_busfreq, 1);
+ do_fixup_by_path_u32(blob, cpu_path,
+ "clock-frequency", bd->bi_intfreq, 1);
+ /*
+ * fixup soc clocks using compatible
+ */
+ do_fixup_by_compat_u32(blob, OF_SOC_COMPAT,
+ "bus-frequency", bd->bi_ipsfreq, 1);
+}
+
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+#ifdef CONFIG_OF_SUPPORT_OLD_DEVICE_TREES
+ old_ft_cpu_setup(blob, bd);
+#endif
+ ft_clock_setup(blob, bd);
+#ifdef CONFIG_HAS_ETH0
+ fdt_fixup_ethernet(blob);
+#endif
+ fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+}
+#endif
+
+#ifdef CONFIG_MPC512x_FEC
+/* Default initializations for FEC controllers. To override,
+ * create a board-specific function called:
+ * int board_eth_init(bd_t *bis)
+ */
+
+int cpu_eth_init(bd_t *bis)
+{
+ return mpc512x_fec_initialize(bis);
+}
+#endif
diff --git a/arch/powerpc/cpu/mpc512x/cpu_init.c b/arch/powerpc/cpu/mpc512x/cpu_init.c
new file mode 100644
index 0000000..0e20ded
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/cpu_init.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2004-2006 Freescale Semiconductor, Inc.
+ * Copyright (C) 2007-2009 DENX Software Engineering
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Derived from the MPC83xx code.
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/mpc512x.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Set up the memory map, initialize registers,
+ */
+void cpu_init_f (volatile immap_t * im)
+{
+ u32 ips_div;
+
+ /* Pointer is writable since we allocated a register for it */
+ gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+ /* Clear initial global data */
+ memset ((void *) gd, 0, sizeof (gd_t));
+
+ /* Local Window and chip select configuration */
+#if defined(CONFIG_SYS_CS0_START) && defined(CONFIG_SYS_CS0_SIZE)
+ out_be32(&im->sysconf.lpcs0aw,
+ CSAW_START(CONFIG_SYS_CS0_START) |
+ CSAW_STOP(CONFIG_SYS_CS0_START, CONFIG_SYS_CS0_SIZE));
+ sync_law(&im->sysconf.lpcs0aw);
+#endif
+#if defined(CONFIG_SYS_CS0_CFG)
+ out_be32(&im->lpc.cs_cfg[0], CONFIG_SYS_CS0_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS1_START) && defined(CONFIG_SYS_CS1_SIZE)
+ out_be32(&im->sysconf.lpcs1aw,
+ CSAW_START(CONFIG_SYS_CS1_START) |
+ CSAW_STOP(CONFIG_SYS_CS1_START, CONFIG_SYS_CS1_SIZE));
+ sync_law(&im->sysconf.lpcs1aw);
+#endif
+#if defined(CONFIG_SYS_CS1_CFG)
+ out_be32(&im->lpc.cs_cfg[1], CONFIG_SYS_CS1_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS2_START) && (defined CONFIG_SYS_CS2_SIZE)
+ out_be32(&im->sysconf.lpcs2aw,
+ CSAW_START(CONFIG_SYS_CS2_START) |
+ CSAW_STOP(CONFIG_SYS_CS2_START, CONFIG_SYS_CS2_SIZE));
+ sync_law(&im->sysconf.lpcs2aw);
+#endif
+#if defined(CONFIG_SYS_CS2_CFG)
+ out_be32(&im->lpc.cs_cfg[2], CONFIG_SYS_CS2_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS3_START) && defined(CONFIG_SYS_CS3_SIZE)
+ out_be32(&im->sysconf.lpcs3aw,
+ CSAW_START(CONFIG_SYS_CS3_START) |
+ CSAW_STOP(CONFIG_SYS_CS3_START, CONFIG_SYS_CS3_SIZE));
+ sync_law(&im->sysconf.lpcs3aw);
+#endif
+#if defined(CONFIG_SYS_CS3_CFG)
+ out_be32(&im->lpc.cs_cfg[3], CONFIG_SYS_CS3_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS4_START) && defined(CONFIG_SYS_CS4_SIZE)
+ out_be32(&im->sysconf.lpcs4aw,
+ CSAW_START(CONFIG_SYS_CS4_START) |
+ CSAW_STOP(CONFIG_SYS_CS4_START, CONFIG_SYS_CS4_SIZE));
+ sync_law(&im->sysconf.lpcs4aw);
+#endif
+#if defined(CONFIG_SYS_CS4_CFG)
+ out_be32(&im->lpc.cs_cfg[4], CONFIG_SYS_CS4_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS5_START) && defined(CONFIG_SYS_CS5_SIZE)
+ out_be32(&im->sysconf.lpcs5aw,
+ CSAW_START(CONFIG_SYS_CS5_START) |
+ CSAW_STOP(CONFIG_SYS_CS5_START, CONFIG_SYS_CS5_SIZE));
+ sync_law(&im->sysconf.lpcs5aw);
+#endif
+#if defined(CONFIG_SYS_CS5_CFG)
+ out_be32(&im->lpc.cs_cfg[5], CONFIG_SYS_CS5_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS6_START) && defined(CONFIG_SYS_CS6_SIZE)
+ out_be32(&im->sysconf.lpcs6aw,
+ CSAW_START(CONFIG_SYS_CS6_START) |
+ CSAW_STOP(CONFIG_SYS_CS6_START, CONFIG_SYS_CS6_SIZE));
+ sync_law(&im->sysconf.lpcs6aw);
+#endif
+#if defined(CONFIG_SYS_CS6_CFG)
+ out_be32(&im->lpc.cs_cfg[6], CONFIG_SYS_CS6_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS7_START) && defined(CONFIG_SYS_CS7_SIZE)
+ out_be32(&im->sysconf.lpcs7aw,
+ CSAW_START(CONFIG_SYS_CS7_START) |
+ CSAW_STOP(CONFIG_SYS_CS7_START, CONFIG_SYS_CS7_SIZE));
+ sync_law(&im->sysconf.lpcs7aw);
+#endif
+#if defined(CONFIG_SYS_CS7_CFG)
+ out_be32(&im->lpc.cs_cfg[7], CONFIG_SYS_CS7_CFG);
+#endif
+
+#if defined CONFIG_SYS_CS_ALETIMING
+ if (SVR_MJREV(in_be32(&im->sysconf.spridr)) >= 2)
+ out_be32(&im->lpc.altr, CONFIG_SYS_CS_ALETIMING);
+#endif
+#if defined CONFIG_SYS_CS_BURST
+ out_be32(&im->lpc.cs_bcr, CONFIG_SYS_CS_BURST);
+#endif
+#if defined CONFIG_SYS_CS_DEADCYCLE
+ out_be32(&im->lpc.cs_dccr, CONFIG_SYS_CS_DEADCYCLE);
+#endif
+#if defined CONFIG_SYS_CS_HOLDCYCLE
+ out_be32(&im->lpc.cs_hccr, CONFIG_SYS_CS_HOLDCYCLE);
+#endif
+
+ /* system performance tweaking */
+
+#ifdef CONFIG_SYS_ACR_PIPE_DEP
+ /* Arbiter pipeline depth */
+ out_be32(&im->arbiter.acr,
+ (im->arbiter.acr & ~ACR_PIPE_DEP) |
+ (CONFIG_SYS_ACR_PIPE_DEP << ACR_PIPE_DEP_SHIFT)
+ );
+#endif
+
+#ifdef CONFIG_SYS_ACR_RPTCNT
+ /* Arbiter repeat count */
+ out_be32(im->arbiter.acr,
+ (im->arbiter.acr & ~(ACR_RPTCNT)) |
+ (CONFIG_SYS_ACR_RPTCNT << ACR_RPTCNT_SHIFT)
+ );
+#endif
+
+ /* RSR - Reset Status Register - clear all status */
+ gd->arch.reset_status = im->reset.rsr;
+ out_be32(&im->reset.rsr, ~RSR_RES);
+
+ /*
+ * RMR - Reset Mode Register - enable checkstop reset
+ */
+ out_be32(&im->reset.rmr, RMR_CSRE & (1 << RMR_CSRE_SHIFT));
+
+ /* Set IPS-CSB divider: IPS = 1/2 CSB */
+ ips_div = in_be32(&im->clk.scfr[0]);
+ ips_div &= ~(SCFR1_IPS_DIV_MASK);
+ ips_div |= SCFR1_IPS_DIV << SCFR1_IPS_DIV_SHIFT;
+ out_be32(&im->clk.scfr[0], ips_div);
+
+#ifdef SCFR1_LPC_DIV
+ clrsetbits_be32(&im->clk.scfr[0], SCFR1_LPC_DIV_MASK,
+ SCFR1_LPC_DIV << SCFR1_LPC_DIV_SHIFT);
+#endif
+
+#ifdef SCFR1_NFC_DIV
+ clrsetbits_be32(&im->clk.scfr[0], SCFR1_NFC_DIV_MASK,
+ SCFR1_NFC_DIV << SCFR1_NFC_DIV_SHIFT);
+#endif
+
+#ifdef SCFR1_DIU_DIV
+ clrsetbits_be32(&im->clk.scfr[0], SCFR1_DIU_DIV_MASK,
+ SCFR1_DIU_DIV << SCFR1_DIU_DIV_SHIFT);
+#endif
+
+ /*
+ * Enable Time Base/Decrementer
+ *
+ * NOTICE: TB needs to be enabled as early as possible in order to
+ * have udelay() working; if not enabled, usually leads to a hang, like
+ * during FLASH chip identification etc.
+ */
+ setbits_be32(&im->sysconf.spcr, SPCR_TBEN);
+
+ /*
+ * Enable clocks
+ */
+ out_be32(&im->clk.sccr[0], SCCR1_CLOCKS_EN);
+ out_be32(&im->clk.sccr[1], SCCR2_CLOCKS_EN);
+#if defined(CONFIG_FSL_IIM) || defined(CONFIG_CMD_FUSE)
+ setbits_be32(&im->clk.sccr[1], CLOCK_SCCR2_IIM_EN);
+#endif
+}
+
+int cpu_init_r (void)
+{
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc512x/diu.c b/arch/powerpc/cpu/mpc512x/diu.c
new file mode 100644
index 0000000..b7db249
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/diu.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ * York Sun <yorksun@freescale.com>
+ *
+ * FSL DIU Framebuffer driver
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+
+#include <fsl_diu_fb.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void diu_set_pixel_clock(unsigned int pixclock)
+{
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+ volatile clk512x_t *clk = &immap->clk;
+ volatile unsigned int *clkdvdr = &clk->scfr[0];
+ unsigned long speed_ccb, temp, pixval;
+
+ speed_ccb = get_bus_freq(0) * 4;
+ temp = 1000000000/pixclock;
+ temp *= 1000;
+ pixval = speed_ccb / temp;
+ debug("DIU pixval = %lu\n", pixval);
+
+ /* Modify PXCLK in GUTS CLKDVDR */
+ debug("DIU: Current value of CLKDVDR = 0x%08x\n", in_be32(clkdvdr));
+ temp = in_be32(clkdvdr) & 0xFFFFFF00;
+ out_be32(clkdvdr, temp | (pixval & 0xFF));
+ debug("DIU: Modified value of CLKDVDR = 0x%08x\n", in_be32(clkdvdr));
+}
+
+int platform_diu_init(unsigned int xres, unsigned int yres, const char *port)
+{
+ unsigned int pixel_format = 0x88883316;
+
+ debug("mpc5121_diu_init\n");
+ return fsl_diu_init(xres, yres, pixel_format, 0);
+}
diff --git a/arch/powerpc/cpu/mpc512x/fixed_sdram.c b/arch/powerpc/cpu/mpc512x/fixed_sdram.c
new file mode 100644
index 0000000..6635fb0
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/fixed_sdram.c
@@ -0,0 +1,172 @@
+/*
+ * (C) Copyright 2007-2009 DENX Software Engineering
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/mpc512x.h>
+
+/*
+ * MDDRC Config Runtime Settings
+ */
+ddr512x_config_t default_mddrc_config = {
+ .ddr_sys_config = CONFIG_SYS_MDDRC_SYS_CFG,
+ .ddr_time_config0 = CONFIG_SYS_MDDRC_TIME_CFG0,
+ .ddr_time_config1 = CONFIG_SYS_MDDRC_TIME_CFG1,
+ .ddr_time_config2 = CONFIG_SYS_MDDRC_TIME_CFG2,
+};
+
+u32 default_init_seq[] = {
+ CONFIG_SYS_DDRCMD_NOP,
+ CONFIG_SYS_DDRCMD_NOP,
+ CONFIG_SYS_DDRCMD_NOP,
+ CONFIG_SYS_DDRCMD_NOP,
+ CONFIG_SYS_DDRCMD_NOP,
+ CONFIG_SYS_DDRCMD_NOP,
+ CONFIG_SYS_DDRCMD_NOP,
+ CONFIG_SYS_DDRCMD_NOP,
+ CONFIG_SYS_DDRCMD_NOP,
+ CONFIG_SYS_DDRCMD_NOP,
+ CONFIG_SYS_DDRCMD_PCHG_ALL,
+ CONFIG_SYS_DDRCMD_NOP,
+ CONFIG_SYS_DDRCMD_RFSH,
+ CONFIG_SYS_DDRCMD_NOP,
+ CONFIG_SYS_DDRCMD_RFSH,
+ CONFIG_SYS_DDRCMD_NOP,
+ CONFIG_SYS_MICRON_INIT_DEV_OP,
+ CONFIG_SYS_DDRCMD_NOP,
+ CONFIG_SYS_DDRCMD_EM2,
+ CONFIG_SYS_DDRCMD_NOP,
+ CONFIG_SYS_DDRCMD_PCHG_ALL,
+ CONFIG_SYS_DDRCMD_EM2,
+ CONFIG_SYS_DDRCMD_EM3,
+ CONFIG_SYS_DDRCMD_EN_DLL,
+ CONFIG_SYS_MICRON_INIT_DEV_OP,
+ CONFIG_SYS_DDRCMD_PCHG_ALL,
+ CONFIG_SYS_DDRCMD_RFSH,
+ CONFIG_SYS_MICRON_INIT_DEV_OP,
+ CONFIG_SYS_DDRCMD_OCD_DEFAULT,
+ CONFIG_SYS_DDRCMD_PCHG_ALL,
+ CONFIG_SYS_DDRCMD_NOP
+};
+
+/*
+ * fixed sdram init:
+ * The board doesn't use memory modules that have serial presence
+ * detect or similar mechanism for discovery of the DRAM settings
+ */
+long int fixed_sdram(ddr512x_config_t *mddrc_config,
+ u32 *dram_init_seq, int seq_sz)
+{
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ u32 msize = CONFIG_SYS_MAX_RAM_SIZE;
+ u32 msize_log2 = __ilog2(msize);
+ u32 i;
+
+ /* take default settings and init sequence if necessary */
+ if (mddrc_config == NULL)
+ mddrc_config = &default_mddrc_config;
+ if (dram_init_seq == NULL) {
+ dram_init_seq = default_init_seq;
+ seq_sz = sizeof(default_init_seq)/sizeof(u32);
+ }
+
+ /* Initialize IO Control */
+ out_be32(&im->io_ctrl.io_control_mem, CONFIG_SYS_IOCTRL_MUX_DDR);
+
+ /* Initialize DDR Local Window */
+ out_be32(&im->sysconf.ddrlaw.bar, CONFIG_SYS_DDR_BASE & 0xFFFFF000);
+ out_be32(&im->sysconf.ddrlaw.ar, msize_log2 - 1);
+ sync_law(&im->sysconf.ddrlaw.ar);
+
+ /* DDR Enable */
+ /*
+ * the "enable" combination: DRAM controller out of reset,
+ * clock enabled, command mode -- BUT leave CKE low for now
+ */
+ i = MDDRC_SYS_CFG_EN & ~MDDRC_SYS_CFG_CKE_MASK;
+ out_be32(&im->mddrc.ddr_sys_config, i);
+ /* maintain 200 microseconds of stable power and clock */
+ udelay(200);
+ /* apply a NOP, it shouldn't harm */
+ out_be32(&im->mddrc.ddr_command, CONFIG_SYS_DDRCMD_NOP);
+ /* now assert CKE (high) */
+ i |= MDDRC_SYS_CFG_CKE_MASK;
+ out_be32(&im->mddrc.ddr_sys_config, i);
+
+ /* Initialize DDR Priority Manager */
+ out_be32(&im->mddrc.prioman_config1, CONFIG_SYS_MDDRCGRP_PM_CFG1);
+ out_be32(&im->mddrc.prioman_config2, CONFIG_SYS_MDDRCGRP_PM_CFG2);
+ out_be32(&im->mddrc.hiprio_config, CONFIG_SYS_MDDRCGRP_HIPRIO_CFG);
+ out_be32(&im->mddrc.lut_table0_main_upper, CONFIG_SYS_MDDRCGRP_LUT0_MU);
+ out_be32(&im->mddrc.lut_table0_main_lower, CONFIG_SYS_MDDRCGRP_LUT0_ML);
+ out_be32(&im->mddrc.lut_table1_main_upper, CONFIG_SYS_MDDRCGRP_LUT1_MU);
+ out_be32(&im->mddrc.lut_table1_main_lower, CONFIG_SYS_MDDRCGRP_LUT1_ML);
+ out_be32(&im->mddrc.lut_table2_main_upper, CONFIG_SYS_MDDRCGRP_LUT2_MU);
+ out_be32(&im->mddrc.lut_table2_main_lower, CONFIG_SYS_MDDRCGRP_LUT2_ML);
+ out_be32(&im->mddrc.lut_table3_main_upper, CONFIG_SYS_MDDRCGRP_LUT3_MU);
+ out_be32(&im->mddrc.lut_table3_main_lower, CONFIG_SYS_MDDRCGRP_LUT3_ML);
+ out_be32(&im->mddrc.lut_table4_main_upper, CONFIG_SYS_MDDRCGRP_LUT4_MU);
+ out_be32(&im->mddrc.lut_table4_main_lower, CONFIG_SYS_MDDRCGRP_LUT4_ML);
+ out_be32(&im->mddrc.lut_table0_alternate_upper, CONFIG_SYS_MDDRCGRP_LUT0_AU);
+ out_be32(&im->mddrc.lut_table0_alternate_lower, CONFIG_SYS_MDDRCGRP_LUT0_AL);
+ out_be32(&im->mddrc.lut_table1_alternate_upper, CONFIG_SYS_MDDRCGRP_LUT1_AU);
+ out_be32(&im->mddrc.lut_table1_alternate_lower, CONFIG_SYS_MDDRCGRP_LUT1_AL);
+ out_be32(&im->mddrc.lut_table2_alternate_upper, CONFIG_SYS_MDDRCGRP_LUT2_AU);
+ out_be32(&im->mddrc.lut_table2_alternate_lower, CONFIG_SYS_MDDRCGRP_LUT2_AL);
+ out_be32(&im->mddrc.lut_table3_alternate_upper, CONFIG_SYS_MDDRCGRP_LUT3_AU);
+ out_be32(&im->mddrc.lut_table3_alternate_lower, CONFIG_SYS_MDDRCGRP_LUT3_AL);
+ out_be32(&im->mddrc.lut_table4_alternate_upper, CONFIG_SYS_MDDRCGRP_LUT4_AU);
+ out_be32(&im->mddrc.lut_table4_alternate_lower, CONFIG_SYS_MDDRCGRP_LUT4_AL);
+
+ /*
+ * Initialize MDDRC
+ * put MDDRC in CMD mode and
+ * set the max time between refreshes to 0 during init process
+ */
+ out_be32(&im->mddrc.ddr_sys_config,
+ mddrc_config->ddr_sys_config | MDDRC_SYS_CFG_CMD_MASK);
+ out_be32(&im->mddrc.ddr_time_config0,
+ mddrc_config->ddr_time_config0 & MDDRC_REFRESH_ZERO_MASK);
+ out_be32(&im->mddrc.ddr_time_config1,
+ mddrc_config->ddr_time_config1);
+ out_be32(&im->mddrc.ddr_time_config2,
+ mddrc_config->ddr_time_config2);
+
+ /* Initialize DDR with either default or supplied init sequence */
+ for (i = 0; i < seq_sz; i++)
+ out_be32(&im->mddrc.ddr_command, dram_init_seq[i]);
+
+ /* Start MDDRC */
+ out_be32(&im->mddrc.ddr_time_config0, mddrc_config->ddr_time_config0);
+ out_be32(&im->mddrc.ddr_sys_config, mddrc_config->ddr_sys_config);
+
+ /* Allow for the DLL to startup before accessing data */
+ udelay(10);
+
+ msize = get_ram_size(CONFIG_SYS_DDR_BASE, CONFIG_SYS_MAX_RAM_SIZE);
+ /* Fix DDR Local Window for new size */
+ out_be32(&im->sysconf.ddrlaw.ar, __ilog2(msize) - 1);
+ sync_law(&im->sysconf.ddrlaw.ar);
+
+ return msize;
+}
diff --git a/arch/powerpc/cpu/mpc512x/i2c.c b/arch/powerpc/cpu/mpc512x/i2c.c
new file mode 100644
index 0000000..59040f8
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/i2c.c
@@ -0,0 +1,402 @@
+/*
+ * (C) Copyright 2003 - 2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Based on the MPC5xxx code.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_HARD_I2C
+
+#include <i2c.h>
+
+/* by default set I2C bus 0 active */
+static unsigned int bus_num __attribute__ ((section (".data"))) = 0;
+
+#define I2C_TIMEOUT 100
+#define I2C_RETRIES 3
+
+struct mpc512x_i2c_tap {
+ int scl2tap;
+ int tap2tap;
+};
+
+static int mpc_reg_in(volatile u32 *reg);
+static void mpc_reg_out(volatile u32 *reg, int val, int mask);
+static int wait_for_bb(void);
+static int wait_for_pin(int *status);
+static int do_address(uchar chip, char rdwr_flag);
+static int send_bytes(uchar chip, char *buf, int len);
+static int receive_bytes(uchar chip, char *buf, int len);
+static int mpc_get_fdr(int);
+
+static int mpc_reg_in (volatile u32 *reg)
+{
+ int ret = in_be32(reg) >> 24;
+
+ return ret;
+}
+
+static void mpc_reg_out (volatile u32 *reg, int val, int mask)
+{
+ if (!mask) {
+ out_be32(reg, val << 24);
+ } else {
+ clrsetbits_be32(reg, mask << 24, (val & mask) << 24);
+ }
+}
+
+static int wait_for_bb (void)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num];
+ int timeout = I2C_TIMEOUT;
+ int status;
+
+ status = mpc_reg_in (&regs->msr);
+
+ while (timeout-- && (status & I2C_BB)) {
+ mpc_reg_out (&regs->mcr, I2C_STA, I2C_STA);
+ (void)mpc_reg_in(&regs->mdr);
+ mpc_reg_out (&regs->mcr, 0, I2C_STA);
+ mpc_reg_out (&regs->mcr, 0, 0);
+ mpc_reg_out (&regs->mcr, I2C_EN, 0);
+
+ udelay (1000);
+ status = mpc_reg_in (&regs->msr);
+ }
+
+ return (status & I2C_BB);
+}
+
+static int wait_for_pin (int *status)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num];
+ int timeout = I2C_TIMEOUT;
+
+ *status = mpc_reg_in (&regs->msr);
+
+ while (timeout-- && !(*status & I2C_IF)) {
+ udelay (1000);
+ *status = mpc_reg_in (&regs->msr);
+ }
+
+ if (!(*status & I2C_IF)) {
+ return -1;
+ }
+
+ mpc_reg_out (&regs->msr, 0, I2C_IF);
+
+ return 0;
+}
+
+static int do_address (uchar chip, char rdwr_flag)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num];
+ int status;
+
+ chip <<= 1;
+
+ if (rdwr_flag) {
+ chip |= 1;
+ }
+
+ mpc_reg_out (&regs->mcr, I2C_TX, I2C_TX);
+ mpc_reg_out (&regs->mdr, chip, 0);
+
+ if (wait_for_pin (&status)) {
+ return -2;
+ }
+
+ if (status & I2C_RXAK) {
+ return -3;
+ }
+
+ return 0;
+}
+
+static int send_bytes (uchar chip, char *buf, int len)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num];
+ int wrcount;
+ int status;
+
+ for (wrcount = 0; wrcount < len; ++wrcount) {
+
+ mpc_reg_out (&regs->mdr, buf[wrcount], 0);
+
+ if (wait_for_pin (&status)) {
+ break;
+ }
+
+ if (status & I2C_RXAK) {
+ break;
+ }
+
+ }
+
+ return !(wrcount == len);
+}
+
+static int receive_bytes (uchar chip, char *buf, int len)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num];
+ int dummy = 1;
+ int rdcount = 0;
+ int status;
+ int i;
+
+ mpc_reg_out (&regs->mcr, 0, I2C_TX);
+
+ for (i = 0; i < len; ++i) {
+ buf[rdcount] = mpc_reg_in (&regs->mdr);
+
+ if (dummy) {
+ dummy = 0;
+ } else {
+ rdcount++;
+ }
+
+ if (wait_for_pin (&status)) {
+ return -4;
+ }
+ }
+
+ mpc_reg_out (&regs->mcr, I2C_TXAK, I2C_TXAK);
+ buf[rdcount++] = mpc_reg_in (&regs->mdr);
+
+ if (wait_for_pin (&status)) {
+ return -5;
+ }
+
+ mpc_reg_out (&regs->mcr, 0, I2C_TXAK);
+
+ return 0;
+}
+
+/**************** I2C API ****************/
+
+void i2c_init (int speed, int saddr)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ int i;
+
+ for (i = 0; i < I2C_BUS_CNT; i++){
+ volatile i2c512x_dev_t *regs = &im->i2c.dev[i];
+
+ mpc_reg_out (&regs->mcr, 0, 0);
+
+ /* Set clock */
+ mpc_reg_out (&regs->mfdr, mpc_get_fdr (speed), 0);
+ mpc_reg_out (&regs->madr, saddr << 1, 0);
+
+ /* Enable module */
+ mpc_reg_out (&regs->mcr, I2C_EN, I2C_INIT_MASK);
+ mpc_reg_out (&regs->msr, 0, I2C_IF);
+ }
+
+ /* Disable interrupts */
+ out_be32(&im->i2c.icr, 0);
+
+ /* Turn off filters */
+ out_be32(&im->i2c.mifr, 0);
+}
+
+static int mpc_get_fdr (int speed)
+{
+ static int fdr = -1;
+
+ if (fdr == -1) {
+ ulong best_speed = 0;
+ ulong divider;
+ ulong ips, scl;
+ ulong bestmatch = 0xffffffffUL;
+ int best_i = 0, best_j = 0, i, j;
+ int SCL_Tap[] = { 9, 10, 12, 15, 5, 6, 7, 8};
+ struct mpc512x_i2c_tap scltap[] = {
+ {4, 1},
+ {4, 2},
+ {6, 4},
+ {6, 8},
+ {14, 16},
+ {30, 32},
+ {62, 64},
+ {126, 128}
+ };
+
+ ips = gd->arch.ips_clk;
+ for (i = 7; i >= 0; i--) {
+ for (j = 7; j >= 0; j--) {
+ scl = 2 * (scltap[j].scl2tap +
+ (SCL_Tap[i] - 1) * scltap[j].tap2tap
+ + 2);
+ if (ips <= speed*scl) {
+ if ((speed*scl - ips) < bestmatch) {
+ bestmatch = speed*scl - ips;
+ best_i = i;
+ best_j = j;
+ best_speed = ips/scl;
+ }
+ }
+ }
+ }
+ divider = (best_i & 3) | ((best_i & 4) << 3) | (best_j << 2);
+ if (gd->flags & GD_FLG_RELOC) {
+ fdr = divider;
+ } else {
+ debug("%ld kHz, \n", best_speed / 1000);
+ return divider;
+ }
+ }
+
+ return fdr;
+}
+
+int i2c_probe (uchar chip)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num];
+ int i;
+
+ for (i = 0; i < I2C_RETRIES; i++) {
+ mpc_reg_out (&regs->mcr, I2C_STA, I2C_STA);
+
+ if (! do_address (chip, 0)) {
+ mpc_reg_out (&regs->mcr, 0, I2C_STA);
+ udelay (500);
+ break;
+ }
+
+ mpc_reg_out (&regs->mcr, 0, I2C_STA);
+ udelay (500);
+ }
+
+ return (i == I2C_RETRIES);
+}
+
+int i2c_read (uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num];
+ char xaddr[4];
+ int ret = -1;
+
+ xaddr[0] = (addr >> 24) & 0xFF;
+ xaddr[1] = (addr >> 16) & 0xFF;
+ xaddr[2] = (addr >> 8) & 0xFF;
+ xaddr[3] = addr & 0xFF;
+
+ if (wait_for_bb ()) {
+ printf ("i2c_read: bus is busy\n");
+ goto Done;
+ }
+
+ mpc_reg_out (&regs->mcr, I2C_STA, I2C_STA);
+ if (do_address (chip, 0)) {
+ printf ("i2c_read: failed to address chip\n");
+ goto Done;
+ }
+
+ if (send_bytes (chip, &xaddr[4-alen], alen)) {
+ printf ("i2c_read: send_bytes failed\n");
+ goto Done;
+ }
+
+ mpc_reg_out (&regs->mcr, I2C_RSTA, I2C_RSTA);
+ if (do_address (chip, 1)) {
+ printf ("i2c_read: failed to address chip\n");
+ goto Done;
+ }
+
+ if (receive_bytes (chip, (char *)buf, len)) {
+ printf ("i2c_read: receive_bytes failed\n");
+ goto Done;
+ }
+
+ ret = 0;
+Done:
+ mpc_reg_out (&regs->mcr, 0, I2C_STA);
+ return ret;
+}
+
+int i2c_write (uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile i2c512x_dev_t *regs = &im->i2c.dev[bus_num];
+ char xaddr[4];
+ int ret = -1;
+
+ xaddr[0] = (addr >> 24) & 0xFF;
+ xaddr[1] = (addr >> 16) & 0xFF;
+ xaddr[2] = (addr >> 8) & 0xFF;
+ xaddr[3] = addr & 0xFF;
+
+ if (wait_for_bb ()) {
+ printf ("i2c_write: bus is busy\n");
+ goto Done;
+ }
+
+ mpc_reg_out (&regs->mcr, I2C_STA, I2C_STA);
+ if (do_address (chip, 0)) {
+ printf ("i2c_write: failed to address chip\n");
+ goto Done;
+ }
+
+ if (send_bytes (chip, &xaddr[4-alen], alen)) {
+ printf ("i2c_write: send_bytes failed\n");
+ goto Done;
+ }
+
+ if (send_bytes (chip, (char *)buf, len)) {
+ printf ("i2c_write: send_bytes failed\n");
+ goto Done;
+ }
+
+ ret = 0;
+Done:
+ mpc_reg_out (&regs->mcr, 0, I2C_STA);
+ return ret;
+}
+
+int i2c_set_bus_num (unsigned int bus)
+{
+ if (bus >= I2C_BUS_CNT) {
+ return -1;
+ }
+ bus_num = bus;
+
+ return 0;
+}
+
+unsigned int i2c_get_bus_num (void)
+{
+ return bus_num;
+}
+
+#endif /* CONFIG_HARD_I2C */
diff --git a/arch/powerpc/cpu/mpc512x/ide.c b/arch/powerpc/cpu/mpc512x/ide.c
new file mode 100644
index 0000000..7a49673
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/ide.c
@@ -0,0 +1,128 @@
+/*
+ * (C) Copyright 2007-2009 DENX Software Engineering
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_IDE_RESET)
+
+void ide_set_reset (int idereset)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ debug ("ide_set_reset(%d)\n", idereset);
+
+ if (idereset) {
+ out_be32(&im->pata.pata_ata_control, 0);
+ } else {
+ out_be32(&im->pata.pata_ata_control, FSL_ATA_CTRL_ATA_RST_B);
+ }
+ udelay(100);
+}
+
+void init_ide_reset (void)
+{
+ debug ("init_ide_reset\n");
+
+ /*
+ * Clear the reset bit to reset the interface
+ * cf. RefMan MPC5121EE: 28.4.1 Resetting the ATA Bus
+ */
+ ide_set_reset(1);
+
+ /* Assert the reset bit to enable the interface */
+ ide_set_reset(0);
+
+}
+
+#define CALC_TIMING(t) (t + period - 1) / period
+
+int ide_preinit (void)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ long t;
+ const struct {
+ short t0;
+ short t1;
+ short t2_8;
+ short t2_16;
+ short t2i;
+ short t4;
+ short t9;
+ short tA;
+ } pio_specs = {
+ .t0 = 600,
+ .t1 = 70,
+ .t2_8 = 290,
+ .t2_16 = 165,
+ .t2i = 0,
+ .t4 = 30,
+ .t9 = 20,
+ .tA = 50,
+ };
+ union {
+ u32 config;
+ struct {
+ u8 field1;
+ u8 field2;
+ u8 field3;
+ u8 field4;
+ }bytes;
+ } cfg;
+
+ debug ("IDE preinit using PATA peripheral at IMMR-ADDR %08x\n",
+ (u32)&im->pata);
+
+ /* Set the reset bit to 1 to enable the interface */
+ ide_set_reset(0);
+
+ /* Init timings : we use PIO mode 0 timings */
+ t = 1000000000 / gd->arch.ips_clk; /* period in ns */
+ cfg.bytes.field1 = 3;
+ cfg.bytes.field2 = 3;
+ cfg.bytes.field3 = (pio_specs.t1 + t) / t;
+ cfg.bytes.field4 = (pio_specs.t2_8 + t) / t;
+
+ out_be32(&im->pata.pata_time1, cfg.config);
+
+ cfg.bytes.field1 = (pio_specs.t2_8 + t) / t;
+ cfg.bytes.field2 = (pio_specs.tA + t) / t + 2;
+ cfg.bytes.field3 = 1;
+ cfg.bytes.field4 = (pio_specs.t4 + t) / t;
+
+ out_be32(&im->pata.pata_time2, cfg.config);
+
+ cfg.config = in_be32(&im->pata.pata_time3);
+ cfg.bytes.field1 = (pio_specs.t9 + t) / t;
+
+ out_be32(&im->pata.pata_time3, cfg.config);
+
+ debug ("PATA preinit complete.\n");
+
+ return 0;
+}
+
+#endif /* defined(CONFIG_IDE_RESET) */
diff --git a/arch/powerpc/cpu/mpc512x/interrupts.c b/arch/powerpc/cpu/mpc512x/interrupts.c
new file mode 100644
index 0000000..ef7c773
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/interrupts.c
@@ -0,0 +1,61 @@
+/*
+ * (C) Copyright 2000-2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright 2004 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Derived from the MPC83xx code.
+ */
+
+#include <common.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct irq_action {
+ interrupt_handler_t *handler;
+ void *arg;
+ ulong count;
+};
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+ *decrementer_count = get_tbclk () / CONFIG_SYS_HZ;
+
+ return 0;
+}
+
+/*
+ * Install and free an interrupt handler.
+ */
+void
+irq_install_handler (int irq, interrupt_handler_t * handler, void *arg)
+{
+}
+
+void irq_free_handler (int irq)
+{
+}
+
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+ /* nothing to do here */
+ return;
+}
diff --git a/arch/powerpc/cpu/mpc512x/iopin.c b/arch/powerpc/cpu/mpc512x/iopin.c
new file mode 100644
index 0000000..1a39101
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/iopin.c
@@ -0,0 +1,103 @@
+/*
+ * (C) Copyright 2008
+ * Martha J Marx, Silicon Turnkey Express, mmarx@silicontkx.com
+ * mpc512x I/O pin/pad initialization for the ADS5121 board
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+void iopin_initialize(iopin_t *ioregs_init, int len)
+{
+ short i, j, p;
+ u32 *reg;
+ immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+
+ reg = (u32 *)&(im->io_ctrl);
+
+ if (sizeof(ioregs_init) == 0)
+ return;
+
+ for (i = 0; i < len; i++) {
+ for (p = 0, j = ioregs_init[i].p_offset / sizeof(u_long);
+ p < ioregs_init[i].nr_pins; p++, j++) {
+ if (ioregs_init[i].bit_or)
+ setbits_be32(reg + j, ioregs_init[i].val);
+ else
+ out_be32 (reg + j, ioregs_init[i].val);
+ }
+ }
+ return;
+}
+
+void iopin_initialize_bits(iopin_t *ioregs_init, int len)
+{
+ short i, j, p;
+ u32 *reg, mask;
+ immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+
+ reg = (u32 *)&(im->io_ctrl);
+
+ /* iterate over table entries */
+ for (i = 0; i < len; i++) {
+ /* iterate over pins within a table entry */
+ for (p = 0, j = ioregs_init[i].p_offset / sizeof(u_long);
+ p < ioregs_init[i].nr_pins; p++, j++) {
+ if (ioregs_init[i].bit_or & IO_PIN_OVER_EACH) {
+ /* replace all settings at once */
+ out_be32(reg + j, ioregs_init[i].val);
+ } else {
+ /*
+ * only replace individual parts, but
+ * REPLACE them instead of just ORing
+ * them in and "inheriting" previously
+ * set bits which we don't want
+ */
+ mask = 0;
+ if (ioregs_init[i].bit_or & IO_PIN_OVER_FMUX)
+ mask |= IO_PIN_FMUX(3);
+
+ if (ioregs_init[i].bit_or & IO_PIN_OVER_HOLD)
+ mask |= IO_PIN_HOLD(3);
+
+ if (ioregs_init[i].bit_or & IO_PIN_OVER_PULL)
+ mask |= IO_PIN_PUD(1) | IO_PIN_PUE(1);
+
+ if (ioregs_init[i].bit_or & IO_PIN_OVER_STRIG)
+ mask |= IO_PIN_ST(1);
+
+ if (ioregs_init[i].bit_or & IO_PIN_OVER_DRVSTR)
+ mask |= IO_PIN_DS(3);
+ /*
+ * DON'T do the "mask, then insert"
+ * in place on the register, it may
+ * break access to external hardware
+ * (like boot ROMs) when configuring
+ * LPB related pins, while the code to
+ * configure the pin is read from this
+ * very address region
+ */
+ clrsetbits_be32(reg + j, mask,
+ ioregs_init[i].val & mask);
+ }
+ }
+ }
+}
diff --git a/arch/powerpc/cpu/mpc512x/pci.c b/arch/powerpc/cpu/mpc512x/pci.c
new file mode 100644
index 0000000..16f034d
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/pci.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2009-2010 DENX Software Engineering <wd@denx.de>
+ * Copyright (C) Freescale Semiconductor, Inc. 2006, 2007.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#include <asm/io.h>
+#include <asm/mmu.h>
+#include <asm/global_data.h>
+#include <pci.h>
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* System RAM mapped to PCI space */
+#define CONFIG_PCI_SYS_MEM_BUS CONFIG_SYS_SDRAM_BASE
+#define CONFIG_PCI_SYS_MEM_PHYS CONFIG_SYS_SDRAM_BASE
+
+static struct pci_controller pci_hose;
+
+
+/**************************************************************************
+ * pci_init_board()
+ *
+ */
+void
+pci_init_board(void)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile law512x_t *pci_law;
+ volatile pot512x_t *pci_pot;
+ volatile pcictrl512x_t *pci_ctrl;
+ u16 reg16;
+ u32 reg32;
+ u32 dev;
+ int i;
+ struct pci_controller *hose;
+
+ /* Set PCI divider for 33MHz */
+ reg32 = in_be32(&im->clk.scfr[0]);
+ reg32 &= ~(SCFR1_PCI_DIV_MASK);
+ reg32 |= SCFR1_PCI_DIV << SCFR1_PCI_DIV_SHIFT;
+ out_be32(&im->clk.scfr[0], reg32);
+
+ clrsetbits_be32(&im->clk.scfr[0],
+ SCFR1_PCI_DIV_MASK,
+ SCFR1_PCI_DIV << SCFR1_PCI_DIV_SHIFT
+ );
+
+ pci_law = im->sysconf.pcilaw;
+ pci_pot = im->ios.pot;
+ pci_ctrl = &im->pci_ctrl;
+
+ hose = &pci_hose;
+
+ /*
+ * Release PCI RST Output signal
+ */
+ out_be32(&pci_ctrl->gcr, 0);
+ udelay(2000);
+ out_be32(&pci_ctrl->gcr, 1);
+
+ /* We need to wait at least a 1sec based on PCI specs */
+ for (i = 0; i < 1000; i++)
+ udelay(1000);
+
+ /*
+ * Configure PCI Local Access Windows
+ */
+ out_be32(&pci_law[0].bar, CONFIG_SYS_PCI_MEM_PHYS & LAWBAR_BAR);
+ out_be32(&pci_law[0].ar, LAWAR_EN | LAWAR_SIZE_512M);
+
+ out_be32(&pci_law[1].bar, CONFIG_SYS_PCI_IO_PHYS & LAWBAR_BAR);
+ out_be32(&pci_law[1].ar, LAWAR_EN | LAWAR_SIZE_16M);
+
+ /*
+ * Configure PCI Outbound Translation Windows
+ */
+
+ /* PCI mem space - prefetch */
+ out_be32(&pci_pot[0].potar,
+ (CONFIG_SYS_PCI_MEM_BASE >> 12) & POTAR_TA_MASK);
+ out_be32(&pci_pot[0].pobar,
+ (CONFIG_SYS_PCI_MEM_PHYS >> 12) & POBAR_BA_MASK);
+ out_be32(&pci_pot[0].pocmr,
+ POCMR_EN | POCMR_PRE | POCMR_CM_256M);
+
+ /* PCI IO space */
+ out_be32(&pci_pot[1].potar,
+ (CONFIG_SYS_PCI_IO_BASE >> 12) & POTAR_TA_MASK);
+ out_be32(&pci_pot[1].pobar,
+ (CONFIG_SYS_PCI_IO_PHYS >> 12) & POBAR_BA_MASK);
+ out_be32(&pci_pot[1].pocmr,
+ POCMR_EN | POCMR_IO | POCMR_CM_16M);
+
+ /* PCI mmio - non-prefetch mem space */
+ out_be32(&pci_pot[2].potar,
+ (CONFIG_SYS_PCI_MMIO_BASE >> 12) & POTAR_TA_MASK);
+ out_be32(&pci_pot[2].pobar,
+ (CONFIG_SYS_PCI_MMIO_PHYS >> 12) & POBAR_BA_MASK);
+ out_be32(&pci_pot[2].pocmr,
+ POCMR_EN | POCMR_CM_256M);
+
+ /*
+ * Configure PCI Inbound Translation Windows
+ */
+
+ /* we need RAM mapped to PCI space for the devices to
+ * access main memory */
+ out_be32(&pci_ctrl[0].pitar1, 0x0);
+ out_be32(&pci_ctrl[0].pibar1, 0x0);
+ out_be32(&pci_ctrl[0].piebar1, 0x0);
+ out_be32(&pci_ctrl[0].piwar1,
+ PIWAR_EN | PIWAR_PF | PIWAR_RTT_SNOOP |
+ PIWAR_WTT_SNOOP | (__ilog2(gd->ram_size) - 1));
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ /* PCI memory prefetch space */
+ pci_set_region(hose->regions + 0,
+ CONFIG_SYS_PCI_MEM_BASE,
+ CONFIG_SYS_PCI_MEM_PHYS,
+ CONFIG_SYS_PCI_MEM_SIZE,
+ PCI_REGION_MEM|PCI_REGION_PREFETCH);
+
+ /* PCI memory space */
+ pci_set_region(hose->regions + 1,
+ CONFIG_SYS_PCI_MMIO_BASE,
+ CONFIG_SYS_PCI_MMIO_PHYS,
+ CONFIG_SYS_PCI_MMIO_SIZE,
+ PCI_REGION_MEM);
+
+ /* PCI IO space */
+ pci_set_region(hose->regions + 2,
+ CONFIG_SYS_PCI_IO_BASE,
+ CONFIG_SYS_PCI_IO_PHYS,
+ CONFIG_SYS_PCI_IO_SIZE,
+ PCI_REGION_IO);
+
+ /* System memory space */
+ pci_set_region(hose->regions + 3,
+ CONFIG_PCI_SYS_MEM_BUS,
+ CONFIG_PCI_SYS_MEM_PHYS,
+ gd->ram_size,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ hose->region_count = 4;
+
+ pci_setup_indirect(hose,
+ (CONFIG_SYS_IMMR + 0x8300),
+ (CONFIG_SYS_IMMR + 0x8304));
+
+ pci_register_hose(hose);
+
+ /*
+ * Write to Command register
+ */
+ reg16 = 0xff;
+ dev = PCI_BDF(hose->first_busno, 0, 0);
+ pci_hose_read_config_word(hose, dev, PCI_COMMAND, &reg16);
+ reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+ pci_hose_write_config_word(hose, dev, PCI_COMMAND, reg16);
+
+ /*
+ * Clear non-reserved bits in status register.
+ */
+ pci_hose_write_config_word(hose, dev, PCI_STATUS, 0xffff);
+ pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
+ pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, 0x08);
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf("PCI: Bus Dev VenId DevId Class Int\n");
+#endif
+ /*
+ * Hose scan.
+ */
+ hose->last_busno = pci_hose_scan(hose);
+}
+
+#if defined(CONFIG_OF_LIBFDT)
+void ft_pci_setup(void *blob, bd_t *bd)
+{
+ int nodeoffset;
+ int tmp[2];
+ const char *path;
+
+ nodeoffset = fdt_path_offset(blob, "/aliases");
+ if (nodeoffset >= 0) {
+ path = fdt_getprop(blob, nodeoffset, "pci", NULL);
+ if (path) {
+ tmp[0] = cpu_to_be32(pci_hose.first_busno);
+ tmp[1] = cpu_to_be32(pci_hose.last_busno);
+ do_fixup_by_path(blob, path, "bus-range",
+ &tmp, sizeof(tmp), 1);
+
+ tmp[0] = cpu_to_be32(gd->pci_clk);
+ do_fixup_by_path(blob, path, "clock-frequency",
+ &tmp, sizeof(tmp[0]), 1);
+ }
+ }
+}
+#endif /* CONFIG_OF_LIBFDT */
diff --git a/arch/powerpc/cpu/mpc512x/serial.c b/arch/powerpc/cpu/mpc512x/serial.c
new file mode 100644
index 0000000..3afbe81
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/serial.c
@@ -0,0 +1,459 @@
+/*
+ * (C) Copyright 2000 - 2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Based ont the MPC5200 PSC driver.
+ * Adapted for MPC512x by Jan Wrobel <wrr@semihalf.com>
+ */
+
+/*
+ * Minimal serial functions needed to use one of the PSC ports
+ * as serial console interface.
+ */
+
+#include <common.h>
+#include <linux/compiler.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <serial.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_PSC_CONSOLE)
+
+static void fifo_init (volatile psc512x_t *psc)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ u32 tfsize, rfsize;
+
+ /* reset Rx & Tx fifo slice */
+ out_be32(&psc->rfcmd, PSC_FIFO_RESET_SLICE);
+ out_be32(&psc->tfcmd, PSC_FIFO_RESET_SLICE);
+
+ /* disable Tx & Rx FIFO interrupts */
+ out_be32(&psc->rfintmask, 0);
+ out_be32(&psc->tfintmask, 0);
+
+ switch (((u32)psc & 0xf00) >> 8) {
+ case 0:
+ tfsize = FIFOC_PSC0_TX_SIZE | (FIFOC_PSC0_TX_ADDR << 16);
+ rfsize = FIFOC_PSC0_RX_SIZE | (FIFOC_PSC0_RX_ADDR << 16);
+ break;
+ case 1:
+ tfsize = FIFOC_PSC1_TX_SIZE | (FIFOC_PSC1_TX_ADDR << 16);
+ rfsize = FIFOC_PSC1_RX_SIZE | (FIFOC_PSC1_RX_ADDR << 16);
+ break;
+ case 2:
+ tfsize = FIFOC_PSC2_TX_SIZE | (FIFOC_PSC2_TX_ADDR << 16);
+ rfsize = FIFOC_PSC2_RX_SIZE | (FIFOC_PSC2_RX_ADDR << 16);
+ break;
+ case 3:
+ tfsize = FIFOC_PSC3_TX_SIZE | (FIFOC_PSC3_TX_ADDR << 16);
+ rfsize = FIFOC_PSC3_RX_SIZE | (FIFOC_PSC3_RX_ADDR << 16);
+ break;
+ case 4:
+ tfsize = FIFOC_PSC4_TX_SIZE | (FIFOC_PSC4_TX_ADDR << 16);
+ rfsize = FIFOC_PSC4_RX_SIZE | (FIFOC_PSC4_RX_ADDR << 16);
+ break;
+ case 5:
+ tfsize = FIFOC_PSC5_TX_SIZE | (FIFOC_PSC5_TX_ADDR << 16);
+ rfsize = FIFOC_PSC5_RX_SIZE | (FIFOC_PSC5_RX_ADDR << 16);
+ break;
+ case 6:
+ tfsize = FIFOC_PSC6_TX_SIZE | (FIFOC_PSC6_TX_ADDR << 16);
+ rfsize = FIFOC_PSC6_RX_SIZE | (FIFOC_PSC6_RX_ADDR << 16);
+ break;
+ case 7:
+ tfsize = FIFOC_PSC7_TX_SIZE | (FIFOC_PSC7_TX_ADDR << 16);
+ rfsize = FIFOC_PSC7_RX_SIZE | (FIFOC_PSC7_RX_ADDR << 16);
+ break;
+ case 8:
+ tfsize = FIFOC_PSC8_TX_SIZE | (FIFOC_PSC8_TX_ADDR << 16);
+ rfsize = FIFOC_PSC8_RX_SIZE | (FIFOC_PSC8_RX_ADDR << 16);
+ break;
+ case 9:
+ tfsize = FIFOC_PSC9_TX_SIZE | (FIFOC_PSC9_TX_ADDR << 16);
+ rfsize = FIFOC_PSC9_RX_SIZE | (FIFOC_PSC9_RX_ADDR << 16);
+ break;
+ case 10:
+ tfsize = FIFOC_PSC10_TX_SIZE | (FIFOC_PSC10_TX_ADDR << 16);
+ rfsize = FIFOC_PSC10_RX_SIZE | (FIFOC_PSC10_RX_ADDR << 16);
+ break;
+ case 11:
+ tfsize = FIFOC_PSC11_TX_SIZE | (FIFOC_PSC11_TX_ADDR << 16);
+ rfsize = FIFOC_PSC11_RX_SIZE | (FIFOC_PSC11_RX_ADDR << 16);
+ break;
+ default:
+ return;
+ }
+
+ out_be32(&psc->tfsize, tfsize);
+ out_be32(&psc->rfsize, rfsize);
+
+ /* enable Tx & Rx FIFO slice */
+ out_be32(&psc->rfcmd, PSC_FIFO_ENABLE_SLICE);
+ out_be32(&psc->tfcmd, PSC_FIFO_ENABLE_SLICE);
+
+ out_be32(&im->fifoc.fifoc_cmd, FIFOC_DISABLE_CLOCK_GATE);
+ __asm__ volatile ("sync");
+}
+
+void serial_setbrg_dev(unsigned int idx)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile psc512x_t *psc = (psc512x_t *) &im->psc[idx];
+ unsigned long baseclk, div;
+ unsigned long baudrate;
+ char buf[16];
+ char *br_env;
+
+ baudrate = gd->baudrate;
+ if (idx != CONFIG_PSC_CONSOLE) {
+ /* Allows setting baudrate for other serial devices
+ * on PSCx using environment. If not specified, use
+ * the same baudrate as for console.
+ */
+ sprintf(buf, "psc%d_baudrate", idx);
+ br_env = getenv(buf);
+ if (br_env)
+ baudrate = simple_strtoul(br_env, NULL, 10);
+
+ debug("%s: idx %d, baudrate %ld\n", __func__, idx, baudrate);
+ }
+
+ /* calculate divisor for setting PSC CTUR and CTLR registers */
+ baseclk = (gd->arch.ips_clk + 8) / 16;
+ div = (baseclk + (baudrate / 2)) / baudrate;
+
+ out_8(&psc->ctur, (div >> 8) & 0xff);
+ out_8(&psc->ctlr, div & 0xff); /* set baudrate */
+}
+
+int serial_init_dev(unsigned int idx)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile psc512x_t *psc = (psc512x_t *) &im->psc[idx];
+ u32 reg;
+
+ reg = in_be32(&im->clk.sccr[0]);
+ out_be32(&im->clk.sccr[0], reg | CLOCK_SCCR1_PSC_EN(idx));
+
+ fifo_init (psc);
+
+ /* set MR register to point to MR1 */
+ out_8(&psc->command, PSC_SEL_MODE_REG_1);
+
+ /* disable Tx/Rx */
+ out_8(&psc->command, PSC_TX_DISABLE | PSC_RX_DISABLE);
+
+ /* choose the prescaler by 16 for the Tx/Rx clock generation */
+ out_be16(&psc->psc_clock_select, 0xdd00);
+
+ /* switch to UART mode */
+ out_be32(&psc->sicr, 0);
+
+ /* mode register points to mr1 */
+ /* configure parity, bit length and so on in mode register 1*/
+ out_8(&psc->mode, PSC_MODE_8_BITS | PSC_MODE_PARNONE);
+ /* now, mode register points to mr2 */
+ out_8(&psc->mode, PSC_MODE_1_STOPBIT);
+
+ /* set baudrate */
+ serial_setbrg_dev(idx);
+
+ /* disable all interrupts */
+ out_be16(&psc->psc_imr, 0);
+
+ /* reset and enable Rx/Tx */
+ out_8(&psc->command, PSC_RST_RX);
+ out_8(&psc->command, PSC_RST_TX);
+ out_8(&psc->command, PSC_RX_ENABLE | PSC_TX_ENABLE);
+
+ return 0;
+}
+
+int serial_uninit_dev(unsigned int idx)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile psc512x_t *psc = (psc512x_t *) &im->psc[idx];
+ u32 reg;
+
+ out_8(&psc->command, PSC_RX_DISABLE | PSC_TX_DISABLE);
+ reg = in_be32(&im->clk.sccr[0]);
+ reg &= ~CLOCK_SCCR1_PSC_EN(idx);
+ out_be32(&im->clk.sccr[0], reg);
+
+ return 0;
+}
+
+void serial_putc_dev(unsigned int idx, const char c)
+{
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile psc512x_t *psc = (psc512x_t *) &im->psc[idx];
+
+ if (c == '\n')
+ serial_putc_dev(idx, '\r');
+
+ /* Wait for last character to go. */
+ while (!(in_be16(&psc->psc_status) & PSC_SR_TXEMP))
+ ;
+
+ out_8(&psc->tfdata_8, c);
+}
+
+void serial_putc_raw_dev(unsigned int idx, const char c)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile psc512x_t *psc = (psc512x_t *) &im->psc[idx];
+
+ /* Wait for last character to go. */
+ while (!(in_be16(&psc->psc_status) & PSC_SR_TXEMP))
+ ;
+
+ out_8(&psc->tfdata_8, c);
+}
+
+void serial_puts_dev(unsigned int idx, const char *s)
+{
+ while (*s)
+ serial_putc_dev(idx, *s++);
+}
+
+int serial_getc_dev(unsigned int idx)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile psc512x_t *psc = (psc512x_t *) &im->psc[idx];
+
+ /* Wait for a character to arrive. */
+ while (in_be32(&psc->rfstat) & PSC_FIFO_EMPTY)
+ ;
+
+ return in_8(&psc->rfdata_8);
+}
+
+int serial_tstc_dev(unsigned int idx)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile psc512x_t *psc = (psc512x_t *) &im->psc[idx];
+
+ return !(in_be32(&psc->rfstat) & PSC_FIFO_EMPTY);
+}
+
+void serial_setrts_dev(unsigned int idx, int s)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile psc512x_t *psc = (psc512x_t *) &im->psc[idx];
+
+ if (s) {
+ /* Assert RTS (become LOW) */
+ out_8(&psc->op1, 0x1);
+ }
+ else {
+ /* Negate RTS (become HIGH) */
+ out_8(&psc->op0, 0x1);
+ }
+}
+
+int serial_getcts_dev(unsigned int idx)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ volatile psc512x_t *psc = (psc512x_t *) &im->psc[idx];
+
+ return (in_8(&psc->ip) & 0x1) ? 0 : 1;
+}
+#endif /* CONFIG_PSC_CONSOLE */
+
+#define DECLARE_PSC_SERIAL_FUNCTIONS(port) \
+ int serial##port##_init(void) \
+ { \
+ return serial_init_dev(port); \
+ } \
+ int serial##port##_uninit(void) \
+ { \
+ return serial_uninit_dev(port); \
+ } \
+ void serial##port##_setbrg(void) \
+ { \
+ serial_setbrg_dev(port); \
+ } \
+ int serial##port##_getc(void) \
+ { \
+ return serial_getc_dev(port); \
+ } \
+ int serial##port##_tstc(void) \
+ { \
+ return serial_tstc_dev(port); \
+ } \
+ void serial##port##_putc(const char c) \
+ { \
+ serial_putc_dev(port, c); \
+ } \
+ void serial##port##_puts(const char *s) \
+ { \
+ serial_puts_dev(port, s); \
+ }
+
+#define INIT_PSC_SERIAL_STRUCTURE(port, __name) { \
+ .name = __name, \
+ .start = serial##port##_init, \
+ .stop = serial##port##_uninit, \
+ .setbrg = serial##port##_setbrg, \
+ .getc = serial##port##_getc, \
+ .tstc = serial##port##_tstc, \
+ .putc = serial##port##_putc, \
+ .puts = serial##port##_puts, \
+}
+
+#if defined(CONFIG_SYS_PSC1)
+DECLARE_PSC_SERIAL_FUNCTIONS(1);
+struct serial_device serial1_device =
+INIT_PSC_SERIAL_STRUCTURE(1, "psc1");
+#endif
+
+#if defined(CONFIG_SYS_PSC3)
+DECLARE_PSC_SERIAL_FUNCTIONS(3);
+struct serial_device serial3_device =
+INIT_PSC_SERIAL_STRUCTURE(3, "psc3");
+#endif
+
+#if defined(CONFIG_SYS_PSC4)
+DECLARE_PSC_SERIAL_FUNCTIONS(4);
+struct serial_device serial4_device =
+INIT_PSC_SERIAL_STRUCTURE(4, "psc4");
+#endif
+
+#if defined(CONFIG_SYS_PSC6)
+DECLARE_PSC_SERIAL_FUNCTIONS(6);
+struct serial_device serial6_device =
+INIT_PSC_SERIAL_STRUCTURE(6, "psc6");
+#endif
+
+__weak struct serial_device *default_serial_console(void)
+{
+#if (CONFIG_PSC_CONSOLE == 3)
+ return &serial3_device;
+#elif (CONFIG_PSC_CONSOLE == 6)
+ return &serial6_device;
+#else
+#error "invalid CONFIG_PSC_CONSOLE"
+#endif
+}
+
+void mpc512x_serial_initialize(void)
+{
+#if defined(CONFIG_SYS_PSC1)
+ serial_register(&serial1_device);
+#endif
+#if defined(CONFIG_SYS_PSC3)
+ serial_register(&serial3_device);
+#endif
+#if defined(CONFIG_SYS_PSC4)
+ serial_register(&serial4_device);
+#endif
+#if defined(CONFIG_SYS_PSC6)
+ serial_register(&serial6_device);
+#endif
+}
+
+#include <stdio_dev.h>
+/*
+ * Routines for communication with serial devices over PSC
+ */
+/* Bitfield for initialized PSCs */
+static unsigned int initialized;
+
+struct stdio_dev *open_port(int num, int baudrate)
+{
+ struct stdio_dev *port;
+ char env_var[16];
+ char env_val[10];
+ char name[7];
+
+ if (num < 0 || num > 11)
+ return NULL;
+
+ sprintf(name, "psc%d", num);
+ port = stdio_get_by_name(name);
+ if (!port)
+ return NULL;
+
+ if (!test_bit(num, &initialized)) {
+ sprintf(env_var, "psc%d_baudrate", num);
+ sprintf(env_val, "%d", baudrate);
+ setenv(env_var, env_val);
+
+ if (port->start())
+ return NULL;
+
+ set_bit(num, &initialized);
+ }
+
+ return port;
+}
+
+int close_port(int num)
+{
+ struct stdio_dev *port;
+ int ret;
+ char name[7];
+
+ if (num < 0 || num > 11)
+ return -1;
+
+ sprintf(name, "psc%d", num);
+ port = stdio_get_by_name(name);
+ if (!port)
+ return -1;
+
+ ret = port->stop();
+ clear_bit(num, &initialized);
+
+ return ret;
+}
+
+int write_port(struct stdio_dev *port, char *buf)
+{
+ if (!port || !buf)
+ return -1;
+
+ port->puts(buf);
+
+ return 0;
+}
+
+int read_port(struct stdio_dev *port, char *buf, int size)
+{
+ int cnt = 0;
+
+ if (!port || !buf)
+ return -1;
+
+ if (!size)
+ return 0;
+
+ while (port->tstc()) {
+ buf[cnt++] = port->getc();
+ if (cnt > size)
+ break;
+ }
+
+ return cnt;
+}
diff --git a/arch/powerpc/cpu/mpc512x/speed.c b/arch/powerpc/cpu/mpc512x/speed.c
new file mode 100644
index 0000000..6761877
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/speed.c
@@ -0,0 +1,153 @@
+/*
+ * (C) Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (C) 2004-2006 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Based on the MPC83xx code.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int spmf_mult[] = {
+ 68, 1, 12, 16,
+ 20, 24, 28, 32,
+ 36, 40, 44, 48,
+ 52, 56, 60, 64
+};
+
+static int cpmf_mult[][2] = {
+ {0, 1}, {0, 1}, /* 0 and 1 are not valid */
+ {1, 1}, {3, 2},
+ {2, 1}, {5, 2},
+ {3, 1}, {7, 2},
+ {0, 1}, {0, 1}, /* and all above 7 are not valid too */
+ {0, 1}, {0, 1},
+ {0, 1}, {0, 1},
+ {0, 1}, {0, 1}
+};
+
+static int sys_dividors[][2] = {
+ {2, 1}, {5, 2}, {3, 1}, {7, 2}, {4, 1},
+ {9, 2}, {5, 1}, {7, 1}, {6, 1}, {8, 1},
+ {9, 1}, {11, 1}, {10, 1}, {12, 1}, {13, 1},
+ {15, 1}, {14, 1}, {16, 1}, {17, 1}, {19, 1},
+ {18, 1}, {20, 1}, {21, 1}, {23, 1}, {22, 1},
+ {24, 1}, {25, 1}, {27, 1}, {26, 1}, {28, 1},
+ {29, 1}, {31, 1}, {30, 1}, {32, 1}, {33, 1}
+};
+
+int get_clocks (void)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ u8 spmf;
+ u8 cpmf;
+ u8 sys_div;
+ u8 ips_div;
+ u8 pci_div;
+ u32 ref_clk = CONFIG_SYS_MPC512X_CLKIN;
+ u32 spll;
+ u32 sys_clk;
+ u32 core_clk;
+ u32 csb_clk;
+ u32 ips_clk;
+ u32 pci_clk;
+ u32 reg;
+
+ reg = in_be32(&im->sysconf.immrbar);
+ if ((reg & IMMRBAR_BASE_ADDR) != (u32) im)
+ return -1;
+
+ reg = in_be32(&im->clk.spmr);
+ spmf = (reg & SPMR_SPMF) >> SPMR_SPMF_SHIFT;
+ spll = ref_clk * spmf_mult[spmf];
+
+ reg = in_be32(&im->clk.scfr[1]);
+ sys_div = (reg & SCFR2_SYS_DIV) >> SCFR2_SYS_DIV_SHIFT;
+ sys_clk = (spll * sys_dividors[sys_div][1]) / sys_dividors[sys_div][0];
+
+ csb_clk = sys_clk / 2;
+
+ reg = in_be32(&im->clk.spmr);
+ cpmf = (reg & SPMR_CPMF) >> SPMR_CPMF_SHIFT;
+ core_clk = (csb_clk * cpmf_mult[cpmf][0]) / cpmf_mult[cpmf][1];
+
+ reg = in_be32(&im->clk.scfr[0]);
+ ips_div = (reg & SCFR1_IPS_DIV_MASK) >> SCFR1_IPS_DIV_SHIFT;
+ if (ips_div != 0) {
+ ips_clk = csb_clk / ips_div;
+ } else {
+ /* in case we cannot get a sane IPS divisor, fail gracefully */
+ ips_clk = 0;
+ }
+
+ reg = in_be32(&im->clk.scfr[0]);
+ pci_div = (reg & SCFR1_PCI_DIV_MASK) >> SCFR1_PCI_DIV_SHIFT;
+ if (pci_div != 0) {
+ pci_clk = csb_clk / pci_div;
+ } else {
+ /* in case we cannot get a sane IPS divisor, fail gracefully */
+ pci_clk = 333333;
+ }
+
+ gd->arch.ips_clk = ips_clk;
+ gd->pci_clk = pci_clk;
+ gd->arch.csb_clk = csb_clk;
+ gd->cpu_clk = core_clk;
+ gd->bus_clk = csb_clk;
+ return 0;
+
+}
+
+/********************************************
+ * get_bus_freq
+ * return system bus freq in Hz
+ *********************************************/
+ulong get_bus_freq (ulong dummy)
+{
+ return gd->arch.csb_clk;
+}
+
+int do_clocks (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ char buf[32];
+
+ printf("Clock configuration:\n");
+ printf(" CPU: %-4s MHz\n", strmhz(buf, gd->cpu_clk));
+ printf(" Coherent System Bus: %-4s MHz\n",
+ strmhz(buf, gd->arch.csb_clk));
+ printf(" IPS Bus: %-4s MHz\n",
+ strmhz(buf, gd->arch.ips_clk));
+ printf(" PCI: %-4s MHz\n", strmhz(buf, gd->pci_clk));
+ printf(" DDR: %-4s MHz\n",
+ strmhz(buf, 2 * gd->arch.csb_clk));
+ return 0;
+}
+
+U_BOOT_CMD(clocks, 1, 0, do_clocks,
+ "print clock configuration",
+ " clocks"
+);
diff --git a/arch/powerpc/cpu/mpc512x/start.S b/arch/powerpc/cpu/mpc512x/start.S
new file mode 100644
index 0000000..6d1a99a
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/start.S
@@ -0,0 +1,708 @@
+/*
+ * Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2000-2009 Wolfgang Denk <wd@denx.de>
+ * Copyright Freescale Semiconductor, Inc. 2004, 2006.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Based on the MPC83xx code.
+ */
+
+/*
+ * U-Boot - Startup Code for MPC512x based Embedded Boards
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#ifndef CONFIG_IDENT_STRING
+#define CONFIG_IDENT_STRING "MPC512X"
+#endif
+#include <version.h>
+
+#define CONFIG_521X 1 /* needed for Linux kernel header files*/
+
+#include <asm/immap_512x.h>
+#include "asm-offsets.h"
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+#include <asm/u-boot.h>
+
+/*
+ * Floating Point enable, Machine Check and Recoverable Interr.
+ */
+#undef MSR_KERNEL
+#ifdef DEBUG
+#define MSR_KERNEL (MSR_FP|MSR_RI)
+#else
+#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI)
+#endif
+
+/* Macros for manipulating CSx_START/STOP */
+#define START_REG(start) ((start) >> 16)
+#define STOP_REG(start, size) (((start) + (size) - 1) >> 16)
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+ START_GOT
+ GOT_ENTRY(_GOT2_TABLE_)
+ GOT_ENTRY(_FIXUP_TABLE_)
+
+ GOT_ENTRY(_start)
+ GOT_ENTRY(_start_of_vectors)
+ GOT_ENTRY(_end_of_vectors)
+ GOT_ENTRY(transfer_to_handler)
+
+ GOT_ENTRY(__init_end)
+ GOT_ENTRY(__bss_end)
+ GOT_ENTRY(__bss_start)
+ END_GOT
+
+/*
+ * Magic number and version string
+ */
+ .long 0x27051956 /* U-Boot Magic Number */
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION_STRING, "\0"
+
+/*
+ * Vector Table
+ */
+ .text
+ . = EXC_OFF_SYS_RESET
+
+ .globl _start
+ /* Start from here after reset/power on */
+_start:
+ b boot_cold
+
+ .globl _start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. */
+ STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+ STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+ STD_EXCEPTION(0x500, ExtInterrupt, UnknownException)
+
+/* Alignment exception. */
+ . = 0x600
+Alignment:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+ . = 0x700
+ProgramCheck:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+ MSR_KERNEL, COPY_EE)
+
+/* Floating Point Unit unavailable exception */
+ STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+/* Decrementer */
+ STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+
+/* Critical interrupt */
+ STD_EXCEPTION(0xa00, Critical, UnknownException)
+
+/* System Call */
+ STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+
+/* Trace interrupt */
+ STD_EXCEPTION(0xd00, Trace, UnknownException)
+
+/* Performance Monitor interrupt */
+ STD_EXCEPTION(0xf00, PerfMon, UnknownException)
+
+/* Intruction Translation Miss */
+ STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException)
+
+/* Data Load Translation Miss */
+ STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException)
+
+/* Data Store Translation Miss */
+ STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException)
+
+/* Instruction Address Breakpoint */
+ STD_EXCEPTION(0x1300, InstructionAddrBreakpoint, DebugException)
+
+/* System Management interrupt */
+ STD_EXCEPTION(0x1400, SystemMgmtInterrupt, UnknownException)
+
+ .globl _end_of_vectors
+_end_of_vectors:
+
+ . = 0x3000
+boot_cold:
+ /* Save msr contents */
+ mfmsr r5
+
+ /* Set IMMR area to our preferred location */
+ lis r4, CONFIG_DEFAULT_IMMR@h
+ lis r3, CONFIG_SYS_IMMR@h
+ ori r3, r3, CONFIG_SYS_IMMR@l
+ stw r3, IMMRBAR(r4)
+ mtspr MBAR, r3 /* IMMRBAR is mirrored into the MBAR SPR (311) */
+
+ /* Initialise the machine */
+ bl cpu_early_init
+
+ /*
+ * Set up Local Access Windows:
+ *
+ * 1) Boot/CS0 (boot FLASH)
+ * 2) On-chip SRAM (initial stack purposes)
+ */
+
+ /* Boot CS/CS0 window range */
+ lis r3, CONFIG_SYS_IMMR@h
+ ori r3, r3, CONFIG_SYS_IMMR@l
+
+ lis r4, START_REG(CONFIG_SYS_FLASH_BASE)
+ ori r4, r4, STOP_REG(CONFIG_SYS_FLASH_BASE, CONFIG_SYS_FLASH_SIZE)
+ stw r4, LPCS0AW(r3)
+
+ /*
+ * The SRAM window has a fixed size (256K), so only the start address
+ * is necessary
+ */
+ lis r4, START_REG(CONFIG_SYS_SRAM_BASE) & 0xff00
+ stw r4, SRAMBAR(r3)
+
+ /*
+ * According to MPC5121e RM, configuring local access windows should
+ * be followed by a dummy read of the config register that was
+ * modified last and an isync
+ */
+ lwz r4, SRAMBAR(r3)
+ isync
+
+ /*
+ * Set configuration of the Boot/CS0, the SRAM window does not have a
+ * config register so no params can be set for it
+ */
+ lis r3, (CONFIG_SYS_IMMR + LPC_OFFSET)@h
+ ori r3, r3, (CONFIG_SYS_IMMR + LPC_OFFSET)@l
+
+ lis r4, CONFIG_SYS_CS0_CFG@h
+ ori r4, r4, CONFIG_SYS_CS0_CFG@l
+ stw r4, CS0_CONFIG(r3)
+
+ /* Master enable all CS's */
+ lis r4, CS_CTRL_ME@h
+ ori r4, r4, CS_CTRL_ME@l
+ stw r4, CS_CTRL(r3)
+
+ lis r4, (CONFIG_SYS_MONITOR_BASE)@h
+ ori r4, r4, (CONFIG_SYS_MONITOR_BASE)@l
+ addi r5, r4, in_flash - _start + EXC_OFF_SYS_RESET
+ mtlr r5
+ blr
+
+in_flash:
+ lis r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@h
+ ori r1, r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@l
+
+ li r0, 0 /* Make room for stack frame header and */
+ stwu r0, -4(r1) /* clear final stack frame so that */
+ stwu r0, -4(r1) /* stack backtraces terminate cleanly */
+
+ /* let the C-code set up the rest */
+ /* */
+ /* Be careful to keep code relocatable & stack humble */
+ /*------------------------------------------------------*/
+
+ GET_GOT /* initialize GOT access */
+
+ /* r3: IMMR */
+ lis r3, CONFIG_SYS_IMMR@h
+ /* run low-level CPU init code (in Flash) */
+ bl cpu_init_f
+
+ /* run 1st part of board init code (in Flash) */
+ bl board_init_f
+
+ /* NOTREACHED - board_init_f() does not return */
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+ .globl transfer_to_handler
+transfer_to_handler:
+ stw r22,_NIP(r21)
+ lis r22,MSR_POW@h
+ andc r23,r23,r22
+ stw r23,_MSR(r21)
+ SAVE_GPR(7, r21)
+ SAVE_4GPRS(8, r21)
+ SAVE_8GPRS(12, r21)
+ SAVE_8GPRS(24, r21)
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
+
+int_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+
+/*
+ * This code initialises the machine, it expects original MSR contents to be in r5.
+ */
+cpu_early_init:
+ /* Initialize machine status; enable machine check interrupt */
+ /*-----------------------------------------------------------*/
+
+ li r3, MSR_KERNEL /* Set ME and RI flags */
+ rlwimi r3, r5, 0, 25, 25 /* preserve IP bit */
+#ifdef DEBUG
+ rlwimi r3, r5, 0, 21, 22 /* debugger might set SE, BE bits */
+#endif
+ mtmsr r3
+ SYNC
+ mtspr SRR1, r3 /* Mirror current MSR state in SRR1 */
+
+ lis r3, CONFIG_SYS_IMMR@h
+
+#if defined(CONFIG_WATCHDOG)
+ /* Initialise the watchdog and reset it */
+ /*--------------------------------------*/
+ lis r4, CONFIG_SYS_WATCHDOG_VALUE
+ ori r4, r4, (SWCRR_SWEN | SWCRR_SWRI | SWCRR_SWPR)
+ stw r4, SWCRR(r3)
+
+ /* reset */
+ li r4, 0x556C
+ sth r4, SWSRR@l(r3)
+ li r4, 0x0
+ ori r4, r4, 0xAA39
+ sth r4, SWSRR@l(r3)
+#else
+ /* Disable the watchdog */
+ /*----------------------*/
+ lwz r4, SWCRR(r3)
+ /*
+ * Check to see if it's enabled for disabling: once disabled by s/w
+ * it's not possible to re-enable it
+ */
+ andi. r4, r4, 0x4
+ beq 1f
+ xor r4, r4, r4
+ stw r4, SWCRR(r3)
+1:
+#endif /* CONFIG_WATCHDOG */
+
+ /* Initialize the Hardware Implementation-dependent Registers */
+ /* HID0 also contains cache control */
+ /*------------------------------------------------------*/
+ lis r3, CONFIG_SYS_HID0_INIT@h
+ ori r3, r3, CONFIG_SYS_HID0_INIT@l
+ SYNC
+ mtspr HID0, r3
+
+ lis r3, CONFIG_SYS_HID0_FINAL@h
+ ori r3, r3, CONFIG_SYS_HID0_FINAL@l
+ SYNC
+ mtspr HID0, r3
+
+ lis r3, CONFIG_SYS_HID2@h
+ ori r3, r3, CONFIG_SYS_HID2@l
+ SYNC
+ mtspr HID2, r3
+ sync
+ blr
+
+
+/* Cache functions.
+ *
+ * Note: requires that all cache bits in
+ * HID0 are in the low half word.
+ */
+ .globl icache_enable
+icache_enable:
+ mfspr r3, HID0
+ ori r3, r3, HID0_ICE
+ lis r4, 0
+ ori r4, r4, HID0_ILOCK
+ andc r3, r3, r4
+ ori r4, r3, HID0_ICFI
+ isync
+ mtspr HID0, r4 /* sets enable and invalidate, clears lock */
+ isync
+ mtspr HID0, r3 /* clears invalidate */
+ blr
+
+ .globl icache_disable
+icache_disable:
+ mfspr r3, HID0
+ lis r4, 0
+ ori r4, r4, HID0_ICE|HID0_ILOCK
+ andc r3, r3, r4
+ ori r4, r3, HID0_ICFI
+ isync
+ mtspr HID0, r4 /* sets invalidate, clears enable and lock*/
+ isync
+ mtspr HID0, r3 /* clears invalidate */
+ blr
+
+ .globl icache_status
+icache_status:
+ mfspr r3, HID0
+ rlwinm r3, r3, (31 - HID0_ICE_SHIFT + 1), 31, 31
+ blr
+
+ .globl dcache_enable
+dcache_enable:
+ mfspr r3, HID0
+ li r5, HID0_DCFI|HID0_DLOCK
+ andc r3, r3, r5
+ mtspr HID0, r3 /* no invalidate, unlock */
+ ori r3, r3, HID0_DCE
+ ori r5, r3, HID0_DCFI
+ mtspr HID0, r5 /* enable + invalidate */
+ mtspr HID0, r3 /* enable */
+ sync
+ blr
+
+ .globl dcache_disable
+dcache_disable:
+ mfspr r3, HID0
+ lis r4, 0
+ ori r4, r4, HID0_DCE|HID0_DLOCK
+ andc r3, r3, r4
+ ori r4, r3, HID0_DCI
+ sync
+ mtspr HID0, r4 /* sets invalidate, clears enable and lock */
+ sync
+ mtspr HID0, r3 /* clears invalidate */
+ blr
+
+ .globl dcache_status
+dcache_status:
+ mfspr r3, HID0
+ rlwinm r3, r3, (31 - HID0_DCE_SHIFT + 1), 31, 31
+ blr
+
+ .globl get_pvr
+get_pvr:
+ mfspr r3, PVR
+ blr
+
+/*-------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+ .globl relocate_code
+relocate_code:
+ mr r1, r3 /* Set new stack pointer */
+ mr r9, r4 /* Save copy of Global Data pointer */
+ mr r10, r5 /* Save copy of Destination Address */
+
+ GET_GOT
+ mr r3, r5 /* Destination Address */
+ lis r4, CONFIG_SYS_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CONFIG_SYS_MONITOR_BASE@l
+ lwz r5, GOT(__init_end)
+ sub r5, r5, r4
+ li r6, CONFIG_SYS_CACHELINE_SIZE /* Cache Line Size */
+
+ /*
+ * Fix GOT pointer:
+ *
+ * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE)
+ * + Destination Address
+ *
+ * Offset:
+ */
+ sub r15, r10, r4
+
+ /* First our own GOT */
+ add r12, r12, r15
+ /* then the one used by the C code */
+ add r30, r30, r15
+
+ /*
+ * Now relocate code
+ */
+ cmplw cr1,r3,r4
+ addi r0,r5,3
+ srwi. r0,r0,2
+ beq cr1,4f /* In place copy is not necessary */
+ beq 7f /* Protect against 0 count */
+ mtctr r0
+ bge cr1,2f
+ la r8,-4(r4)
+ la r7,-4(r3)
+
+ /* copy */
+1: lwzu r0,4(r8)
+ stwu r0,4(r7)
+ bdnz 1b
+
+ addi r0,r5,3
+ srwi. r0,r0,2
+ mtctr r0
+ la r8,-4(r4)
+ la r7,-4(r3)
+
+ /* and compare */
+20: lwzu r20,4(r8)
+ lwzu r21,4(r7)
+ xor. r22, r20, r21
+ bne 30f
+ bdnz 20b
+ b 4f
+
+ /* compare failed */
+30: li r3, 0
+ blr
+
+2: slwi r0,r0,2 /* re copy in reverse order ... y do we needed it? */
+ add r8,r4,r0
+ add r7,r3,r0
+3: lwzu r0,-4(r8)
+ stwu r0,-4(r7)
+ bdnz 3b
+
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4: cmpwi r6,0
+ add r5,r3,r5
+ beq 7f /* Always flush prefetch queue in any case */
+ subi r0,r6,1
+ andc r3,r3,r0
+ mr r4,r3
+5: dcbst 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 5b
+ sync /* Wait for all dcbst to complete on bus */
+ mr r4,r3
+6: icbi 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 6b
+7: sync /* Wait for all icbi to complete on bus */
+ isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+ addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+ mtlr r0
+ blr
+
+in_ram:
+ /*
+ * Relocation Function, r12 point to got2+0x8000
+ *
+ * Adjust got2 pointers, no need to check for 0, this code
+ * already puts a few entries in the table.
+ */
+ li r0,__got2_entries@sectoff@l
+ la r3,GOT(_GOT2_TABLE_)
+ lwz r11,GOT(_GOT2_TABLE_)
+ mtctr r0
+ sub r11,r3,r11
+ addi r3,r3,-4
+1: lwzu r0,4(r3)
+ cmpwi r0,0
+ beq- 2f
+ add r0,r0,r11
+ stw r0,0(r3)
+2: bdnz 1b
+
+ /*
+ * Now adjust the fixups and the pointers to the fixups
+ * in case we need to move ourselves again.
+ */
+ li r0,__fixup_entries@sectoff@l
+ lwz r3,GOT(_FIXUP_TABLE_)
+ cmpwi r0,0
+ mtctr r0
+ addi r3,r3,-4
+ beq 4f
+3: lwzu r4,4(r3)
+ lwzux r0,r4,r11
+ cmpwi r0,0
+ add r0,r0,r11
+ stw r4,0(r3)
+ beq- 5f
+ stw r0,0(r4)
+5: bdnz 3b
+4:
+clear_bss:
+ /*
+ * Now clear BSS segment
+ */
+ lwz r3,GOT(__bss_start)
+ lwz r4,GOT(__bss_end)
+
+ cmplw 0, r3, r4
+ beq 6f
+
+ li r0, 0
+5:
+ stw r0, 0(r3)
+ addi r3, r3, 4
+ cmplw 0, r3, r4
+ bne 5b
+6:
+ mr r3, r9 /* Global Data pointer */
+ mr r4, r10 /* Destination Address */
+ bl board_init_r
+
+ /*
+ * Copy exception vector code to low memory
+ *
+ * r3: dest_addr
+ * r7: source address, r8: end address, r9: target address
+ */
+ .globl trap_init
+trap_init:
+ mflr r4 /* save link register */
+ GET_GOT
+ lwz r7, GOT(_start)
+ lwz r8, GOT(_end_of_vectors)
+
+ li r9, 0x100 /* reset vector at 0x100 */
+
+ cmplw 0, r7, r8
+ bgelr /* return if r7>=r8 - just in case */
+1:
+ lwz r0, 0(r7)
+ stw r0, 0(r9)
+ addi r7, r7, 4
+ addi r9, r9, 4
+ cmplw 0, r7, r8
+ bne 1b
+
+ /*
+ * relocate `hdlr' and `int_return' entries
+ */
+ li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+ li r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 2b
+
+ li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+ li r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 3b
+
+ li r7, .L_Trace - _start + EXC_OFF_SYS_RESET
+ li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 4b
+
+ mfmsr r3 /* now that the vectors have */
+ lis r7, MSR_IP@h /* relocated into low memory */
+ ori r7, r7, MSR_IP@l /* MSR[IP] can be turned off */
+ andc r3, r3, r7 /* (if it was on) */
+ SYNC /* Some chip revs need this... */
+ mtmsr r3
+ SYNC
+
+ mtlr r4 /* restore link register */
+ blr
diff --git a/arch/powerpc/cpu/mpc512x/traps.c b/arch/powerpc/cpu/mpc512x/traps.c
new file mode 100644
index 0000000..15468e5
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/traps.c
@@ -0,0 +1,204 @@
+/*
+ * (C) Copyright 2000 - 2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Derived from the MPC83xx code.
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware
+ * exceptions
+ */
+
+#include <common.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+extern unsigned long search_exception_table(unsigned long);
+
+/*
+ * End of addressable memory. This may be less than the actual
+ * amount of memory on the system if we're unable to keep all
+ * the memory mapped in.
+ */
+extern ulong get_effective_memsize(void);
+#define END_OF_MEM (gd->bd->bi_memstart + get_effective_memsize())
+
+/*
+ * Trap & Exception support
+ */
+
+static void print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ puts("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ putc('\n');
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *) *sp;
+ }
+ putc('\n');
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ int i;
+
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr & MSR_EE ? 1 : 0, regs->msr & MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr & MSR_ME ? 1 : 0,
+ regs->msr & MSR_IR ? 1 : 0,
+ regs->msr & MSR_DR ? 1 : 0);
+
+ putc('\n');
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0) {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7) {
+ putc('\n');
+ }
+ }
+}
+
+
+static void _exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception at pc %lx signal %d", regs->nip, signr);
+}
+
+
+void MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup = search_exception_table(regs->nip);
+
+ if (fixup) {
+ regs->nip = fixup;
+ return;
+ }
+
+#ifdef CONFIG_CMD_KGDB
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ puts("Machine check.\nCaused by (from msr): ");
+ printf("regs %p ", regs);
+ switch (regs->msr & 0x00FF0000) {
+ case (0x80000000 >> 10):
+ puts("Instruction cache parity signal\n");
+ break;
+ case (0x80000000 >> 11):
+ puts("Data cache parity signal\n");
+ break;
+ case (0x80000000 >> 12):
+ puts("Machine check signal\n");
+ break;
+ case (0x80000000 >> 13):
+ puts("Transfer error ack signal\n");
+ break;
+ case (0x80000000 >> 14):
+ puts("Data parity signal\n");
+ break;
+ case (0x80000000 >> 15):
+ puts("Address parity signal\n");
+ break;
+ default:
+ puts("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+
+ panic("machine check");
+}
+
+void AlignmentException(struct pt_regs *regs)
+{
+#ifdef CONFIG_CMD_KGDB
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void ProgramCheckException(struct pt_regs *regs)
+{
+#ifdef CONFIG_CMD_KGDB
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void SoftEmuException(struct pt_regs *regs)
+{
+#ifdef CONFIG_CMD_KGDB
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Software Emulation Exception");
+}
+
+
+void UnknownException(struct pt_regs *regs)
+{
+#ifdef CONFIG_CMD_KGDB
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+#ifdef CONFIG_CMD_BEDBUG
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+void DebugException(struct pt_regs *regs)
+{
+ printf("Debugger trap at @ %lx\n", regs->nip);
+ show_regs(regs);
+#ifdef CONFIG_CMD_BEDBUG
+ do_bedbug_breakpoint(regs);
+#endif
+}
diff --git a/arch/powerpc/cpu/mpc512x/u-boot.lds b/arch/powerpc/cpu/mpc512x/u-boot.lds
new file mode 100644
index 0000000..0d86979
--- /dev/null
+++ b/arch/powerpc/cpu/mpc512x/u-boot.lds
@@ -0,0 +1,90 @@
+/*
+ * (C) Copyright 2007-2010 DENX Software Engineering.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+SECTIONS
+{
+ .text :
+ {
+ arch/powerpc/cpu/mpc512x/start.o (.text*)
+ *(.text*)
+ . = ALIGN(16);
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ }
+
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x0FFF) & 0xFFFFF000;
+ _erotext = .;
+ PROVIDE (erotext = .);
+ .reloc :
+ {
+ _GOT2_TABLE_ = .;
+ KEEP(*(.got2))
+ KEEP(*(.got))
+ PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
+ _FIXUP_TABLE_ = .;
+ KEEP(*(.fixup))
+ *(.fixup)
+ }
+ __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
+ __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+ .data :
+ {
+ *(.data*)
+ *(.sdata*)
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+
+ . = .;
+
+ . = ALIGN(4);
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+
+ . = .;
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ . = ALIGN(4096);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(4096);
+ __init_end = .;
+
+ __bss_start = .;
+ .bss (NOLOAD) :
+ {
+ *(.bss*)
+ *(.sbss*)
+ *(COMMON)
+ . = ALIGN(4);
+ }
+ __bss_end = . ;
+ PROVIDE (end = .);
+}
+ENTRY(_start)
diff --git a/arch/powerpc/cpu/mpc5xx/Makefile b/arch/powerpc/cpu/mpc5xx/Makefile
new file mode 100644
index 0000000..078b524
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xx/Makefile
@@ -0,0 +1,59 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# (C) Copyright 2003
+# Martin Winistoerfer, martinwinistoerfer@gmx.ch.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+#
+# File: arch/powerpc/cpu/mpc5xx/Makefile
+#
+# Discription: Makefile to build mpc5xx cpu configuration.
+# Will include top config.mk which itselfs
+# uses the definitions made in arch/powerpc/cpu/mpc5xx/config.mk
+#
+
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(CPU).o
+
+START = start.o
+COBJS = serial.o cpu.o cpu_init.o interrupts.o traps.o speed.o spi.o
+
+SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
+START := $(addprefix $(obj),$(START))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/powerpc/cpu/mpc5xx/config.mk b/arch/powerpc/cpu/mpc5xx/config.mk
new file mode 100644
index 0000000..ab55040
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xx/config.mk
@@ -0,0 +1,26 @@
+#
+# (C) Copyright 2003
+# Martin Winistoerfer, martinwinistoerfer@gmx.ch.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_RELFLAGS += -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_5xx -ffixed-r2 -mpowerpc -msoft-float
diff --git a/arch/powerpc/cpu/mpc5xx/cpu.c b/arch/powerpc/cpu/mpc5xx/cpu.c
new file mode 100644
index 0000000..5aa7f84
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xx/cpu.c
@@ -0,0 +1,171 @@
+/*
+ * (C) Copyright 2003
+ * Martin Winistoerfer, martinwinistoerfer@gmx.ch.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation,
+ */
+
+/*
+ * File: cpu.c
+ *
+ * Discription: Some cpu specific function for watchdog,
+ * cpu version test, clock setting ...
+ *
+ */
+
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc5xx.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if (defined(CONFIG_MPC555))
+# define ID_STR "MPC555/556"
+
+/*
+ * Check version of cpu with Processor Version Register (PVR)
+ */
+static int check_cpu_version (long clock, uint pvr, uint immr)
+{
+ char buf[32];
+ /* The highest 16 bits should be 0x0002 for a MPC555/556 */
+ if ((pvr >> 16) == 0x0002) {
+ printf (" " ID_STR " Version %x", (pvr >> 16));
+ printf (" at %s MHz:", strmhz (buf, clock));
+ } else {
+ printf ("Not supported cpu version");
+ return -1;
+ }
+ return 0;
+}
+#endif /* CONFIG_MPC555 */
+
+
+/*
+ * Check version of mpc5xx
+ */
+int checkcpu (void)
+{
+ ulong clock = gd->cpu_clk;
+ uint immr = get_immr (0); /* Return full IMMR contents */
+ uint pvr = get_pvr (); /* Retrieve PVR register */
+
+ puts ("CPU: ");
+
+ return check_cpu_version (clock, pvr, immr);
+}
+
+/*
+ * Called by macro WATCHDOG_RESET
+ */
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset (void)
+{
+ int re_enable = disable_interrupts ();
+
+ reset_5xx_watchdog ((immap_t *) CONFIG_SYS_IMMR);
+ if (re_enable)
+ enable_interrupts ();
+}
+
+/*
+ * Will clear software reset
+ */
+void reset_5xx_watchdog (volatile immap_t * immr)
+{
+ /* Use the MPC5xx Internal Watchdog */
+ immr->im_siu_conf.sc_swsr = 0x556c; /* Prevent SW time-out */
+ immr->im_siu_conf.sc_swsr = 0xaa39;
+}
+
+#endif /* CONFIG_WATCHDOG */
+
+
+/*
+ * Get timebase clock frequency
+ */
+unsigned long get_tbclk (void)
+{
+ volatile immap_t *immr = (volatile immap_t *) CONFIG_SYS_IMMR;
+ ulong oscclk, factor;
+
+ if (immr->im_clkrst.car_sccr & SCCR_TBS) {
+ return (gd->cpu_clk / 16);
+ }
+
+ factor = (((CONFIG_SYS_PLPRCR) & PLPRCR_MF_MSK) >> PLPRCR_MF_SHIFT) + 1;
+
+ oscclk = gd->cpu_clk / factor;
+
+ if ((immr->im_clkrst.car_sccr & SCCR_RTSEL) == 0 || factor > 2) {
+ return (oscclk / 4);
+ }
+ return (oscclk / 16);
+}
+
+void dcache_enable (void)
+{
+ return;
+}
+
+void dcache_disable (void)
+{
+ return;
+}
+
+int dcache_status (void)
+{
+ return 0; /* always off */
+}
+
+/*
+ * Reset board
+ */
+int do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+#if defined(CONFIG_PATI)
+ volatile ulong *addr = (ulong *) CONFIG_SYS_RESET_ADDRESS;
+ *addr = 1;
+#else
+ ulong addr;
+
+ /* Interrupts off, enable reset */
+ __asm__ volatile (" mtspr 81, %r0 \n\t"
+ " mfmsr %r3 \n\t"
+ " rlwinm %r31,%r3,0,25,23\n\t"
+ " mtmsr %r31 \n\t");
+ /*
+ * Trying to execute the next instruction at a non-existing address
+ * should cause a machine check, resulting in reset
+ */
+#ifdef CONFIG_SYS_RESET_ADDRESS
+ addr = CONFIG_SYS_RESET_ADDRESS;
+#else
+ /*
+ * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address, CONFIG_SYS_MONITOR_BASE * - sizeof (ulong) is usually a valid address. Better pick an address
+ * known to be invalid on your system and assign it to CONFIG_SYS_RESET_ADDRESS.
+ * "(ulong)-1" used to be a good choice for many systems...
+ */
+ addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong);
+#endif
+ ((void (*) (void)) addr) ();
+#endif /* #if defined(CONFIG_PATI) */
+ return 1;
+}
diff --git a/arch/powerpc/cpu/mpc5xx/cpu_init.c b/arch/powerpc/cpu/mpc5xx/cpu_init.c
new file mode 100644
index 0000000..cb4bf84
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xx/cpu_init.c
@@ -0,0 +1,123 @@
+/*
+ * (C) Copyright 2003 Martin Winistoerfer, martinwinistoerfer@gmx.ch.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation,
+ */
+
+/*
+ * File: cpu_init.c
+ *
+ * Discription: Contains initialisation functions to setup
+ * the cpu properly
+ *
+ */
+
+#include <common.h>
+#include <mpc5xx.h>
+#include <watchdog.h>
+
+/*
+ * Setup essential cpu registers to run
+ */
+void cpu_init_f (volatile immap_t * immr)
+{
+ volatile memctl5xx_t *memctl = &immr->im_memctl;
+ ulong reg;
+
+ /* SYPCR - contains watchdog control. This will enable watchdog */
+ /* if CONFIG_WATCHDOG is set */
+ immr->im_siu_conf.sc_sypcr = CONFIG_SYS_SYPCR;
+
+#if defined(CONFIG_WATCHDOG)
+ reset_5xx_watchdog (immr);
+#endif
+
+ /* SIUMCR - contains debug pin configuration */
+ immr->im_siu_conf.sc_siumcr |= CONFIG_SYS_SIUMCR;
+
+ /* Initialize timebase. Unlock TBSCRK */
+ immr->im_sitk.sitk_tbscrk = KAPWR_KEY;
+ immr->im_sit.sit_tbscr = CONFIG_SYS_TBSCR;
+
+ /* Full IMB bus speed */
+ immr->im_uimb.uimb_umcr = CONFIG_SYS_UMCR;
+
+ /* Time base and decrementer will be enables (TBE) */
+ /* in init_timebase() in time.c called from board_init_f(). */
+
+ /* Initialize the PIT. Unlock PISCRK */
+ immr->im_sitk.sitk_piscrk = KAPWR_KEY;
+ immr->im_sit.sit_piscr = CONFIG_SYS_PISCR;
+
+#if !defined(CONFIG_PATI)
+ /* PATI sest PLL in start.S */
+ /* PLL (CPU clock) settings */
+ immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+
+ /* If CONFIG_SYS_PLPRCR (set in the various *_config.h files) tries to
+ * set the MF field, then just copy CONFIG_SYS_PLPRCR over car_plprcr,
+ * otherwise OR in CONFIG_SYS_PLPRCR so we do not change the currentMF
+ * field value.
+ */
+#if ((CONFIG_SYS_PLPRCR & PLPRCR_MF_MSK) != 0)
+ reg = CONFIG_SYS_PLPRCR; /* reset control bits */
+#else
+ reg = immr->im_clkrst.car_plprcr;
+ reg &= PLPRCR_MF_MSK; /* isolate MF field */
+ reg |= CONFIG_SYS_PLPRCR; /* reset control bits */
+#endif
+ immr->im_clkrst.car_plprcr = reg;
+
+#endif /* !defined(CONFIG_PATI) */
+
+ /* System integration timers. CONFIG_SYS_MASK has EBDF configuration */
+ immr->im_clkrstk.cark_sccrk = KAPWR_KEY;
+ reg = immr->im_clkrst.car_sccr;
+ reg &= SCCR_MASK;
+ reg |= CONFIG_SYS_SCCR;
+ immr->im_clkrst.car_sccr = reg;
+
+ /* Memory Controller */
+ memctl->memc_br0 = CONFIG_SYS_BR0_PRELIM;
+ memctl->memc_or0 = CONFIG_SYS_OR0_PRELIM;
+
+#if (defined(CONFIG_SYS_OR1_PRELIM) && defined(CONFIG_SYS_BR1_PRELIM))
+ memctl->memc_or1 = CONFIG_SYS_OR1_PRELIM;
+ memctl->memc_br1 = CONFIG_SYS_BR1_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR2_PRELIM) && defined(CONFIG_SYS_BR2_PRELIM)
+ memctl->memc_or2 = CONFIG_SYS_OR2_PRELIM;
+ memctl->memc_br2 = CONFIG_SYS_BR2_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR3_PRELIM) && defined(CONFIG_SYS_BR3_PRELIM)
+ memctl->memc_or3 = CONFIG_SYS_OR3_PRELIM;
+ memctl->memc_br3 = CONFIG_SYS_BR3_PRELIM;
+#endif
+
+}
+
+/*
+ * Initialize higher level parts of cpu
+ */
+int cpu_init_r (void)
+{
+ /* Nothing to do at the moment */
+ return (0);
+}
diff --git a/arch/powerpc/cpu/mpc5xx/interrupts.c b/arch/powerpc/cpu/mpc5xx/interrupts.c
new file mode 100644
index 0000000..66bce30
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xx/interrupts.c
@@ -0,0 +1,207 @@
+/*
+ * (C) Copyright 2000-2002 Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * (C) Copyright 2003 Martin Winistoerfer, martinwinistoerfer@gmx.ch.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation,
+ */
+
+/*
+ * File: interrupt.c
+ *
+ * Discription: Contains interrupt routines needed by U-Boot
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <mpc5xx.h>
+#include <asm/processor.h>
+
+#if defined(CONFIG_PATI)
+/* PATI uses IRQs for PCI doorbell */
+#undef NR_IRQS
+#define NR_IRQS 16
+#endif
+
+struct interrupt_action {
+ interrupt_handler_t *handler;
+ void *arg;
+ int count;
+};
+
+static struct interrupt_action irq_vecs[NR_IRQS];
+
+/*
+ * Initialise interrupts
+ */
+
+int interrupt_init_cpu (ulong *decrementer_count)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ int vec;
+
+ /* Decrementer used here for status led */
+ *decrementer_count = get_tbclk () / CONFIG_SYS_HZ;
+
+ /* Disable all interrupts */
+ immr->im_siu_conf.sc_simask = 0;
+ for (vec=0; vec<NR_IRQS; vec++) {
+ irq_vecs[vec].handler = NULL;
+ irq_vecs[vec].arg = NULL;
+ irq_vecs[vec].count = 0;
+ }
+
+ return (0);
+}
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt (struct pt_regs *regs)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ int irq;
+ ulong simask, newmask;
+ ulong vec, v_bit;
+
+ /*
+ * read the SIVEC register and shift the bits down
+ * to get the irq number
+ */
+ vec = immr->im_siu_conf.sc_sivec;
+ irq = vec >> 26;
+ v_bit = 0x80000000UL >> irq;
+
+ /*
+ * Read Interrupt Mask Register and Mask Interrupts
+ */
+ simask = immr->im_siu_conf.sc_simask;
+ newmask = simask & (~(0xFFFF0000 >> irq));
+ immr->im_siu_conf.sc_simask = newmask;
+
+ if (!(irq & 0x1)) { /* External Interrupt ? */
+ ulong siel;
+
+ /*
+ * Read Interrupt Edge/Level Register
+ */
+ siel = immr->im_siu_conf.sc_siel;
+
+ if (siel & v_bit) { /* edge triggered interrupt ? */
+ /*
+ * Rewrite SIPEND Register to clear interrupt
+ */
+ immr->im_siu_conf.sc_sipend = v_bit;
+ }
+ }
+
+ if (irq_vecs[irq].handler != NULL) {
+ irq_vecs[irq].handler (irq_vecs[irq].arg);
+ } else {
+ printf ("\nBogus External Interrupt IRQ %d Vector %ld\n",
+ irq, vec);
+ /* turn off the bogus interrupt to avoid it from now */
+ simask &= ~v_bit;
+ }
+ /*
+ * Re-Enable old Interrupt Mask
+ */
+ immr->im_siu_conf.sc_simask = simask;
+}
+
+/*
+ * Install and free an interrupt handler
+ */
+void irq_install_handler (int vec, interrupt_handler_t * handler,
+ void *arg)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ /* SIU interrupt */
+ if (irq_vecs[vec].handler != NULL) {
+ printf ("SIU interrupt %d 0x%x\n",
+ vec,
+ (uint) handler);
+ }
+ irq_vecs[vec].handler = handler;
+ irq_vecs[vec].arg = arg;
+ immr->im_siu_conf.sc_simask |= 1 << (31 - vec);
+#if 0
+ printf ("Install SIU interrupt for vector %d ==> %p\n",
+ vec, handler);
+#endif
+}
+
+void irq_free_handler (int vec)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ /* SIU interrupt */
+#if 0
+ printf ("Free CPM interrupt for vector %d\n",
+ vec);
+#endif
+ immr->im_siu_conf.sc_simask &= ~(1 << (31 - vec));
+ irq_vecs[vec].handler = NULL;
+ irq_vecs[vec].arg = NULL;
+}
+
+/*
+ * Timer interrupt - gets called when bit 0 of DEC changes from
+ * 0. Decrementer is enabled with bit TBE in TBSCR.
+ */
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+#if 0
+ printf ("*** Timer Interrupt *** ");
+#endif
+ /* Reset Timer Status Bit and Timers Interrupt Status */
+ immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+ __asm__ ("nop");
+ immr->im_clkrst.car_plprcr |= PLPRCR_TEXPS | PLPRCR_TMIST;
+
+ return;
+}
+
+#if defined(CONFIG_CMD_IRQ)
+/*******************************************************************************
+ *
+ * irqinfo - print information about IRQs
+ *
+ */
+int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int vec;
+
+ printf ("\nInterrupt-Information:\n");
+ printf ("Nr Routine Arg Count\n");
+
+ for (vec=0; vec<NR_IRQS; vec++) {
+ if (irq_vecs[vec].handler != NULL) {
+ printf ("%02d %08lx %08lx %d\n",
+ vec,
+ (ulong)irq_vecs[vec].handler,
+ (ulong)irq_vecs[vec].arg,
+ irq_vecs[vec].count);
+ }
+ }
+ return 0;
+}
+
+
+#endif
diff --git a/arch/powerpc/cpu/mpc5xx/serial.c b/arch/powerpc/cpu/mpc5xx/serial.c
new file mode 100644
index 0000000..732856a
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xx/serial.c
@@ -0,0 +1,183 @@
+/*
+ * (C) Copyright 2003
+ * Martin Winistoerfer, martinwinistoerfer@gmx.ch.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation,
+ */
+
+/*
+ * File: serial.c
+ *
+ * Discription: Serial interface driver for SCI1 and SCI2.
+ * Since this code will be called from ROM use
+ * only non-static local variables.
+ *
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc5xx.h>
+#include <serial.h>
+#include <linux/compiler.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Local functions
+ */
+
+static int ready_to_send(void)
+{
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ volatile short status;
+
+ do {
+#if defined(CONFIG_5xx_CONS_SCI1)
+ status = immr->im_qsmcm.qsmcm_sc1sr;
+#else
+ status = immr->im_qsmcm.qsmcm_sc2sr;
+#endif
+
+#if defined(CONFIG_WATCHDOG)
+ reset_5xx_watchdog (immr);
+#endif
+ } while ((status & SCI_TDRE) == 0);
+ return 1;
+
+}
+
+/*
+ * Minimal global serial functions needed to use one of the SCI modules.
+ */
+
+static int mpc5xx_serial_init(void)
+{
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+
+ serial_setbrg();
+
+#if defined(CONFIG_5xx_CONS_SCI1)
+ /* 10-Bit, 1 start bit, 8 data bit, no parity, 1 stop bit */
+ immr->im_qsmcm.qsmcm_scc1r1 = SCI_M_10;
+ immr->im_qsmcm.qsmcm_scc1r1 = SCI_TE | SCI_RE;
+#else
+ immr->im_qsmcm.qsmcm_scc2r1 = SCI_M_10;
+ immr->im_qsmcm.qsmcm_scc2r1 = SCI_TE | SCI_RE;
+#endif
+ return 0;
+}
+
+static void mpc5xx_serial_putc(const char c)
+{
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+
+ /* Test for completition */
+ if(ready_to_send()) {
+#if defined(CONFIG_5xx_CONS_SCI1)
+ immr->im_qsmcm.qsmcm_sc1dr = (short)c;
+#else
+ immr->im_qsmcm.qsmcm_sc2dr = (short)c;
+#endif
+ if(c == '\n') {
+ if(ready_to_send());
+#if defined(CONFIG_5xx_CONS_SCI1)
+ immr->im_qsmcm.qsmcm_sc1dr = (short)'\r';
+#else
+ immr->im_qsmcm.qsmcm_sc2dr = (short)'\r';
+#endif
+ }
+ }
+}
+
+static int mpc5xx_serial_getc(void)
+{
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ volatile short status;
+ unsigned char tmp;
+
+ /* New data ? */
+ do {
+#if defined(CONFIG_5xx_CONS_SCI1)
+ status = immr->im_qsmcm.qsmcm_sc1sr;
+#else
+ status = immr->im_qsmcm.qsmcm_sc2sr;
+#endif
+
+#if defined(CONFIG_WATCHDOG)
+ reset_5xx_watchdog (immr);
+#endif
+ } while ((status & SCI_RDRF) == 0);
+
+ /* Read data */
+#if defined(CONFIG_5xx_CONS_SCI1)
+ tmp = (unsigned char)(immr->im_qsmcm.qsmcm_sc1dr & SCI_SCXDR_MK);
+#else
+ tmp = (unsigned char)( immr->im_qsmcm.qsmcm_sc2dr & SCI_SCXDR_MK);
+#endif
+ return tmp;
+}
+
+static int mpc5xx_serial_tstc(void)
+{
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ short status;
+
+ /* New data character ? */
+#if defined(CONFIG_5xx_CONS_SCI1)
+ status = immr->im_qsmcm.qsmcm_sc1sr;
+#else
+ status = immr->im_qsmcm.qsmcm_sc2sr;
+#endif
+ return (status & SCI_RDRF);
+}
+
+static void mpc5xx_serial_setbrg(void)
+{
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ short scxbr;
+
+ /* Set baudrate */
+ scxbr = (gd->cpu_clk / (32 * gd->baudrate));
+#if defined(CONFIG_5xx_CONS_SCI1)
+ immr->im_qsmcm.qsmcm_scc1r0 = (scxbr & SCI_SCXBR_MK);
+#else
+ immr->im_qsmcm.qsmcm_scc2r0 = (scxbr & SCI_SCXBR_MK);
+#endif
+}
+
+static struct serial_device mpc5xx_serial_drv = {
+ .name = "mpc5xx_serial",
+ .start = mpc5xx_serial_init,
+ .stop = NULL,
+ .setbrg = mpc5xx_serial_setbrg,
+ .putc = mpc5xx_serial_putc,
+ .puts = default_serial_puts,
+ .getc = mpc5xx_serial_getc,
+ .tstc = mpc5xx_serial_tstc,
+};
+
+void mpc5xx_serial_initialize(void)
+{
+ serial_register(&mpc5xx_serial_drv);
+}
+
+__weak struct serial_device *default_serial_console(void)
+{
+ return &mpc5xx_serial_drv;
+}
diff --git a/arch/powerpc/cpu/mpc5xx/speed.c b/arch/powerpc/cpu/mpc5xx/speed.c
new file mode 100644
index 0000000..ea5c1de
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xx/speed.c
@@ -0,0 +1,67 @@
+/*
+ * (C) Copyright 2003
+ * Martin Winistoerfer, martinwinistoerfer@gmx.ch.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation,
+ */
+
+/*
+ * File: speed.c
+ *
+ * Discription: Provides cpu speed calculation
+ *
+ */
+
+#include <common.h>
+#include <mpc5xx.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Get cpu and bus clock
+ */
+int get_clocks (void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+#ifndef CONFIG_5xx_GCLK_FREQ
+ uint divf = (immr->im_clkrst.car_plprcr & PLPRCR_DIVF_MSK);
+ uint mf = ((immr->im_clkrst.car_plprcr & PLPRCR_MF_MSK) >> PLPRCR_MF_SHIFT);
+ ulong vcoout;
+
+ vcoout = (CONFIG_SYS_OSC_CLK / (divf + 1)) * (mf + 1) * 2;
+ if(immr->im_clkrst.car_plprcr & PLPRCR_CSRC_MSK) {
+ gd->cpu_clk = vcoout / (2^(((immr->im_clkrst.car_sccr & SCCR_DFNL_MSK) >> SCCR_DFNL_SHIFT) + 1));
+ } else {
+ gd->cpu_clk = vcoout / (2^(immr->im_clkrst.car_sccr & SCCR_DFNH_MSK));
+ }
+
+#else /* CONFIG_5xx_GCLK_FREQ */
+ gd->bus_clk = CONFIG_5xx_GCLK_FREQ;
+#endif /* CONFIG_5xx_GCLK_FREQ */
+
+ if ((immr->im_clkrst.car_sccr & SCCR_EBDF11) == 0) {
+ /* No Bus Divider active */
+ gd->bus_clk = gd->cpu_clk;
+ } else {
+ /* CLKOUT is GCLK / 2 */
+ gd->bus_clk = gd->cpu_clk / 2;
+ }
+ return (0);
+}
diff --git a/arch/powerpc/cpu/mpc5xx/spi.c b/arch/powerpc/cpu/mpc5xx/spi.c
new file mode 100644
index 0000000..3ca15ea
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xx/spi.c
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2001 Navin Boppuri / Prashant Patel
+ * <nboppuri@trinetcommunication.com>,
+ * <pmpatel@trinetcommunication.com>
+ * Copyright (c) 2001 Gerd Mennchen <Gerd.Mennchen@icn.siemens.de>
+ * Copyright (c) 2001 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * MPC5xx CPM SPI interface.
+ *
+ * Parts of this code are probably not portable and/or specific to
+ * the board which I used for the tests. Please send fixes/complaints
+ * to wd@denx.de
+ *
+ * Ported to MPC5xx
+ * Copyright (c) 2003 Denis Peter, MPL AG Switzerland, d.petr@mpl.ch.
+ */
+
+#include <common.h>
+#include <mpc5xx.h>
+#include <asm/5xx_immap.h>
+#include <linux/ctype.h>
+#include <malloc.h>
+#include <post.h>
+#include <net.h>
+
+#if defined(CONFIG_SPI)
+
+#undef DEBUG
+
+#define SPI_EEPROM_WREN 0x06
+#define SPI_EEPROM_RDSR 0x05
+#define SPI_EEPROM_READ 0x03
+#define SPI_EEPROM_WRITE 0x02
+
+
+#ifdef DEBUG
+
+#define DPRINT(a) printf a;
+/* -----------------------------------------------
+ * Helper functions to peek into tx and rx buffers
+ * ----------------------------------------------- */
+static const char * const hex_digit = "0123456789ABCDEF";
+
+static char quickhex (int i)
+{
+ return hex_digit[i];
+}
+
+static void memdump (void *pv, int num)
+{
+ int i;
+ unsigned char *pc = (unsigned char *) pv;
+
+ for (i = 0; i < num; i++)
+ printf ("%c%c ", quickhex (pc[i] >> 4), quickhex (pc[i] & 0x0f));
+ printf ("\t");
+ for (i = 0; i < num; i++)
+ printf ("%c", isprint (pc[i]) ? pc[i] : '.');
+ printf ("\n");
+}
+#else /* !DEBUG */
+
+#define DPRINT(a)
+
+#endif /* DEBUG */
+
+/* -------------------
+ * Function prototypes
+ * ------------------- */
+void spi_init (void);
+
+ssize_t spi_read (uchar *, int, uchar *, int);
+ssize_t spi_write (uchar *, int, uchar *, int);
+ssize_t spi_xfer (size_t);
+
+
+/* **************************************************************************
+ *
+ * Function: spi_init_f
+ *
+ * Description: Init SPI-Controller (ROM part)
+ *
+ * return: ---
+ *
+ * *********************************************************************** */
+
+void spi_init_f (void)
+{
+ int i;
+
+ volatile immap_t *immr;
+ volatile qsmcm5xx_t *qsmcm;
+
+ immr = (immap_t *) CONFIG_SYS_IMMR;
+ qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm;
+
+ qsmcm->qsmcm_qsmcr = 0; /* all accesses enabled */
+ qsmcm->qsmcm_qspi_il = 0; /* lowest IRQ */
+
+ /* --------------------------------------------
+ * GPIO or per. Function
+ * PQSPAR[00] = 0 reserved
+ * PQSPAR[01] = 1 [0x4000] -> PERI: (SPICS3)
+ * PQSPAR[02] = 0 [0x0000] -> GPIO
+ * PQSPAR[03] = 0 [0x0000] -> GPIO
+ * PQSPAR[04] = 1 [0x0800] -> PERI: (SPICS0)
+ * PQSPAR[05] = 0 reseved
+ * PQSPAR[06] = 1 [0x0200] -> PERI: (SPIMOSI)
+ * PQSPAR[07] = 1 [0x0100] -> PERI: (SPIMISO)
+ * -------------------------------------------- */
+ qsmcm->qsmcm_pqspar = 0x3 | (CONFIG_SYS_SPI_CS_USED << 3);
+
+ /* --------------------------------------------
+ * DDRQS[00] = 0 reserved
+ * DDRQS[01] = 1 [0x0040] -> SPICS3 Output
+ * DDRQS[02] = 0 [0x0000] -> GPIO Output
+ * DDRQS[03] = 0 [0x0000] -> GPIO Output
+ * DDRQS[04] = 1 [0x0008] -> SPICS0 Output
+ * DDRQS[05] = 1 [0x0004] -> SPICLK Output
+ * DDRQS[06] = 1 [0x0002] -> SPIMOSI Output
+ * DDRQS[07] = 0 [0x0001] -> SPIMISO Input
+ * -------------------------------------------- */
+ qsmcm->qsmcm_ddrqs = 0x7E;
+ /* --------------------------------------------
+ * Base state for used SPI CS pins, if base = 0 active must be 1
+ * PORTQS[00] = 0 reserved
+ * PORTQS[01] = 0 reserved
+ * PORTQS[02] = 0 reserved
+ * PORTQS[03] = 0 reserved
+ * PORTQS[04] = 0 [0x0000] RxD2
+ * PORTQS[05] = 1 [0x0400] TxD2
+ * PORTQS[06] = 0 [0x0000] RxD1
+ * PORTQS[07] = 1 [0x0100] TxD1
+ * PORTQS[08] = 0 reserved
+ * PORTQS[09] = 0 [0x0000] -> SPICS3 Base Output
+ * PORTQS[10] = 0 [0x0000] -> SPICS2 Base Output
+ * PORTQS[11] = 0 [0x0000] -> SPICS1 Base Output
+ * PORTQS[12] = 0 [0x0000] -> SPICS0 Base Output
+ * PORTQS[13] = 0 [0x0004] -> SPICLK Output
+ * PORTQS[14] = 0 [0x0002] -> SPIMOSI Output
+ * PORTQS[15] = 0 [0x0001] -> SPIMISO Input
+ * -------------------------------------------- */
+ qsmcm->qsmcm_portqs |= (CONFIG_SYS_SPI_CS_BASE << 3);
+ /* --------------------------------------------
+ * Controll Register 0
+ * SPCR0[00] = 1 (0x8000) Master
+ * SPCR0[01] = 0 (0x0000) Wired-Or
+ * SPCR0[2..5] = (0x2000) Bits per transfer (default 8)
+ * SPCR0[06] = 0 (0x0000) Normal polarity
+ * SPCR0[07] = 0 (0x0000) Normal Clock Phase
+ * SPCR0[08..15] = 14 1.4MHz
+ */
+ qsmcm->qsmcm_spcr0=0xA00E;
+ /* --------------------------------------------
+ * Controll Register 1
+ * SPCR1[00] = 0 (0x0000) QSPI enabled
+ * SPCR1[1..7] = (0x7F00) Delay before Transfer
+ * SPCR1[8..15] = (0x0000) Delay After transfer (204.8usec@40MHz)
+ */
+ qsmcm->qsmcm_spcr1=0x7F00;
+ /* --------------------------------------------
+ * Controll Register 2
+ * SPCR2[00] = 0 (0x0000) SPI IRQs Disabeld
+ * SPCR2[01] = 0 (0x0000) No Wrap around
+ * SPCR2[02] = 0 (0x0000) Wrap to 0
+ * SPCR2[3..7] = (0x0000) End Queue pointer = 0
+ * SPCR2[8..10] = 0 (0x0000) reserved
+ * SPCR2[11..15] = 0 (0x0000) NewQueue Address = 0
+ */
+ qsmcm->qsmcm_spcr2=0x0000;
+ /* --------------------------------------------
+ * Controll Register 3
+ * SPCR3[00..04] = 0 (0x0000) reserved
+ * SPCR3[05] = 0 (0x0000) Feedback disabled
+ * SPCR3[06] = 0 (0x0000) IRQ on HALTA & MODF disabled
+ * SPCR3[07] = 0 (0x0000) Not halted
+ */
+ qsmcm->qsmcm_spcr3=0x00;
+ /* --------------------------------------------
+ * SPSR (Controll Register 3) Read only/ reset Flags 08,09,10
+ * SPCR3[08] = 1 (0x80) QSPI finished
+ * SPCR3[09] = 1 (0x40) Mode Fault Flag
+ * SPCR3[10] = 1 (0x20) HALTA
+ * SPCR3[11..15] = 0 (0x0000) Last executed command
+ */
+ qsmcm->qsmcm_spsr=0xE0;
+ /*-------------------------------------------
+ * Setup RAM
+ */
+ for(i=0;i<32;i++) {
+ qsmcm->qsmcm_recram[i]=0x0000;
+ qsmcm->qsmcm_tranram[i]=0x0000;
+ qsmcm->qsmcm_comdram[i]=0x00;
+ }
+ return;
+}
+
+/* **************************************************************************
+ *
+ * Function: spi_init_r
+ * Dummy, all initializations have been done in spi_init_r
+ * *********************************************************************** */
+void spi_init_r (void)
+{
+ return;
+
+}
+
+/****************************************************************************
+ * Function: spi_write
+ **************************************************************************** */
+ssize_t short_spi_write (uchar *addr, int alen, uchar *buffer, int len)
+{
+ int i,dlen;
+ volatile immap_t *immr;
+ volatile qsmcm5xx_t *qsmcm;
+
+ immr = (immap_t *) CONFIG_SYS_IMMR;
+ qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm;
+ for(i=0;i<32;i++) {
+ qsmcm->qsmcm_recram[i]=0x0000;
+ qsmcm->qsmcm_tranram[i]=0x0000;
+ qsmcm->qsmcm_comdram[i]=0x00;
+ }
+ qsmcm->qsmcm_tranram[0] = SPI_EEPROM_WREN; /* write enable */
+ spi_xfer(1);
+ i=0;
+ qsmcm->qsmcm_tranram[i++] = SPI_EEPROM_WRITE; /* WRITE memory array */
+ qsmcm->qsmcm_tranram[i++] = addr[0];
+ qsmcm->qsmcm_tranram[i++] = addr[1];
+
+ for(dlen=0;dlen<len;dlen++) {
+ qsmcm->qsmcm_tranram[i+dlen] = buffer[dlen]; /* WRITE memory array */
+ }
+ /* transmit it */
+ spi_xfer(i+dlen);
+ /* ignore received data */
+ for (i = 0; i < 1000; i++) {
+ qsmcm->qsmcm_tranram[0] = SPI_EEPROM_RDSR; /* read status */
+ qsmcm->qsmcm_tranram[1] = 0;
+ spi_xfer(2);
+ if (!(qsmcm->qsmcm_recram[1] & 1)) {
+ break;
+ }
+ udelay(1000);
+ }
+ if (i >= 1000) {
+ printf ("*** spi_write: Time out while writing!\n");
+ }
+ return len;
+}
+
+#define TRANSFER_LEN 16
+
+ssize_t spi_write (uchar *addr, int alen, uchar *buffer, int len)
+{
+ int index,i,newlen;
+ uchar newaddr[2];
+ int curraddr;
+
+ curraddr=(addr[alen-2]<<8)+addr[alen-1];
+ i=len;
+ index=0;
+ do {
+ newaddr[1]=(curraddr & 0xff);
+ newaddr[0]=((curraddr>>8) & 0xff);
+ if(i>TRANSFER_LEN) {
+ newlen=TRANSFER_LEN;
+ i-=TRANSFER_LEN;
+ }
+ else {
+ newlen=i;
+ i=0;
+ }
+ short_spi_write (newaddr, 2, &buffer[index], newlen);
+ index+=newlen;
+ curraddr+=newlen;
+ }while(i);
+ return (len);
+}
+
+/****************************************************************************
+ * Function: spi_read
+ **************************************************************************** */
+ssize_t short_spi_read (uchar *addr, int alen, uchar *buffer, int len)
+{
+ int i;
+ volatile immap_t *immr;
+ volatile qsmcm5xx_t *qsmcm;
+
+ immr = (immap_t *) CONFIG_SYS_IMMR;
+ qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm;
+
+ for(i=0;i<32;i++) {
+ qsmcm->qsmcm_recram[i]=0x0000;
+ qsmcm->qsmcm_tranram[i]=0x0000;
+ qsmcm->qsmcm_comdram[i]=0x00;
+ }
+ i=0;
+ qsmcm->qsmcm_tranram[i++] = (SPI_EEPROM_READ); /* READ memory array */
+ qsmcm->qsmcm_tranram[i++] = addr[0] & 0xff;
+ qsmcm->qsmcm_tranram[i++] = addr[1] & 0xff;
+ spi_xfer(3 + len);
+ for(i=0;i<len;i++) {
+ *buffer++=(char)qsmcm->qsmcm_recram[i+3];
+ }
+ return len;
+}
+
+ssize_t spi_read (uchar *addr, int alen, uchar *buffer, int len)
+{
+ int index,i,newlen;
+ uchar newaddr[2];
+ int curraddr;
+
+ curraddr=(addr[alen-2]<<8)+addr[alen-1];
+ i=len;
+ index=0;
+ do {
+ newaddr[1]=(curraddr & 0xff);
+ newaddr[0]=((curraddr>>8) & 0xff);
+ if(i>TRANSFER_LEN) {
+ newlen=TRANSFER_LEN;
+ i-=TRANSFER_LEN;
+ }
+ else {
+ newlen=i;
+ i=0;
+ }
+ short_spi_read (newaddr, 2, &buffer[index], newlen);
+ index+=newlen;
+ curraddr+=newlen;
+ }while(i);
+ return (len);
+}
+
+/****************************************************************************
+ * Function: spi_xfer
+ **************************************************************************** */
+ssize_t spi_xfer (size_t count)
+{
+ volatile immap_t *immr;
+ volatile qsmcm5xx_t *qsmcm;
+ int i;
+ int tm;
+ ushort status;
+ immr = (immap_t *) CONFIG_SYS_IMMR;
+ qsmcm = (qsmcm5xx_t *)&immr->im_qsmcm;
+ DPRINT (("*** spi_xfer entered count %d***\n",count));
+
+ /* Set CS for device */
+ for(i=0;i<(count-1);i++)
+ qsmcm->qsmcm_comdram[i] = 0x80 | CONFIG_SYS_SPI_CS_ACT; /* CS3 is connected to the SPI EEPROM */
+
+ qsmcm->qsmcm_comdram[i] = CONFIG_SYS_SPI_CS_ACT; /* CS3 is connected to the SPI EEPROM */
+ qsmcm->qsmcm_spcr2=((count-1)&0x1F)<<8;
+
+ DPRINT (("*** spi_xfer: Bytes to be xferred: %d ***\n", count));
+
+ qsmcm->qsmcm_spsr=0xE0; /* clear all flags */
+
+ /* start spi transfer */
+ DPRINT (("*** spi_xfer: Performing transfer ...\n"));
+ qsmcm->qsmcm_spcr1 |= 0x8000; /* Start transmit */
+
+ /* --------------------------------
+ * Wait for SPI transmit to get out
+ * or time out (1 second = 1000 ms)
+ * -------------------------------- */
+ for (tm=0; tm<1000; ++tm) {
+ status=qsmcm->qsmcm_spcr1;
+ if((status & 0x8000)==0)
+ break;
+ udelay (1000);
+ }
+ if (tm >= 1000) {
+ printf ("*** spi_xfer: Time out while xferring to/from SPI!\n");
+ }
+#ifdef DEBUG
+ printf ("\nspi_xfer: txbuf after xfer\n");
+ memdump ((void *) qsmcm->qsmcm_tranram, 32); /* dump of txbuf before transmit */
+ printf ("spi_xfer: rxbuf after xfer\n");
+ memdump ((void *) qsmcm->qsmcm_recram, 32); /* dump of rxbuf after transmit */
+ printf ("\nspi_xfer: commbuf after xfer\n");
+ memdump ((void *) qsmcm->qsmcm_comdram, 32); /* dump of txbuf before transmit */
+ printf ("\n");
+#endif
+
+ return count;
+}
+
+#endif /* CONFIG_SPI */
diff --git a/arch/powerpc/cpu/mpc5xx/start.S b/arch/powerpc/cpu/mpc5xx/start.S
new file mode 100644
index 0000000..1b275c6
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xx/start.S
@@ -0,0 +1,561 @@
+/*
+ * Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2000, 2001, 2002 Wolfgang Denk <wd@denx.de>
+ * Copyright (C) 2003 Martin Winistoerfer, martinwinistoerfer@gmx.ch.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * File: start.S
+ *
+ * Discription: startup code
+ *
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <mpc5xx.h>
+#include <version.h>
+
+#define CONFIG_5xx 1 /* needed for Linux kernel header files */
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/u-boot.h>
+
+/* We don't have a MMU.
+*/
+#undef MSR_KERNEL
+#define MSR_KERNEL ( MSR_ME | MSR_RI ) /* Machine Check and Recoverable Interr. */
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+ START_GOT
+ GOT_ENTRY(_GOT2_TABLE_)
+ GOT_ENTRY(_FIXUP_TABLE_)
+
+ GOT_ENTRY(_start)
+ GOT_ENTRY(_start_of_vectors)
+ GOT_ENTRY(_end_of_vectors)
+ GOT_ENTRY(transfer_to_handler)
+
+ GOT_ENTRY(__init_end)
+ GOT_ENTRY(__bss_end)
+ GOT_ENTRY(__bss_start)
+ END_GOT
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+ .text
+ .long 0x27051956 /* U-Boot Magic Number */
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION_STRING, "\0"
+
+ . = EXC_OFF_SYS_RESET
+ .globl _start
+_start:
+ mfspr r3, 638
+ li r4, CONFIG_SYS_ISB /* Set ISB bit */
+ or r3, r3, r4
+ mtspr 638, r3
+
+ /* Initialize machine status; enable machine check interrupt */
+ /*----------------------------------------------------------------------*/
+ li r3, MSR_KERNEL /* Set ME, RI flags */
+ mtmsr r3
+ mtspr SRR1, r3 /* Make SRR1 match MSR */
+
+ /* Initialize debug port registers */
+ /*----------------------------------------------------------------------*/
+ xor r0, r0, r0 /* Clear R0 */
+ mtspr LCTRL1, r0 /* Initialize debug port regs */
+ mtspr LCTRL2, r0
+ mtspr COUNTA, r0
+ mtspr COUNTB, r0
+
+#if defined(CONFIG_PATI)
+ /* the external flash access on PATI fails if programming the PLL to 40MHz.
+ * Copy the PLL programming code to the internal RAM and execute it
+ *----------------------------------------------------------------------*/
+ lis r3, CONFIG_SYS_MONITOR_BASE@h
+ ori r3, r3, CONFIG_SYS_MONITOR_BASE@l
+ addi r3, r3, pll_prog_code_start - _start + EXC_OFF_SYS_RESET
+
+ lis r4, CONFIG_SYS_INIT_RAM_ADDR@h
+ ori r4, r4, CONFIG_SYS_INIT_RAM_ADDR@l
+ mtlr r4
+ addis r5,0,0x0
+ ori r5,r5,((pll_prog_code_end - pll_prog_code_start) >>2)
+ mtctr r5
+ addi r3, r3, -4
+ addi r4, r4, -4
+0:
+ lwzu r0,4(r3)
+ stwu r0,4(r4)
+ bdnz 0b /* copy loop */
+ blrl
+#endif
+
+ /*
+ * Calculate absolute address in FLASH and jump there
+ *----------------------------------------------------------------------*/
+
+ lis r3, CONFIG_SYS_MONITOR_BASE@h
+ ori r3, r3, CONFIG_SYS_MONITOR_BASE@l
+ addi r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
+ mtlr r3
+ blr
+
+in_flash:
+
+ /* Initialize some SPRs that are hard to access from C */
+ /*----------------------------------------------------------------------*/
+
+ lis r3, CONFIG_SYS_IMMR@h /* Pass IMMR as arg1 to C routine */
+ lis r2, CONFIG_SYS_INIT_SP_ADDR@h
+ ori r1, r2, CONFIG_SYS_INIT_SP_ADDR@l /* Set up the stack in internal SRAM */
+ /* Note: R0 is still 0 here */
+ stwu r0, -4(r1) /* Clear final stack frame so that */
+ stwu r0, -4(r1) /* stack backtraces terminate cleanly */
+
+ /*
+ * Disable serialized ifetch and show cycles
+ * (i.e. set processor to normal mode) for maximum
+ * performance.
+ */
+
+ li r2, 0x0007
+ mtspr ICTRL, r2
+
+ /* Set up debug mode entry */
+
+ lis r2, CONFIG_SYS_DER@h
+ ori r2, r2, CONFIG_SYS_DER@l
+ mtspr DER, r2
+
+ /* Let the C-code set up the rest */
+ /* */
+ /* Be careful to keep code relocatable ! */
+ /*----------------------------------------------------------------------*/
+
+ GET_GOT /* initialize GOT access */
+
+ /* r3: IMMR */
+ bl cpu_init_f /* run low-level CPU init code (from Flash) */
+
+ bl board_init_f /* run 1st part of board init code (from Flash) */
+
+ /* NOTREACHED - board_init_f() does not return */
+
+
+ .globl _start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. "Never" generated on the 860. */
+ STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. "Never" generated on the 860. */
+ STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+ STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+ . = 0x600
+Alignment:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+ . = 0x700
+ProgramCheck:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+ MSR_KERNEL, COPY_EE)
+
+ /* FPU on MPC5xx available. We will use it later.
+ */
+ STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+ /* I guess we could implement decrementer, and may have
+ * to someday for timekeeping.
+ */
+ STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+ STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+ STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+ STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+ STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+ STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+ STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+ /* On the MPC8xx, this is a software emulation interrupt. It occurs
+ * for all unimplemented and illegal instructions.
+ */
+ STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException)
+ STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
+ STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
+
+ STD_EXCEPTION(0x1500, Reserved5, UnknownException)
+ STD_EXCEPTION(0x1600, Reserved6, UnknownException)
+ STD_EXCEPTION(0x1700, Reserved7, UnknownException)
+ STD_EXCEPTION(0x1800, Reserved8, UnknownException)
+ STD_EXCEPTION(0x1900, Reserved9, UnknownException)
+ STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
+ STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
+
+ STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1d00, InstructionBreakpoint, DebugException)
+ STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
+
+
+ .globl _end_of_vectors
+_end_of_vectors:
+
+
+ . = 0x2000
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+ .globl transfer_to_handler
+transfer_to_handler:
+ stw r22,_NIP(r21)
+ lis r22,MSR_POW@h
+ andc r23,r23,r22
+ stw r23,_MSR(r21)
+ SAVE_GPR(7, r21)
+ SAVE_4GPRS(8, r21)
+ SAVE_8GPRS(12, r21)
+ SAVE_8GPRS(24, r21)
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ mtspr SPRG2,r22 /* r1 is now kernel sp */
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
+
+int_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+
+
+/*
+ * unsigned int get_immr (unsigned int mask)
+ *
+ * return (mask ? (IMMR & mask) : IMMR);
+ */
+ .globl get_immr
+get_immr:
+ mr r4,r3 /* save mask */
+ mfspr r3, IMMR /* IMMR */
+ cmpwi 0,r4,0 /* mask != 0 ? */
+ beq 4f
+ and r3,r3,r4 /* IMMR & mask */
+4:
+ blr
+
+ .globl get_pvr
+get_pvr:
+ mfspr r3, PVR
+ blr
+
+
+/*------------------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+ .globl relocate_code
+relocate_code:
+ mr r1, r3 /* Set new stack pointer in SRAM */
+ mr r9, r4 /* Save copy of global data pointer in SRAM */
+ mr r10, r5 /* Save copy of monitor destination Address in SRAM */
+
+ GET_GOT
+ mr r3, r5 /* Destination Address */
+ lis r4, CONFIG_SYS_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CONFIG_SYS_MONITOR_BASE@l
+ lwz r5, GOT(__init_end)
+ sub r5, r5, r4
+
+ /*
+ * Fix GOT pointer:
+ *
+ * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+ *
+ * Offset:
+ */
+ sub r15, r10, r4
+
+ /* First our own GOT */
+ add r12, r12, r15
+ /* the the one used by the C code */
+ add r30, r30, r15
+
+ /*
+ * Now relocate code
+ */
+
+ cmplw cr1,r3,r4
+ addi r0,r5,3
+ srwi. r0,r0,2
+ beq cr1,4f /* In place copy is not necessary */
+ beq 4f /* Protect against 0 count */
+ mtctr r0
+ bge cr1,2f
+
+ la r8,-4(r4)
+ la r7,-4(r3)
+1: lwzu r0,4(r8)
+ stwu r0,4(r7)
+ bdnz 1b
+ b 4f
+
+2: slwi r0,r0,2
+ add r8,r4,r0
+ add r7,r3,r0
+3: lwzu r0,-4(r8)
+ stwu r0,-4(r7)
+ bdnz 3b
+
+4: sync
+ isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+ addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+ mtlr r0
+ blr
+
+in_ram:
+
+ /*
+ * Relocation Function, r12 point to got2+0x8000
+ *
+ * Adjust got2 pointers, no need to check for 0, this code
+ * already puts a few entries in the table.
+ */
+ li r0,__got2_entries@sectoff@l
+ la r3,GOT(_GOT2_TABLE_)
+ lwz r11,GOT(_GOT2_TABLE_)
+ mtctr r0
+ sub r11,r3,r11
+ addi r3,r3,-4
+1: lwzu r0,4(r3)
+ cmpwi r0,0
+ beq- 2f
+ add r0,r0,r11
+ stw r0,0(r3)
+2: bdnz 1b
+
+ /*
+ * Now adjust the fixups and the pointers to the fixups
+ * in case we need to move ourselves again.
+ */
+ li r0,__fixup_entries@sectoff@l
+ lwz r3,GOT(_FIXUP_TABLE_)
+ cmpwi r0,0
+ mtctr r0
+ addi r3,r3,-4
+ beq 4f
+3: lwzu r4,4(r3)
+ lwzux r0,r4,r11
+ cmpwi r0,0
+ add r0,r0,r11
+ stw r4,0(r3)
+ beq- 5f
+ stw r0,0(r4)
+5: bdnz 3b
+4:
+clear_bss:
+ /*
+ * Now clear BSS segment
+ */
+ lwz r3,GOT(__bss_start)
+ lwz r4,GOT(__bss_end)
+ cmplw 0, r3, r4
+ beq 6f
+
+ li r0, 0
+5:
+ stw r0, 0(r3)
+ addi r3, r3, 4
+ cmplw 0, r3, r4
+ bne 5b
+6:
+
+ mr r3, r9 /* Global Data pointer */
+ mr r4, r10 /* Destination Address */
+ bl board_init_r
+
+ /*
+ * Copy exception vector code to low memory
+ *
+ * r3: dest_addr
+ * r7: source address, r8: end address, r9: target address
+ */
+ .globl trap_init
+trap_init:
+ mflr r4 /* save link register */
+ GET_GOT
+ lwz r7, GOT(_start)
+ lwz r8, GOT(_end_of_vectors)
+
+ li r9, 0x100 /* reset vector always at 0x100 */
+
+ cmplw 0, r7, r8
+ bgelr /* return if r7>=r8 - just in case */
+1:
+ lwz r0, 0(r7)
+ stw r0, 0(r9)
+ addi r7, r7, 4
+ addi r9, r9, 4
+ cmplw 0, r7, r8
+ bne 1b
+
+ /*
+ * relocate `hdlr' and `int_return' entries
+ */
+ li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+ li r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 2b
+
+ li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+ li r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 3b
+
+ li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+ li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 4b
+
+ mtlr r4 /* restore link register */
+ blr
+
+#if defined(CONFIG_PATI)
+/* Program the PLL */
+pll_prog_code_start:
+ lis r4, (CONFIG_SYS_IMMR + 0x002fc384)@h
+ ori r4, r4, (CONFIG_SYS_IMMR + 0x002fc384)@l
+ lis r3, (0x55ccaa33)@h
+ ori r3, r3, (0x55ccaa33)@l
+ stw r3, 0(r4)
+ lis r4, (CONFIG_SYS_IMMR + 0x002fc284)@h
+ ori r4, r4, (CONFIG_SYS_IMMR + 0x002fc284)@l
+ lis r3, CONFIG_SYS_PLPRCR@h
+ ori r3, r3, CONFIG_SYS_PLPRCR@l
+ stw r3, 0(r4)
+ addis r3,0,0x0
+ ori r3,r3,0xA000
+ mtctr r3
+..spinlp:
+ bdnz ..spinlp /* spin loop */
+ blr
+pll_prog_code_end:
+ nop
+ blr
+#endif
diff --git a/arch/powerpc/cpu/mpc5xx/traps.c b/arch/powerpc/cpu/mpc5xx/traps.c
new file mode 100644
index 0000000..90da73b
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xx/traps.c
@@ -0,0 +1,227 @@
+/*
+ * linux/arch/powerpc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM 0x0001000
+
+
+/*
+ * Print stack backtrace
+ */
+static void print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ printf("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ printf("\n");
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *)*sp;
+ }
+ printf("\n");
+}
+
+/*
+ * Print current registers
+ */
+void show_regs(struct pt_regs *regs)
+{
+ int i;
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+ regs->msr&MSR_IR ? 1 : 0,
+ regs->msr&MSR_DR ? 1 : 0);
+
+ printf("\n");
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0)
+ {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7)
+ {
+ printf("\n");
+ }
+ }
+}
+
+
+/*
+ * General exception handler routine
+ */
+static void _exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+/*
+ * Machine check exception handler routine
+ */
+void MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup;
+
+ /* Probing PCI using config cycles cause this exception
+ * when a device is not present. Catch it and return to
+ * the PCI exception handler.
+ */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ return;
+ }
+
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ printf("Machine check in kernel mode.\n");
+ printf("Caused by (from msr): ");
+ printf("regs %p ",regs);
+ switch( regs->msr & 0x000F0000) {
+ case (0x80000000>>12):
+ printf("Machine check signal\n");
+ break;
+ case (0x80000000>>13):
+ printf("Transfer error ack signal\n");
+ break;
+ case (0x80000000>>14):
+ printf("Data parity signal\n");
+ break;
+ case (0x80000000>>15):
+ printf("Address parity signal\n");
+ break;
+ default:
+ printf("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("machine check");
+}
+
+/*
+ * Alignment exception handler routine
+ */
+void AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+/*
+ * Program check exception handler routine
+ */
+void ProgramCheckException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+/*
+ * Software emulation exception handler routine
+ */
+void SoftEmuException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Software Emulation Exception");
+}
+
+
+/*
+ * Unknown exception handler routine
+ */
+void UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+/*
+ * Debug exception handler routine
+ */
+void DebugException(struct pt_regs *regs)
+{
+ printf("Debugger trap at @ %lx\n", regs->nip );
+ show_regs(regs);
+#if defined(CONFIG_CMD_BEDBUG)
+ do_bedbug_breakpoint( regs );
+#endif
+}
diff --git a/arch/powerpc/cpu/mpc5xx/u-boot.lds b/arch/powerpc/cpu/mpc5xx/u-boot.lds
new file mode 100644
index 0000000..8385a29
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xx/u-boot.lds
@@ -0,0 +1,103 @@
+/*
+ * (C) Copyright 2001-2010 Wolfgang Denk, DENX Software Engineering, wd@denx.de
+ * (C) Copyright 2003 Martin Winistoerfer, martinwinistoerfer@gmx.ch
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = + SIZEOF_HEADERS;
+ .text :
+ {
+ arch/powerpc/cpu/mpc5xx/start.o (.text*)
+
+ *(.text*)
+ }
+ _etext = .;
+ PROVIDE (etext = .);
+ .rodata :
+ {
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ }
+
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x00FF) & 0xFFFFFF00;
+ _erotext = .;
+ PROVIDE (erotext = .);
+ .reloc :
+ {
+ _GOT2_TABLE_ = .;
+ KEEP(*(.got2))
+ KEEP(*(.got))
+ PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
+ _FIXUP_TABLE_ = .;
+ KEEP(*(.fixup))
+ }
+ __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
+ __fixup_entries = (. - _FIXUP_TABLE_)>>2;
+
+ .data :
+ {
+ *(.data*)
+ *(.sdata*)
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+
+ . = .;
+
+ . = ALIGN(4);
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+
+ . = .;
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ . = ALIGN(256);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(256);
+ __init_end = .;
+
+ __bss_start = .;
+ .bss (NOLOAD) :
+ {
+ *(.bss*)
+ *(.sbss*)
+ *(COMMON)
+ . = ALIGN(4);
+ }
+
+ __bss_end = . ;
+ PROVIDE (end = .);
+ . = env_start;
+ .ppcenv :
+ {
+ common/env_embedded.o (.ppcenv)
+ }
+}
diff --git a/arch/powerpc/cpu/mpc5xxx/Makefile b/arch/powerpc/cpu/mpc5xxx/Makefile
new file mode 100644
index 0000000..8de2c13
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/Makefile
@@ -0,0 +1,64 @@
+#
+# (C) Copyright 2003-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(CPU).o
+
+SSTART = start.o
+CSTART = traps.o
+SOBJS += io.o
+SOBJS += firmware_sc_task_bestcomm.impl.o
+COBJS-y += i2c.o
+COBJS-y += cpu.o
+COBJS-y += cpu_init.o
+COBJS-y += ide.o
+COBJS-y += interrupts.o
+COBJS-y += loadtask.o
+COBJS-y += pci_mpc5200.o
+COBJS-y += serial.o
+COBJS-y += speed.o
+COBJS-$(CONFIG_CMD_USB) += usb_ohci.o
+COBJS-$(CONFIG_CMD_USB) += usb.o
+
+ifdef CONFIG_SPL_BUILD
+COBJS-y += spl_boot.o
+endif
+
+SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS-y:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS-y))
+START := $(addprefix $(obj),$(SSTART) $(CSTART))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/powerpc/cpu/mpc5xxx/config.mk b/arch/powerpc/cpu/mpc5xxx/config.mk
new file mode 100644
index 0000000..fb87980
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/config.mk
@@ -0,0 +1,27 @@
+#
+# (C) Copyright 2003-2010
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_RELFLAGS += -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_MPC5xxx -ffixed-r2 \
+ -mstring -mcpu=603e -mmultiple
diff --git a/arch/powerpc/cpu/mpc5xxx/cpu.c b/arch/powerpc/cpu/mpc5xxx/cpu.c
new file mode 100644
index 0000000..dc021e3
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/cpu.c
@@ -0,0 +1,184 @@
+/*
+ * (C) Copyright 2000-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * CPU specific code for the MPC5xxx CPUs
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <net.h>
+#include <mpc5xxx.h>
+#include <netdev.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+
+#if defined(CONFIG_OF_IDE_FIXUP)
+#include <ide.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int checkcpu (void)
+{
+ ulong clock = gd->cpu_clk;
+ char buf[32];
+ uint svr, pvr;
+
+ puts ("CPU: ");
+
+ svr = get_svr();
+ pvr = get_pvr();
+
+ switch (pvr) {
+ case PVR_5200:
+ printf("MPC5200");
+ break;
+ case PVR_5200B:
+ printf("MPC5200B");
+ break;
+ default:
+ printf("Unknown MPC5xxx");
+ break;
+ }
+
+ printf (" v%d.%d, Core v%d.%d", SVR_MJREV (svr), SVR_MNREV (svr),
+ PVR_MAJ(pvr), PVR_MIN(pvr));
+ printf (" at %s MHz\n", strmhz (buf, clock));
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int
+do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong msr;
+ /* Interrupts and MMU off */
+ __asm__ __volatile__ ("mfmsr %0":"=r" (msr):);
+
+ msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR);
+ __asm__ __volatile__ ("mtmsr %0"::"r" (msr));
+
+ /* Charge the watchdog timer */
+ *(vu_long *)(MPC5XXX_GPT0_COUNTER) = 0x0001000f;
+ *(vu_long *)(MPC5XXX_GPT0_ENABLE) = 0x9004; /* wden|ce|timer_ms */
+ while(1);
+
+ return 1;
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ *
+ */
+unsigned long get_tbclk (void)
+{
+ ulong tbclk;
+
+ tbclk = (gd->bus_clk + 3L) / 4L;
+
+ return (tbclk);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if defined(CONFIG_OF_LIBFDT) && defined (CONFIG_OF_BOARD_SETUP)
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+ int div = in_8((void*)CONFIG_SYS_MBAR + 0x204) & 0x0020 ? 8 : 4;
+ char * cpu_path = "/cpus/" OF_CPU;
+#ifdef CONFIG_MPC5xxx_FEC
+ uchar enetaddr[6];
+ char * eth_path = "/" OF_SOC "/ethernet@3000";
+#endif
+
+ do_fixup_by_path_u32(blob, cpu_path, "timebase-frequency", OF_TBCLK, 1);
+ do_fixup_by_path_u32(blob, cpu_path, "bus-frequency", bd->bi_busfreq, 1);
+ do_fixup_by_path_u32(blob, cpu_path, "clock-frequency", bd->bi_intfreq, 1);
+ do_fixup_by_path_u32(blob, "/" OF_SOC, "bus-frequency", bd->bi_ipbfreq, 1);
+ do_fixup_by_path_u32(blob, "/" OF_SOC, "system-frequency",
+ bd->bi_busfreq*div, 1);
+#ifdef CONFIG_MPC5xxx_FEC
+ eth_getenv_enetaddr("ethaddr", enetaddr);
+ do_fixup_by_path(blob, eth_path, "mac-address", enetaddr, 6, 0);
+ do_fixup_by_path(blob, eth_path, "local-mac-address", enetaddr, 6, 0);
+#endif
+#if defined(CONFIG_OF_IDE_FIXUP)
+ if (!ide_device_present(0)) {
+ /* NO CF card detected -> delete ata node in DTS */
+ int nodeoffset = 0;
+ char nodename[] = "/soc5200@f0000000/ata@3a00";
+
+ nodeoffset = fdt_path_offset(blob, nodename);
+ if (nodeoffset >= 0) {
+ fdt_del_node(blob, nodeoffset);
+ } else {
+ printf("%s: cannot find %s node err:%s\n",
+ __func__, nodename, fdt_strerror(nodeoffset));
+ }
+ }
+
+#endif
+ fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+}
+#endif
+
+#ifdef CONFIG_MPC5xxx_FEC
+/* Default initializations for FEC controllers. To override,
+ * create a board-specific function called:
+ * int board_eth_init(bd_t *bis)
+ */
+
+int cpu_eth_init(bd_t *bis)
+{
+ return mpc5xxx_fec_initialize(bis);
+}
+#endif
+
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset(void)
+{
+ int re_enable = disable_interrupts();
+ reset_5xxx_watchdog();
+ if (re_enable) enable_interrupts();
+}
+
+void reset_5xxx_watchdog(void)
+{
+ volatile struct mpc5xxx_gpt *gpt0 =
+ (struct mpc5xxx_gpt *) MPC5XXX_GPT;
+
+ /* Trigger TIMER_0 by writing A5 to OCPW */
+ clrsetbits_be32(&gpt0->emsr, 0xff000000, 0xa5000000);
+}
+#endif /* CONFIG_WATCHDOG */
diff --git a/arch/powerpc/cpu/mpc5xxx/cpu_init.c b/arch/powerpc/cpu/mpc5xxx/cpu_init.c
new file mode 100644
index 0000000..3044b41
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/cpu_init.c
@@ -0,0 +1,247 @@
+/*
+ * (C) Copyright 2000-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc5xxx.h>
+#include <asm/io.h>
+#include <watchdog.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Breath some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers.
+ */
+void cpu_init_f (void)
+{
+ volatile struct mpc5xxx_mmap_ctl *mm =
+ (struct mpc5xxx_mmap_ctl *) CONFIG_SYS_MBAR;
+ volatile struct mpc5xxx_lpb *lpb =
+ (struct mpc5xxx_lpb *) MPC5XXX_LPB;
+ volatile struct mpc5xxx_gpio *gpio =
+ (struct mpc5xxx_gpio *) MPC5XXX_GPIO;
+ volatile struct mpc5xxx_xlb *xlb =
+ (struct mpc5xxx_xlb *) MPC5XXX_XLBARB;
+#if defined(CONFIG_SYS_IPBCLK_EQUALS_XLBCLK)
+ volatile struct mpc5xxx_cdm *cdm =
+ (struct mpc5xxx_cdm *) MPC5XXX_CDM;
+#endif /* CONFIG_SYS_IPBCLK_EQUALS_XLBCLK */
+#if defined(CONFIG_WATCHDOG)
+ volatile struct mpc5xxx_gpt *gpt0 =
+ (struct mpc5xxx_gpt *) MPC5XXX_GPT;
+#endif /* CONFIG_WATCHDOG */
+ unsigned long addecr = (1 << 25); /* Boot_CS */
+ /* Pointer is writable since we allocated a register for it */
+ gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+ /* Clear initial global data */
+ memset ((void *) gd, 0, sizeof (gd_t));
+
+ /*
+ * Memory Controller: configure chip selects and enable them
+ */
+#if defined(CONFIG_SYS_BOOTCS_START) && defined(CONFIG_SYS_BOOTCS_SIZE)
+ out_be32(&mm->boot_start, START_REG(CONFIG_SYS_BOOTCS_START));
+ out_be32(&mm->boot_stop, STOP_REG(CONFIG_SYS_BOOTCS_START,
+ CONFIG_SYS_BOOTCS_SIZE));
+#endif
+#if defined(CONFIG_SYS_BOOTCS_CFG)
+ out_be32(&lpb->cs0_cfg, CONFIG_SYS_BOOTCS_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS0_START) && defined(CONFIG_SYS_CS0_SIZE)
+ out_be32(&mm->cs0_start, START_REG(CONFIG_SYS_CS0_START));
+ out_be32(&mm->cs0_stop, STOP_REG(CONFIG_SYS_CS0_START,
+ CONFIG_SYS_CS0_SIZE));
+ /* CS0 and BOOT_CS cannot be enabled at once. */
+ /* addecr |= (1 << 16); */
+#endif
+#if defined(CONFIG_SYS_CS0_CFG)
+ out_be32(&lpb->cs0_cfg, CONFIG_SYS_CS0_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS1_START) && defined(CONFIG_SYS_CS1_SIZE)
+ out_be32(&mm->cs1_start, START_REG(CONFIG_SYS_CS1_START));
+ out_be32(&mm->cs1_stop, STOP_REG(CONFIG_SYS_CS1_START,
+ CONFIG_SYS_CS1_SIZE));
+ addecr |= (1 << 17);
+#endif
+#if defined(CONFIG_SYS_CS1_CFG)
+ out_be32(&lpb->cs1_cfg, CONFIG_SYS_CS1_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS2_START) && defined(CONFIG_SYS_CS2_SIZE)
+ out_be32(&mm->cs2_start, START_REG(CONFIG_SYS_CS2_START));
+ out_be32(&mm->cs2_stop, STOP_REG(CONFIG_SYS_CS2_START,
+ CONFIG_SYS_CS2_SIZE));
+ addecr |= (1 << 18);
+#endif
+#if defined(CONFIG_SYS_CS2_CFG)
+ out_be32(&lpb->cs2_cfg, CONFIG_SYS_CS2_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS3_START) && defined(CONFIG_SYS_CS3_SIZE)
+ out_be32(&mm->cs3_start, START_REG(CONFIG_SYS_CS3_START));
+ out_be32(&mm->cs3_stop, STOP_REG(CONFIG_SYS_CS3_START,
+ CONFIG_SYS_CS3_SIZE));
+ addecr |= (1 << 19);
+#endif
+#if defined(CONFIG_SYS_CS3_CFG)
+ out_be32(&lpb->cs3_cfg, CONFIG_SYS_CS3_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS4_START) && defined(CONFIG_SYS_CS4_SIZE)
+ out_be32(&mm->cs4_start, START_REG(CONFIG_SYS_CS4_START));
+ out_be32(&mm->cs4_stop, STOP_REG(CONFIG_SYS_CS4_START,
+ CONFIG_SYS_CS4_SIZE));
+ addecr |= (1 << 20);
+#endif
+#if defined(CONFIG_SYS_CS4_CFG)
+ out_be32(&lpb->cs4_cfg, CONFIG_SYS_CS4_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS5_START) && defined(CONFIG_SYS_CS5_SIZE)
+ out_be32(&mm->cs5_start, START_REG(CONFIG_SYS_CS5_START));
+ out_be32(&mm->cs5_stop, STOP_REG(CONFIG_SYS_CS5_START,
+ CONFIG_SYS_CS5_SIZE));
+ addecr |= (1 << 21);
+#endif
+#if defined(CONFIG_SYS_CS5_CFG)
+ out_be32(&lpb->cs5_cfg, CONFIG_SYS_CS5_CFG);
+#endif
+
+ addecr |= 1;
+#if defined(CONFIG_SYS_CS6_START) && defined(CONFIG_SYS_CS6_SIZE)
+ out_be32(&mm->cs6_start, START_REG(CONFIG_SYS_CS6_START));
+ out_be32(&mm->cs6_stop, STOP_REG(CONFIG_SYS_CS6_START,
+ CONFIG_SYS_CS6_SIZE));
+ addecr |= (1 << 26);
+#endif
+#if defined(CONFIG_SYS_CS6_CFG)
+ out_be32(&lpb->cs6_cfg, CONFIG_SYS_CS6_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS7_START) && defined(CONFIG_SYS_CS7_SIZE)
+ out_be32(&mm->cs7_start, START_REG(CONFIG_SYS_CS7_START));
+ out_be32(&mm->cs7_stop, STOP_REG(CONFIG_SYS_CS7_START,
+ CONFIG_SYS_CS7_SIZE));
+ addecr |= (1 << 27);
+#endif
+#if defined(CONFIG_SYS_CS7_CFG)
+ out_be32(&lpb->cs7_cfg, CONFIG_SYS_CS7_CFG);
+#endif
+
+#if defined(CONFIG_SYS_CS_BURST)
+ out_be32(&lpb->cs_burst, CONFIG_SYS_CS_BURST);
+#endif
+#if defined(CONFIG_SYS_CS_DEADCYCLE)
+ out_be32(&lpb->cs_deadcycle, CONFIG_SYS_CS_DEADCYCLE);
+#endif
+
+ /* Enable chip selects */
+ out_be32(&mm->ipbi_ws_ctrl, addecr);
+ out_be32(&lpb->cs_ctrl, (1 << 24));
+
+ /* Setup pin multiplexing */
+#if defined(CONFIG_SYS_GPS_PORT_CONFIG)
+ out_be32(&gpio->port_config, CONFIG_SYS_GPS_PORT_CONFIG);
+#endif
+
+ /* Setup gpios */
+#if defined(CONFIG_SYS_GPIO_DATADIR)
+ out_be32(&gpio->simple_ddr, CONFIG_SYS_GPIO_DATADIR);
+#endif
+#if defined(CONFIG_SYS_GPIO_OPENDRAIN)
+ out_be32(&gpio->simple_ode, CONFIG_SYS_GPIO_OPENDRAIN);
+#endif
+#if defined(CONFIG_SYS_GPIO_DATAVALUE)
+ out_be32(&gpio->simple_dvo, CONFIG_SYS_GPIO_DATAVALUE);
+#endif
+#if defined(CONFIG_SYS_GPIO_ENABLE)
+ out_be32(&gpio->simple_gpioe, CONFIG_SYS_GPIO_ENABLE);
+#endif
+
+ /* enable timebase */
+ setbits_be32(&xlb->config, (1 << 13));
+
+ /* Enable snooping for RAM */
+ setbits_be32(&xlb->config, (1 << 15));
+ out_be32(&xlb->snoop_window, CONFIG_SYS_SDRAM_BASE | 0x1d);
+
+#if defined(CONFIG_SYS_IPBCLK_EQUALS_XLBCLK)
+ /* Motorola reports IPB should better run at 133 MHz. */
+ setbits_be32(&mm->ipbi_ws_ctrl, 1);
+ /* pci_clk_sel = 0x02, ipb_clk_sel = 0x00; */
+ addecr = in_be32(&cdm->cfg);
+ addecr &= ~0x103;
+# if defined(CONFIG_SYS_PCICLK_EQUALS_IPBCLK_DIV2)
+ /* pci_clk_sel = 0x01 -> IPB_CLK/2 */
+ addecr |= 0x01;
+# else
+ /* pci_clk_sel = 0x02 -> XLB_CLK/4 = IPB_CLK/4 */
+ addecr |= 0x02;
+# endif /* CONFIG_SYS_PCICLK_EQUALS_IPBCLK_DIV2 */
+ out_be32(&cdm->cfg, addecr);
+#endif /* CONFIG_SYS_IPBCLK_EQUALS_XLBCLK */
+ /* Configure the XLB Arbiter */
+ out_be32(&xlb->master_pri_enable, 0xff);
+ out_be32(&xlb->master_priority, 0x11111111);
+
+#if defined(CONFIG_SYS_XLB_PIPELINING)
+ /* Enable piplining */
+ clrbits_be32(&xlb->config, (1 << 31));
+#endif
+
+#if defined(CONFIG_WATCHDOG)
+ /* Charge the watchdog timer - prescaler = 64k, count = 64k*/
+ out_be32(&gpt0->cir, 0x0000ffff);
+ out_be32(&gpt0->emsr, 0x9004); /* wden|ce|timer_ms */
+
+ reset_5xxx_watchdog();
+#endif /* CONFIG_WATCHDOG */
+}
+
+/*
+ * initialize higher level parts of CPU like time base and timers
+ */
+int cpu_init_r (void)
+{
+ volatile struct mpc5xxx_intr *intr =
+ (struct mpc5xxx_intr *) MPC5XXX_ICTL;
+
+ /* mask all interrupts */
+ out_be32(&intr->per_mask, 0xffffff00);
+ setbits_be32(&intr->main_mask, 0x0001ffff);
+ clrbits_be32(&intr->ctrl, 0x00000f00);
+ /* route critical ints to normal ints */
+ setbits_be32(&intr->ctrl, 0x00000001);
+
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_MPC5xxx_FEC)
+ /* load FEC microcode */
+ loadtask(0, 2);
+#endif
+
+ return (0);
+}
diff --git a/arch/powerpc/cpu/mpc5xxx/firmware_sc_task_bestcomm.impl.S b/arch/powerpc/cpu/mpc5xxx/firmware_sc_task_bestcomm.impl.S
new file mode 100644
index 0000000..00c2312
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/firmware_sc_task_bestcomm.impl.S
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2001, Software Center, Motorola China.
+ *
+ * This file contains microcode for the FEC controller of the MPC5200 CPU.
+ */
+
+#include <config.h>
+
+/* sas/sccg, gas target */
+.section smartdmaInitData,"aw",@progbits /* Initialized data for task variables */
+.section smartdmaTaskTable,"aw",@progbits /* Task tables */
+.align 9
+.globl taskTable
+taskTable:
+.globl scEthernetRecv_Entry
+scEthernetRecv_Entry: /* Task 0 */
+.long scEthernetRecv_TDT - taskTable /* Task 0 Descriptor Table */
+.long scEthernetRecv_TDT - taskTable + 0x000000a4
+.long scEthernetRecv_VarTab - taskTable /* Task 0 Variable Table */
+.long scEthernetRecv_FDT - taskTable + 0x03 /* Task 0 Function Descriptor Table & Flags */
+.long 0x00000000
+.long 0x00000000
+.long scEthernetRecv_CSave - taskTable /* Task 0 context save space */
+.long CONFIG_SYS_MBAR
+.globl scEthernetXmit_Entry
+scEthernetXmit_Entry: /* Task 1 */
+.long scEthernetXmit_TDT - taskTable /* Task 1 Descriptor Table */
+.long scEthernetXmit_TDT - taskTable + 0x000000d0
+.long scEthernetXmit_VarTab - taskTable /* Task 1 Variable Table */
+.long scEthernetXmit_FDT - taskTable + 0x03 /* Task 1 Function Descriptor Table & Flags */
+.long 0x00000000
+.long 0x00000000
+.long scEthernetXmit_CSave - taskTable /* Task 1 context save space */
+.long CONFIG_SYS_MBAR
+
+
+.globl scEthernetRecv_TDT
+scEthernetRecv_TDT: /* Task 0 Descriptor Table */
+.long 0xc4c50000 /* 0000: LCDEXT: idx0 = var9 + var10; idx0 once var0; idx0 += inc0 */
+.long 0x84c5e000 /* 0004: LCD: idx1 = var9 + var11; ; idx1 += inc0 */
+.long 0x10001f08 /* 0008: DRD1A: var7 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x10000380 /* 000C: DRD1A: var0 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x00000f88 /* 0010: DRD1A: var3 = *idx1; FN=0 init=0 WS=0 RS=0 */
+.long 0x81980000 /* 0014: LCD: idx0 = var3; idx0 once var0; idx0 += inc0 */
+.long 0x10000780 /* 0018: DRD1A: var1 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x60000000 /* 001C: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long 0x010cf04c /* 0020: DRD2B1: var4 = EU3(); EU3(var1,var12) */
+.long 0x82180349 /* 0024: LCD: idx0 = var4; idx0 != var13; idx0 += inc1 */
+.long 0x81c68004 /* 0028: LCD: idx1 = var3 + var13 + 4; idx1 once var0; idx1 += inc0 */
+.long 0x70000000 /* 002C: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long 0x018cf04e /* 0030: DRD2B1: var6 = EU3(); EU3(var1,var14) */
+.long 0x70000000 /* 0034: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long 0x020cf04f /* 0038: DRD2B1: var8 = EU3(); EU3(var1,var15) */
+.long 0x00000b88 /* 003C: DRD1A: var2 = *idx1; FN=0 init=0 WS=0 RS=0 */
+.long 0x8000d184 /* 0040: LCDEXT: idx1 = 0xf0003184; ; */
+.long 0xc6990452 /* 0044: LCDEXT: idx2 = var13; idx2 < var17; idx2 += inc2 */
+.long 0x81486010 /* 0048: LCD: idx3 = var2 + var16; ; idx3 += inc2 */
+.long 0x006acf88 /* 004C: DRD1A: *idx3 = *idx1; FN=0 init=3 WS=1 RS=1 */
+.long 0x8000d184 /* 0050: LCDEXT: idx1 = 0xf0003184; ; */
+.long 0x86810492 /* 0054: LCD: idx2 = var13, idx3 = var2; idx2 < var18; idx2 += inc2, idx3 += inc2 */
+.long 0x006acf88 /* 0058: DRD1A: *idx3 = *idx1; FN=0 init=3 WS=1 RS=1 */
+.long 0x8000d184 /* 005C: LCDEXT: idx1 = 0xf0003184; ; */
+.long 0x868184d2 /* 0060: LCD: idx2 = var13, idx3 = var3; idx2 < var19; idx2 += inc2, idx3 += inc2 */
+.long 0x000acf88 /* 0064: DRD1A: *idx3 = *idx1; FN=0 init=0 WS=1 RS=1 */
+.long 0xc318839b /* 0068: LCDEXT: idx1 = var6; idx1 == var14; idx1 += inc3 */
+.long 0x80190000 /* 006C: LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */
+.long 0x04008468 /* 0070: DRD1A: idx1 = var13; FN=0 INT init=0 WS=0 RS=0 */
+.long 0xc4038358 /* 0074: LCDEXT: idx1 = var8, idx2 = var7; idx1 == var13; idx1 += inc3, idx2 += inc0 */
+.long 0x81c50000 /* 0078: LCD: idx3 = var3 + var10; idx3 once var0; idx3 += inc0 */
+.long 0x1000cb18 /* 007C: DRD1A: *idx2 = idx3; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x00000f18 /* 0080: DRD1A: var3 = idx3; FN=0 init=0 WS=0 RS=0 */
+.long 0xc4188364 /* 0084: LCDEXT: idx1 = var8; idx1 > var13; idx1 += inc4 */
+.long 0x83990000 /* 0088: LCD: idx2 = var7; idx2 once var0; idx2 += inc0 */
+.long 0x10000c00 /* 008C: DRD1A: var3 = var0; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x0000c800 /* 0090: DRD1A: *idx2 = var0; FN=0 init=0 WS=0 RS=0 */
+.long 0x81988000 /* 0094: LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+.long 0x10000788 /* 0098: DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x60000000 /* 009C: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long 0x080cf04c /* 00A0: DRD2B1: idx0 = EU3(); EU3(var1,var12) */
+.long 0x000001f8 /* 00A4(:0): NOP */
+
+
+.globl scEthernetXmit_TDT
+scEthernetXmit_TDT: /* Task 1 Descriptor Table */
+.long 0x80024800 /* 0000: LCDEXT: idx0 = 0xf0008800; ; */
+.long 0x85c60004 /* 0004: LCD: idx1 = var11 + var12 + 4; idx1 once var0; idx1 += inc0 */
+.long 0x10002308 /* 0008: DRD1A: var8 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x10000f88 /* 000C: DRD1A: var3 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x00000380 /* 0010: DRD1A: var0 = *idx0; FN=0 init=0 WS=0 RS=0 */
+.long 0x81980000 /* 0014: LCD: idx0 = var3; idx0 once var0; idx0 += inc0 */
+.long 0x10000780 /* 0018: DRD1A: var1 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x60000000 /* 001C: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long 0x024cf04d /* 0020: DRD2B1: var9 = EU3(); EU3(var1,var13) */
+.long 0x84980309 /* 0024: LCD: idx0 = var9; idx0 != var12; idx0 += inc1 */
+.long 0xc0004003 /* 0028: LCDEXT: idx1 = 0x00000003; ; */
+.long 0x81c60004 /* 002C: LCD: idx2 = var3 + var12 + 4; idx2 once var0; idx2 += inc0 */
+.long 0x70000000 /* 0030: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long 0x010cf04e /* 0034: DRD2B1: var4 = EU3(); EU3(var1,var14) */
+.long 0x70000000 /* 0038: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long 0x014cf04f /* 003C: DRD2B1: var5 = EU3(); EU3(var1,var15) */
+.long 0x70000000 /* 0040: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long 0x028cf050 /* 0044: DRD2B1: var10 = EU3(); EU3(var1,var16) */
+.long 0x70000000 /* 0048: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */
+.long 0x018cf051 /* 004C: DRD2B1: var6 = EU3(); EU3(var1,var17) */
+.long 0x10000b90 /* 0050: DRD1A: var2 = *idx2; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x60000000 /* 0054: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long 0x01ccf0a1 /* 0058: DRD2B1: var7 = EU3(); EU3(var2,idx1) */
+.long 0xc2988312 /* 005C: LCDEXT: idx1 = var5; idx1 > var12; idx1 += inc2 */
+.long 0x83490000 /* 0060: LCD: idx2 = var6 + var18; idx2 once var0; idx2 += inc0 */
+.long 0x00001b10 /* 0064: DRD1A: var6 = idx2; FN=0 init=0 WS=0 RS=0 */
+.long 0x8000d1a4 /* 0068: LCDEXT: idx1 = 0xf00031a4; ; */
+.long 0x8301031c /* 006C: LCD: idx2 = var6, idx3 = var2; idx2 > var12; idx2 += inc3, idx3 += inc4 */
+.long 0x008ac798 /* 0070: DRD1A: *idx1 = *idx3; FN=0 init=4 WS=1 RS=1 */
+.long 0x8000d1a4 /* 0074: LCDEXT: idx1 = 0xf00031a4; ; */
+.long 0xc1430000 /* 0078: LCDEXT: idx2 = var2 + var6; idx2 once var0; idx2 += inc0 */
+.long 0x82998312 /* 007C: LCD: idx3 = var5; idx3 > var12; idx3 += inc2 */
+.long 0x088ac790 /* 0080: DRD1A: *idx1 = *idx2; FN=0 TFD init=4 WS=1 RS=1 */
+.long 0x81988000 /* 0084: LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+.long 0x60000001 /* 0088: DRD2A: EU0=0 EU1=0 EU2=0 EU3=1 EXT init=0 WS=0 RS=0 */
+.long 0x0c4cfc4d /* 008C: DRD2B1: *idx1 = EU3(); EU3(*idx1,var13) */
+.long 0xc21883ad /* 0090: LCDEXT: idx1 = var4; idx1 == var14; idx1 += inc5 */
+.long 0x80190000 /* 0094: LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */
+.long 0x04008460 /* 0098: DRD1A: idx1 = var12; FN=0 INT init=0 WS=0 RS=0 */
+.long 0xc4052305 /* 009C: LCDEXT: idx1 = var8, idx2 = var10; idx2 == var12; idx1 += inc0, idx2 += inc5 */
+.long 0x81c98000 /* 00A0: LCD: idx3 = var3 + var19; idx3 once var0; idx3 += inc0 */
+.long 0x1000c718 /* 00A4: DRD1A: *idx1 = idx3; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x00000f18 /* 00A8: DRD1A: var3 = idx3; FN=0 init=0 WS=0 RS=0 */
+.long 0xc4188000 /* 00AC: LCDEXT: idx1 = var8; idx1 once var0; idx1 += inc0 */
+.long 0x85190312 /* 00B0: LCD: idx2 = var10; idx2 > var12; idx2 += inc2 */
+.long 0x10000c00 /* 00B4: DRD1A: var3 = var0; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x1000c400 /* 00B8: DRD1A: *idx1 = var0; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x00008860 /* 00BC: DRD1A: idx2 = var12; FN=0 init=0 WS=0 RS=0 */
+.long 0x81988000 /* 00C0: LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */
+.long 0x10000788 /* 00C4: DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */
+.long 0x60000000 /* 00C8: DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */
+.long 0x080cf04d /* 00CC: DRD2B1: idx0 = EU3(); EU3(var1,var13) */
+.long 0x000001f8 /* 00D0(:0): NOP */
+
+.align 8
+
+.globl scEthernetRecv_VarTab
+scEthernetRecv_VarTab: /* Task 0 Variable Table */
+.long 0x00000000 /* var[0] */
+.long 0x00000000 /* var[1] */
+.long 0x00000000 /* var[2] */
+.long 0x00000000 /* var[3] */
+.long 0x00000000 /* var[4] */
+.long 0x00000000 /* var[5] */
+.long 0x00000000 /* var[6] */
+.long 0x00000000 /* var[7] */
+.long 0x00000000 /* var[8] */
+.long (CONFIG_SYS_MBAR + 0x8800) /* var[9] */
+.long 0x00000008 /* var[10] */
+.long 0x0000000c /* var[11] */
+.long 0x80000000 /* var[12] */
+.long 0x00000000 /* var[13] */
+.long 0x10000000 /* var[14] */
+.long 0x20000000 /* var[15] */
+.long 0x000005e4 /* var[16] */
+.long 0x0000000e /* var[17] */
+.long 0x000005e0 /* var[18] */
+.long 0x00000004 /* var[19] */
+.long 0x00000000 /* var[20] */
+.long 0x00000000 /* var[21] */
+.long 0x00000000 /* var[22] */
+.long 0x00000000 /* var[23] */
+.long 0x00000000 /* inc[0] */
+.long 0x60000000 /* inc[1] */
+.long 0x20000001 /* inc[2] */
+.long 0x80000000 /* inc[3] */
+.long 0x40000000 /* inc[4] */
+.long 0x00000000 /* inc[5] */
+.long 0x00000000 /* inc[6] */
+.long 0x00000000 /* inc[7] */
+
+.align 8
+
+.globl scEthernetXmit_VarTab
+scEthernetXmit_VarTab: /* Task 1 Variable Table */
+.long 0x00000000 /* var[0] */
+.long 0x00000000 /* var[1] */
+.long 0x00000000 /* var[2] */
+.long 0x00000000 /* var[3] */
+.long 0x00000000 /* var[4] */
+.long 0x00000000 /* var[5] */
+.long 0x00000000 /* var[6] */
+.long 0x00000000 /* var[7] */
+.long 0x00000000 /* var[8] */
+.long 0x00000000 /* var[9] */
+.long 0x00000000 /* var[10] */
+.long (CONFIG_SYS_MBAR + 0x8800) /* var[11] */
+.long 0x00000000 /* var[12] */
+.long 0x80000000 /* var[13] */
+.long 0x10000000 /* var[14] */
+.long 0x08000000 /* var[15] */
+.long 0x20000000 /* var[16] */
+.long 0x0000ffff /* var[17] */
+.long 0xffffffff /* var[18] */
+.long 0x00000008 /* var[19] */
+.long 0x00000000 /* var[20] */
+.long 0x00000000 /* var[21] */
+.long 0x00000000 /* var[22] */
+.long 0x00000000 /* var[23] */
+.long 0x00000000 /* inc[0] */
+.long 0x60000000 /* inc[1] */
+.long 0x40000000 /* inc[2] */
+.long 0x4000ffff /* inc[3] */
+.long 0xe0000001 /* inc[4] */
+.long 0x80000000 /* inc[5] */
+.long 0x00000000 /* inc[6] */
+.long 0x00000000 /* inc[7] */
+
+.align 8
+
+.globl scEthernetRecv_FDT
+scEthernetRecv_FDT: /* Task 0 Function Descriptor Table */
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x21800000 /* and(), EU# 3 */
+.long 0x21400000 /* andn(), EU# 3 */
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+
+.align 8
+
+.globl scEthernetXmit_FDT
+scEthernetXmit_FDT: /* Task 1 Function Descriptor Table */
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x21800000 /* and(), EU# 3 */
+.long 0x21400000 /* andn(), EU# 3 */
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+.long 0x00000000
+
+
+.globl scEthernetRecv_CSave
+scEthernetRecv_CSave: /* Task 0 context save space */
+.space 128, 0x0
+
+
+.globl scEthernetXmit_CSave
+scEthernetXmit_CSave: /* Task 1 context save space */
+.space 128, 0x0
diff --git a/arch/powerpc/cpu/mpc5xxx/i2c.c b/arch/powerpc/cpu/mpc5xxx/i2c.c
new file mode 100644
index 0000000..8d5f47b
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/i2c.c
@@ -0,0 +1,472 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_HARD_I2C
+
+#include <mpc5xxx.h>
+#include <i2c.h>
+
+#if !defined(CONFIG_I2C_MULTI_BUS)
+#if (CONFIG_SYS_I2C_MODULE == 2)
+#define I2C_BASE MPC5XXX_I2C2
+#elif (CONFIG_SYS_I2C_MODULE == 1)
+#define I2C_BASE MPC5XXX_I2C1
+#else
+#error CONFIG_SYS_I2C_MODULE is not properly configured
+#endif
+#else
+static unsigned int i2c_bus_num __attribute__ ((section (".data"))) =
+ CONFIG_SYS_SPD_BUS_NUM;
+static unsigned int i2c_bus_speed[2] = {CONFIG_SYS_I2C_SPEED,
+ CONFIG_SYS_I2C_SPEED};
+
+static const unsigned long i2c_dev[2] = {
+ MPC5XXX_I2C1,
+ MPC5XXX_I2C2,
+};
+
+#define I2C_BASE ((struct mpc5xxx_i2c *)i2c_dev[i2c_bus_num])
+#endif
+
+#define I2C_TIMEOUT 6667
+#define I2C_RETRIES 3
+
+struct mpc5xxx_i2c_tap {
+ int scl2tap;
+ int tap2tap;
+};
+
+static int mpc_reg_in (volatile u32 *reg);
+static void mpc_reg_out (volatile u32 *reg, int val, int mask);
+static int wait_for_bb (void);
+static int wait_for_pin (int *status);
+static int do_address (uchar chip, char rdwr_flag);
+static int send_bytes (uchar chip, char *buf, int len);
+static int receive_bytes (uchar chip, char *buf, int len);
+static int mpc_get_fdr (int);
+
+static int mpc_reg_in(volatile u32 *reg)
+{
+ int ret = *reg >> 24;
+ __asm__ __volatile__ ("eieio");
+ return ret;
+}
+
+static void mpc_reg_out(volatile u32 *reg, int val, int mask)
+{
+ int tmp;
+
+ if (!mask) {
+ *reg = val << 24;
+ } else {
+ tmp = mpc_reg_in(reg);
+ *reg = ((tmp & ~mask) | (val & mask)) << 24;
+ }
+ __asm__ __volatile__ ("eieio");
+
+ return;
+}
+
+static int wait_for_bb(void)
+{
+ struct mpc5xxx_i2c *regs = (struct mpc5xxx_i2c *)I2C_BASE;
+ int timeout = I2C_TIMEOUT;
+ int status;
+
+ status = mpc_reg_in(&regs->msr);
+
+ while (timeout-- && (status & I2C_BB)) {
+ mpc_reg_out(&regs->mcr, I2C_STA, I2C_STA);
+ (void)mpc_reg_in(&regs->mdr);
+ mpc_reg_out(&regs->mcr, 0, I2C_STA);
+ mpc_reg_out(&regs->mcr, 0, 0);
+ mpc_reg_out(&regs->mcr, I2C_EN, 0);
+ udelay(15);
+ status = mpc_reg_in(&regs->msr);
+ }
+
+ return (status & I2C_BB);
+}
+
+static int wait_for_pin(int *status)
+{
+ struct mpc5xxx_i2c *regs = (struct mpc5xxx_i2c *)I2C_BASE;
+ int timeout = I2C_TIMEOUT;
+
+ *status = mpc_reg_in(&regs->msr);
+
+ while (timeout-- && !(*status & I2C_IF)) {
+ udelay(15);
+ *status = mpc_reg_in(&regs->msr);
+ }
+
+ if (!(*status & I2C_IF)) {
+ return -1;
+ }
+
+ mpc_reg_out(&regs->msr, 0, I2C_IF);
+
+ return 0;
+}
+
+static int do_address(uchar chip, char rdwr_flag)
+{
+ struct mpc5xxx_i2c *regs = (struct mpc5xxx_i2c *)I2C_BASE;
+ int status;
+
+ chip <<= 1;
+
+ if (rdwr_flag) {
+ chip |= 1;
+ }
+
+ mpc_reg_out(&regs->mcr, I2C_TX, I2C_TX);
+ mpc_reg_out(&regs->mdr, chip, 0);
+
+ if (wait_for_pin(&status)) {
+ return -2;
+ }
+
+ if (status & I2C_RXAK) {
+ return -3;
+ }
+
+ return 0;
+}
+
+static int send_bytes(uchar chip, char *buf, int len)
+{
+ struct mpc5xxx_i2c *regs = (struct mpc5xxx_i2c *)I2C_BASE;
+ int wrcount;
+ int status;
+
+ for (wrcount = 0; wrcount < len; ++wrcount) {
+
+ mpc_reg_out(&regs->mdr, buf[wrcount], 0);
+
+ if (wait_for_pin(&status)) {
+ break;
+ }
+
+ if (status & I2C_RXAK) {
+ break;
+ }
+
+ }
+
+ return !(wrcount == len);
+}
+
+static int receive_bytes(uchar chip, char *buf, int len)
+{
+ struct mpc5xxx_i2c *regs = (struct mpc5xxx_i2c *)I2C_BASE;
+ int dummy = 1;
+ int rdcount = 0;
+ int status;
+ int i;
+
+ mpc_reg_out(&regs->mcr, 0, I2C_TX);
+
+ for (i = 0; i < len; ++i) {
+ buf[rdcount] = mpc_reg_in(&regs->mdr);
+
+ if (dummy) {
+ dummy = 0;
+ } else {
+ rdcount++;
+ }
+
+
+ if (wait_for_pin(&status)) {
+ return -4;
+ }
+ }
+
+ mpc_reg_out(&regs->mcr, I2C_TXAK, I2C_TXAK);
+ buf[rdcount++] = mpc_reg_in(&regs->mdr);
+
+ if (wait_for_pin(&status)) {
+ return -5;
+ }
+
+ mpc_reg_out(&regs->mcr, 0, I2C_TXAK);
+
+ return 0;
+}
+
+#if defined(CONFIG_SYS_I2C_INIT_MPC5XXX)
+
+#define FDR510(x) (u8) (((x & 0x20) >> 3) | (x & 0x3))
+#define FDR432(x) (u8) ((x & 0x1C) >> 2)
+/*
+ * Reset any i2c devices that may have been interrupted during a system reset.
+ * Normally this would be accomplished by clocking the line until SCL and SDA
+ * are released and then sending a start condtiion (From an Atmel datasheet).
+ * There is no direct access to the i2c pins so instead create start commands
+ * through the i2c interface. Send a start command then delay for the SDA Hold
+ * time, repeat this by disabling/enabling the bus a total of 9 times.
+ */
+static void send_reset(void)
+{
+ struct mpc5xxx_i2c *regs = (struct mpc5xxx_i2c *)I2C_BASE;
+ int i;
+ u32 delay;
+ u8 fdr;
+ int SDA_Tap[] = { 3, 3, 4, 4, 1, 1, 2, 2};
+ struct mpc5xxx_i2c_tap scltap[] = {
+ {4, 1},
+ {4, 2},
+ {6, 4},
+ {6, 8},
+ {14, 16},
+ {30, 32},
+ {62, 64},
+ {126, 128}
+ };
+
+ fdr = (u8)mpc_reg_in(&regs->mfdr);
+
+ delay = scltap[FDR432(fdr)].scl2tap + ((SDA_Tap[FDR510(fdr)] - 1) * \
+ scltap[FDR432(fdr)].tap2tap) + 3;
+
+ for (i = 0; i < 9; i++) {
+ mpc_reg_out(&regs->mcr, I2C_EN|I2C_STA|I2C_TX, I2C_INIT_MASK);
+ udelay(delay);
+ mpc_reg_out(&regs->mcr, 0, I2C_INIT_MASK);
+ udelay(delay);
+ }
+
+ mpc_reg_out(&regs->mcr, I2C_EN, I2C_INIT_MASK);
+}
+#endif /* CONFIG_SYS_I2c_INIT_MPC5XXX */
+
+/**************** I2C API ****************/
+
+void i2c_init(int speed, int saddr)
+{
+ struct mpc5xxx_i2c *regs = (struct mpc5xxx_i2c *)I2C_BASE;
+
+ mpc_reg_out(&regs->mcr, 0, 0);
+ mpc_reg_out(&regs->madr, saddr << 1, 0);
+
+ /* Set clock
+ */
+ mpc_reg_out(&regs->mfdr, mpc_get_fdr(speed), 0);
+
+ /* Enable module
+ */
+ mpc_reg_out(&regs->mcr, I2C_EN, I2C_INIT_MASK);
+ mpc_reg_out(&regs->msr, 0, I2C_IF);
+
+#if defined(CONFIG_SYS_I2C_INIT_MPC5XXX)
+ send_reset();
+#endif
+ return;
+}
+
+static int mpc_get_fdr(int speed)
+{
+ static int fdr = -1;
+
+ if (fdr == -1) {
+ ulong best_speed = 0;
+ ulong divider;
+ ulong ipb, scl;
+ ulong bestmatch = 0xffffffffUL;
+ int best_i = 0, best_j = 0, i, j;
+ int SCL_Tap[] = { 9, 10, 12, 15, 5, 6, 7, 8};
+ struct mpc5xxx_i2c_tap scltap[] = {
+ {4, 1},
+ {4, 2},
+ {6, 4},
+ {6, 8},
+ {14, 16},
+ {30, 32},
+ {62, 64},
+ {126, 128}
+ };
+
+ ipb = gd->arch.ipb_clk;
+ for (i = 7; i >= 0; i--) {
+ for (j = 7; j >= 0; j--) {
+ scl = 2 * (scltap[j].scl2tap +
+ (SCL_Tap[i] - 1) * scltap[j].tap2tap + 2);
+ if (ipb <= speed*scl) {
+ if ((speed*scl - ipb) < bestmatch) {
+ bestmatch = speed*scl - ipb;
+ best_i = i;
+ best_j = j;
+ best_speed = ipb/scl;
+ }
+ }
+ }
+ }
+ divider = (best_i & 3) | ((best_i & 4) << 3) | (best_j << 2);
+ if (gd->flags & GD_FLG_RELOC) {
+ fdr = divider;
+ } else {
+ printf("%ld kHz, ", best_speed / 1000);
+ return divider;
+ }
+ }
+
+ return fdr;
+}
+
+int i2c_probe(uchar chip)
+{
+ struct mpc5xxx_i2c *regs = (struct mpc5xxx_i2c *)I2C_BASE;
+ int i;
+
+ for (i = 0; i < I2C_RETRIES; i++) {
+ mpc_reg_out(&regs->mcr, I2C_STA, I2C_STA);
+
+ if (! do_address(chip, 0)) {
+ mpc_reg_out(&regs->mcr, 0, I2C_STA);
+ udelay(500);
+ break;
+ }
+
+ mpc_reg_out(&regs->mcr, 0, I2C_STA);
+ udelay(500);
+ }
+
+ return (i == I2C_RETRIES);
+}
+
+int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+ char xaddr[4];
+ struct mpc5xxx_i2c * regs = (struct mpc5xxx_i2c *)I2C_BASE;
+ int ret = -1;
+
+ xaddr[0] = (addr >> 24) & 0xFF;
+ xaddr[1] = (addr >> 16) & 0xFF;
+ xaddr[2] = (addr >> 8) & 0xFF;
+ xaddr[3] = addr & 0xFF;
+
+ if (wait_for_bb()) {
+ printf("i2c_read: bus is busy\n");
+ goto Done;
+ }
+
+ mpc_reg_out(&regs->mcr, I2C_STA, I2C_STA);
+ if (do_address(chip, 0)) {
+ printf("i2c_read: failed to address chip\n");
+ goto Done;
+ }
+
+ if (send_bytes(chip, &xaddr[4-alen], alen)) {
+ printf("i2c_read: send_bytes failed\n");
+ goto Done;
+ }
+
+ mpc_reg_out(&regs->mcr, I2C_RSTA, I2C_RSTA);
+ if (do_address(chip, 1)) {
+ printf("i2c_read: failed to address chip\n");
+ goto Done;
+ }
+
+ if (receive_bytes(chip, (char *)buf, len)) {
+ printf("i2c_read: receive_bytes failed\n");
+ goto Done;
+ }
+
+ ret = 0;
+Done:
+ mpc_reg_out(&regs->mcr, 0, I2C_STA);
+ return ret;
+}
+
+int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+ char xaddr[4];
+ struct mpc5xxx_i2c *regs = (struct mpc5xxx_i2c *)I2C_BASE;
+ int ret = -1;
+
+ xaddr[0] = (addr >> 24) & 0xFF;
+ xaddr[1] = (addr >> 16) & 0xFF;
+ xaddr[2] = (addr >> 8) & 0xFF;
+ xaddr[3] = addr & 0xFF;
+
+ if (wait_for_bb()) {
+ printf("i2c_write: bus is busy\n");
+ goto Done;
+ }
+
+ mpc_reg_out(&regs->mcr, I2C_STA, I2C_STA);
+ if (do_address(chip, 0)) {
+ printf("i2c_write: failed to address chip\n");
+ goto Done;
+ }
+
+ if (send_bytes(chip, &xaddr[4-alen], alen)) {
+ printf("i2c_write: send_bytes failed\n");
+ goto Done;
+ }
+
+ if (send_bytes(chip, (char *)buf, len)) {
+ printf("i2c_write: send_bytes failed\n");
+ goto Done;
+ }
+
+ ret = 0;
+Done:
+ mpc_reg_out(&regs->mcr, 0, I2C_STA);
+ return ret;
+}
+
+#if defined(CONFIG_I2C_MULTI_BUS)
+int i2c_set_bus_num(unsigned int bus)
+{
+ if (bus > 1)
+ return -1;
+
+ i2c_bus_num = bus;
+ i2c_init(i2c_bus_speed[bus], CONFIG_SYS_I2C_SLAVE);
+ return 0;
+}
+
+int i2c_set_bus_speed(unsigned int speed)
+{
+ i2c_init(speed, CONFIG_SYS_I2C_SLAVE);
+ return 0;
+}
+
+unsigned int i2c_get_bus_num(void)
+{
+ return i2c_bus_num;
+}
+
+unsigned int i2c_get_bus_speed(void)
+{
+ return i2c_bus_speed[i2c_bus_num];
+}
+#endif
+
+
+#endif /* CONFIG_HARD_I2C */
diff --git a/arch/powerpc/cpu/mpc5xxx/ide.c b/arch/powerpc/cpu/mpc5xxx/ide.c
new file mode 100644
index 0000000..094f62b
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/ide.c
@@ -0,0 +1,99 @@
+/*
+ * (C) Copyright 2004
+ * Pierre AUBERT, Staubli Faverges, <p.aubert@staubli.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Init is derived from Linux code.
+ */
+#include <common.h>
+
+#if defined(CONFIG_CMD_IDE)
+#include <mpc5xxx.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define CALC_TIMING(t) (t + period - 1) / period
+
+#ifdef CONFIG_IDE_RESET
+extern void init_ide_reset (void);
+#endif
+
+int ide_preinit (void)
+{
+ long period, t0, t1, t2_8, t2_16, t4, ta;
+ vu_long reg;
+ struct mpc5xxx_sdma *psdma = (struct mpc5xxx_sdma *) MPC5XXX_SDMA;
+
+ reg = *(vu_long *) MPC5XXX_GPS_PORT_CONFIG;
+#if defined(CONFIG_SYS_ATA_CS_ON_I2C2)
+ /* ATA cs0/1 on i2c2 clk/io */
+ reg = (reg & ~0x03000000ul) | 0x02000000ul;
+#elif defined(CONFIG_SYS_ATA_CS_ON_TIMER01)
+ /* ATA cs0/1 on Timer 0/1 */
+ reg = (reg & ~0x03000000ul) | 0x03000000ul;
+#else
+ /* ATA cs0/1 on Local Plus cs4/5 */
+ reg = (reg & ~0x03000000ul) | 0x01000000ul;
+#endif /* CONFIG_TOTAL5200 */
+ *(vu_long *) MPC5XXX_GPS_PORT_CONFIG = reg;
+
+ /* All sample codes do that... */
+ *(vu_long *) MPC5XXX_ATA_SHARE_COUNT = 0;
+
+#if defined(CONFIG_UC101)
+ /* Configure and reset host */
+ *(vu_long *) MPC5XXX_ATA_HOST_CONFIG =
+ MPC5xxx_ATA_HOSTCONF_SMR | MPC5xxx_ATA_HOSTCONF_FR;
+ udelay (10);
+ *(vu_long *) MPC5XXX_ATA_HOST_CONFIG = 0;
+#else
+ /* Configure and reset host */
+ *(vu_long *) MPC5XXX_ATA_HOST_CONFIG = MPC5xxx_ATA_HOSTCONF_IORDY |
+ MPC5xxx_ATA_HOSTCONF_SMR | MPC5xxx_ATA_HOSTCONF_FR;
+ udelay (10);
+ *(vu_long *) MPC5XXX_ATA_HOST_CONFIG = MPC5xxx_ATA_HOSTCONF_IORDY;
+#endif
+
+ /* Disable prefetch on Commbus */
+ psdma->PtdCntrl |= 1;
+
+ /* Init timings : we use PIO mode 0 timings */
+ period = 1000000000 / gd->arch.ipb_clk; /* period in ns */
+
+ t0 = CALC_TIMING (600);
+ t2_8 = CALC_TIMING (290);
+ t2_16 = CALC_TIMING (165);
+ reg = (t0 << 24) | (t2_8 << 16) | (t2_16 << 8);
+ *(vu_long *) MPC5XXX_ATA_PIO1 = reg;
+
+ t4 = CALC_TIMING (30);
+ t1 = CALC_TIMING (70);
+ ta = CALC_TIMING (35);
+ reg = (t4 << 24) | (t1 << 16) | (ta << 8);
+
+ *(vu_long *) MPC5XXX_ATA_PIO2 = reg;
+
+#ifdef CONFIG_IDE_RESET
+ init_ide_reset ();
+#endif /* CONFIG_IDE_RESET */
+
+ return (0);
+}
+#endif
diff --git a/arch/powerpc/cpu/mpc5xxx/interrupts.c b/arch/powerpc/cpu/mpc5xxx/interrupts.c
new file mode 100644
index 0000000..50455d0
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/interrupts.c
@@ -0,0 +1,346 @@
+/*
+ * (C) Copyright 2006
+ * Detlev Zundel, DENX Software Engineering, dzu@denx.de
+ *
+ * (C) Copyright -2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* this section was ripped out of arch/powerpc/syslib/mpc52xx_pic.c in the
+ * Linux 2.6 source with the following copyright.
+ *
+ * Based on (well, mostly copied from) the code from the 2.4 kernel by
+ * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
+ *
+ * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 Montavista Software, Inc
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <command.h>
+
+struct irq_action {
+ interrupt_handler_t *handler;
+ void *arg;
+ ulong count;
+};
+
+static struct irq_action irq_handlers[NR_IRQS];
+
+static struct mpc5xxx_intr *intr;
+static struct mpc5xxx_sdma *sdma;
+
+static void mpc5xxx_ic_disable(unsigned int irq)
+{
+ u32 val;
+
+ if (irq == MPC5XXX_IRQ0) {
+ val = in_be32(&intr->ctrl);
+ val &= ~(1 << 11);
+ out_be32(&intr->ctrl, val);
+ } else if (irq < MPC5XXX_IRQ1) {
+ BUG();
+ } else if (irq <= MPC5XXX_IRQ3) {
+ val = in_be32(&intr->ctrl);
+ val &= ~(1 << (10 - (irq - MPC5XXX_IRQ1)));
+ out_be32(&intr->ctrl, val);
+ } else if (irq < MPC5XXX_SDMA_IRQ_BASE) {
+ val = in_be32(&intr->main_mask);
+ val |= 1 << (16 - (irq - MPC5XXX_MAIN_IRQ_BASE));
+ out_be32(&intr->main_mask, val);
+ } else if (irq < MPC5XXX_PERP_IRQ_BASE) {
+ val = in_be32(&sdma->IntMask);
+ val |= 1 << (irq - MPC5XXX_SDMA_IRQ_BASE);
+ out_be32(&sdma->IntMask, val);
+ } else {
+ val = in_be32(&intr->per_mask);
+ val |= 1 << (31 - (irq - MPC5XXX_PERP_IRQ_BASE));
+ out_be32(&intr->per_mask, val);
+ }
+}
+
+static void mpc5xxx_ic_enable(unsigned int irq)
+{
+ u32 val;
+
+ if (irq == MPC5XXX_IRQ0) {
+ val = in_be32(&intr->ctrl);
+ val |= 1 << 11;
+ out_be32(&intr->ctrl, val);
+ } else if (irq < MPC5XXX_IRQ1) {
+ BUG();
+ } else if (irq <= MPC5XXX_IRQ3) {
+ val = in_be32(&intr->ctrl);
+ val |= 1 << (10 - (irq - MPC5XXX_IRQ1));
+ out_be32(&intr->ctrl, val);
+ } else if (irq < MPC5XXX_SDMA_IRQ_BASE) {
+ val = in_be32(&intr->main_mask);
+ val &= ~(1 << (16 - (irq - MPC5XXX_MAIN_IRQ_BASE)));
+ out_be32(&intr->main_mask, val);
+ } else if (irq < MPC5XXX_PERP_IRQ_BASE) {
+ val = in_be32(&sdma->IntMask);
+ val &= ~(1 << (irq - MPC5XXX_SDMA_IRQ_BASE));
+ out_be32(&sdma->IntMask, val);
+ } else {
+ val = in_be32(&intr->per_mask);
+ val &= ~(1 << (31 - (irq - MPC5XXX_PERP_IRQ_BASE)));
+ out_be32(&intr->per_mask, val);
+ }
+}
+
+static void mpc5xxx_ic_ack(unsigned int irq)
+{
+ u32 val;
+
+ /*
+ * Only some irqs are reset here, others in interrupting hardware.
+ */
+
+ switch (irq) {
+ case MPC5XXX_IRQ0:
+ val = in_be32(&intr->ctrl);
+ val |= 0x08000000;
+ out_be32(&intr->ctrl, val);
+ break;
+ case MPC5XXX_CCS_IRQ:
+ val = in_be32(&intr->enc_status);
+ val |= 0x00000400;
+ out_be32(&intr->enc_status, val);
+ break;
+ case MPC5XXX_IRQ1:
+ val = in_be32(&intr->ctrl);
+ val |= 0x04000000;
+ out_be32(&intr->ctrl, val);
+ break;
+ case MPC5XXX_IRQ2:
+ val = in_be32(&intr->ctrl);
+ val |= 0x02000000;
+ out_be32(&intr->ctrl, val);
+ break;
+ case MPC5XXX_IRQ3:
+ val = in_be32(&intr->ctrl);
+ val |= 0x01000000;
+ out_be32(&intr->ctrl, val);
+ break;
+ default:
+ if (irq >= MPC5XXX_SDMA_IRQ_BASE
+ && irq < (MPC5XXX_SDMA_IRQ_BASE + MPC5XXX_SDMA_IRQ_NUM)) {
+ out_be32(&sdma->IntPend,
+ 1 << (irq - MPC5XXX_SDMA_IRQ_BASE));
+ }
+ break;
+ }
+}
+
+static void mpc5xxx_ic_disable_and_ack(unsigned int irq)
+{
+ mpc5xxx_ic_disable(irq);
+ mpc5xxx_ic_ack(irq);
+}
+
+static void mpc5xxx_ic_end(unsigned int irq)
+{
+ mpc5xxx_ic_enable(irq);
+}
+
+void mpc5xxx_init_irq(void)
+{
+ u32 intr_ctrl;
+
+ /* Remap the necessary zones */
+ intr = (struct mpc5xxx_intr *)(MPC5XXX_ICTL);
+ sdma = (struct mpc5xxx_sdma *)(MPC5XXX_SDMA);
+
+ /* Disable all interrupt sources. */
+ out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */
+ out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */
+ out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */
+ out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */
+ intr_ctrl = in_be32(&intr->ctrl);
+ intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */
+ 0x00ff0000 | /* IRQ 0-3 level sensitive low active */
+ 0x00001000 | /* MEE master external enable */
+ 0x00000000 | /* 0 means disable IRQ 0-3 */
+ 0x00000001; /* CEb route critical normally */
+ out_be32(&intr->ctrl, intr_ctrl);
+
+ /* Zero a bunch of the priority settings. */
+ out_be32(&intr->per_pri1, 0);
+ out_be32(&intr->per_pri2, 0);
+ out_be32(&intr->per_pri3, 0);
+ out_be32(&intr->main_pri1, 0);
+ out_be32(&intr->main_pri2, 0);
+}
+
+int mpc5xxx_get_irq(struct pt_regs *regs)
+{
+ u32 status;
+ int irq = -1;
+
+ status = in_be32(&intr->enc_status);
+
+ if (status & 0x00000400) { /* critical */
+ irq = (status >> 8) & 0x3;
+ if (irq == 2) /* high priority peripheral */
+ goto peripheral;
+ irq += MPC5XXX_CRIT_IRQ_BASE;
+ } else if (status & 0x00200000) { /* main */
+ irq = (status >> 16) & 0x1f;
+ if (irq == 4) /* low priority peripheral */
+ goto peripheral;
+ irq += MPC5XXX_MAIN_IRQ_BASE;
+ } else if (status & 0x20000000) { /* peripheral */
+ peripheral:
+ irq = (status >> 24) & 0x1f;
+ if (irq == 0) { /* bestcomm */
+ status = in_be32(&sdma->IntPend);
+ irq = ffs(status) + MPC5XXX_SDMA_IRQ_BASE - 1;
+ } else
+ irq += MPC5XXX_PERP_IRQ_BASE;
+ }
+
+ return irq;
+}
+
+/****************************************************************************/
+
+int interrupt_init_cpu(ulong * decrementer_count)
+{
+ *decrementer_count = get_tbclk() / CONFIG_SYS_HZ;
+
+ mpc5xxx_init_irq();
+
+ return (0);
+}
+
+/****************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt(struct pt_regs *regs)
+{
+ int irq, unmask = 1;
+
+ irq = mpc5xxx_get_irq(regs);
+
+ mpc5xxx_ic_disable_and_ack(irq);
+
+ enable_interrupts();
+
+ if (irq_handlers[irq].handler != NULL)
+ (*irq_handlers[irq].handler) (irq_handlers[irq].arg);
+ else {
+ printf("\nBogus External Interrupt IRQ %d\n", irq);
+ /*
+ * turn off the bogus interrupt, otherwise it
+ * might repeat forever
+ */
+ unmask = 0;
+ }
+
+ if (unmask)
+ mpc5xxx_ic_end(irq);
+}
+
+void timer_interrupt_cpu(struct pt_regs *regs)
+{
+ /* nothing to do here */
+ return;
+}
+
+/****************************************************************************/
+
+/*
+ * Install and free a interrupt handler.
+ */
+
+void irq_install_handler(int irq, interrupt_handler_t * handler, void *arg)
+{
+ if (irq < 0 || irq >= NR_IRQS) {
+ printf("irq_install_handler: bad irq number %d\n", irq);
+ return;
+ }
+
+ if (irq_handlers[irq].handler != NULL)
+ printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n",
+ (ulong) handler, (ulong) irq_handlers[irq].handler);
+
+ irq_handlers[irq].handler = handler;
+ irq_handlers[irq].arg = arg;
+
+ mpc5xxx_ic_enable(irq);
+}
+
+void irq_free_handler(int irq)
+{
+ if (irq < 0 || irq >= NR_IRQS) {
+ printf("irq_free_handler: bad irq number %d\n", irq);
+ return;
+ }
+
+ mpc5xxx_ic_disable(irq);
+
+ irq_handlers[irq].handler = NULL;
+ irq_handlers[irq].arg = NULL;
+}
+
+/****************************************************************************/
+
+#if defined(CONFIG_CMD_IRQ)
+void do_irqinfo(cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char * const argv[])
+{
+ int irq, re_enable;
+ u32 intr_ctrl;
+ char *irq_config[] = { "level sensitive, active high",
+ "edge sensitive, rising active edge",
+ "edge sensitive, falling active edge",
+ "level sensitive, active low"
+ };
+
+ re_enable = disable_interrupts();
+
+ intr_ctrl = in_be32(&intr->ctrl);
+ printf("Interrupt configuration:\n");
+
+ for (irq = 0; irq <= 3; irq++) {
+ printf("IRQ%d: %s\n", irq,
+ irq_config[(intr_ctrl >> (22 - 2 * irq)) & 0x3]);
+ }
+
+ puts("\nInterrupt-Information:\n" "Nr Routine Arg Count\n");
+
+ for (irq = 0; irq < NR_IRQS; irq++)
+ if (irq_handlers[irq].handler != NULL)
+ printf("%02d %08lx %08lx %ld\n", irq,
+ (ulong) irq_handlers[irq].handler,
+ (ulong) irq_handlers[irq].arg,
+ irq_handlers[irq].count);
+
+ if (re_enable)
+ enable_interrupts();
+}
+#endif
diff --git a/arch/powerpc/cpu/mpc5xxx/io.S b/arch/powerpc/cpu/mpc5xxx/io.S
new file mode 100644
index 0000000..2178a26
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/io.S
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ * Copyright (C) 2003 Wolfgang Denk <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <ppc_asm.tmpl>
+
+/* ------------------------------------------------------------------------------- */
+/* Function: in8 */
+/* Description: Input 8 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl in8
+in8:
+ lbz r3,0(r3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: in16 */
+/* Description: Input 16 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl in16
+in16:
+ lhz r3,0(r3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: in16r */
+/* Description: Input 16 bits and byte reverse */
+/* ------------------------------------------------------------------------------- */
+ .globl in16r
+in16r:
+ lhbrx r3,0,r3
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: in32 */
+/* Description: Input 32 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl in32
+in32:
+ lwz 3,0(3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: in32r */
+/* Description: Input 32 bits and byte reverse */
+/* ------------------------------------------------------------------------------- */
+ .globl in32r
+in32r:
+ lwbrx r3,0,r3
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: out8 */
+/* Description: Output 8 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl out8
+out8:
+ stb r4,0(r3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: out16 */
+/* Description: Output 16 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl out16
+out16:
+ sth r4,0(r3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: out16r */
+/* Description: Byte reverse and output 16 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl out16r
+out16r:
+ sthbrx r4,0,r3
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: out32 */
+/* Description: Output 32 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl out32
+out32:
+ stw r4,0(r3)
+ sync
+ blr
+
+/* ------------------------------------------------------------------------------- */
+/* Function: out32r */
+/* Description: Byte reverse and output 32 bits */
+/* ------------------------------------------------------------------------------- */
+ .globl out32r
+out32r:
+ stwbrx r4,0,r3
+ sync
+ blr
diff --git a/arch/powerpc/cpu/mpc5xxx/loadtask.c b/arch/powerpc/cpu/mpc5xxx/loadtask.c
new file mode 100644
index 0000000..47e7b59
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/loadtask.c
@@ -0,0 +1,76 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This file is based on code
+ * (C) Copyright Motorola, Inc., 2000
+ */
+
+#include <common.h>
+#include <mpc5xxx.h>
+
+/* BestComm/SmartComm microcode */
+extern int taskTable;
+
+void loadtask(int basetask, int tasks)
+{
+ int *sram = (int *)MPC5XXX_SRAM;
+ int *task_org = &taskTable;
+ unsigned int start, offset, end;
+ int i;
+
+#ifdef DEBUG
+ printf("basetask = %d, tasks = %d\n", basetask, tasks);
+ printf("task_org = 0x%08x\n", (unsigned int)task_org);
+#endif
+
+ /* setup TaskBAR register */
+ *(vu_long *)MPC5XXX_SDMA = MPC5XXX_SRAM;
+
+ /* relocate task table entries */
+ offset = (unsigned int)sram;
+ for (i = basetask; i < basetask + tasks; i++) {
+ sram[i * 8 + 0] = task_org[i * 8 + 0] + offset;
+ sram[i * 8 + 1] = task_org[i * 8 + 1] + offset;
+ sram[i * 8 + 2] = task_org[i * 8 + 2] + offset;
+ sram[i * 8 + 3] = task_org[i * 8 + 3] + offset;
+ sram[i * 8 + 4] = task_org[i * 8 + 4];
+ sram[i * 8 + 5] = task_org[i * 8 + 5];
+ sram[i * 8 + 6] = task_org[i * 8 + 6] + offset;
+ sram[i * 8 + 7] = task_org[i * 8 + 7];
+ }
+
+ /* relocate task descriptors */
+ start = (sram[basetask * 8] - (unsigned int)sram);
+ end = (sram[(basetask + tasks - 1) * 8 + 1] - (unsigned int)sram);
+
+#ifdef DEBUG
+ printf ("TDT start = 0x%08x, end = 0x%08x\n", start, end);
+#endif
+
+ start /= 4;
+ end /= 4;
+ for (i = start; i <= end; i++) {
+ sram[i] = task_org[i];
+ }
+
+ /* relocate variables */
+ start = (sram[basetask * 8 + 2] - (unsigned int)sram);
+ end = (sram[(basetask + tasks - 1) * 8 + 2] + 256 - (unsigned int)sram);
+ start /= 4;
+ end /= 4;
+ for (i = start; i < end; i++) {
+ sram[i] = task_org[i];
+ }
+
+ /* relocate function decriptors */
+ start = ((sram[basetask * 8 + 3] & 0xfffffffc) - (unsigned int)sram);
+ end = ((sram[(basetask + tasks - 1) * 8 + 3] & 0xfffffffc) + 256 - (unsigned int)sram);
+ start /= 4;
+ end /= 4;
+ for (i = start; i < end; i++) {
+ sram[i] = task_org[i];
+ }
+
+ asm volatile ("sync");
+}
diff --git a/arch/powerpc/cpu/mpc5xxx/pci_mpc5200.c b/arch/powerpc/cpu/mpc5xxx/pci_mpc5200.c
new file mode 100644
index 0000000..8268f8a
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/pci_mpc5200.c
@@ -0,0 +1,187 @@
+/*
+ * (C) Copyright 2000-2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_PCI)
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+#include <mpc5xxx.h>
+
+/* System RAM mapped over PCI */
+#define CONFIG_PCI_MEMORY_BUS CONFIG_SYS_SDRAM_BASE
+#define CONFIG_PCI_MEMORY_PHYS CONFIG_SYS_SDRAM_BASE
+#define CONFIG_PCI_MEMORY_SIZE (1024 * 1024 * 1024)
+
+/* PCIIWCR bit fields */
+#define IWCR_MEM (0 << 3)
+#define IWCR_IO (1 << 3)
+#define IWCR_READ (0 << 1)
+#define IWCR_READLINE (1 << 1)
+#define IWCR_READMULT (2 << 1)
+#define IWCR_EN (1 << 0)
+
+static int mpc5200_read_config_dword(struct pci_controller *hose,
+ pci_dev_t dev, int offset, u32* value)
+{
+ *(volatile u32 *)MPC5XXX_PCI_CAR = (1 << 31) | dev | offset;
+ eieio();
+ udelay(10);
+#if (defined CONFIG_PF5200 || defined CONFIG_CPCI5200)
+ if (dev & 0x00ff0000) {
+ u32 val;
+ val = in_le16((volatile u16 *)(CONFIG_PCI_IO_PHYS+2));
+ udelay(10);
+ val = val << 16;
+ val |= in_le16((volatile u16 *)(CONFIG_PCI_IO_PHYS+0));
+ *value = val;
+ } else {
+ *value = in_le32((volatile u32 *)CONFIG_PCI_IO_PHYS);
+ }
+ udelay(10);
+#else
+ *value = in_le32((volatile u32 *)CONFIG_PCI_IO_PHYS);
+#endif
+ eieio();
+ *(volatile u32 *)MPC5XXX_PCI_CAR = 0;
+ udelay(10);
+ return 0;
+}
+
+static int mpc5200_write_config_dword(struct pci_controller *hose,
+ pci_dev_t dev, int offset, u32 value)
+{
+ *(volatile u32 *)MPC5XXX_PCI_CAR = (1 << 31) | dev | offset;
+ eieio();
+ udelay(10);
+ out_le32((volatile u32 *)CONFIG_PCI_IO_PHYS, value);
+ eieio();
+ *(volatile u32 *)MPC5XXX_PCI_CAR = 0;
+ udelay(10);
+ return 0;
+}
+
+void pci_mpc5xxx_init (struct pci_controller *hose)
+{
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ /* System space */
+ pci_set_region(hose->regions + 0,
+ CONFIG_PCI_MEMORY_BUS,
+ CONFIG_PCI_MEMORY_PHYS,
+ CONFIG_PCI_MEMORY_SIZE,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ /* PCI memory space */
+ pci_set_region(hose->regions + 1,
+ CONFIG_PCI_MEM_BUS,
+ CONFIG_PCI_MEM_PHYS,
+ CONFIG_PCI_MEM_SIZE,
+ PCI_REGION_MEM);
+
+ /* PCI IO space */
+ pci_set_region(hose->regions + 2,
+ CONFIG_PCI_IO_BUS,
+ CONFIG_PCI_IO_PHYS,
+ CONFIG_PCI_IO_SIZE,
+ PCI_REGION_IO);
+
+ hose->region_count = 3;
+
+ pci_register_hose(hose);
+
+ /* GPIO Multiplexing - enable PCI */
+ *(vu_long *)MPC5XXX_GPS_PORT_CONFIG &= ~(1 << 15);
+
+ /* Set host bridge as pci master and enable memory decoding */
+ *(vu_long *)MPC5XXX_PCI_CMD |=
+ PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+
+ /* Set maximum latency timer */
+ *(vu_long *)MPC5XXX_PCI_CFG |= (0xf800);
+
+ /* Set cache line size */
+ *(vu_long *)MPC5XXX_PCI_CFG = (*(vu_long *)MPC5XXX_PCI_CFG & ~0xff) |
+ (CONFIG_SYS_CACHELINE_SIZE / 4);
+
+ /* Map MBAR to PCI space */
+ *(vu_long *)MPC5XXX_PCI_BAR0 = CONFIG_SYS_MBAR;
+ *(vu_long *)MPC5XXX_PCI_TBATR0 = CONFIG_SYS_MBAR | 1;
+
+ /* Map RAM to PCI space */
+ *(vu_long *)MPC5XXX_PCI_BAR1 = CONFIG_PCI_MEMORY_BUS | (1 << 3);
+ *(vu_long *)MPC5XXX_PCI_TBATR1 = CONFIG_PCI_MEMORY_PHYS | 1;
+
+ /* Park XLB on PCI */
+ *(vu_long *)(MPC5XXX_XLBARB + 0x40) &= ~((7 << 8) | (3 << 5));
+ *(vu_long *)(MPC5XXX_XLBARB + 0x40) |= (3 << 8) | (3 << 5);
+
+ /* Disable interrupts from PCI controller */
+ *(vu_long *)MPC5XXX_PCI_GSCR &= ~(7 << 12);
+ *(vu_long *)MPC5XXX_PCI_ICR &= ~(7 << 24);
+
+ /* Set PCI retry counter to 0 = infinite retry. */
+ /* The default of 255 is too short for slow devices. */
+ *(vu_long *)MPC5XXX_PCI_ICR &= 0xFFFFFF00;
+
+ /* Disable initiator windows */
+ *(vu_long *)MPC5XXX_PCI_IWCR = 0;
+
+ /* Map PCI memory to physical space */
+ *(vu_long *)MPC5XXX_PCI_IW0BTAR = CONFIG_PCI_MEM_PHYS |
+ (((CONFIG_PCI_MEM_SIZE - 1) >> 8) & 0x00ff0000) |
+ (CONFIG_PCI_MEM_BUS >> 16);
+ *(vu_long *)MPC5XXX_PCI_IWCR |= (IWCR_MEM | IWCR_READ | IWCR_EN) << 24;
+
+ /* Map PCI I/O to physical space */
+ *(vu_long *)MPC5XXX_PCI_IW1BTAR = CONFIG_PCI_IO_PHYS |
+ (((CONFIG_PCI_IO_SIZE - 1) >> 8) & 0x00ff0000) |
+ (CONFIG_PCI_IO_BUS >> 16);
+ *(vu_long *)MPC5XXX_PCI_IWCR |= (IWCR_IO | IWCR_READ | IWCR_EN) << 16;
+
+ /* Reset the PCI bus */
+ *(vu_long *)MPC5XXX_PCI_GSCR |= 1;
+ udelay(1000);
+ *(vu_long *)MPC5XXX_PCI_GSCR &= ~1;
+ udelay(1000);
+
+ pci_set_ops(hose,
+ pci_hose_read_config_byte_via_dword,
+ pci_hose_read_config_word_via_dword,
+ mpc5200_read_config_dword,
+ pci_hose_write_config_byte_via_dword,
+ pci_hose_write_config_word_via_dword,
+ mpc5200_write_config_dword);
+
+ udelay(1000);
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf("PCI: Bus Dev VenId DevId Class Int\n");
+#endif
+
+ hose->last_busno = pci_hose_scan(hose);
+}
+#endif /* CONFIG_PCI */
diff --git a/arch/powerpc/cpu/mpc5xxx/serial.c b/arch/powerpc/cpu/mpc5xxx/serial.c
new file mode 100644
index 0000000..1ccb4e3
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/serial.c
@@ -0,0 +1,292 @@
+/*
+ * (C) Copyright 2000 - 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00, with
+ * changes based on the file arch/powerpc/mbxboot/m8260_tty.c from the
+ * Linux/PPC sources (m8260_tty.c had no copyright info in it).
+ *
+ * Martin Krause, 8 Jun 2006
+ * Added SERIAL_MULTI support
+ */
+
+/*
+ * Minimal serial functions needed to use one of the PSC ports
+ * as serial console interface.
+ */
+
+#include <common.h>
+#include <linux/compiler.h>
+#include <mpc5xxx.h>
+#include <serial.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_PSC_CONSOLE)
+
+#if CONFIG_PSC_CONSOLE == 1
+#define PSC_BASE MPC5XXX_PSC1
+#elif CONFIG_PSC_CONSOLE == 2
+#define PSC_BASE MPC5XXX_PSC2
+#elif CONFIG_PSC_CONSOLE == 3
+#define PSC_BASE MPC5XXX_PSC3
+#elif CONFIG_PSC_CONSOLE == 4
+#define PSC_BASE MPC5XXX_PSC4
+#elif CONFIG_PSC_CONSOLE == 5
+#define PSC_BASE MPC5XXX_PSC5
+#elif CONFIG_PSC_CONSOLE == 6
+#define PSC_BASE MPC5XXX_PSC6
+#else
+#error CONFIG_PSC_CONSOLE must be in 1 ... 6
+#endif
+
+#if defined(CONFIG_PSC_CONSOLE2)
+
+#if CONFIG_PSC_CONSOLE2 == 1
+#define PSC_BASE2 MPC5XXX_PSC1
+#elif CONFIG_PSC_CONSOLE2 == 2
+#define PSC_BASE2 MPC5XXX_PSC2
+#elif CONFIG_PSC_CONSOLE2 == 3
+#define PSC_BASE2 MPC5XXX_PSC3
+#elif CONFIG_PSC_CONSOLE2 == 4
+#define PSC_BASE2 MPC5XXX_PSC4
+#elif CONFIG_PSC_CONSOLE2 == 5
+#define PSC_BASE2 MPC5XXX_PSC5
+#elif CONFIG_PSC_CONSOLE2 == 6
+#define PSC_BASE2 MPC5XXX_PSC6
+#else
+#error CONFIG_PSC_CONSOLE2 must be in 1 ... 6
+#endif
+
+#endif
+
+int serial_init_dev (unsigned long dev_base)
+{
+ volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
+ unsigned long baseclk;
+ int div;
+
+ /* reset PSC */
+ psc->command = PSC_SEL_MODE_REG_1;
+
+ /* select clock sources */
+ psc->psc_clock_select = 0;
+ baseclk = (gd->arch.ipb_clk + 16) / 32;
+
+ /* switch to UART mode */
+ psc->sicr = 0;
+
+ /* configure parity, bit length and so on */
+ psc->mode = PSC_MODE_8_BITS | PSC_MODE_PARNONE;
+ psc->mode = PSC_MODE_ONE_STOP;
+
+ /* set up UART divisor */
+ div = (baseclk + (gd->baudrate/2)) / gd->baudrate;
+ psc->ctur = (div >> 8) & 0xff;
+ psc->ctlr = div & 0xff;
+
+ /* disable all interrupts */
+ psc->psc_imr = 0;
+
+ /* reset and enable Rx/Tx */
+ psc->command = PSC_RST_RX;
+ psc->command = PSC_RST_TX;
+ psc->command = PSC_RX_ENABLE | PSC_TX_ENABLE;
+
+ return (0);
+}
+
+void serial_putc_dev (unsigned long dev_base, const char c)
+{
+ volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
+
+ if (c == '\n')
+ serial_putc_dev (dev_base, '\r');
+
+ /* Wait for last character to go. */
+ while (!(psc->psc_status & PSC_SR_TXEMP))
+ ;
+
+ psc->psc_buffer_8 = c;
+}
+
+void serial_putc_raw_dev(unsigned long dev_base, const char c)
+{
+ volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
+ /* Wait for last character to go. */
+ while (!(psc->psc_status & PSC_SR_TXEMP))
+ ;
+
+ psc->psc_buffer_8 = c;
+}
+
+
+void serial_puts_dev (unsigned long dev_base, const char *s)
+{
+ while (*s) {
+ serial_putc_dev (dev_base, *s++);
+ }
+}
+
+int serial_getc_dev (unsigned long dev_base)
+{
+ volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
+
+ /* Wait for a character to arrive. */
+ while (!(psc->psc_status & PSC_SR_RXRDY))
+ ;
+
+ return psc->psc_buffer_8;
+}
+
+int serial_tstc_dev (unsigned long dev_base)
+{
+ volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
+
+ return (psc->psc_status & PSC_SR_RXRDY);
+}
+
+void serial_setbrg_dev (unsigned long dev_base)
+{
+ volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
+ unsigned long baseclk, div;
+
+ baseclk = (gd->arch.ipb_clk + 16) / 32;
+
+ /* set up UART divisor */
+ div = (baseclk + (gd->baudrate/2)) / gd->baudrate;
+ psc->ctur = (div >> 8) & 0xFF;
+ psc->ctlr = div & 0xff;
+}
+
+void serial_setrts_dev (unsigned long dev_base, int s)
+{
+ volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
+
+ if (s) {
+ /* Assert RTS (become LOW) */
+ psc->op1 = 0x1;
+ }
+ else {
+ /* Negate RTS (become HIGH) */
+ psc->op0 = 0x1;
+ }
+}
+
+int serial_getcts_dev (unsigned long dev_base)
+{
+ volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base;
+
+ return (psc->ip & 0x1) ? 0 : 1;
+}
+
+int serial0_init(void)
+{
+ return (serial_init_dev(PSC_BASE));
+}
+
+void serial0_setbrg (void)
+{
+ serial_setbrg_dev(PSC_BASE);
+}
+
+void serial0_putc(const char c)
+{
+ serial_putc_dev(PSC_BASE,c);
+}
+
+void serial0_puts(const char *s)
+{
+ serial_puts_dev(PSC_BASE, s);
+}
+
+int serial0_getc(void)
+{
+ return(serial_getc_dev(PSC_BASE));
+}
+
+int serial0_tstc(void)
+{
+ return (serial_tstc_dev(PSC_BASE));
+}
+
+struct serial_device serial0_device =
+{
+ .name = "serial0",
+ .start = serial0_init,
+ .stop = NULL,
+ .setbrg = serial0_setbrg,
+ .getc = serial0_getc,
+ .tstc = serial0_tstc,
+ .putc = serial0_putc,
+ .puts = serial0_puts,
+};
+
+__weak struct serial_device *default_serial_console(void)
+{
+ return &serial0_device;
+}
+
+#ifdef CONFIG_PSC_CONSOLE2
+int serial1_init(void)
+{
+ return serial_init_dev(PSC_BASE2);
+}
+
+void serial1_setbrg(void)
+{
+ serial_setbrg_dev(PSC_BASE2);
+}
+
+void serial1_putc(const char c)
+{
+ serial_putc_dev(PSC_BASE2, c);
+}
+
+void serial1_puts(const char *s)
+{
+ serial_puts_dev(PSC_BASE2, s);
+}
+
+int serial1_getc(void)
+{
+ return serial_getc_dev(PSC_BASE2);
+}
+
+int serial1_tstc(void)
+{
+ return serial_tstc_dev(PSC_BASE2);
+}
+
+struct serial_device serial1_device =
+{
+ .name = "serial1",
+ .start = serial1_init,
+ .stop = NULL,
+ .setbrg = serial1_setbrg,
+ .getc = serial1_getc,
+ .tstc = serial1_tstc,
+ .putc = serial1_putc,
+ .puts = serial1_puts,
+};
+#endif /* CONFIG_PSC_CONSOLE2 */
+
+#endif /* CONFIG_PSC_CONSOLE */
diff --git a/arch/powerpc/cpu/mpc5xxx/speed.c b/arch/powerpc/cpu/mpc5xxx/speed.c
new file mode 100644
index 0000000..5353e3d
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/speed.c
@@ -0,0 +1,100 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc5xxx.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* ------------------------------------------------------------------------- */
+
+/* Bus-to-Core Multipliers */
+
+static int bus2core[] = {
+ 3, 2, 2, 2, 4, 4, 5, 9,
+ 6, 11, 8, 10, 3, 12, 7, 0,
+ 6, 5, 13, 2, 14, 4, 15, 9,
+ 0, 11, 8, 10, 16, 12, 7, 0
+};
+/* ------------------------------------------------------------------------- */
+
+/*
+ *
+ */
+
+int get_clocks (void)
+{
+ ulong val, vco;
+
+#if !defined(CONFIG_SYS_MPC5XXX_CLKIN)
+#error clock measuring not implemented yet - define CONFIG_SYS_MPC5XXX_CLKIN
+#endif
+
+ val = *(vu_long *)MPC5XXX_CDM_PORCFG;
+ if (val & (1 << 6)) {
+ vco = CONFIG_SYS_MPC5XXX_CLKIN * 12;
+ } else {
+ vco = CONFIG_SYS_MPC5XXX_CLKIN * 16;
+ }
+ if (val & (1 << 5)) {
+ gd->bus_clk = vco / 8;
+ } else {
+ gd->bus_clk = vco / 4;
+ }
+ gd->cpu_clk = gd->bus_clk * bus2core[val & 0x1f] / 2;
+
+ val = *(vu_long *)MPC5XXX_CDM_CFG;
+ if (val & (1 << 8)) {
+ gd->arch.ipb_clk = gd->bus_clk / 2;
+ } else {
+ gd->arch.ipb_clk = gd->bus_clk;
+ }
+ switch (val & 3) {
+ case 0:
+ gd->pci_clk = gd->arch.ipb_clk;
+ break;
+ case 1:
+ gd->pci_clk = gd->arch.ipb_clk / 2;
+ break;
+ default:
+ gd->pci_clk = gd->bus_clk / 4;
+ break;
+ }
+
+ return (0);
+}
+
+int prt_mpc5xxx_clks (void)
+{
+ char buf1[32], buf2[32], buf3[32];
+
+ printf (" Bus %s MHz, IPB %s MHz, PCI %s MHz\n",
+ strmhz(buf1, gd->bus_clk),
+ strmhz(buf2, gd->arch.ipb_clk),
+ strmhz(buf3, gd->pci_clk)
+ );
+ return (0);
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/arch/powerpc/cpu/mpc5xxx/spl_boot.c b/arch/powerpc/cpu/mpc5xxx/spl_boot.c
new file mode 100644
index 0000000..35611cc
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/spl_boot.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 Stefan Roese <sr@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <spl.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Needed to align size SPL image to a 4-byte length
+ */
+u32 end_align __attribute__ ((section(".end_align")));
+
+/*
+ * Return selected boot device. On MPC5200 its only NOR flash right now.
+ */
+u32 spl_boot_device(void)
+{
+ return BOOT_DEVICE_NOR;
+}
+
+/*
+ * SPL version of board_init_f()
+ */
+void board_init_f(ulong bootflag)
+{
+ end_align = (u32)__spl_flash_end;
+
+ /*
+ * On MPC5200, the initial RAM (and gd) is located in the internal
+ * SRAM. So we can actually call the preloader console init code
+ * before calling initdram(). This makes serial output (printf)
+ * available very early, even before SDRAM init, which has been
+ * an U-Boot priciple from day 1.
+ */
+
+ /*
+ * Init global_data pointer. Has to be done before calling
+ * get_clocks(), as it stores some clock values into gd needed
+ * later on in the serial driver.
+ */
+ /* Pointer is writable since we allocated a register for it */
+ gd = (gd_t *)(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+ /* Clear initial global data */
+ memset((void *)gd, 0, sizeof(gd_t));
+
+ /*
+ * get_clocks() needs to be called so that the serial driver
+ * works correctly
+ */
+ get_clocks();
+
+ /*
+ * Do rudimental console / serial setup
+ */
+ preloader_console_init();
+
+ /*
+ * First we need to initialize the SDRAM, so that the real
+ * U-Boot or the OS (Linux) can be loaded
+ */
+ initdram(0);
+
+ /* Clear bss */
+ memset(__bss_start, '\0', __bss_end - __bss_start);
+
+ /*
+ * Call board_init_r() (SPL framework version) to load and boot
+ * real U-Boot or OS
+ */
+ board_init_r(NULL, 0);
+ /* Does not return!!! */
+}
diff --git a/arch/powerpc/cpu/mpc5xxx/start.S b/arch/powerpc/cpu/mpc5xxx/start.S
new file mode 100644
index 0000000..2b6a800
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/start.S
@@ -0,0 +1,783 @@
+/*
+ * Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2000 - 2003 Wolfgang Denk <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * U-Boot - Startup Code for MPC5xxx CPUs
+ */
+#include <asm-offsets.h>
+#include <config.h>
+#include <mpc5xxx.h>
+#include <version.h>
+
+#define CONFIG_MPC5xxx 1 /* needed for Linux kernel header files */
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+#include <asm/u-boot.h>
+
+/* We don't want the MMU yet.
+*/
+#undef MSR_KERNEL
+/* Floating Point enable, Machine Check and Recoverable Interr. */
+#ifdef DEBUG
+#define MSR_KERNEL (MSR_FP|MSR_RI)
+#else
+#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI)
+#endif
+
+#ifndef CONFIG_SPL_BUILD
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+ START_GOT
+ GOT_ENTRY(_GOT2_TABLE_)
+ GOT_ENTRY(_FIXUP_TABLE_)
+
+ GOT_ENTRY(_start)
+ GOT_ENTRY(_start_of_vectors)
+ GOT_ENTRY(_end_of_vectors)
+ GOT_ENTRY(transfer_to_handler)
+
+ GOT_ENTRY(__init_end)
+ GOT_ENTRY(__bss_end)
+ GOT_ENTRY(__bss_start)
+ END_GOT
+#endif
+
+/*
+ * Version string
+ */
+ .data
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION_STRING, "\0"
+
+/*
+ * Exception vectors
+ */
+ .text
+ . = EXC_OFF_SYS_RESET
+ .globl _start
+_start:
+
+#if defined(CONFIG_SPL) && !defined(CONFIG_SPL_BUILD)
+ /*
+ * This is the entry of the real U-Boot from a board port
+ * that supports SPL booting on the MPC5200. We only need
+ * to call board_init_f() here. Everything else has already
+ * been done in the SPL u-boot version.
+ */
+ GET_GOT /* initialize GOT access */
+ bl board_init_f /* run 1st part of board init code (in Flash)*/
+ /* NOTREACHED - board_init_f() does not return */
+#else
+ mfmsr r5 /* save msr contents */
+
+ /* Move CSBoot and adjust instruction pointer */
+ /*--------------------------------------------------------------*/
+
+#if defined(CONFIG_SYS_LOWBOOT)
+# if defined(CONFIG_SYS_RAMBOOT)
+# error CONFIG_SYS_LOWBOOT is incompatible with CONFIG_SYS_RAMBOOT
+# endif /* CONFIG_SYS_RAMBOOT */
+ lis r4, CONFIG_SYS_DEFAULT_MBAR@h
+ lis r3, START_REG(CONFIG_SYS_BOOTCS_START)@h
+ ori r3, r3, START_REG(CONFIG_SYS_BOOTCS_START)@l
+ stw r3, 0x4(r4) /* CS0 start */
+ lis r3, STOP_REG(CONFIG_SYS_BOOTCS_START, CONFIG_SYS_BOOTCS_SIZE)@h
+ ori r3, r3, STOP_REG(CONFIG_SYS_BOOTCS_START, CONFIG_SYS_BOOTCS_SIZE)@l
+ stw r3, 0x8(r4) /* CS0 stop */
+ lis r3, 0x02010000@h
+ ori r3, r3, 0x02010000@l
+ stw r3, 0x54(r4) /* CS0 and Boot enable */
+
+ lis r3, lowboot_reentry@h /* jump from bootlow address space (0x0000xxxx) */
+ ori r3, r3, lowboot_reentry@l /* to the address space the linker used */
+ mtlr r3
+ blr
+
+lowboot_reentry:
+ lis r3, START_REG(CONFIG_SYS_BOOTCS_START)@h
+ ori r3, r3, START_REG(CONFIG_SYS_BOOTCS_START)@l
+ stw r3, 0x4c(r4) /* Boot start */
+ lis r3, STOP_REG(CONFIG_SYS_BOOTCS_START, CONFIG_SYS_BOOTCS_SIZE)@h
+ ori r3, r3, STOP_REG(CONFIG_SYS_BOOTCS_START, CONFIG_SYS_BOOTCS_SIZE)@l
+ stw r3, 0x50(r4) /* Boot stop */
+ lis r3, 0x02000001@h
+ ori r3, r3, 0x02000001@l
+ stw r3, 0x54(r4) /* Boot enable, CS0 disable */
+#endif /* CONFIG_SYS_LOWBOOT */
+
+#if defined(CONFIG_SYS_DEFAULT_MBAR) && !defined(CONFIG_SYS_RAMBOOT)
+ lis r3, CONFIG_SYS_MBAR@h
+ ori r3, r3, CONFIG_SYS_MBAR@l
+ /* MBAR is mirrored into the MBAR SPR */
+ mtspr MBAR,r3
+ rlwinm r3, r3, 16, 16, 31
+ lis r4, CONFIG_SYS_DEFAULT_MBAR@h
+ stw r3, 0(r4)
+#endif /* CONFIG_SYS_DEFAULT_MBAR */
+
+ /* Initialise the MPC5xxx processor core */
+ /*--------------------------------------------------------------*/
+
+ bl init_5xxx_core
+
+ /* initialize some things that are hard to access from C */
+ /*--------------------------------------------------------------*/
+
+ /* set up stack in on-chip SRAM */
+ lis r3, CONFIG_SYS_INIT_RAM_ADDR@h
+ ori r3, r3, CONFIG_SYS_INIT_RAM_ADDR@l
+ ori r1, r3, CONFIG_SYS_INIT_SP_OFFSET
+ li r0, 0 /* Make room for stack frame header and */
+ stwu r0, -4(r1) /* clear final stack frame so that */
+ stwu r0, -4(r1) /* stack backtraces terminate cleanly */
+
+ /* let the C-code set up the rest */
+ /* */
+ /* Be careful to keep code relocatable ! */
+ /*--------------------------------------------------------------*/
+
+#ifndef CONFIG_SPL_BUILD
+ GET_GOT /* initialize GOT access */
+#endif
+
+ /* r3: IMMR */
+ bl cpu_init_f /* run low-level CPU init code (in Flash)*/
+
+ bl board_init_f /* run 1st part of board init code (in Flash)*/
+
+ /* NOTREACHED - board_init_f() does not return */
+#endif
+
+#ifndef CONFIG_SPL_BUILD
+/*
+ * Vector Table
+ */
+
+ .globl _start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. */
+ STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+ STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+ STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+ . = 0x600
+Alignment:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+ . = 0x700
+ProgramCheck:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+ MSR_KERNEL, COPY_EE)
+
+ STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+ /* I guess we could implement decrementer, and may have
+ * to someday for timekeeping.
+ */
+ STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+
+ STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+ STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+ STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+ STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+ STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+ STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+ STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException)
+#ifdef DEBUG
+ . = 0x1300
+ /*
+ * This exception occurs when the program counter matches the
+ * Instruction Address Breakpoint Register (IABR).
+ *
+ * I want the cpu to halt if this occurs so I can hunt around
+ * with the debugger and look at things.
+ *
+ * When DEBUG is defined, both machine check enable (in the MSR)
+ * and checkstop reset enable (in the reset mode register) are
+ * turned off and so a checkstop condition will result in the cpu
+ * halting.
+ *
+ * I force the cpu into a checkstop condition by putting an illegal
+ * instruction here (at least this is the theory).
+ *
+ * well - that didnt work, so just do an infinite loop!
+ */
+1: b 1b
+#else
+ STD_EXCEPTION(0x1300, InstructionBreakpoint, DebugException)
+#endif
+ STD_EXCEPTION(0x1400, SMI, UnknownException)
+
+ STD_EXCEPTION(0x1500, Trap_15, UnknownException)
+ STD_EXCEPTION(0x1600, Trap_16, UnknownException)
+ STD_EXCEPTION(0x1700, Trap_17, UnknownException)
+ STD_EXCEPTION(0x1800, Trap_18, UnknownException)
+ STD_EXCEPTION(0x1900, Trap_19, UnknownException)
+ STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
+ STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+ STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
+ STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
+ STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
+ STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
+ STD_EXCEPTION(0x2000, Trap_20, UnknownException)
+ STD_EXCEPTION(0x2100, Trap_21, UnknownException)
+ STD_EXCEPTION(0x2200, Trap_22, UnknownException)
+ STD_EXCEPTION(0x2300, Trap_23, UnknownException)
+ STD_EXCEPTION(0x2400, Trap_24, UnknownException)
+ STD_EXCEPTION(0x2500, Trap_25, UnknownException)
+ STD_EXCEPTION(0x2600, Trap_26, UnknownException)
+ STD_EXCEPTION(0x2700, Trap_27, UnknownException)
+ STD_EXCEPTION(0x2800, Trap_28, UnknownException)
+ STD_EXCEPTION(0x2900, Trap_29, UnknownException)
+ STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
+ STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
+ STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
+ STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
+ STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
+ STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
+
+
+ .globl _end_of_vectors
+_end_of_vectors:
+
+ . = 0x3000
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+ .globl transfer_to_handler
+transfer_to_handler:
+ stw r22,_NIP(r21)
+ lis r22,MSR_POW@h
+ andc r23,r23,r22
+ stw r23,_MSR(r21)
+ SAVE_GPR(7, r21)
+ SAVE_4GPRS(8, r21)
+ SAVE_8GPRS(12, r21)
+ SAVE_8GPRS(24, r21)
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
+
+int_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+#endif /* CONFIG_SPL_BUILD */
+
+/*
+ * This code initialises the MPC5xxx processor core
+ * (conforms to PowerPC 603e spec)
+ * Note: expects original MSR contents to be in r5.
+ */
+
+ .globl init_5xx_core
+init_5xxx_core:
+
+ /* Initialize machine status; enable machine check interrupt */
+ /*--------------------------------------------------------------*/
+
+ li r3, MSR_KERNEL /* Set ME and RI flags */
+ rlwimi r3, r5, 0, 25, 25 /* preserve IP bit set by HRCW */
+#ifdef DEBUG
+ rlwimi r3, r5, 0, 21, 22 /* debugger might set SE & BE bits */
+#endif
+ SYNC /* Some chip revs need this... */
+ mtmsr r3
+ SYNC
+ mtspr SRR1, r3 /* Make SRR1 match MSR */
+
+ /* Initialize the Hardware Implementation-dependent Registers */
+ /* HID0 also contains cache control */
+ /*--------------------------------------------------------------*/
+
+ lis r3, CONFIG_SYS_HID0_INIT@h
+ ori r3, r3, CONFIG_SYS_HID0_INIT@l
+ SYNC
+ mtspr HID0, r3
+
+ lis r3, CONFIG_SYS_HID0_FINAL@h
+ ori r3, r3, CONFIG_SYS_HID0_FINAL@l
+ SYNC
+ mtspr HID0, r3
+
+ /* clear all BAT's */
+ /*--------------------------------------------------------------*/
+
+ li r0, 0
+ mtspr DBAT0U, r0
+ mtspr DBAT0L, r0
+ mtspr DBAT1U, r0
+ mtspr DBAT1L, r0
+ mtspr DBAT2U, r0
+ mtspr DBAT2L, r0
+ mtspr DBAT3U, r0
+ mtspr DBAT3L, r0
+ mtspr DBAT4U, r0
+ mtspr DBAT4L, r0
+ mtspr DBAT5U, r0
+ mtspr DBAT5L, r0
+ mtspr DBAT6U, r0
+ mtspr DBAT6L, r0
+ mtspr DBAT7U, r0
+ mtspr DBAT7L, r0
+ mtspr IBAT0U, r0
+ mtspr IBAT0L, r0
+ mtspr IBAT1U, r0
+ mtspr IBAT1L, r0
+ mtspr IBAT2U, r0
+ mtspr IBAT2L, r0
+ mtspr IBAT3U, r0
+ mtspr IBAT3L, r0
+ mtspr IBAT4U, r0
+ mtspr IBAT4L, r0
+ mtspr IBAT5U, r0
+ mtspr IBAT5L, r0
+ mtspr IBAT6U, r0
+ mtspr IBAT6L, r0
+ mtspr IBAT7U, r0
+ mtspr IBAT7L, r0
+ SYNC
+
+ /* invalidate all tlb's */
+ /* */
+ /* From the 603e User Manual: "The 603e provides the ability to */
+ /* invalidate a TLB entry. The TLB Invalidate Entry (tlbie) */
+ /* instruction invalidates the TLB entry indexed by the EA, and */
+ /* operates on both the instruction and data TLBs simultaneously*/
+ /* invalidating four TLB entries (both sets in each TLB). The */
+ /* index corresponds to bits 15-19 of the EA. To invalidate all */
+ /* entries within both TLBs, 32 tlbie instructions should be */
+ /* issued, incrementing this field by one each time." */
+ /* */
+ /* "Note that the tlbia instruction is not implemented on the */
+ /* 603e." */
+ /* */
+ /* bits 15-19 correspond to addresses 0x00000000 to 0x0001F000 */
+ /* incrementing by 0x1000 each time. The code below is sort of */
+ /* based on code in "flush_tlbs" from arch/powerpc/kernel/head.S */
+ /* */
+ /*--------------------------------------------------------------*/
+
+ li r3, 32
+ mtctr r3
+ li r3, 0
+1: tlbie r3
+ addi r3, r3, 0x1000
+ bdnz 1b
+ SYNC
+
+ /* Done! */
+ /*--------------------------------------------------------------*/
+
+ blr
+
+/* Cache functions.
+ *
+ * Note: requires that all cache bits in
+ * HID0 are in the low half word.
+ */
+ .globl icache_enable
+icache_enable:
+ mfspr r3, HID0
+ ori r3, r3, HID0_ICE
+ lis r4, 0
+ ori r4, r4, HID0_ILOCK
+ andc r3, r3, r4
+ ori r4, r3, HID0_ICFI
+ isync
+ mtspr HID0, r4 /* sets enable and invalidate, clears lock */
+ isync
+ mtspr HID0, r3 /* clears invalidate */
+ blr
+
+ .globl icache_disable
+icache_disable:
+ mfspr r3, HID0
+ lis r4, 0
+ ori r4, r4, HID0_ICE|HID0_ILOCK
+ andc r3, r3, r4
+ ori r4, r3, HID0_ICFI
+ isync
+ mtspr HID0, r4 /* sets invalidate, clears enable and lock */
+ isync
+ mtspr HID0, r3 /* clears invalidate */
+ blr
+
+ .globl icache_status
+icache_status:
+ mfspr r3, HID0
+ rlwinm r3, r3, HID0_ICE_BITPOS + 1, 31, 31
+ blr
+
+ .globl dcache_enable
+dcache_enable:
+ mfspr r3, HID0
+ ori r3, r3, HID0_DCE
+ lis r4, 0
+ ori r4, r4, HID0_DLOCK
+ andc r3, r3, r4
+ ori r4, r3, HID0_DCI
+ sync
+ mtspr HID0, r4 /* sets enable and invalidate, clears lock */
+ sync
+ mtspr HID0, r3 /* clears invalidate */
+ blr
+
+ .globl dcache_disable
+dcache_disable:
+ mfspr r3, HID0
+ lis r4, 0
+ ori r4, r4, HID0_DCE|HID0_DLOCK
+ andc r3, r3, r4
+ ori r4, r3, HID0_DCI
+ sync
+ mtspr HID0, r4 /* sets invalidate, clears enable and lock */
+ sync
+ mtspr HID0, r3 /* clears invalidate */
+ blr
+
+ .globl dcache_status
+dcache_status:
+ mfspr r3, HID0
+ rlwinm r3, r3, HID0_DCE_BITPOS + 1, 31, 31
+ blr
+
+ .globl get_svr
+get_svr:
+ mfspr r3, SVR
+ blr
+
+ .globl get_pvr
+get_pvr:
+ mfspr r3, PVR
+ blr
+
+#ifndef CONFIG_SPL_BUILD
+/*------------------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+ .globl relocate_code
+relocate_code:
+ mr r1, r3 /* Set new stack pointer */
+ mr r9, r4 /* Save copy of Global Data pointer */
+ mr r10, r5 /* Save copy of Destination Address */
+
+ GET_GOT
+ mr r3, r5 /* Destination Address */
+ lis r4, CONFIG_SYS_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CONFIG_SYS_MONITOR_BASE@l
+ lwz r5, GOT(__init_end)
+ sub r5, r5, r4
+ li r6, CONFIG_SYS_CACHELINE_SIZE /* Cache Line Size */
+
+ /*
+ * Fix GOT pointer:
+ *
+ * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+ *
+ * Offset:
+ */
+ sub r15, r10, r4
+
+ /* First our own GOT */
+ add r12, r12, r15
+ /* then the one used by the C code */
+ add r30, r30, r15
+
+ /*
+ * Now relocate code
+ */
+
+ cmplw cr1,r3,r4
+ addi r0,r5,3
+ srwi. r0,r0,2
+ beq cr1,4f /* In place copy is not necessary */
+ beq 7f /* Protect against 0 count */
+ mtctr r0
+ bge cr1,2f
+
+ la r8,-4(r4)
+ la r7,-4(r3)
+1: lwzu r0,4(r8)
+ stwu r0,4(r7)
+ bdnz 1b
+ b 4f
+
+2: slwi r0,r0,2
+ add r8,r4,r0
+ add r7,r3,r0
+3: lwzu r0,-4(r8)
+ stwu r0,-4(r7)
+ bdnz 3b
+
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4: cmpwi r6,0
+ add r5,r3,r5
+ beq 7f /* Always flush prefetch queue in any case */
+ subi r0,r6,1
+ andc r3,r3,r0
+ mfspr r7,HID0 /* don't do dcbst if dcache is disabled */
+ rlwinm r7,r7,HID0_DCE_BITPOS+1,31,31
+ cmpwi r7,0
+ beq 9f
+ mr r4,r3
+5: dcbst 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 5b
+ sync /* Wait for all dcbst to complete on bus */
+9: mfspr r7,HID0 /* don't do icbi if icache is disabled */
+ rlwinm r7,r7,HID0_ICE_BITPOS+1,31,31
+ cmpwi r7,0
+ beq 7f
+ mr r4,r3
+6: icbi 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 6b
+7: sync /* Wait for all icbi to complete on bus */
+ isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+ addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+ mtlr r0
+ blr
+
+in_ram:
+
+ /*
+ * Relocation Function, r12 point to got2+0x8000
+ *
+ * Adjust got2 pointers, no need to check for 0, this code
+ * already puts a few entries in the table.
+ */
+ li r0,__got2_entries@sectoff@l
+ la r3,GOT(_GOT2_TABLE_)
+ lwz r11,GOT(_GOT2_TABLE_)
+ mtctr r0
+ sub r11,r3,r11
+ addi r3,r3,-4
+1: lwzu r0,4(r3)
+ cmpwi r0,0
+ beq- 2f
+ add r0,r0,r11
+ stw r0,0(r3)
+2: bdnz 1b
+
+ /*
+ * Now adjust the fixups and the pointers to the fixups
+ * in case we need to move ourselves again.
+ */
+ li r0,__fixup_entries@sectoff@l
+ lwz r3,GOT(_FIXUP_TABLE_)
+ cmpwi r0,0
+ mtctr r0
+ addi r3,r3,-4
+ beq 4f
+3: lwzu r4,4(r3)
+ lwzux r0,r4,r11
+ cmpwi r0,0
+ add r0,r0,r11
+ stw r4,0(r3)
+ beq- 5f
+ stw r0,0(r4)
+5: bdnz 3b
+4:
+clear_bss:
+ /*
+ * Now clear BSS segment
+ */
+ lwz r3,GOT(__bss_start)
+ lwz r4,GOT(__bss_end)
+
+ cmplw 0, r3, r4
+ beq 6f
+
+ li r0, 0
+5:
+ stw r0, 0(r3)
+ addi r3, r3, 4
+ cmplw 0, r3, r4
+ bne 5b
+6:
+
+ mr r3, r9 /* Global Data pointer */
+ mr r4, r10 /* Destination Address */
+ bl board_init_r
+
+ /*
+ * Copy exception vector code to low memory
+ *
+ * r3: dest_addr
+ * r7: source address, r8: end address, r9: target address
+ */
+ .globl trap_init
+trap_init:
+ mflr r4 /* save link register */
+ GET_GOT
+ lwz r7, GOT(_start)
+ lwz r8, GOT(_end_of_vectors)
+
+ li r9, 0x100 /* reset vector always at 0x100 */
+
+ cmplw 0, r7, r8
+ bgelr /* return if r7>=r8 - just in case */
+1:
+ lwz r0, 0(r7)
+ stw r0, 0(r9)
+ addi r7, r7, 4
+ addi r9, r9, 4
+ cmplw 0, r7, r8
+ bne 1b
+
+ /*
+ * relocate `hdlr' and `int_return' entries
+ */
+ li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+ li r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 2b
+
+ li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+ li r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 3b
+
+ li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+ li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 4b
+
+ mfmsr r3 /* now that the vectors have */
+ lis r7, MSR_IP@h /* relocated into low memory */
+ ori r7, r7, MSR_IP@l /* MSR[IP] can be turned off */
+ andc r3, r3, r7 /* (if it was on) */
+ SYNC /* Some chip revs need this... */
+ mtmsr r3
+ SYNC
+
+ mtlr r4 /* restore link register */
+ blr
+
+#endif /* CONFIG_SPL_BUILD */
diff --git a/arch/powerpc/cpu/mpc5xxx/traps.c b/arch/powerpc/cpu/mpc5xxx/traps.c
new file mode 100644
index 0000000..438f8d3
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/traps.c
@@ -0,0 +1,236 @@
+/*
+ * linux/arch/powerpc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ * fixed Machine Check Reasons by Reinhard Meyer (r.meyer@emk-elektronik.de)
+ *
+ * (C) Copyright 2000-2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM 0x02000000
+
+/*
+ * Trap & Exception support
+ */
+
+static void print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ printf("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ printf("\n");
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *)*sp;
+ }
+ printf("\n");
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ int i;
+
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+ regs->msr&MSR_IR ? 1 : 0,
+ regs->msr&MSR_DR ? 1 : 0);
+
+ printf("\n");
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0)
+ {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7)
+ {
+ printf("\n");
+ }
+ }
+}
+
+
+static void _exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup;
+
+ /* Probing PCI using config cycles cause this exception
+ * when a device is not present. Catch it and return to
+ * the PCI exception handler.
+ */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ return;
+ }
+
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ printf("Machine check in kernel mode.\n");
+ printf("Caused by (from msr): ");
+ printf("regs %p ",regs);
+ /* refer to 603e Manual (MPC603EUM/AD), chapter 4.5.2.1 */
+ switch( regs->msr & 0x000F0000)
+ {
+ case (0x80000000>>12) :
+ printf("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (0x80000000>>13) :
+ printf("Transfer error ack signal\n");
+ break;
+ case (0x80000000>>14) :
+ printf("Data parity signal\n");
+ break;
+ case (0x80000000>>15) :
+ printf("Address parity signal\n");
+ break;
+ default:
+ printf("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("machine check");
+}
+
+void AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void ProgramCheckException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void SoftEmuException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Software Emulation Exception");
+}
+
+
+void UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+void DebugException(struct pt_regs *regs)
+{
+
+ printf("Debugger trap at @ %lx\n", regs->nip );
+ show_regs(regs);
+#if defined(CONFIG_CMD_BEDBUG)
+ do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading. If not present, return -1, otherwise
+ * return 0.
+ */
+int addr_probe(uint *addr)
+{
+#if 0
+ int retval;
+
+ __asm__ __volatile__( \
+ "1: lwz %0,0(%1)\n" \
+ " eieio\n" \
+ " li %0,0\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,-1\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r" (retval) : "r"(addr));
+
+ return (retval);
+#endif
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc5xxx/u-boot-customlayout.lds b/arch/powerpc/cpu/mpc5xxx/u-boot-customlayout.lds
new file mode 100644
index 0000000..590952f
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/u-boot-customlayout.lds
@@ -0,0 +1,96 @@
+/*
+ * (C) Copyright 2003-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ .text :
+ {
+ /* WARNING - the following is hand-optimized to fit within */
+ /* the sector layout of our flash chips! XXX FIXME XXX */
+
+ arch/powerpc/cpu/mpc5xxx/start.o (.text*)
+ arch/powerpc/cpu/mpc5xxx/traps.o (.text*)
+
+ . = DEFINED(env_offset) ? env_offset : .;
+ common/env_embedded.o (.ppcenv*)
+
+ *(.text*)
+ . = ALIGN(16);
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ }
+
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x0FFF) & 0xFFFFF000;
+ _erotext = .;
+ PROVIDE (erotext = .);
+ .reloc :
+ {
+ KEEP(*(.got))
+ _GOT2_TABLE_ = .;
+ KEEP(*(.got2))
+ _FIXUP_TABLE_ = .;
+ KEEP(*(.fixup))
+ }
+ __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;
+ __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+ .data :
+ {
+ *(.data*)
+ *(.sdata*)
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+
+ . = .;
+
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+ . = .;
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ . = ALIGN(4096);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(4096);
+ __init_end = .;
+
+ __bss_start = .;
+ .bss (NOLOAD) :
+ {
+ *(.bss*)
+ *(.sbss*)
+ *(COMMON)
+ . = ALIGN(4);
+ }
+ __bss_end = . ;
+ PROVIDE (end = .);
+}
diff --git a/arch/powerpc/cpu/mpc5xxx/u-boot-spl.lds b/arch/powerpc/cpu/mpc5xxx/u-boot-spl.lds
new file mode 100644
index 0000000..0500739
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/u-boot-spl.lds
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012 Stefan Roese <sr@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+MEMORY
+{
+ sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR,
+ LENGTH = CONFIG_SPL_BSS_MAX_SIZE
+ flash : ORIGIN = CONFIG_SPL_TEXT_BASE,
+ LENGTH = CONFIG_SYS_SPL_MAX_LEN
+}
+
+OUTPUT_ARCH(powerpc)
+ENTRY(_start)
+SECTIONS
+{
+ .text :
+ {
+ __start = .;
+ arch/powerpc/cpu/mpc5xxx/start.o (.text)
+ *(.text*)
+ } > flash
+
+ . = ALIGN(4);
+ .data : { *(SORT_BY_ALIGNMENT(.data*)) } > flash
+
+ . = ALIGN(4);
+ .rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } > flash
+
+ . = ALIGN(4);
+ .end_align : { *(.end_align*) } > flash
+ __spl_flash_end = .;
+
+ .bss :
+ {
+ . = ALIGN(4);
+ __bss_start = .;
+ *(.bss*)
+ . = ALIGN(4);
+ __bss_end = .;
+ } > sdram
+}
diff --git a/arch/powerpc/cpu/mpc5xxx/u-boot.lds b/arch/powerpc/cpu/mpc5xxx/u-boot.lds
new file mode 100644
index 0000000..06ece78
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/u-boot.lds
@@ -0,0 +1,92 @@
+/*
+ * (C) Copyright 2003-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ .text :
+ {
+ arch/powerpc/cpu/mpc5xxx/start.o (.text*)
+ arch/powerpc/cpu/mpc5xxx/traps.o (.text*)
+ *(.text*)
+ . = ALIGN(16);
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ }
+
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x0FFF) & 0xFFFFF000;
+ _erotext = .;
+ PROVIDE (erotext = .);
+ .reloc :
+ {
+ _GOT2_TABLE_ = .;
+ KEEP(*(.got2))
+ KEEP(*(.got))
+ PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
+ _FIXUP_TABLE_ = .;
+ KEEP(*(.fixup))
+ }
+ __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
+ __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+ .data :
+ {
+ *(.data*)
+ *(.sdata*)
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+
+ . = .;
+
+ . = ALIGN(4);
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+
+ . = .;
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ . = ALIGN(4096);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(4096);
+ __init_end = .;
+
+ __bss_start = .;
+ .bss (NOLOAD) :
+ {
+ *(COMMON)
+ *(.bss*)
+ *(.sbss*)
+ . = ALIGN(4);
+ }
+ __bss_end = . ;
+ PROVIDE (end = .);
+}
diff --git a/arch/powerpc/cpu/mpc5xxx/usb.c b/arch/powerpc/cpu/mpc5xxx/usb.c
new file mode 100644
index 0000000..bec7da3
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/usb.c
@@ -0,0 +1,58 @@
+/*
+ * (C) Copyright 2007
+ * Markus Klotzbuecher, DENX Software Engineering <mk@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT)
+
+#include <mpc5xxx.h>
+
+int usb_cpu_init(void)
+{
+ /* Set the USB Clock */
+ *(vu_long *)MPC5XXX_CDM_48_FDC = CONFIG_USB_CLOCK;
+
+#ifdef CONFIG_PSC3_USB /* USB is using the alternate configuration */
+ /* remove all PSC3 USB bits first before ORing in ours */
+ *(vu_long *)MPC5XXX_GPS_PORT_CONFIG &= ~0x00804f00;
+#else
+ /* remove all USB bits first before ORing in ours */
+ *(vu_long *)MPC5XXX_GPS_PORT_CONFIG &= ~0x00807000;
+#endif
+ /* Activate USB port */
+ *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= CONFIG_USB_CONFIG;
+
+ return 0;
+}
+
+int usb_cpu_stop(void)
+{
+ return 0;
+}
+
+int usb_cpu_init_fail(void)
+{
+ return 0;
+}
+
+#endif /* defined(CONFIG_USB_OHCI) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT) */
diff --git a/arch/powerpc/cpu/mpc5xxx/usb_ohci.c b/arch/powerpc/cpu/mpc5xxx/usb_ohci.c
new file mode 100644
index 0000000..de07343
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/usb_ohci.c
@@ -0,0 +1,1644 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB on the MPC5200.
+ *
+ * (C) Copyright 2003-2004
+ * Gary Jennejohn, DENX Software Engineering <garyj@denx.de>
+ *
+ * (C) Copyright 2004
+ * Pierre Aubert, Staubli Faverges <p.aubert@staubli.com>
+ *
+ * Note: Much of this code has been derived from Linux 2.4
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+/*
+ * IMPORTANT NOTES
+ * 1 - this driver is intended for use with USB Mass Storage Devices
+ * (BBB) ONLY. There is NO support for Interrupt or Isochronous pipes!
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_USB_OHCI
+
+#include <malloc.h>
+#include <usb.h>
+#include "usb_ohci.h"
+
+#include <mpc5xxx.h>
+
+#define OHCI_USE_NPS /* force NoPowerSwitching mode */
+#undef OHCI_VERBOSE_DEBUG /* not always helpful */
+#undef DEBUG
+#undef SHOW_INFO
+#undef OHCI_FILL_TRACE
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define OHCI_CONTROL_INIT \
+ (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
+#define readl(a) (*((volatile u32 *)(a)))
+#define writel(a, b) (*((volatile u32 *)(b)) = ((volatile u32)a))
+
+#define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+
+#ifdef DEBUG
+#define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg)
+#else
+#define dbg(format, arg...) do {} while(0)
+#endif /* DEBUG */
+#define err(format, arg...) printf("ERROR: " format "\n", ## arg)
+#ifdef SHOW_INFO
+#define info(format, arg...) printf("INFO: " format "\n", ## arg)
+#else
+#define info(format, arg...) do {} while(0)
+#endif
+
+#define m16_swap(x) swap_16(x)
+#define m32_swap(x) swap_32(x)
+
+#define ohci_cpu_to_le16(x) (x)
+#define ohci_cpu_to_le32(x) (x)
+
+/* global ohci_t */
+static ohci_t gohci;
+/* this must be aligned to a 256 byte boundary */
+struct ohci_hcca ghcca[1];
+/* a pointer to the aligned storage */
+struct ohci_hcca *phcca;
+/* this allocates EDs for all possible endpoints */
+struct ohci_device ohci_dev;
+/* urb_priv */
+urb_priv_t urb_priv;
+/* RHSC flag */
+int got_rhsc;
+/* device which was disconnected */
+struct usb_device *devgone;
+/* flag guarding URB transation */
+int urb_finished = 0;
+
+/*-------------------------------------------------------------------------*/
+
+/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
+ * The erratum (#4) description is incorrect. AMD's workaround waits
+ * till some bits (mostly reserved) are clear; ok for all revs.
+ */
+#define OHCI_QUIRK_AMD756 0xabcd
+#define read_roothub(hc, register, mask) ({ \
+ u32 temp = readl (&hc->regs->roothub.register); \
+ if (hc->flags & OHCI_QUIRK_AMD756) \
+ while (temp & mask) \
+ temp = readl (&hc->regs->roothub.register); \
+ temp; })
+
+static u32 roothub_a (struct ohci *hc)
+ { return read_roothub (hc, a, 0xfc0fe000); }
+static inline u32 roothub_b (struct ohci *hc)
+ { return readl (&hc->regs->roothub.b); }
+static inline u32 roothub_status (struct ohci *hc)
+ { return readl (&hc->regs->roothub.status); }
+static u32 roothub_portstatus (struct ohci *hc, int i)
+ { return read_roothub (hc, portstatus [i], 0xffe0fce0); }
+
+
+/* forward declaration */
+static int hc_interrupt (void);
+static void
+td_submit_job (struct usb_device * dev, unsigned long pipe, void * buffer,
+ int transfer_len, struct devrequest * setup, urb_priv_t * urb, int interval);
+
+/*-------------------------------------------------------------------------*
+ * URB support functions
+ *-------------------------------------------------------------------------*/
+
+/* free HCD-private data associated with this URB */
+
+static void urb_free_priv (urb_priv_t * urb)
+{
+ int i;
+ int last;
+ struct td * td;
+
+ last = urb->length - 1;
+ if (last >= 0) {
+ for (i = 0; i <= last; i++) {
+ td = urb->td[i];
+ if (td) {
+ td->usb_dev = NULL;
+ urb->td[i] = NULL;
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+static int sohci_get_current_frame_number (struct usb_device * dev);
+
+/* debug| print the main components of an URB
+ * small: 0) header + data packets 1) just header */
+
+static void pkt_print (struct usb_device * dev, unsigned long pipe, void * buffer,
+ int transfer_len, struct devrequest * setup, char * str, int small)
+{
+ urb_priv_t * purb = &urb_priv;
+
+ dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d/%d stat:%#lx",
+ str,
+ sohci_get_current_frame_number (dev),
+ usb_pipedevice (pipe),
+ usb_pipeendpoint (pipe),
+ usb_pipeout (pipe)? 'O': 'I',
+ usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
+ (usb_pipecontrol (pipe)? "CTRL": "BULK"),
+ purb->actual_length,
+ transfer_len, dev->status);
+#ifdef OHCI_VERBOSE_DEBUG
+ if (!small) {
+ int i, len;
+
+ if (usb_pipecontrol (pipe)) {
+ printf (__FILE__ ": cmd(8):");
+ for (i = 0; i < 8 ; i++)
+ printf (" %02x", ((__u8 *) setup) [i]);
+ printf ("\n");
+ }
+ if (transfer_len > 0 && buffer) {
+ printf (__FILE__ ": data(%d/%d):",
+ purb->actual_length,
+ transfer_len);
+ len = usb_pipeout (pipe)?
+ transfer_len: purb->actual_length;
+ for (i = 0; i < 16 && i < len; i++)
+ printf (" %02x", ((__u8 *) buffer) [i]);
+ printf ("%s\n", i < len? "...": "");
+ }
+ }
+#endif
+}
+
+/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
+void ep_print_int_eds (ohci_t *ohci, char * str) {
+ int i, j;
+ __u32 * ed_p;
+ for (i= 0; i < 32; i++) {
+ j = 5;
+ ed_p = &(ohci->hcca->int_table [i]);
+ if (*ed_p == 0)
+ continue;
+ printf (__FILE__ ": %s branch int %2d(%2x):", str, i, i);
+ while (*ed_p != 0 && j--) {
+ ed_t *ed = (ed_t *)ohci_cpu_to_le32(ed_p);
+ printf (" ed: %4x;", ed->hwINFO);
+ ed_p = &ed->hwNextED;
+ }
+ printf ("\n");
+ }
+}
+
+static void ohci_dump_intr_mask (char *label, __u32 mask)
+{
+ dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+ label,
+ mask,
+ (mask & OHCI_INTR_MIE) ? " MIE" : "",
+ (mask & OHCI_INTR_OC) ? " OC" : "",
+ (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+ (mask & OHCI_INTR_FNO) ? " FNO" : "",
+ (mask & OHCI_INTR_UE) ? " UE" : "",
+ (mask & OHCI_INTR_RD) ? " RD" : "",
+ (mask & OHCI_INTR_SF) ? " SF" : "",
+ (mask & OHCI_INTR_WDH) ? " WDH" : "",
+ (mask & OHCI_INTR_SO) ? " SO" : ""
+ );
+}
+
+static void maybe_print_eds (char *label, __u32 value)
+{
+ ed_t *edp = (ed_t *)value;
+
+ if (value) {
+ dbg ("%s %08x", label, value);
+ dbg ("%08x", edp->hwINFO);
+ dbg ("%08x", edp->hwTailP);
+ dbg ("%08x", edp->hwHeadP);
+ dbg ("%08x", edp->hwNextED);
+ }
+}
+
+static char * hcfs2string (int state)
+{
+ switch (state) {
+ case OHCI_USB_RESET: return "reset";
+ case OHCI_USB_RESUME: return "resume";
+ case OHCI_USB_OPER: return "operational";
+ case OHCI_USB_SUSPEND: return "suspend";
+ }
+ return "?";
+}
+
+/* dump control and status registers */
+static void ohci_dump_status (ohci_t *controller)
+{
+ struct ohci_regs *regs = controller->regs;
+ __u32 temp;
+
+ temp = readl (&regs->revision) & 0xff;
+ if (temp != 0x10)
+ dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+ temp = readl (&regs->control);
+ dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+ (temp & OHCI_CTRL_RWE) ? " RWE" : "",
+ (temp & OHCI_CTRL_RWC) ? " RWC" : "",
+ (temp & OHCI_CTRL_IR) ? " IR" : "",
+ hcfs2string (temp & OHCI_CTRL_HCFS),
+ (temp & OHCI_CTRL_BLE) ? " BLE" : "",
+ (temp & OHCI_CTRL_CLE) ? " CLE" : "",
+ (temp & OHCI_CTRL_IE) ? " IE" : "",
+ (temp & OHCI_CTRL_PLE) ? " PLE" : "",
+ temp & OHCI_CTRL_CBSR
+ );
+
+ temp = readl (&regs->cmdstatus);
+ dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+ (temp & OHCI_SOC) >> 16,
+ (temp & OHCI_OCR) ? " OCR" : "",
+ (temp & OHCI_BLF) ? " BLF" : "",
+ (temp & OHCI_CLF) ? " CLF" : "",
+ (temp & OHCI_HCR) ? " HCR" : ""
+ );
+
+ ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
+ ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
+
+ maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
+
+ maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
+ maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
+
+ maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
+ maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+
+ maybe_print_eds ("donehead", readl (&regs->donehead));
+}
+
+static void ohci_dump_roothub (ohci_t *controller, int verbose)
+{
+ __u32 temp, ndp, i;
+
+ temp = roothub_a (controller);
+ ndp = (temp & RH_A_NDP);
+
+ if (verbose) {
+ dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+ ((temp & RH_A_POTPGT) >> 24) & 0xff,
+ (temp & RH_A_NOCP) ? " NOCP" : "",
+ (temp & RH_A_OCPM) ? " OCPM" : "",
+ (temp & RH_A_DT) ? " DT" : "",
+ (temp & RH_A_NPS) ? " NPS" : "",
+ (temp & RH_A_PSM) ? " PSM" : "",
+ ndp
+ );
+ temp = roothub_b (controller);
+ dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+ temp,
+ (temp & RH_B_PPCM) >> 16,
+ (temp & RH_B_DR)
+ );
+ temp = roothub_status (controller);
+ dbg ("roothub.status: %08x%s%s%s%s%s%s",
+ temp,
+ (temp & RH_HS_CRWE) ? " CRWE" : "",
+ (temp & RH_HS_OCIC) ? " OCIC" : "",
+ (temp & RH_HS_LPSC) ? " LPSC" : "",
+ (temp & RH_HS_DRWE) ? " DRWE" : "",
+ (temp & RH_HS_OCI) ? " OCI" : "",
+ (temp & RH_HS_LPS) ? " LPS" : ""
+ );
+ }
+
+ for (i = 0; i < ndp; i++) {
+ temp = roothub_portstatus (controller, i);
+ dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+ i,
+ temp,
+ (temp & RH_PS_PRSC) ? " PRSC" : "",
+ (temp & RH_PS_OCIC) ? " OCIC" : "",
+ (temp & RH_PS_PSSC) ? " PSSC" : "",
+ (temp & RH_PS_PESC) ? " PESC" : "",
+ (temp & RH_PS_CSC) ? " CSC" : "",
+
+ (temp & RH_PS_LSDA) ? " LSDA" : "",
+ (temp & RH_PS_PPS) ? " PPS" : "",
+ (temp & RH_PS_PRS) ? " PRS" : "",
+ (temp & RH_PS_POCI) ? " POCI" : "",
+ (temp & RH_PS_PSS) ? " PSS" : "",
+
+ (temp & RH_PS_PES) ? " PES" : "",
+ (temp & RH_PS_CCS) ? " CCS" : ""
+ );
+ }
+}
+
+static void ohci_dump (ohci_t *controller, int verbose)
+{
+ dbg ("OHCI controller usb-%s state", controller->slot_name);
+
+ /* dumps some of the state we know about */
+ ohci_dump_status (controller);
+ if (verbose)
+ ep_print_int_eds (controller, "hcca");
+ dbg ("hcca frame #%04x", controller->hcca->frame_no);
+ ohci_dump_roothub (controller, 1);
+}
+
+
+#endif /* DEBUG */
+
+/*-------------------------------------------------------------------------*
+ * Interface functions (URB)
+ *-------------------------------------------------------------------------*/
+
+/* get a transfer request */
+
+int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup, int interval)
+{
+ ohci_t *ohci;
+ ed_t * ed;
+ urb_priv_t *purb_priv;
+ int i, size = 0;
+
+ ohci = &gohci;
+
+ /* when controller's hung, permit only roothub cleanup attempts
+ * such as powering down ports */
+ if (ohci->disabled) {
+ err("sohci_submit_job: EPIPE");
+ return -1;
+ }
+
+ /* if we have an unfinished URB from previous transaction let's
+ * fail and scream as quickly as possible so as not to corrupt
+ * further communication */
+ if (!urb_finished) {
+ err("sohci_submit_job: URB NOT FINISHED");
+ return -1;
+ }
+ /* we're about to begin a new transaction here so mark the URB unfinished */
+ urb_finished = 0;
+
+ /* every endpoint has a ed, locate and fill it */
+ if (!(ed = ep_add_ed (dev, pipe))) {
+ err("sohci_submit_job: ENOMEM");
+ return -1;
+ }
+
+ /* for the private part of the URB we need the number of TDs (size) */
+ switch (usb_pipetype (pipe)) {
+ case PIPE_BULK: /* one TD for every 4096 Byte */
+ size = (transfer_len - 1) / 4096 + 1;
+ break;
+ case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
+ size = (transfer_len == 0)? 2:
+ (transfer_len - 1) / 4096 + 3;
+ break;
+ }
+
+ if (size >= (N_URB_TD - 1)) {
+ err("need %d TDs, only have %d", size, N_URB_TD);
+ return -1;
+ }
+ purb_priv = &urb_priv;
+ purb_priv->pipe = pipe;
+
+ /* fill the private part of the URB */
+ purb_priv->length = size;
+ purb_priv->ed = ed;
+ purb_priv->actual_length = 0;
+
+ /* allocate the TDs */
+ /* note that td[0] was allocated in ep_add_ed */
+ for (i = 0; i < size; i++) {
+ purb_priv->td[i] = td_alloc (dev);
+ if (!purb_priv->td[i]) {
+ purb_priv->length = i;
+ urb_free_priv (purb_priv);
+ err("sohci_submit_job: ENOMEM");
+ return -1;
+ }
+ }
+
+ if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
+ urb_free_priv (purb_priv);
+ err("sohci_submit_job: EINVAL");
+ return -1;
+ }
+
+ /* link the ed into a chain if is not already */
+ if (ed->state != ED_OPER)
+ ep_link (ohci, ed);
+
+ /* fill the TDs and link it to the ed */
+ td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv, interval);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+/* tell us the current USB frame number */
+
+static int sohci_get_current_frame_number (struct usb_device *usb_dev)
+{
+ ohci_t *ohci = &gohci;
+
+ return ohci_cpu_to_le16 (ohci->hcca->frame_no);
+}
+#endif
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/
+
+/* link an ed into one of the HC chains */
+
+static int ep_link (ohci_t *ohci, ed_t *edi)
+{
+ volatile ed_t *ed = edi;
+
+ ed->state = ED_OPER;
+
+ switch (ed->type) {
+ case PIPE_CONTROL:
+ ed->hwNextED = 0;
+ if (ohci->ed_controltail == NULL) {
+ writel (ed, &ohci->regs->ed_controlhead);
+ } else {
+ ohci->ed_controltail->hwNextED = ohci_cpu_to_le32 ((unsigned long)ed);
+ }
+ ed->ed_prev = ohci->ed_controltail;
+ if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
+ !ohci->ed_rm_list[1] && !ohci->sleeping) {
+ ohci->hc_control |= OHCI_CTRL_CLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ ohci->ed_controltail = edi;
+ break;
+
+ case PIPE_BULK:
+ ed->hwNextED = 0;
+ if (ohci->ed_bulktail == NULL) {
+ writel (ed, &ohci->regs->ed_bulkhead);
+ } else {
+ ohci->ed_bulktail->hwNextED = ohci_cpu_to_le32 ((unsigned long)ed);
+ }
+ ed->ed_prev = ohci->ed_bulktail;
+ if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
+ !ohci->ed_rm_list[1] && !ohci->sleeping) {
+ ohci->hc_control |= OHCI_CTRL_BLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ ohci->ed_bulktail = edi;
+ break;
+ }
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* unlink an ed from one of the HC chains.
+ * just the link to the ed is unlinked.
+ * the link from the ed still points to another operational ed or 0
+ * so the HC can eventually finish the processing of the unlinked ed */
+
+static int ep_unlink (ohci_t *ohci, ed_t *edi)
+{
+ volatile ed_t *ed = edi;
+
+ ed->hwINFO |= ohci_cpu_to_le32 (OHCI_ED_SKIP);
+
+ switch (ed->type) {
+ case PIPE_CONTROL:
+ if (ed->ed_prev == NULL) {
+ if (!ed->hwNextED) {
+ ohci->hc_control &= ~OHCI_CTRL_CLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ writel (ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_controlhead);
+ } else {
+ ed->ed_prev->hwNextED = ed->hwNextED;
+ }
+ if (ohci->ed_controltail == ed) {
+ ohci->ed_controltail = ed->ed_prev;
+ } else {
+ ((ed_t *)ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+ }
+ break;
+
+ case PIPE_BULK:
+ if (ed->ed_prev == NULL) {
+ if (!ed->hwNextED) {
+ ohci->hc_control &= ~OHCI_CTRL_BLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ writel (ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_bulkhead);
+ } else {
+ ed->ed_prev->hwNextED = ed->hwNextED;
+ }
+ if (ohci->ed_bulktail == ed) {
+ ohci->ed_bulktail = ed->ed_prev;
+ } else {
+ ((ed_t *)ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+ }
+ break;
+ }
+ ed->state = ED_UNLINK;
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
+ * but the USB stack is a little bit stateless so we do it at every transaction
+ * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK
+ * in all other cases the state is left unchanged
+ * the ed info fields are setted anyway even though most of them should not change */
+
+static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe)
+{
+ td_t *td;
+ ed_t *ed_ret;
+ volatile ed_t *ed;
+
+ ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) |
+ (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))];
+
+ if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
+ err("ep_add_ed: pending delete");
+ /* pending delete request */
+ return NULL;
+ }
+
+ if (ed->state == ED_NEW) {
+ ed->hwINFO = ohci_cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */
+ /* dummy td; end of td list for ed */
+ td = td_alloc (usb_dev);
+ ed->hwTailP = ohci_cpu_to_le32 ((unsigned long)td);
+ ed->hwHeadP = ed->hwTailP;
+ ed->state = ED_UNLINK;
+ ed->type = usb_pipetype (pipe);
+ ohci_dev.ed_cnt++;
+ }
+
+ ed->hwINFO = ohci_cpu_to_le32 (usb_pipedevice (pipe)
+ | usb_pipeendpoint (pipe) << 7
+ | (usb_pipeisoc (pipe)? 0x8000: 0)
+ | (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
+ | (usb_dev->speed == USB_SPEED_LOW) << 13
+ | usb_maxpacket (usb_dev, pipe) << 16);
+
+ return ed_ret;
+}
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
+
+static void td_fill (ohci_t *ohci, unsigned int info,
+ void *data, int len,
+ struct usb_device *dev, int index, urb_priv_t *urb_priv)
+{
+ volatile td_t *td, *td_pt;
+#ifdef OHCI_FILL_TRACE
+ int i;
+#endif
+
+ if (index > urb_priv->length) {
+ err("index > length");
+ return;
+ }
+ /* use this td as the next dummy */
+ td_pt = urb_priv->td [index];
+ td_pt->hwNextTD = 0;
+
+ /* fill the old dummy TD */
+ td = urb_priv->td [index] = (td_t *)(ohci_cpu_to_le32 (urb_priv->ed->hwTailP) & ~0xf);
+
+ td->ed = urb_priv->ed;
+ td->next_dl_td = NULL;
+ td->index = index;
+ td->data = (__u32)data;
+#ifdef OHCI_FILL_TRACE
+ if (usb_pipebulk(urb_priv->pipe) && usb_pipeout(urb_priv->pipe)) {
+ for (i = 0; i < len; i++)
+ printf("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]);
+ printf("\n");
+ }
+#endif
+ if (!len)
+ data = 0;
+
+ td->hwINFO = ohci_cpu_to_le32 (info);
+ td->hwCBP = ohci_cpu_to_le32 ((unsigned long)data);
+ if (data)
+ td->hwBE = ohci_cpu_to_le32 ((unsigned long)(data + len - 1));
+ else
+ td->hwBE = 0;
+ td->hwNextTD = ohci_cpu_to_le32 ((unsigned long)td_pt);
+
+ /* append to queue */
+ td->ed->hwTailP = td->hwNextTD;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* prepare all TDs of a transfer */
+static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval)
+{
+ ohci_t *ohci = &gohci;
+ int data_len = transfer_len;
+ void *data;
+ int cnt = 0;
+ __u32 info = 0;
+ unsigned int toggle = 0;
+
+ /* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
+ if(usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
+ toggle = TD_T_TOGGLE;
+ } else {
+ toggle = TD_T_DATA0;
+ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1);
+ }
+ urb->td_cnt = 0;
+ if (data_len)
+ data = buffer;
+ else
+ data = 0;
+
+ switch (usb_pipetype (pipe)) {
+ case PIPE_BULK:
+ info = usb_pipeout (pipe)?
+ TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
+ while(data_len > 4096) {
+ td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, dev, cnt, urb);
+ data += 4096; data_len -= 4096; cnt++;
+ }
+ info = usb_pipeout (pipe)?
+ TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+ td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, dev, cnt, urb);
+ cnt++;
+
+ if (!ohci->sleeping)
+ writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+ break;
+
+ case PIPE_CONTROL:
+ info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+ td_fill (ohci, info, setup, 8, dev, cnt++, urb);
+ if (data_len > 0) {
+ info = usb_pipeout (pipe)?
+ TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
+ /* NOTE: mishandles transfers >8K, some >4K */
+ td_fill (ohci, info, data, data_len, dev, cnt++, urb);
+ }
+ info = usb_pipeout (pipe)?
+ TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
+ td_fill (ohci, info, data, 0, dev, cnt++, urb);
+ if (!ohci->sleeping)
+ writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+ break;
+ }
+ if (urb->length != cnt)
+ dbg("TD LENGTH %d != CNT %d", urb->length, cnt);
+}
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+
+
+/* calculate the transfer length and update the urb */
+
+static void dl_transfer_length(td_t * td)
+{
+ __u32 tdBE, tdCBP;
+ urb_priv_t *lurb_priv = &urb_priv;
+
+ tdBE = ohci_cpu_to_le32 (td->hwBE);
+ tdCBP = ohci_cpu_to_le32 (td->hwCBP);
+
+
+ if (!(usb_pipecontrol(lurb_priv->pipe) &&
+ ((td->index == 0) || (td->index == lurb_priv->length - 1)))) {
+ if (tdBE != 0) {
+ if (td->hwCBP == 0)
+ lurb_priv->actual_length += tdBE - td->data + 1;
+ else
+ lurb_priv->actual_length += tdCBP - td->data;
+ }
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+
+static td_t * dl_reverse_done_list (ohci_t *ohci)
+{
+ __u32 td_list_hc;
+ td_t *td_rev = NULL;
+ td_t *td_list = NULL;
+ urb_priv_t *lurb_priv = NULL;
+
+ td_list_hc = ohci_cpu_to_le32 (ohci->hcca->done_head) & 0xfffffff0;
+ ohci->hcca->done_head = 0;
+
+ while (td_list_hc) {
+ td_list = (td_t *)td_list_hc;
+
+ if (TD_CC_GET (ohci_cpu_to_le32 (td_list->hwINFO))) {
+ lurb_priv = &urb_priv;
+ dbg(" USB-error/status: %x : %p",
+ TD_CC_GET (ohci_cpu_to_le32 (td_list->hwINFO)), td_list);
+ if (td_list->ed->hwHeadP & ohci_cpu_to_le32 (0x1)) {
+ if (lurb_priv && ((td_list->index + 1) < lurb_priv->length)) {
+ td_list->ed->hwHeadP =
+ (lurb_priv->td[lurb_priv->length - 1]->hwNextTD & ohci_cpu_to_le32 (0xfffffff0)) |
+ (td_list->ed->hwHeadP & ohci_cpu_to_le32 (0x2));
+ lurb_priv->td_cnt += lurb_priv->length - td_list->index - 1;
+ } else
+ td_list->ed->hwHeadP &= ohci_cpu_to_le32 (0xfffffff2);
+ }
+ td_list->hwNextTD = 0;
+ }
+
+ td_list->next_dl_td = td_rev;
+ td_rev = td_list;
+ td_list_hc = ohci_cpu_to_le32 (td_list->hwNextTD) & 0xfffffff0;
+ }
+ return td_list;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* td done list */
+static int dl_done_list (ohci_t *ohci, td_t *td_list)
+{
+ td_t *td_list_next = NULL;
+ ed_t *ed;
+ int cc = 0;
+ int stat = 0;
+ /* urb_t *urb; */
+ urb_priv_t *lurb_priv;
+ __u32 tdINFO, edHeadP, edTailP;
+
+ while (td_list) {
+ td_list_next = td_list->next_dl_td;
+
+ lurb_priv = &urb_priv;
+ tdINFO = ohci_cpu_to_le32 (td_list->hwINFO);
+
+ ed = td_list->ed;
+
+ dl_transfer_length(td_list);
+
+ /* error code of transfer */
+ cc = TD_CC_GET (tdINFO);
+ if (++(lurb_priv->td_cnt) == lurb_priv->length) {
+ if ((ed->state & (ED_OPER | ED_UNLINK))
+ && (lurb_priv->state != URB_DEL)) {
+ dbg("ConditionCode %#x", cc);
+ stat = cc_to_error[cc];
+ urb_finished = 1;
+ }
+ }
+
+ if (ed->state != ED_NEW) {
+ edHeadP = ohci_cpu_to_le32 (ed->hwHeadP) & 0xfffffff0;
+ edTailP = ohci_cpu_to_le32 (ed->hwTailP);
+
+ /* unlink eds if they are not busy */
+ if ((edHeadP == edTailP) && (ed->state == ED_OPER))
+ ep_unlink (ohci, ed);
+ }
+
+ td_list = td_list_next;
+ }
+ return stat;
+}
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub
+ *-------------------------------------------------------------------------*/
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] =
+{
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __u8 bDescriptorType; Device */
+ 0x10, /* __u16 bcdUSB; v1.1 */
+ 0x01,
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; */
+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
+ 0x00, /* __u16 idVendor; */
+ 0x00,
+ 0x00, /* __u16 idProduct; */
+ 0x00,
+ 0x00, /* __u16 bcdDevice; */
+ 0x00,
+ 0x00, /* __u8 iManufacturer; */
+ 0x01, /* __u8 iProduct; */
+ 0x00, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, /* __u16 wTotalLength; */
+ 0x00,
+ 0x01, /* __u8 bNumInterfaces; */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes;
+ Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* endpoint */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+ 0x00,
+ 0xff /* __u8 ep_bInterval; 255 ms */
+};
+
+static unsigned char root_hub_str_index0[] =
+{
+ 0x04, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 0x09, /* __u8 lang ID */
+ 0x04, /* __u8 lang ID */
+};
+
+static unsigned char root_hub_str_index1[] =
+{
+ 28, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 'O', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'C', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'I', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'R', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 't', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'u', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'b', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+};
+
+/* Hub class-specific descriptor is constructed dynamically */
+
+
+/*-------------------------------------------------------------------------*/
+
+#define OK(x) len = (x); break
+#ifdef DEBUG
+#define WR_RH_STAT(x) {info("WR:status %#8x", (x));writel((x), &gohci.regs->roothub.status);}
+#define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, (x));writel((x), &gohci.regs->roothub.portstatus[wIndex-1]);}
+#else
+#define WR_RH_STAT(x) writel((x), &gohci.regs->roothub.status)
+#define WR_RH_PORTSTAT(x) writel((x), &gohci.regs->roothub.portstatus[wIndex-1])
+#endif
+#define RD_RH_STAT roothub_status(&gohci)
+#define RD_RH_PORTSTAT roothub_portstatus(&gohci,wIndex-1)
+
+/* request to virtual root hub */
+
+int rh_check_port_status(ohci_t *controller)
+{
+ __u32 temp, ndp, i;
+ int res;
+
+ res = -1;
+ temp = roothub_a (controller);
+ ndp = (temp & RH_A_NDP);
+ for (i = 0; i < ndp; i++) {
+ temp = roothub_portstatus (controller, i);
+ /* check for a device disconnect */
+ if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
+ (RH_PS_PESC | RH_PS_CSC)) &&
+ ((temp & RH_PS_CCS) == 0)) {
+ res = i;
+ break;
+ }
+ }
+ return res;
+}
+
+static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len, struct devrequest *cmd)
+{
+ void * data = buffer;
+ int leni = transfer_len;
+ int len = 0;
+ int stat = 0;
+ __u32 datab[4];
+ __u8 *data_buf = (__u8 *)datab;
+ __u16 bmRType_bReq;
+ __u16 wValue;
+ __u16 wIndex;
+ __u16 wLength;
+
+#ifdef DEBUG
+urb_priv.actual_length = 0;
+pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));
+#endif
+ if (usb_pipeint(pipe)) {
+ info("Root-Hub submit IRQ: NOT implemented");
+ return 0;
+ }
+
+ bmRType_bReq = cmd->requesttype | (cmd->request << 8);
+ wValue = m16_swap (cmd->value);
+ wIndex = m16_swap (cmd->index);
+ wLength = m16_swap (cmd->length);
+
+ info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x",
+ dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
+
+ switch (bmRType_bReq) {
+ /* Request Destination:
+ without flags: Device,
+ RH_INTERFACE: interface,
+ RH_ENDPOINT: endpoint,
+ RH_CLASS means HUB here,
+ RH_OTHER | RH_CLASS almost ever means HUB_PORT here
+ */
+
+ case RH_GET_STATUS:
+ *(__u16 *) data_buf = m16_swap (1); OK (2);
+ case RH_GET_STATUS | RH_INTERFACE:
+ *(__u16 *) data_buf = m16_swap (0); OK (2);
+ case RH_GET_STATUS | RH_ENDPOINT:
+ *(__u16 *) data_buf = m16_swap (0); OK (2);
+ case RH_GET_STATUS | RH_CLASS:
+ *(__u32 *) data_buf = m32_swap (
+ RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
+ OK (4);
+ case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+ *(__u32 *) data_buf = m32_swap (RD_RH_PORTSTAT); OK (4);
+
+ case RH_CLEAR_FEATURE | RH_ENDPOINT:
+ switch (wValue) {
+ case (RH_ENDPOINT_STALL): OK (0);
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_CLASS:
+ switch (wValue) {
+ case RH_C_HUB_LOCAL_POWER:
+ OK(0);
+ case (RH_C_HUB_OVER_CURRENT):
+ WR_RH_STAT(RH_HS_OCIC); OK (0);
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case (RH_PORT_ENABLE):
+ WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
+ case (RH_PORT_SUSPEND):
+ WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
+ case (RH_PORT_POWER):
+ WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
+ case (RH_C_PORT_CONNECTION):
+ WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
+ case (RH_C_PORT_ENABLE):
+ WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
+ case (RH_C_PORT_SUSPEND):
+ WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
+ case (RH_C_PORT_OVER_CURRENT):
+ WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
+ case (RH_C_PORT_RESET):
+ WR_RH_PORTSTAT (RH_PS_PRSC); OK (0);
+ }
+ break;
+
+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case (RH_PORT_SUSPEND):
+ WR_RH_PORTSTAT (RH_PS_PSS ); OK (0);
+ case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT (RH_PS_PRS);
+ OK (0);
+ case (RH_PORT_POWER):
+ WR_RH_PORTSTAT (RH_PS_PPS ); OK (0);
+ case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT (RH_PS_PES );
+ OK (0);
+ }
+ break;
+
+ case RH_SET_ADDRESS: gohci.rh.devnum = wValue; OK(0);
+
+ case RH_GET_DESCRIPTOR:
+ switch ((wValue & 0xff00) >> 8) {
+ case (0x01): /* device descriptor */
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof (root_hub_dev_des),
+ wLength));
+ data_buf = root_hub_dev_des; OK(len);
+ case (0x02): /* configuration descriptor */
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof (root_hub_config_des),
+ wLength));
+ data_buf = root_hub_config_des; OK(len);
+ case (0x03): /* string descriptors */
+ if(wValue==0x0300) {
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof (root_hub_str_index0),
+ wLength));
+ data_buf = root_hub_str_index0;
+ OK(len);
+ }
+ if(wValue==0x0301) {
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof (root_hub_str_index1),
+ wLength));
+ data_buf = root_hub_str_index1;
+ OK(len);
+ }
+ default:
+ stat = USB_ST_STALLED;
+ }
+ break;
+
+ case RH_GET_DESCRIPTOR | RH_CLASS:
+ {
+ __u32 temp = roothub_a (&gohci);
+
+ data_buf [0] = 9; /* min length; */
+ data_buf [1] = 0x29;
+ data_buf [2] = temp & RH_A_NDP;
+ data_buf [3] = 0;
+ if (temp & RH_A_PSM) /* per-port power switching? */
+ data_buf [3] |= 0x1;
+ if (temp & RH_A_NOCP) /* no overcurrent reporting? */
+ data_buf [3] |= 0x10;
+ else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */
+ data_buf [3] |= 0x8;
+
+ /* corresponds to data_buf[4-7] */
+ datab [1] = 0;
+ data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+ temp = roothub_b (&gohci);
+ data_buf [7] = temp & RH_B_DR;
+ if (data_buf [2] < 7) {
+ data_buf [8] = 0xff;
+ } else {
+ data_buf [0] += 2;
+ data_buf [8] = (temp & RH_B_DR) >> 8;
+ data_buf [10] = data_buf [9] = 0xff;
+ }
+
+ len = min_t(unsigned int, leni,
+ min_t(unsigned int, data_buf [0], wLength));
+ OK (len);
+ }
+
+ case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1);
+
+ case RH_SET_CONFIGURATION: WR_RH_STAT (0x10000); OK (0);
+
+ default:
+ dbg ("unsupported root hub command");
+ stat = USB_ST_STALLED;
+ }
+
+#ifdef DEBUG
+ ohci_dump_roothub (&gohci, 1);
+#endif
+
+ len = min_t(int, len, leni);
+ if (data != data_buf)
+ memcpy (data, data_buf, len);
+ dev->act_len = len;
+ dev->status = stat;
+
+#ifdef DEBUG
+ if (transfer_len)
+ urb_priv.actual_length = transfer_len;
+ pkt_print(dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
+#endif
+
+ return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* common code for handling submit messages - used for all but root hub */
+/* accesses. */
+int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup, int interval)
+{
+ int stat = 0;
+ int maxsize = usb_maxpacket(dev, pipe);
+ int timeout;
+
+ /* device pulled? Shortcut the action. */
+ if (devgone == dev) {
+ dev->status = USB_ST_CRC_ERR;
+ return 0;
+ }
+
+#ifdef DEBUG
+ urb_priv.actual_length = 0;
+ pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+#endif
+ if (!maxsize) {
+ err("submit_common_message: pipesize for pipe %lx is zero",
+ pipe);
+ return -1;
+ }
+
+ if (sohci_submit_job(dev, pipe, buffer, transfer_len, setup, interval) < 0) {
+ err("sohci_submit_job failed");
+ return -1;
+ }
+
+ /* allow more time for a BULK device to react - some are slow */
+#define BULK_TO 5000 /* timeout in milliseconds */
+ if (usb_pipebulk(pipe))
+ timeout = BULK_TO;
+ else
+ timeout = 100;
+
+ /* wait for it to complete */
+ for (;;) {
+ /* check whether the controller is done */
+ stat = hc_interrupt();
+ if (stat < 0) {
+ stat = USB_ST_CRC_ERR;
+ break;
+ }
+
+ /* NOTE: since we are not interrupt driven in U-Boot and always
+ * handle only one URB at a time, we cannot assume the
+ * transaction finished on the first successful return from
+ * hc_interrupt().. unless the flag for current URB is set,
+ * meaning that all TD's to/from device got actually
+ * transferred and processed. If the current URB is not
+ * finished we need to re-iterate this loop so as
+ * hc_interrupt() gets called again as there needs to be some
+ * more TD's to process still */
+ if ((stat >= 0) && (stat != 0xff) && (urb_finished)) {
+ /* 0xff is returned for an SF-interrupt */
+ break;
+ }
+
+ if (--timeout) {
+ mdelay(1);
+ if (!urb_finished)
+ dbg("\%");
+
+ } else {
+ err("CTL:TIMEOUT ");
+ dbg("submit_common_msg: TO status %x\n", stat);
+ stat = USB_ST_CRC_ERR;
+ urb_finished = 1;
+ break;
+ }
+ }
+#if 0
+ /* we got an Root Hub Status Change interrupt */
+ if (got_rhsc) {
+#ifdef DEBUG
+ ohci_dump_roothub (&gohci, 1);
+#endif
+ got_rhsc = 0;
+ /* abuse timeout */
+ timeout = rh_check_port_status(&gohci);
+ if (timeout >= 0) {
+#if 0 /* this does nothing useful, but leave it here in case that changes */
+ /* the called routine adds 1 to the passed value */
+ usb_hub_port_connect_change(gohci.rh.dev, timeout - 1);
+#endif
+ /*
+ * XXX
+ * This is potentially dangerous because it assumes
+ * that only one device is ever plugged in!
+ */
+ devgone = dev;
+ }
+ }
+#endif
+
+ dev->status = stat;
+ dev->act_len = transfer_len;
+
+#ifdef DEBUG
+ pkt_print(dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe));
+#endif
+
+ /* free TDs in urb_priv */
+ urb_free_priv (&urb_priv);
+ return 0;
+}
+
+/* submit routines called from usb.c */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len)
+{
+ info("submit_bulk_msg");
+ return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0);
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup)
+{
+ int maxsize = usb_maxpacket(dev, pipe);
+
+ info("submit_control_msg");
+#ifdef DEBUG
+ urb_priv.actual_length = 0;
+ pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+#endif
+ if (!maxsize) {
+ err("submit_control_message: pipesize for pipe %lx is zero",
+ pipe);
+ return -1;
+ }
+ if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) {
+ gohci.rh.dev = dev;
+ /* root hub - redirect */
+ return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len,
+ setup);
+ }
+
+ return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, int interval)
+{
+ info("submit_int_msg");
+ return -1;
+}
+
+/*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+
+/* reset the HC and BUS */
+
+static int hc_reset (ohci_t *ohci)
+{
+ int timeout = 30;
+ int smm_timeout = 50; /* 0,5 sec */
+
+ if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
+ writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
+ info("USB HC TakeOver from SMM");
+ while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
+ mdelay (10);
+ if (--smm_timeout == 0) {
+ err("USB HC TakeOver failed!");
+ return -1;
+ }
+ }
+ }
+
+ /* Disable HC interrupts */
+ writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
+ dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;",
+ ohci->slot_name,
+ readl (&ohci->regs->control));
+
+ /* Reset USB (needed by some controllers) */
+ ohci->hc_control = 0;
+ writel (ohci->hc_control, &ohci->regs->control);
+
+ /* HC Reset requires max 10 us delay */
+ writel (OHCI_HCR, &ohci->regs->cmdstatus);
+ while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+ if (--timeout == 0) {
+ err("USB HC reset timed out!");
+ return -1;
+ }
+ udelay (1);
+ }
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Start an OHCI controller, set the BUS operational
+ * enable interrupts
+ * connect the virtual root hub */
+
+static int hc_start (ohci_t * ohci)
+{
+ __u32 mask;
+ unsigned int fminterval;
+
+ ohci->disabled = 1;
+
+ /* Tell the controller where the control and bulk lists are
+ * The lists are empty now. */
+
+ writel (0, &ohci->regs->ed_controlhead);
+ writel (0, &ohci->regs->ed_bulkhead);
+
+ writel ((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */
+
+ fminterval = 0x2edf;
+ writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
+ fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
+ writel (fminterval, &ohci->regs->fminterval);
+ writel (0x628, &ohci->regs->lsthresh);
+
+ /* start controller operations */
+ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ ohci->disabled = 0;
+ writel (ohci->hc_control, &ohci->regs->control);
+
+ /* disable all interrupts */
+ mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD |
+ OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC |
+ OHCI_INTR_OC | OHCI_INTR_MIE);
+ writel (mask, &ohci->regs->intrdisable);
+ /* clear all interrupts */
+ mask &= ~OHCI_INTR_MIE;
+ writel (mask, &ohci->regs->intrstatus);
+ /* Choose the interrupts we care about now - but w/o MIE */
+ mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
+ writel (mask, &ohci->regs->intrenable);
+
+#ifdef OHCI_USE_NPS
+ /* required for AMD-756 and some Mac platforms */
+ writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
+ &ohci->regs->roothub.a);
+ writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+#endif /* OHCI_USE_NPS */
+
+ /* POTPGT delay is bits 24-31, in 2 ms units. */
+ mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
+
+ /* connect the virtual root hub */
+ ohci->rh.devnum = 0;
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* an interrupt happens */
+
+static int
+hc_interrupt (void)
+{
+ ohci_t *ohci = &gohci;
+ struct ohci_regs *regs = ohci->regs;
+ int ints;
+ int stat = -1;
+
+ if ((ohci->hcca->done_head != 0) &&
+ !(ohci_cpu_to_le32(ohci->hcca->done_head) & 0x01)) {
+
+ ints = OHCI_INTR_WDH;
+
+ } else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+ ohci->disabled++;
+ err ("%s device removed!", ohci->slot_name);
+ return -1;
+
+ } else if ((ints &= readl (&regs->intrenable)) == 0) {
+ dbg("hc_interrupt: returning..\n");
+ return 0xff;
+ }
+
+ /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */
+
+ if (ints & OHCI_INTR_RHSC) {
+ got_rhsc = 1;
+ stat = 0xff;
+ }
+
+ if (ints & OHCI_INTR_UE) {
+ ohci->disabled++;
+ err ("OHCI Unrecoverable Error, controller usb-%s disabled",
+ ohci->slot_name);
+ /* e.g. due to PCI Master/Target Abort */
+
+#ifdef DEBUG
+ ohci_dump (ohci, 1);
+#endif
+ /* FIXME: be optimistic, hope that bug won't repeat often. */
+ /* Make some non-interrupt context restart the controller. */
+ /* Count and limit the retries though; either hardware or */
+ /* software errors can go forever... */
+ hc_reset (ohci);
+ return -1;
+ }
+
+ if (ints & OHCI_INTR_WDH) {
+ writel (OHCI_INTR_WDH, &regs->intrdisable);
+ stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci));
+ writel (OHCI_INTR_WDH, &regs->intrenable);
+ }
+
+ if (ints & OHCI_INTR_SO) {
+ dbg("USB Schedule overrun\n");
+ writel (OHCI_INTR_SO, &regs->intrenable);
+ stat = -1;
+ }
+
+ /* FIXME: this assumes SOF (1/ms) interrupts don't get lost... */
+ if (ints & OHCI_INTR_SF) {
+ unsigned int frame = ohci_cpu_to_le16 (ohci->hcca->frame_no) & 1;
+ mdelay(1);
+ writel (OHCI_INTR_SF, &regs->intrdisable);
+ if (ohci->ed_rm_list[frame] != NULL)
+ writel (OHCI_INTR_SF, &regs->intrenable);
+ stat = 0xff;
+ }
+
+ writel (ints, &regs->intrstatus);
+ return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+
+/* De-allocate all resources.. */
+
+static void hc_release_ohci (ohci_t *ohci)
+{
+ dbg ("USB HC release ohci usb-%s", ohci->slot_name);
+
+ if (!ohci->disabled)
+ hc_reset (ohci);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * low level initalisation routine, called from usb.c
+ */
+static char ohci_inited = 0;
+
+int usb_lowlevel_init(int index, void **controller)
+{
+
+ /* Set the USB Clock */
+ *(vu_long *)MPC5XXX_CDM_48_FDC = CONFIG_USB_CLOCK;
+
+#ifdef CONFIG_PSC3_USB /* USB is using the alternate configuration */
+ /* remove all PSC3 USB bits first before ORing in ours */
+ *(vu_long *)MPC5XXX_GPS_PORT_CONFIG &= ~0x00804f00;
+#else
+ /* remove all USB bits first before ORing in ours */
+ *(vu_long *)MPC5XXX_GPS_PORT_CONFIG &= ~0x00807000;
+#endif
+ /* Activate USB port */
+ *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= CONFIG_USB_CONFIG;
+
+ memset (&gohci, 0, sizeof (ohci_t));
+ memset (&urb_priv, 0, sizeof (urb_priv_t));
+
+ /* align the storage */
+ if ((__u32)&ghcca[0] & 0xff) {
+ err("HCCA not aligned!!");
+ return -1;
+ }
+ phcca = &ghcca[0];
+ info("aligned ghcca %p", phcca);
+ memset(&ohci_dev, 0, sizeof(struct ohci_device));
+ if ((__u32)&ohci_dev.ed[0] & 0x7) {
+ err("EDs not aligned!!");
+ return -1;
+ }
+ memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1));
+ if ((__u32)gtd & 0x7) {
+ err("TDs not aligned!!");
+ return -1;
+ }
+ ptd = gtd;
+ gohci.hcca = phcca;
+ memset (phcca, 0, sizeof (struct ohci_hcca));
+
+ gohci.disabled = 1;
+ gohci.sleeping = 0;
+ gohci.irq = -1;
+ gohci.regs = (struct ohci_regs *)MPC5XXX_USB;
+
+ gohci.flags = 0;
+ gohci.slot_name = "mpc5200";
+
+ if (hc_reset (&gohci) < 0) {
+ hc_release_ohci (&gohci);
+ return -1;
+ }
+
+ if (hc_start (&gohci) < 0) {
+ err ("can't start usb-%s", gohci.slot_name);
+ hc_release_ohci (&gohci);
+ return -1;
+ }
+
+#ifdef DEBUG
+ ohci_dump (&gohci, 1);
+#endif
+ ohci_inited = 1;
+ urb_finished = 1;
+
+ return 0;
+}
+
+int usb_lowlevel_stop(int index)
+{
+ /* this gets called really early - before the controller has */
+ /* even been initialized! */
+ if (!ohci_inited)
+ return 0;
+ /* TODO release any interrupts, etc. */
+ /* call hc_release_ohci() here ? */
+ hc_reset (&gohci);
+ return 0;
+}
+
+#endif /* CONFIG_USB_OHCI */
diff --git a/arch/powerpc/cpu/mpc5xxx/usb_ohci.h b/arch/powerpc/cpu/mpc5xxx/usb_ohci.h
new file mode 100644
index 0000000..629b529
--- /dev/null
+++ b/arch/powerpc/cpu/mpc5xxx/usb_ohci.h
@@ -0,0 +1,418 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * usb-ohci.h
+ */
+
+
+static int cc_to_error[16] = {
+
+/* mapping of the OHCI CC status to error codes */
+ /* No Error */ 0,
+ /* CRC Error */ USB_ST_CRC_ERR,
+ /* Bit Stuff */ USB_ST_BIT_ERR,
+ /* Data Togg */ USB_ST_CRC_ERR,
+ /* Stall */ USB_ST_STALLED,
+ /* DevNotResp */ -1,
+ /* PIDCheck */ USB_ST_BIT_ERR,
+ /* UnExpPID */ USB_ST_BIT_ERR,
+ /* DataOver */ USB_ST_BUF_ERR,
+ /* DataUnder */ USB_ST_BUF_ERR,
+ /* reservd */ -1,
+ /* reservd */ -1,
+ /* BufferOver */ USB_ST_BUF_ERR,
+ /* BuffUnder */ USB_ST_BUF_ERR,
+ /* Not Access */ -1,
+ /* Not Access */ -1
+};
+
+/* ED States */
+
+#define ED_NEW 0x00
+#define ED_UNLINK 0x01
+#define ED_OPER 0x02
+#define ED_DEL 0x04
+#define ED_URB_DEL 0x08
+
+/* usb_ohci_ed */
+struct ed {
+ __u32 hwINFO;
+ __u32 hwTailP;
+ __u32 hwHeadP;
+ __u32 hwNextED;
+
+ struct ed *ed_prev;
+ __u8 int_period;
+ __u8 int_branch;
+ __u8 int_load;
+ __u8 int_interval;
+ __u8 state;
+ __u8 type;
+ __u16 last_iso;
+ struct ed *ed_rm_list;
+
+ struct usb_device *usb_dev;
+ __u32 unused[3];
+} __attribute__((aligned(16)));
+typedef struct ed ed_t;
+
+
+/* TD info field */
+#define TD_CC 0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC 0x0C000000
+#define TD_T 0x03000000
+#define TD_T_DATA0 0x02000000
+#define TD_T_DATA1 0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R 0x00040000
+#define TD_DI 0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP 0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN 0x00100000
+#define TD_DP_OUT 0x00080000
+
+#define TD_ISO 0x00010000
+#define TD_DEL 0x00020000
+
+/* CC Codes */
+#define TD_CC_NOERROR 0x00
+#define TD_CC_CRC 0x01
+#define TD_CC_BITSTUFFING 0x02
+#define TD_CC_DATATOGGLEM 0x03
+#define TD_CC_STALL 0x04
+#define TD_DEVNOTRESP 0x05
+#define TD_PIDCHECKFAIL 0x06
+#define TD_UNEXPECTEDPID 0x07
+#define TD_DATAOVERRUN 0x08
+#define TD_DATAUNDERRUN 0x09
+#define TD_BUFFEROVERRUN 0x0C
+#define TD_BUFFERUNDERRUN 0x0D
+#define TD_NOTACCESSED 0x0F
+
+
+#define MAXPSW 1
+
+struct td {
+ __u32 hwINFO;
+ __u32 hwCBP; /* Current Buffer Pointer */
+ __u32 hwNextTD; /* Next TD Pointer */
+ __u32 hwBE; /* Memory Buffer End Pointer */
+
+ __u8 unused;
+ __u8 index;
+ struct ed *ed;
+ struct td *next_dl_td;
+ struct usb_device *usb_dev;
+ int transfer_len;
+ __u32 data;
+
+ __u32 unused2[2];
+} __attribute__((aligned(32)));
+typedef struct td td_t;
+
+#define OHCI_ED_SKIP (1 << 14)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of. It must be 256-byte aligned.
+ */
+
+#define NUM_INTS 32 /* part of the OHCI standard */
+struct ohci_hcca {
+ __u32 int_table[NUM_INTS]; /* Interrupt ED table */
+ __u16 pad1; /* set to 0 on each frame_no change */
+ __u16 frame_no; /* current frame number */
+ __u32 done_head; /* info returned for an interrupt */
+ u8 reserved_for_hc[116];
+} __attribute__((aligned(256)));
+
+
+/*
+ * Maximum number of root hub ports.
+ */
+#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region. This is Memory Mapped I/O. You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+ /* control and status registers */
+ __u32 revision;
+ __u32 control;
+ __u32 cmdstatus;
+ __u32 intrstatus;
+ __u32 intrenable;
+ __u32 intrdisable;
+ /* memory pointers */
+ __u32 hcca;
+ __u32 ed_periodcurrent;
+ __u32 ed_controlhead;
+ __u32 ed_controlcurrent;
+ __u32 ed_bulkhead;
+ __u32 ed_bulkcurrent;
+ __u32 donehead;
+ /* frame counters */
+ __u32 fminterval;
+ __u32 fmremaining;
+ __u32 fmnumber;
+ __u32 periodicstart;
+ __u32 lsthresh;
+ /* Root hub ports */
+ struct ohci_roothub_regs {
+ __u32 a;
+ __u32 b;
+ __u32 status;
+ __u32 portstatus[MAX_ROOT_PORTS];
+ } roothub;
+} __attribute__((aligned(32)));
+
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */
+#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */
+#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */
+#define OHCI_CTRL_CLE (1 << 4) /* control list enable */
+#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */
+#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */
+#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
+#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
+#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+# define OHCI_USB_RESET (0 << 6)
+# define OHCI_USB_RESUME (1 << 6)
+# define OHCI_USB_OPER (2 << 6)
+# define OHCI_USB_SUSPEND (3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR (1 << 0) /* host controller reset */
+#define OHCI_CLF (1 << 1) /* control list filled */
+#define OHCI_BLF (1 << 2) /* bulk list filled */
+#define OHCI_OCR (1 << 3) /* ownership change request */
+#define OHCI_SOC (3 << 16) /* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */
+#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */
+#define OHCI_INTR_SF (1 << 2) /* start frame */
+#define OHCI_INTR_RD (1 << 3) /* resume detect */
+#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */
+#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */
+#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */
+#define OHCI_INTR_OC (1 << 30) /* ownership change */
+#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */
+
+
+/* Virtual Root HUB */
+struct virt_root_hub {
+ int devnum; /* Address of Root Hub endpoint */
+ void *dev; /* was urb */
+ void *int_addr;
+ int send;
+ int interval;
+};
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
+
+/* destination of request */
+#define RH_INTERFACE 0x01
+#define RH_ENDPOINT 0x02
+#define RH_OTHER 0x03
+
+#define RH_CLASS 0x20
+#define RH_VENDOR 0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS 0x0080
+#define RH_CLEAR_FEATURE 0x0100
+#define RH_SET_FEATURE 0x0300
+#define RH_SET_ADDRESS 0x0500
+#define RH_GET_DESCRIPTOR 0x0680
+#define RH_SET_DESCRIPTOR 0x0700
+#define RH_GET_CONFIGURATION 0x0880
+#define RH_SET_CONFIGURATION 0x0900
+#define RH_GET_STATE 0x0280
+#define RH_GET_INTERFACE 0x0A80
+#define RH_SET_INTERFACE 0x0B00
+#define RH_SYNC_FRAME 0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP 0x2000
+
+
+/* Hub port features */
+#define RH_PORT_CONNECTION 0x00
+#define RH_PORT_ENABLE 0x01
+#define RH_PORT_SUSPEND 0x02
+#define RH_PORT_OVER_CURRENT 0x03
+#define RH_PORT_RESET 0x04
+#define RH_PORT_POWER 0x08
+#define RH_PORT_LOW_SPEED 0x09
+
+#define RH_C_PORT_CONNECTION 0x10
+#define RH_C_PORT_ENABLE 0x11
+#define RH_C_PORT_SUSPEND 0x12
+#define RH_C_PORT_OVER_CURRENT 0x13
+#define RH_C_PORT_RESET 0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER 0x00
+#define RH_C_HUB_OVER_CURRENT 0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP 0x00
+#define RH_ENDPOINT_STALL 0x01
+
+#define RH_ACK 0x01
+#define RH_REQ_ERR -1
+#define RH_NACK 0x00
+
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS 0x00000001 /* current connect status */
+#define RH_PS_PES 0x00000002 /* port enable status*/
+#define RH_PS_PSS 0x00000004 /* port suspend status */
+#define RH_PS_POCI 0x00000008 /* port over current indicator */
+#define RH_PS_PRS 0x00000010 /* port reset status */
+#define RH_PS_PPS 0x00000100 /* port power status */
+#define RH_PS_LSDA 0x00000200 /* low speed device attached */
+#define RH_PS_CSC 0x00010000 /* connect status change */
+#define RH_PS_PESC 0x00020000 /* port enable status change */
+#define RH_PS_PSSC 0x00040000 /* port suspend status change */
+#define RH_PS_OCIC 0x00080000 /* over current indicator change */
+#define RH_PS_PRSC 0x00100000 /* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS 0x00000001 /* local power status */
+#define RH_HS_OCI 0x00000002 /* over current indicator */
+#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
+#define RH_HS_LPSC 0x00010000 /* local power status change */
+#define RH_HS_OCIC 0x00020000 /* over current indicator change */
+#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR 0x0000ffff /* device removable flags */
+#define RH_B_PPCM 0xffff0000 /* port power control mask */
+
+/* roothub.a masks */
+#define RH_A_NDP (0xff << 0) /* number of downstream ports */
+#define RH_A_PSM (1 << 8) /* power switching mode */
+#define RH_A_NPS (1 << 9) /* no power switching */
+#define RH_A_DT (1 << 10) /* device type (mbz) */
+#define RH_A_OCPM (1 << 11) /* over current protection mode */
+#define RH_A_NOCP (1 << 12) /* no over current protection */
+#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
+
+/* urb */
+#define N_URB_TD 48
+typedef struct
+{
+ ed_t *ed;
+ __u16 length; /* number of tds associated with this request */
+ __u16 td_cnt; /* number of tds already serviced */
+ int state;
+ unsigned long pipe;
+ int actual_length;
+ td_t *td[N_URB_TD]; /* list pointer to all corresponding TDs associated with this request */
+} urb_priv_t;
+#define URB_DEL 1
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+
+typedef struct ohci {
+ struct ohci_hcca *hcca; /* hcca */
+ /*dma_addr_t hcca_dma;*/
+
+ int irq;
+ int disabled; /* e.g. got a UE, we're hung */
+ int sleeping;
+ unsigned long flags; /* for HC bugs */
+
+ struct ohci_regs *regs; /* OHCI controller's memory */
+
+ ed_t *ed_rm_list[2]; /* lists of all endpoints to be removed */
+ ed_t *ed_bulktail; /* last endpoint of bulk list */
+ ed_t *ed_controltail; /* last endpoint of control list */
+ int intrstatus;
+ __u32 hc_control; /* copy of the hc control reg */
+ struct usb_device *dev[32];
+ struct virt_root_hub rh;
+
+ const char *slot_name;
+} ohci_t;
+
+#define NUM_EDS 8 /* num of preallocated endpoint descriptors */
+
+struct ohci_device {
+ ed_t ed[NUM_EDS];
+ int ed_cnt;
+};
+
+/* hcd */
+/* endpoint */
+static int ep_link(ohci_t * ohci, ed_t * ed);
+static int ep_unlink(ohci_t * ohci, ed_t * ed);
+static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe);
+
+/*-------------------------------------------------------------------------*/
+
+/* we need more TDs than EDs */
+#define NUM_TD 64
+
+/* +1 so we can align the storage */
+td_t gtd[NUM_TD+1];
+/* pointers to aligned storage */
+td_t *ptd;
+
+/* TDs ... */
+static inline struct td *
+td_alloc (struct usb_device *usb_dev)
+{
+ int i;
+ struct td *td;
+
+ td = NULL;
+ for (i = 0; i < NUM_TD; i++)
+ {
+ if (ptd[i].usb_dev == NULL)
+ {
+ td = &ptd[i];
+ td->usb_dev = usb_dev;
+ break;
+ }
+ }
+
+ return td;
+}
+
+static inline void
+ed_free (struct ed *ed)
+{
+ ed->usb_dev = NULL;
+}
diff --git a/arch/powerpc/cpu/mpc824x/.gitignore b/arch/powerpc/cpu/mpc824x/.gitignore
new file mode 100644
index 0000000..2d79931
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/.gitignore
@@ -0,0 +1 @@
+/bedbug_603e.c
diff --git a/arch/powerpc/cpu/mpc824x/Makefile b/arch/powerpc/cpu/mpc824x/Makefile
new file mode 100644
index 0000000..ebf4cb2
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/Makefile
@@ -0,0 +1,55 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+ifneq ($(OBJTREE),$(SRCTREE))
+$(shell mkdir -p $(obj)drivers/epic $(obj)drivers/i2c)
+endif
+
+LIB = $(obj)lib$(CPU).o
+
+START = start.o
+COBJS = traps.o cpu.o cpu_init.o interrupts.o speed.o \
+ drivers/epic/epic1.o drivers/i2c/i2c.o pci.o
+COBJS_LN = bedbug_603e.o
+
+SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) $(addprefix $(obj),$(COBJS_LN:.o=.c))
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS) $(COBJS_LN))
+START := $(addprefix $(obj),$(START))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+$(obj)bedbug_603e.c:
+ ln -sf $(src)../mpc8260/bedbug_603e.c $(obj)bedbug_603e.c
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/powerpc/cpu/mpc824x/config.mk b/arch/powerpc/cpu/mpc824x/config.mk
new file mode 100644
index 0000000..82b8cc6
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/config.mk
@@ -0,0 +1,26 @@
+#
+# (C) Copyright 2000-2010
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_RELFLAGS += -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_MPC824X -ffixed-r2 -mstring -mcpu=603e -msoft-float
diff --git a/arch/powerpc/cpu/mpc824x/cpu.c b/arch/powerpc/cpu/mpc824x/cpu.c
new file mode 100644
index 0000000..44f91b2
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/cpu.c
@@ -0,0 +1,280 @@
+/*
+ * (C) Copyright 2000 - 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <mpc824x.h>
+#include <common.h>
+#include <command.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int checkcpu (void)
+{
+ unsigned int pvr = get_pvr ();
+ unsigned int version = pvr >> 16;
+ unsigned char revision;
+ ulong clock = gd->cpu_clk;
+ char buf[32];
+
+ puts ("CPU: ");
+
+ switch (version) {
+ case CPU_TYPE_8240:
+ puts ("MPC8240");
+ break;
+
+ case CPU_TYPE_8245:
+ puts ("MPC8245");
+ break;
+
+ default:
+ return -1; /*not valid for this source */
+ }
+
+ CONFIG_READ_BYTE (REVID, revision);
+
+ if (revision) {
+ printf (" Revision %d.%d",
+ (revision & 0xf0) >> 4,
+ (revision & 0x0f));
+ } else {
+ return -1; /* no valid CPU revision info */
+ }
+
+ printf (" at %s MHz:", strmhz (buf, clock));
+
+ printf (" %u kB I-Cache", checkicache () >> 10);
+ printf (" %u kB D-Cache", checkdcache () >> 10);
+
+ puts ("\n");
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+/* L1 i-cache */
+
+int checkicache (void)
+{
+ /*TODO*/
+ return 128 * 4 * 32;
+};
+
+/* ------------------------------------------------------------------------- */
+/* L1 d-cache */
+
+int checkdcache (void)
+{
+ /*TODO*/
+ return 128 * 4 * 32;
+
+};
+
+/*------------------------------------------------------------------- */
+
+int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong msr, addr;
+
+ /* Interrupts and MMU off */
+ __asm__ ("mtspr 81, 0");
+
+ /* Interrupts and MMU off */
+ __asm__ __volatile__ ("mfmsr %0":"=r" (msr):);
+
+ msr &= ~0x1030;
+ __asm__ __volatile__ ("mtmsr %0"::"r" (msr));
+
+ /*
+ * Trying to execute the next instruction at a non-existing address
+ * should cause a machine check, resulting in reset
+ */
+#ifdef CONFIG_SYS_RESET_ADDRESS
+ addr = CONFIG_SYS_RESET_ADDRESS;
+#else
+ /*
+ * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address,
+ * CONFIG_SYS_MONITOR_BASE - sizeof (ulong) is usually a valid
+ * address. Better pick an address known to be invalid on
+ * your system and assign it to CONFIG_SYS_RESET_ADDRESS.
+ * "(ulong)-1" used to be a good choice for many systems...
+ */
+ addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong);
+#endif
+ ((void (*)(void)) addr) ();
+ return 1;
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ * This is the sys_logic_clk (memory bus) divided by 4
+ */
+unsigned long get_tbclk (void)
+{
+ return ((get_bus_freq (0) + 2L) / 4L);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * The MPC824x has an integrated PCI controller known as the MPC107.
+ * The following are MPC107 Bridge Controller and PCI Support functions
+ *
+ */
+
+/*
+ * This procedure reads a 32-bit address MPC107 register, and returns
+ * a 32 bit value. It swaps the address to little endian before
+ * writing it to config address, and swaps the value to big endian
+ * before returning to the caller.
+ */
+unsigned int mpc824x_mpc107_getreg (unsigned int regNum)
+{
+ unsigned int temp;
+
+ /* swap the addr. to little endian */
+ *(volatile unsigned int *) CHRP_REG_ADDR = PCISWAP (regNum);
+ temp = *(volatile unsigned int *) CHRP_REG_DATA;
+ return PCISWAP (temp); /* swap the data upon return */
+}
+
+/*
+ * This procedure writes a 32-bit address MPC107 register. It swaps
+ * the address to little endian before writing it to config address.
+ */
+
+void mpc824x_mpc107_setreg (unsigned int regNum, unsigned int regVal)
+{
+ /* swap the addr. to little endian */
+ *(volatile unsigned int *) CHRP_REG_ADDR = PCISWAP (regNum);
+ *(volatile unsigned int *) CHRP_REG_DATA = PCISWAP (regVal);
+ return;
+}
+
+
+/*
+ * Write a byte (8 bits) to a memory location.
+ */
+void mpc824x_mpc107_write8 (unsigned int addr, unsigned char data)
+{
+ *(unsigned char *) addr = data;
+ __asm__ ("sync");
+}
+
+/*
+ * Write a word (16 bits) to a memory location after the value
+ * has been byte swapped (big to little endian or vice versa)
+ */
+
+void mpc824x_mpc107_write16 (unsigned int address, unsigned short data)
+{
+ *(volatile unsigned short *) address = BYTE_SWAP_16_BIT (data);
+ __asm__ ("sync");
+}
+
+/*
+ * Write a long word (32 bits) to a memory location after the value
+ * has been byte swapped (big to little endian or vice versa)
+ */
+
+void mpc824x_mpc107_write32 (unsigned int address, unsigned int data)
+{
+ *(volatile unsigned int *) address = LONGSWAP (data);
+ __asm__ ("sync");
+}
+
+/*
+ * Read a byte (8 bits) from a memory location.
+ */
+unsigned char mpc824x_mpc107_read8 (unsigned int addr)
+{
+ return *(volatile unsigned char *) addr;
+}
+
+
+/*
+ * Read a word (16 bits) from a memory location, and byte swap the
+ * value before returning to the caller.
+ */
+unsigned short mpc824x_mpc107_read16 (unsigned int address)
+{
+ unsigned short retVal;
+
+ retVal = BYTE_SWAP_16_BIT (*(unsigned short *) address);
+ return retVal;
+}
+
+
+/*
+ * Read a long word (32 bits) from a memory location, and byte
+ * swap the value before returning to the caller.
+ */
+unsigned int mpc824x_mpc107_read32 (unsigned int address)
+{
+ unsigned int retVal;
+
+ retVal = LONGSWAP (*(unsigned int *) address);
+ return (retVal);
+}
+
+
+/*
+ * Read a register in the Embedded Utilities Memory Block address
+ * space.
+ * Input: regNum - register number + utility base address. Example,
+ * the base address of EPIC is 0x40000, the register number
+ * being passed is 0x40000+the address of the target register.
+ * (See epic.h for register addresses).
+ * Output: The 32 bit little endian value of the register.
+ */
+
+unsigned int mpc824x_eummbar_read (unsigned int regNum)
+{
+ unsigned int temp;
+
+ temp = *(volatile unsigned int *) (EUMBBAR_VAL + regNum);
+ temp = PCISWAP (temp);
+ return temp;
+}
+
+
+/*
+ * Write a value to a register in the Embedded Utilities Memory
+ * Block address space.
+ * Input: regNum - register number + utility base address. Example,
+ * the base address of EPIC is 0x40000, the register
+ * number is 0x40000+the address of the target register.
+ * (See epic.h for register addresses).
+ * regVal - value to be written to the register.
+ */
+
+void mpc824x_eummbar_write (unsigned int regNum, unsigned int regVal)
+{
+ *(volatile unsigned int *) (EUMBBAR_VAL + regNum) = PCISWAP (regVal);
+ return;
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/arch/powerpc/cpu/mpc824x/cpu_init.c b/arch/powerpc/cpu/mpc824x/cpu_init.c
new file mode 100644
index 0000000..cfc665d
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/cpu_init.c
@@ -0,0 +1,417 @@
+/*
+ * (C) Copyright 2000
+ * Rob Taylor. Flying Pig Systems. robt@flyingpig.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <mpc824x.h>
+
+#ifndef CONFIG_SYS_BANK0_ROW
+#define CONFIG_SYS_BANK0_ROW 0
+#endif
+#ifndef CONFIG_SYS_BANK1_ROW
+#define CONFIG_SYS_BANK1_ROW 0
+#endif
+#ifndef CONFIG_SYS_BANK2_ROW
+#define CONFIG_SYS_BANK2_ROW 0
+#endif
+#ifndef CONFIG_SYS_BANK3_ROW
+#define CONFIG_SYS_BANK3_ROW 0
+#endif
+#ifndef CONFIG_SYS_BANK4_ROW
+#define CONFIG_SYS_BANK4_ROW 0
+#endif
+#ifndef CONFIG_SYS_BANK5_ROW
+#define CONFIG_SYS_BANK5_ROW 0
+#endif
+#ifndef CONFIG_SYS_BANK6_ROW
+#define CONFIG_SYS_BANK6_ROW 0
+#endif
+#ifndef CONFIG_SYS_BANK7_ROW
+#define CONFIG_SYS_BANK7_ROW 0
+#endif
+#ifndef CONFIG_SYS_DBUS_SIZE2
+#define CONFIG_SYS_DBUS_SIZE2 0
+#endif
+
+/*
+ * Breath some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers,
+ */
+void
+cpu_init_f (void)
+{
+/* MOUSSE board is initialized in asm */
+#if !defined(CONFIG_MOUSSE)
+ register unsigned long val;
+ CONFIG_WRITE_HALFWORD(PCICR, 0x06); /* Bus Master, respond to PCI memory space acesses*/
+/* CONFIG_WRITE_HALFWORD(PCISR, 0xffff); */ /*reset PCISR*/
+
+#if defined(CONFIG_MUSENKI) || defined(CONFIG_PN62)
+/* Why is this here, you ask? Try, just try setting 0x8000
+ * in PCIACR with CONFIG_WRITE_HALFWORD()
+ * this one was a stumper, and we are annoyed
+ */
+
+#define M_CONFIG_WRITE_HALFWORD( addr, data ) \
+ __asm__ __volatile__(" \
+ stw %2,0(%0)\n \
+ sync\n \
+ sth %3,2(%1)\n \
+ sync\n \
+ " \
+ : /* no output */ \
+ : "r" (CONFIG_ADDR), "r" (CONFIG_DATA), \
+ "r" (PCISWAP(addr & ~3)), "r" (PCISWAP(data << 16)) \
+ );
+
+ M_CONFIG_WRITE_HALFWORD(PCIACR, 0x8000);
+#endif
+
+ CONFIG_WRITE_BYTE(PCLSR, 0x8); /* set PCI cache line size */
+ CONFIG_WRITE_BYTE (PLTR, 0x40); /* set PCI latency timer */
+ /*
+ * Note that although this bit is cleared after a hard reset, it
+ * must be explicitly set and then cleared by software during
+ * initialization in order to guarantee correct operation of the
+ * DLL and the SDRAM_CLK[0:3] signals (if they are used).
+ */
+ CONFIG_READ_BYTE (AMBOR, val);
+ CONFIG_WRITE_BYTE(AMBOR, val & 0xDF);
+ CONFIG_WRITE_BYTE(AMBOR, val | 0x20);
+ CONFIG_WRITE_BYTE(AMBOR, val & 0xDF);
+#ifdef CONFIG_MPC8245
+ /* silicon bug 28 MPC8245 */
+ CONFIG_READ_BYTE(AMBOR,val);
+ CONFIG_WRITE_BYTE(AMBOR,val|0x1);
+
+#if 0
+ /*
+ * The following bug only affects older (XPC8245) processors.
+ * DMA transfers initiated by external devices get corrupted due
+ * to a hardware scheduling problem.
+ *
+ * The effect is:
+ * when transferring X words, the first 32 words are transferred
+ * OK, the next 3 x 32 words are 'old' data (from previous DMA)
+ * while the rest of the X words is xferred fine.
+ *
+ * Disabling 3 of the 4 32 word hardware buffers solves the problem
+ * with no significant performance loss.
+ */
+
+ CONFIG_READ_BYTE(PCMBCR,val);
+ /* in order not to corrupt data which is being read over the PCI bus
+ * with the PPC as slave, we need to reduce the number of PCMRBs to 1,
+ * 4.11 in the processor user manual
+ * */
+
+#if 1
+ CONFIG_WRITE_BYTE(PCMBCR,(val|0xC0)); /* 1 PCMRB */
+#else
+ CONFIG_WRITE_BYTE(PCMBCR,(val|0x80)); /* 2 PCMRBs */
+ CONFIG_WRITE_BYTE(PCMBCR,(val|0x40)); /* 3 PCMRBs */
+ /* default, 4 PCMRBs are used */
+#endif
+#endif
+#endif
+
+ CONFIG_READ_WORD(PICR1, val);
+#if defined(CONFIG_MPC8240)
+ CONFIG_WRITE_WORD( PICR1,
+ (val & (PICR1_ADDRESS_MAP | PICR1_RCS0)) |
+ PIRC1_MSK | PICR1_PROC_TYPE_603E |
+ PICR1_FLASH_WR_EN | PICR1_MCP_EN |
+ PICR1_CF_DPARK | PICR1_EN_PCS |
+ PICR1_CF_APARK );
+#elif defined(CONFIG_MPC8245)
+ CONFIG_WRITE_WORD( PICR1,
+ (val & (PICR1_RCS0)) |
+ PICR1_PROC_TYPE_603E |
+ PICR1_FLASH_WR_EN | PICR1_MCP_EN |
+ PICR1_CF_DPARK | PICR1_NO_BUSW_CK |
+ PICR1_DEC| PICR1_CF_APARK | 0x10); /* 8245 UM says bit 4 must be set */
+#else
+#error Specific type of MPC824x must be defined (i.e. CONFIG_MPC8240)
+#endif
+
+ CONFIG_READ_WORD(PICR2, val);
+ val= val & ~ (PICR2_CF_SNOOP_WS_MASK | PICR2_CF_APHASE_WS_MASK); /*mask off waitstate bits*/
+#ifndef CONFIG_PN62
+ val |= PICR2_CF_SNOOP_WS_1WS | PICR2_CF_APHASE_WS_1WS; /*1 wait state*/
+#endif
+ CONFIG_WRITE_WORD(PICR2, val);
+
+ CONFIG_WRITE_WORD(EUMBBAR, CONFIG_SYS_EUMB_ADDR);
+#ifndef CONFIG_SYS_RAMBOOT
+ CONFIG_WRITE_WORD(MCCR1, (CONFIG_SYS_ROMNAL << MCCR1_ROMNAL_SHIFT) |
+ (CONFIG_SYS_BANK0_ROW) |
+ (CONFIG_SYS_BANK1_ROW << MCCR1_BANK1ROW_SHIFT) |
+ (CONFIG_SYS_BANK2_ROW << MCCR1_BANK2ROW_SHIFT) |
+ (CONFIG_SYS_BANK3_ROW << MCCR1_BANK3ROW_SHIFT) |
+ (CONFIG_SYS_BANK4_ROW << MCCR1_BANK4ROW_SHIFT) |
+ (CONFIG_SYS_BANK5_ROW << MCCR1_BANK5ROW_SHIFT) |
+ (CONFIG_SYS_BANK6_ROW << MCCR1_BANK6ROW_SHIFT) |
+ (CONFIG_SYS_BANK7_ROW << MCCR1_BANK7ROW_SHIFT) |
+ (CONFIG_SYS_ROMFAL << MCCR1_ROMFAL_SHIFT));
+#endif
+
+#if defined(CONFIG_SYS_ASRISE) && defined(CONFIG_SYS_ASFALL)
+ CONFIG_WRITE_WORD(MCCR2, CONFIG_SYS_REFINT << MCCR2_REFINT_SHIFT |
+ CONFIG_SYS_ASRISE << MCCR2_ASRISE_SHIFT |
+ CONFIG_SYS_ASFALL << MCCR2_ASFALL_SHIFT);
+#else
+ CONFIG_WRITE_WORD(MCCR2, CONFIG_SYS_REFINT << MCCR2_REFINT_SHIFT);
+#endif
+
+#if defined(CONFIG_MPC8240)
+ CONFIG_WRITE_WORD(MCCR3,
+ (((CONFIG_SYS_BSTOPRE & 0x003c) >> 2) << MCCR3_BSTOPRE2TO5_SHIFT) |
+ (CONFIG_SYS_REFREC << MCCR3_REFREC_SHIFT) |
+ (CONFIG_SYS_RDLAT << MCCR3_RDLAT_SHIFT));
+#elif defined(CONFIG_MPC8245)
+ CONFIG_WRITE_WORD(MCCR3,
+ (((CONFIG_SYS_BSTOPRE & 0x003c) >> 2) << MCCR3_BSTOPRE2TO5_SHIFT) |
+ (CONFIG_SYS_REFREC << MCCR3_REFREC_SHIFT));
+#else
+#error Specific type of MPC824x must be defined (i.e. CONFIG_MPC8240)
+#endif
+
+/* this is gross. We think these should all be the same, and various boards
+ * should define CONFIG_SYS_ACTORW to 0 if they don't want to set it, or even, if
+ * its not set, we define it to zero in this file
+ */
+#if defined(CONFIG_CU824) || defined(CONFIG_PN62)
+ CONFIG_WRITE_WORD(MCCR4,
+ (CONFIG_SYS_PRETOACT << MCCR4_PRETOACT_SHIFT) |
+ (CONFIG_SYS_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) |
+ MCCR4_BIT21 |
+ (CONFIG_SYS_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) |
+ ((CONFIG_SYS_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) |
+ (((CONFIG_SYS_SDMODE_CAS_LAT <<4) | (CONFIG_SYS_SDMODE_WRAP <<3) |
+ CONFIG_SYS_SDMODE_BURSTLEN) << MCCR4_SDMODE_SHIFT) |
+ (CONFIG_SYS_ACTORW << MCCR4_ACTTORW_SHIFT) |
+ (((CONFIG_SYS_BSTOPRE & 0x03c0) >> 6) << MCCR4_BSTOPRE6TO9_SHIFT));
+#elif defined(CONFIG_MPC8240)
+ CONFIG_WRITE_WORD(MCCR4,
+ (CONFIG_SYS_PRETOACT << MCCR4_PRETOACT_SHIFT) |
+ (CONFIG_SYS_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) |
+ MCCR4_BIT21 |
+ (CONFIG_SYS_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) |
+ ((CONFIG_SYS_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) |
+ (((CONFIG_SYS_SDMODE_CAS_LAT <<4) | (CONFIG_SYS_SDMODE_WRAP <<3) |
+ (CONFIG_SYS_SDMODE_BURSTLEN)) <<MCCR4_SDMODE_SHIFT) |
+ (((CONFIG_SYS_BSTOPRE & 0x03c0) >> 6) <<MCCR4_BSTOPRE6TO9_SHIFT ));
+#elif defined(CONFIG_MPC8245)
+ CONFIG_READ_WORD(MCCR1, val);
+ val &= MCCR1_DBUS_SIZE0; /* test for 64-bit mem bus */
+
+ CONFIG_WRITE_WORD(MCCR4,
+ (CONFIG_SYS_PRETOACT << MCCR4_PRETOACT_SHIFT) |
+ (CONFIG_SYS_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) |
+ (CONFIG_SYS_EXTROM ? MCCR4_EXTROM : 0) |
+ (CONFIG_SYS_REGDIMM ? MCCR4_REGDIMM : 0) |
+ (CONFIG_SYS_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) |
+ ((CONFIG_SYS_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) |
+ (CONFIG_SYS_DBUS_SIZE2 << MCCR4_DBUS_SIZE2_SHIFT) |
+ (((CONFIG_SYS_SDMODE_CAS_LAT <<4) | (CONFIG_SYS_SDMODE_WRAP <<3) |
+ (val ? 2 : 3)) << MCCR4_SDMODE_SHIFT) |
+ (CONFIG_SYS_ACTORW << MCCR4_ACTTORW_SHIFT) |
+ (((CONFIG_SYS_BSTOPRE & 0x03c0) >> 6) <<MCCR4_BSTOPRE6TO9_SHIFT ));
+#else
+#error Specific type of MPC824x must be defined (i.e. CONFIG_MPC8240)
+#endif
+
+ CONFIG_WRITE_WORD(MSAR1,
+ ( (CONFIG_SYS_BANK0_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
+ (((CONFIG_SYS_BANK1_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
+ (((CONFIG_SYS_BANK2_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
+ (((CONFIG_SYS_BANK3_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
+ CONFIG_WRITE_WORD(EMSAR1,
+ ( (CONFIG_SYS_BANK0_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
+ (((CONFIG_SYS_BANK1_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
+ (((CONFIG_SYS_BANK2_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
+ (((CONFIG_SYS_BANK3_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
+ CONFIG_WRITE_WORD(MSAR2,
+ ( (CONFIG_SYS_BANK4_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
+ (((CONFIG_SYS_BANK5_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
+ (((CONFIG_SYS_BANK6_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
+ (((CONFIG_SYS_BANK7_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
+ CONFIG_WRITE_WORD(EMSAR2,
+ ( (CONFIG_SYS_BANK4_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
+ (((CONFIG_SYS_BANK5_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
+ (((CONFIG_SYS_BANK6_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
+ (((CONFIG_SYS_BANK7_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
+ CONFIG_WRITE_WORD(MEAR1,
+ ( (CONFIG_SYS_BANK0_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
+ (((CONFIG_SYS_BANK1_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
+ (((CONFIG_SYS_BANK2_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
+ (((CONFIG_SYS_BANK3_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
+ CONFIG_WRITE_WORD(EMEAR1,
+ ( (CONFIG_SYS_BANK0_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
+ (((CONFIG_SYS_BANK1_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
+ (((CONFIG_SYS_BANK2_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
+ (((CONFIG_SYS_BANK3_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
+ CONFIG_WRITE_WORD(MEAR2,
+ ( (CONFIG_SYS_BANK4_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
+ (((CONFIG_SYS_BANK5_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
+ (((CONFIG_SYS_BANK6_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
+ (((CONFIG_SYS_BANK7_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
+ CONFIG_WRITE_WORD(EMEAR2,
+ ( (CONFIG_SYS_BANK4_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
+ (((CONFIG_SYS_BANK5_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
+ (((CONFIG_SYS_BANK6_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
+ (((CONFIG_SYS_BANK7_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
+
+ CONFIG_WRITE_BYTE(ODCR, CONFIG_SYS_ODCR);
+#ifdef CONFIG_SYS_DLL_MAX_DELAY
+ CONFIG_WRITE_BYTE(MIOCR1, CONFIG_SYS_DLL_MAX_DELAY); /* needed to make DLL lock */
+#endif
+#if defined(CONFIG_SYS_DLL_EXTEND) && defined(CONFIG_SYS_PCI_HOLD_DEL)
+ CONFIG_WRITE_BYTE(PMCR2, CONFIG_SYS_DLL_EXTEND | CONFIG_SYS_PCI_HOLD_DEL);
+#endif
+#if defined(MIOCR2) && defined(CONFIG_SYS_SDRAM_DSCD)
+ CONFIG_WRITE_BYTE(MIOCR2, CONFIG_SYS_SDRAM_DSCD); /* change memory input */
+#endif /* setup & hold time */
+
+ CONFIG_WRITE_BYTE(MBER,
+ CONFIG_SYS_BANK0_ENABLE |
+ (CONFIG_SYS_BANK1_ENABLE << 1) |
+ (CONFIG_SYS_BANK2_ENABLE << 2) |
+ (CONFIG_SYS_BANK3_ENABLE << 3) |
+ (CONFIG_SYS_BANK4_ENABLE << 4) |
+ (CONFIG_SYS_BANK5_ENABLE << 5) |
+ (CONFIG_SYS_BANK6_ENABLE << 6) |
+ (CONFIG_SYS_BANK7_ENABLE << 7));
+
+#ifdef CONFIG_SYS_PGMAX
+ CONFIG_WRITE_BYTE(MPMR, CONFIG_SYS_PGMAX);
+#endif
+
+ /* ! Wait 200us before initialize other registers */
+ /*FIXME: write a decent udelay wait */
+ __asm__ __volatile__(
+ " mtctr %0 \n \
+ 0: bdnz 0b\n"
+ :
+ : "r" (0x10000));
+
+ CONFIG_READ_WORD(MCCR1, val);
+ CONFIG_WRITE_WORD(MCCR1, val | MCCR1_MEMGO); /* set memory access going */
+ __asm__ __volatile__("eieio");
+
+#endif /* !CONFIG_MOUSSE */
+}
+
+
+#ifdef CONFIG_MOUSSE
+#ifdef INCLUDE_MPC107_REPORT
+struct MPC107_s {
+ unsigned int iobase;
+ char desc[120];
+} MPC107Regs[] = {
+ { BMC_BASE + 0x00, "MPC107 Vendor/Device ID" },
+ { BMC_BASE + 0x04, "MPC107 PCI Command/Status Register" },
+ { BMC_BASE + 0x08, "MPC107 Revision" },
+ { BMC_BASE + 0x0C, "MPC107 Cache Line Size" },
+ { BMC_BASE + 0x10, "MPC107 LMBAR" },
+ { BMC_BASE + 0x14, "MPC824x PCSR" },
+ { BMC_BASE + 0xA8, "MPC824x PICR1" },
+ { BMC_BASE + 0xAC, "MPC824x PICR2" },
+ { BMC_BASE + 0x46, "MPC824x PACR" },
+ { BMC_BASE + 0x310, "MPC824x ITWR" },
+ { BMC_BASE + 0x300, "MPC824x OMBAR" },
+ { BMC_BASE + 0x308, "MPC824x OTWR" },
+ { BMC_BASE + 0x14, "MPC107 Peripheral Control and Status Register" },
+ { BMC_BASE + 0x78, "MPC107 EUMBAR" },
+ { BMC_BASE + 0xC0, "MPC107 Processor Bus Error Status" },
+ { BMC_BASE + 0xC4, "MPC107 PCI Bus Error Status" },
+ { BMC_BASE + 0xC8, "MPC107 Processor/PCI Error Address" },
+ { BMC_BASE + 0xE0, "MPC107 AMBOR Register" },
+ { BMC_BASE + 0xF0, "MPC107 MCCR1 Register" },
+ { BMC_BASE + 0xF4, "MPC107 MCCR2 Register" },
+ { BMC_BASE + 0xF8, "MPC107 MCCR3 Register" },
+ { BMC_BASE + 0xFC, "MPC107 MCCR4 Register" },
+};
+#define N_MPC107_Regs (sizeof(MPC107Regs)/sizeof(MPC107Regs[0]))
+#endif /* INCLUDE_MPC107_REPORT */
+#endif /* CONFIG_MOUSSE */
+
+/*
+ * initialize higher level parts of CPU like time base and timers
+ */
+int cpu_init_r (void)
+{
+#ifdef CONFIG_MOUSSE
+#ifdef INCLUDE_MPC107_REPORT
+ unsigned int tmp = 0, i;
+#endif
+ /*
+ * Initialize the EUMBBAR (Embedded Util Mem Block Base Addr Reg).
+ * This is necessary before the EPIC, DMA ctlr, I2C ctlr, etc. can
+ * be accessed.
+ */
+
+#ifdef CONFIG_MPC8240 /* only on MPC8240 */
+ mpc824x_mpc107_setreg (EUMBBAR, EUMBBAR_VAL);
+ /* MOT/SPS: Issue #10002, PCI (FD Alias enable) */
+ mpc824x_mpc107_setreg (AMBOR, 0x000000C0);
+#endif
+
+
+#ifdef INCLUDE_MPC107_REPORT
+ /* Check MPC824x PCI Device and Vendor ID */
+ while ((tmp = mpc824x_mpc107_getreg (BMC_BASE)) != 0x31057) {
+ printf (" MPC107: offset=0x%x, val = 0x%x\n",
+ BMC_BASE,
+ tmp);
+ }
+
+ for (i = 0; i < N_MPC107_Regs; i++) {
+ printf (" 0x%x/%s = 0x%x\n",
+ MPC107Regs[i].iobase,
+ MPC107Regs[i].desc,
+ mpc824x_mpc107_getreg (MPC107Regs[i].iobase));
+ }
+
+ printf ("IBAT0L = 0x%08X\n", mfspr (IBAT0L));
+ printf ("IBAT0U = 0x%08X\n", mfspr (IBAT0U));
+ printf ("IBAT1L = 0x%08X\n", mfspr (IBAT1L));
+ printf ("IBAT1U = 0x%08X\n", mfspr (IBAT1U));
+ printf ("IBAT2L = 0x%08X\n", mfspr (IBAT2L));
+ printf ("IBAT2U = 0x%08X\n", mfspr (IBAT2U));
+ printf ("IBAT3L = 0x%08X\n", mfspr (IBAT3L));
+ printf ("IBAT3U = 0x%08X\n", mfspr (IBAT3U));
+ printf ("DBAT0L = 0x%08X\n", mfspr (DBAT0L));
+ printf ("DBAT0U = 0x%08X\n", mfspr (DBAT0U));
+ printf ("DBAT1L = 0x%08X\n", mfspr (DBAT1L));
+ printf ("DBAT1U = 0x%08X\n", mfspr (DBAT1U));
+ printf ("DBAT2L = 0x%08X\n", mfspr (DBAT2L));
+ printf ("DBAT2U = 0x%08X\n", mfspr (DBAT2U));
+ printf ("DBAT3L = 0x%08X\n", mfspr (DBAT3L));
+ printf ("DBAT3U = 0x%08X\n", mfspr (DBAT3U));
+#endif /* INCLUDE_MPC107_REPORT */
+#endif /* CONFIG_MOUSSE */
+ return (0);
+}
diff --git a/arch/powerpc/cpu/mpc824x/drivers/epic.h b/arch/powerpc/cpu/mpc824x/drivers/epic.h
new file mode 100644
index 0000000..2803f63
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/drivers/epic.h
@@ -0,0 +1 @@
+#include "epic/epic.h"
diff --git a/arch/powerpc/cpu/mpc824x/drivers/epic/README b/arch/powerpc/cpu/mpc824x/drivers/epic/README
new file mode 100644
index 0000000..5798996
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/drivers/epic/README
@@ -0,0 +1,102 @@
+CONTENT:
+
+ epic.h
+ epic1.c
+ epic2.s
+
+WHAT ARE THESE FILES:
+
+These files contain MPC8240 (Kahlua) EPIC
+driver routines. The driver routines are not
+written for any specific operating system.
+They serves the purpose of code sample, and
+jump-start for using the MPC8240 EPIC unit.
+
+For the reason of correctness of C language
+syntax, these files are compiled by Metaware
+C compiler and assembler.
+
+ENDIAN NOTATION:
+
+The algorithm is designed for big-endian mode,
+software is responsible for byte swapping.
+
+USAGE:
+
+1. The host system that is running on MPC8240
+ shall link the files listed here. The memory
+ location of driver routines shall take into
+ account of that driver routines need to run
+ in supervisor mode and they process external
+ interrupts.
+
+ The routine epic_exception shall be called by
+ exception vector at location 0x500, i.e.,
+ 603e core external exception vector.
+
+2. The host system is responsible for configuring
+ the MPC8240 including Embedded Utilities Memory
+ Block. All EPIC driver functions require the
+ content of Embedded Utilities Memory Block
+ Base Address Register, EUMBBAR, as the first
+ parameter.
+
+3. Before EPIC unit of MPC8240 can be used,
+ initialize EPIC unit by calling epicInit
+ with the corresponding parameters.
+
+ The initialization shall disable the 603e
+ core External Exception by calling CoreExtIntDisable( ).
+ Next, call epicInit( ). Last, enable the 603e core
+ External Exception by calling CoreExtIntEnable( ).
+
+4. After EPIC unit has been successfully initialized,
+ epicIntSourceSet( ) shall be used to register each
+ external interrupt source. Anytime, an external
+ interrupt source can be disabled or enabled by
+ calling corresponding function, epicIntDisable( ),
+ or epicIntEnable( ).
+
+ Global Timers' resource, base count and frequency,
+ can be changed by calling epicTmFrequencySet( )
+ and epicTmBaseSet( ).
+
+ To stop counting a specific global timer, use
+ the function, epicTmInhibit while epicTmEnable
+ can be used to start counting a timer.
+
+5. To mask a set of external interrupts that are
+ are certain level below, epicIntPrioritySet( )
+ can be used. For example, if the processor's
+ current task priority register is set to 0x7,
+ only interrupts of priority 0x8 or higher will
+ be passed to the processor.
+
+ Be careful when using this function. It may
+ corrupt the current interrupt pending, selector,
+ and request registers, resulting an invalid vetor.
+
+ After enabling an interrupt, disable it may also
+ cause an invalid vector. User may consider using
+ the spurious vector interrupt service routine to
+ handle this case.
+
+6. The EPIC driver routines contains a set
+ of utilities, Set and Get, for host system
+ to query and modify the desired EPIC source
+ registers.
+
+7. Each external interrupt source shall register
+ its interrupt service routine. The routine
+ shall contain all interrupt source specific
+ processes and keep as short as possible.
+
+ Special customized end of interrupt routine
+ is optional. If it is needed, it shall contain
+ the external interrupt source specific end of
+ interrupt process.
+
+ External interrupt exception vector at 0x500
+ shall always call the epicEOI just before
+ rfi instruction. Refer to the routine,
+ epic_exception, for a code sample.
diff --git a/arch/powerpc/cpu/mpc824x/drivers/epic/epic.h b/arch/powerpc/cpu/mpc824x/drivers/epic/epic.h
new file mode 100644
index 0000000..58f81c5
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/drivers/epic/epic.h
@@ -0,0 +1,163 @@
+/*********************************************************************
+ * mpc8240epic.h - EPIC module of the MPC8240 micro-controller
+ *
+ * Copyrigh 1999 Motorola Inc.
+ *
+ * Modification History:
+ * =====================
+ * 01a,04Feb99,My Created.
+ * 15Nov200, robt -modified to use in U-Boot
+ *
+*/
+
+#ifndef __INCEPICh
+#define __INCEPICh
+
+#define ULONG unsigned long
+#define MAXVEC 20
+#define MAXIRQ 5 /* IRQs */
+#define EPIC_DIRECT_IRQ 0 /* Direct interrupt type */
+
+/* EPIC register addresses */
+
+#define EPIC_EUMBBAR 0x40000 /* EUMBBAR of EPIC */
+#define EPIC_FEATURES_REG (EPIC_EUMBBAR + 0x01000)/* Feature reporting */
+#define EPIC_GLOBAL_REG (EPIC_EUMBBAR + 0x01020)/* Global config. */
+#define EPIC_INT_CONF_REG (EPIC_EUMBBAR + 0x01030)/* Interrupt config. */
+#define EPIC_VENDOR_ID_REG (EPIC_EUMBBAR + 0x01080)/* Vendor id */
+#define EPIC_PROC_INIT_REG (EPIC_EUMBBAR + 0x01090)/* Processor init. */
+#define EPIC_SPUR_VEC_REG (EPIC_EUMBBAR + 0x010e0)/* Spurious vector */
+#define EPIC_TM_FREQ_REG (EPIC_EUMBBAR + 0x010f0)/* Timer Frequency */
+
+#define EPIC_TM0_CUR_COUNT_REG (EPIC_EUMBBAR + 0x01100)/* Gbl TM0 Cur. Count*/
+#define EPIC_TM0_BASE_COUNT_REG (EPIC_EUMBBAR + 0x01110)/* Gbl TM0 Base Count*/
+#define EPIC_TM0_VEC_REG (EPIC_EUMBBAR + 0x01120)/* Gbl TM0 Vector Pri*/
+#define EPIC_TM0_DES_REG (EPIC_EUMBBAR + 0x01130)/* Gbl TM0 Dest. */
+
+#define EPIC_TM1_CUR_COUNT_REG (EPIC_EUMBBAR + 0x01140)/* Gbl TM1 Cur. Count*/
+#define EPIC_TM1_BASE_COUNT_REG (EPIC_EUMBBAR + 0x01150)/* Gbl TM1 Base Count*/
+#define EPIC_TM1_VEC_REG (EPIC_EUMBBAR + 0x01160)/* Gbl TM1 Vector Pri*/
+#define EPIC_TM1_DES_REG (EPIC_EUMBBAR + 0x01170)/* Gbl TM1 Dest. */
+
+#define EPIC_TM2_CUR_COUNT_REG (EPIC_EUMBBAR + 0x01180)/* Gbl TM2 Cur. Count*/
+#define EPIC_TM2_BASE_COUNT_REG (EPIC_EUMBBAR + 0x01190)/* Gbl TM2 Base Count*/
+#define EPIC_TM2_VEC_REG (EPIC_EUMBBAR + 0x011a0)/* Gbl TM2 Vector Pri*/
+#define EPIC_TM2_DES_REG (EPIC_EUMBBAR + 0x011b0)/* Gbl TM2 Dest */
+
+#define EPIC_TM3_CUR_COUNT_REG (EPIC_EUMBBAR + 0x011c0)/* Gbl TM3 Cur. Count*/
+#define EPIC_TM3_BASE_COUNT_REG (EPIC_EUMBBAR + 0x011d0)/* Gbl TM3 Base Count*/
+#define EPIC_TM3_VEC_REG (EPIC_EUMBBAR + 0x011e0)/* Gbl TM3 Vector Pri*/
+#define EPIC_TM3_DES_REG (EPIC_EUMBBAR + 0x011f0)/* Gbl TM3 Dest. */
+
+#define EPIC_EX_INT0_VEC_REG (EPIC_EUMBBAR + 0x10200)/* Ext. Int. Sr0 Des */
+#define EPIC_EX_INT0_DES_REG (EPIC_EUMBBAR + 0x10210)/* Ext. Int. Sr0 Vect*/
+#define EPIC_EX_INT1_VEC_REG (EPIC_EUMBBAR + 0x10220)/* Ext. Int. Sr1 Des */
+#define EPIC_EX_INT1_DES_REG (EPIC_EUMBBAR + 0x10230)/* Ext. Int. Sr1 Vect*/
+#define EPIC_EX_INT2_VEC_REG (EPIC_EUMBBAR + 0x10240)/* Ext. Int. Sr2 Des */
+#define EPIC_EX_INT2_DES_REG (EPIC_EUMBBAR + 0x10250)/* Ext. Int. Sr2 Vect*/
+#define EPIC_EX_INT3_VEC_REG (EPIC_EUMBBAR + 0x10260)/* Ext. Int. Sr3 Des */
+#define EPIC_EX_INT3_DES_REG (EPIC_EUMBBAR + 0x10270)/* Ext. Int. Sr3 Vect*/
+#define EPIC_EX_INT4_VEC_REG (EPIC_EUMBBAR + 0x10280)/* Ext. Int. Sr4 Des */
+#define EPIC_EX_INT4_DES_REG (EPIC_EUMBBAR + 0x10290)/* Ext. Int. Sr4 Vect*/
+
+#define EPIC_SR_INT0_VEC_REG (EPIC_EUMBBAR + 0x10200)/* Sr. Int. Sr0 Des */
+#define EPIC_SR_INT0_DES_REG (EPIC_EUMBBAR + 0x10210)/* Sr. Int. Sr0 Vect */
+#define EPIC_SR_INT1_VEC_REG (EPIC_EUMBBAR + 0x10220)/* Sr. Int. Sr1 Des */
+#define EPIC_SR_INT1_DES_REG (EPIC_EUMBBAR + 0x10230)/* Sr. Int. Sr1 Vect.*/
+#define EPIC_SR_INT2_VEC_REG (EPIC_EUMBBAR + 0x10240)/* Sr. Int. Sr2 Des */
+#define EPIC_SR_INT2_DES_REG (EPIC_EUMBBAR + 0x10250)/* Sr. Int. Sr2 Vect.*/
+#define EPIC_SR_INT3_VEC_REG (EPIC_EUMBBAR + 0x10260)/* Sr. Int. Sr3 Des */
+#define EPIC_SR_INT3_DES_REG (EPIC_EUMBBAR + 0x10270)/* Sr. Int. Sr3 Vect.*/
+#define EPIC_SR_INT4_VEC_REG (EPIC_EUMBBAR + 0x10280)/* Sr. Int. Sr4 Des */
+#define EPIC_SR_INT4_DES_REG (EPIC_EUMBBAR + 0x10290)/* Sr. Int. Sr4 Vect.*/
+
+#define EPIC_SR_INT5_VEC_REG (EPIC_EUMBBAR + 0x102a0)/* Sr. Int. Sr5 Des */
+#define EPIC_SR_INT5_DES_REG (EPIC_EUMBBAR + 0x102b0)/* Sr. Int. Sr5 Vect.*/
+#define EPIC_SR_INT6_VEC_REG (EPIC_EUMBBAR + 0x102c0)/* Sr. Int. Sr6 Des */
+#define EPIC_SR_INT6_DES_REG (EPIC_EUMBBAR + 0x102d0)/* Sr. Int. Sr6 Vect.*/
+#define EPIC_SR_INT7_VEC_REG (EPIC_EUMBBAR + 0x102e0)/* Sr. Int. Sr7 Des */
+#define EPIC_SR_INT7_DES_REG (EPIC_EUMBBAR + 0x102f0)/* Sr. Int. Sr7 Vect.*/
+#define EPIC_SR_INT8_VEC_REG (EPIC_EUMBBAR + 0x10300)/* Sr. Int. Sr8 Des */
+#define EPIC_SR_INT8_DES_REG (EPIC_EUMBBAR + 0x10310)/* Sr. Int. Sr8 Vect.*/
+#define EPIC_SR_INT9_VEC_REG (EPIC_EUMBBAR + 0x10320)/* Sr. Int. Sr9 Des */
+#define EPIC_SR_INT9_DES_REG (EPIC_EUMBBAR + 0x10330)/* Sr. Int. Sr9 Vect.*/
+
+#define EPIC_SR_INT10_VEC_REG (EPIC_EUMBBAR + 0x10340)/* Sr. Int. Sr10 Des */
+#define EPIC_SR_INT10_DES_REG (EPIC_EUMBBAR + 0x10350)/* Sr. Int. Sr10 Vect*/
+#define EPIC_SR_INT11_VEC_REG (EPIC_EUMBBAR + 0x10360)/* Sr. Int. Sr11 Des */
+#define EPIC_SR_INT11_DES_REG (EPIC_EUMBBAR + 0x10370)/* Sr. Int. Sr11 Vect*/
+#define EPIC_SR_INT12_VEC_REG (EPIC_EUMBBAR + 0x10380)/* Sr. Int. Sr12 Des */
+#define EPIC_SR_INT12_DES_REG (EPIC_EUMBBAR + 0x10390)/* Sr. Int. Sr12 Vect*/
+#define EPIC_SR_INT13_VEC_REG (EPIC_EUMBBAR + 0x103a0)/* Sr. Int. Sr13 Des */
+#define EPIC_SR_INT13_DES_REG (EPIC_EUMBBAR + 0x103b0)/* Sr. Int. Sr13 Vect*/
+#define EPIC_SR_INT14_VEC_REG (EPIC_EUMBBAR + 0x103c0)/* Sr. Int. Sr14 Des */
+#define EPIC_SR_INT14_DES_REG (EPIC_EUMBBAR + 0x103d0)/* Sr. Int. Sr14 Vect*/
+#define EPIC_SR_INT15_VEC_REG (EPIC_EUMBBAR + 0x103e0)/* Sr. Int. Sr15 Des */
+#define EPIC_SR_INT15_DES_REG (EPIC_EUMBBAR + 0x103f0)/* Sr. Int. Sr15 Vect*/
+
+#define EPIC_I2C_INT_VEC_REG (EPIC_EUMBBAR + 0x11020)/* I2C Int. Vect Pri.*/
+#define EPIC_I2C_INT_DES_REG (EPIC_EUMBBAR + 0x11030)/* I2C Int. Dest */
+#define EPIC_DMA0_INT_VEC_REG (EPIC_EUMBBAR + 0x11040)/* DMA0 Int. Vect Pri*/
+#define EPIC_DMA0_INT_DES_REG (EPIC_EUMBBAR + 0x11050)/* DMA0 Int. Dest */
+#define EPIC_DMA1_INT_VEC_REG (EPIC_EUMBBAR + 0x11060)/* DMA1 Int. Vect Pri*/
+#define EPIC_DMA1_INT_DES_REG (EPIC_EUMBBAR + 0x11070)/* DMA1 Int. Dest */
+#define EPIC_MSG_INT_VEC_REG (EPIC_EUMBBAR + 0x110c0)/* Msg Int. Vect Pri*/
+#define EPIC_MSG_INT_DES_REG (EPIC_EUMBBAR + 0x110d0)/* Msg Int. Dest */
+
+#define EPIC_PROC_CTASK_PRI_REG (EPIC_EUMBBAR + 0x20080)/* Proc. current task*/
+#define EPIC_PROC_INT_ACK_REG (EPIC_EUMBBAR + 0x200a0)/* Int. acknowledge */
+#define EPIC_PROC_EOI_REG (EPIC_EUMBBAR + 0x200b0)/* End of interrupt */
+
+#define EPIC_VEC_PRI_MASK 0x80000000 /* Mask Interrupt bit in IVPR */
+#define EPIC_VEC_PRI_DFLT_PRI 8 /* Interrupt Priority in IVPR */
+
+/* Error code */
+
+#define OK 0
+#define ERROR -1
+
+/* function prototypes */
+
+void epicVendorId( unsigned int *step,
+ unsigned int *devId,
+ unsigned int *venId
+ );
+void epicFeatures( unsigned int *noIRQs,
+ unsigned int *noCPUs,
+ unsigned int *VerId );
+extern void epicInit( unsigned int IRQType, unsigned int clkRatio);
+ULONG sysEUMBBARRead ( ULONG regNum );
+void sysEUMBBARWrite ( ULONG regNum, ULONG regVal);
+extern void epicTmFrequencySet( unsigned int frq );
+extern unsigned int epicTmFrequencyGet(void);
+extern unsigned int epicTmBaseSet( ULONG srcAddr,
+ unsigned int cnt,
+ unsigned int inhibit );
+extern unsigned int epicTmBaseGet ( ULONG srcAddr, unsigned int *val );
+extern unsigned int epicTmCountGet( ULONG srcAddr, unsigned int *val );
+extern unsigned int epicTmInhibit( unsigned int timer );
+extern unsigned int epicTmEnable( ULONG srcAdr );
+extern void CoreExtIntEnable(void); /* Enable 603e external interrupts */
+extern void CoreExtIntDisable(void); /* Disable 603e external interrupts */
+extern unsigned char epicIntTaskGet(void);
+extern void epicIntTaskSet( unsigned char val );
+extern unsigned int epicIntAck(void);
+extern void epicSprSet( unsigned int eumbbar, unsigned char );
+extern void epicConfigGet( unsigned int *clkRatio,
+ unsigned int *serEnable );
+extern void SrcVecTableInit(void);
+extern unsigned int epicModeGet(void);
+extern void epicIntEnable(int Vect);
+extern void epicIntDisable(int Vect);
+extern int epicIntSourceConfig(int Vect, int Polarity, int Sense, int Prio);
+extern unsigned int epicIntAck(void);
+extern void epicEOI(void);
+extern int epicCurTaskPrioSet(int Vect);
+
+struct SrcVecTable
+ {
+ ULONG srcAddr;
+ char srcName[40];
+ };
+
+#endif /* EPIC_H */
diff --git a/arch/powerpc/cpu/mpc824x/drivers/epic/epic1.c b/arch/powerpc/cpu/mpc824x/drivers/epic/epic1.c
new file mode 100644
index 0000000..ecbb42d
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/drivers/epic/epic1.c
@@ -0,0 +1,517 @@
+/**************************************************
+ *
+ * copyright @ motorola, 1999
+ *
+ *************************************************/
+#include <mpc824x.h>
+#include <common.h>
+#include "epic.h"
+
+
+#define PRINT(format, args...) printf(format , ## args)
+
+typedef void (*VOIDFUNCPTR) (void); /* ptr to function returning void */
+struct SrcVecTable SrcVecTable[MAXVEC] = /* Addr/Vector cross-reference tbl */
+ {
+ { EPIC_EX_INT0_VEC_REG, "External Direct/Serial Source 0"},
+ { EPIC_EX_INT1_VEC_REG, "External Direct/Serial Source 1"},
+ { EPIC_EX_INT2_VEC_REG, "External Direct/Serial Source 2"},
+ { EPIC_EX_INT3_VEC_REG, "External Direct/Serial Source 3"},
+ { EPIC_EX_INT4_VEC_REG, "External Direct/Serial Source 4"},
+
+ { EPIC_SR_INT5_VEC_REG, "External Serial Source 5"},
+ { EPIC_SR_INT6_VEC_REG, "External Serial Source 6"},
+ { EPIC_SR_INT7_VEC_REG, "External Serial Source 7"},
+ { EPIC_SR_INT8_VEC_REG, "External Serial Source 8"},
+ { EPIC_SR_INT9_VEC_REG, "External Serial Source 9"},
+ { EPIC_SR_INT10_VEC_REG, "External Serial Source 10"},
+ { EPIC_SR_INT11_VEC_REG, "External Serial Source 11"},
+ { EPIC_SR_INT12_VEC_REG, "External Serial Source 12"},
+ { EPIC_SR_INT13_VEC_REG, "External Serial Source 13"},
+ { EPIC_SR_INT14_VEC_REG, "External Serial Source 14"},
+ { EPIC_SR_INT15_VEC_REG, "External Serial Source 15"},
+
+ { EPIC_I2C_INT_VEC_REG, "Internal I2C Source"},
+ { EPIC_DMA0_INT_VEC_REG, "Internal DMA0 Source"},
+ { EPIC_DMA1_INT_VEC_REG, "Internal DMA1 Source"},
+ { EPIC_MSG_INT_VEC_REG, "Internal Message Source"},
+ };
+
+VOIDFUNCPTR intVecTbl[MAXVEC]; /* Interrupt vector table */
+
+
+/****************************************************************************
+* epicInit - Initialize the EPIC registers
+*
+* This routine resets the Global Configuration Register, thus it:
+* - Disables all interrupts
+* - Sets epic registers to reset values
+* - Sets the value of the Processor Current Task Priority to the
+* highest priority (0xF).
+* epicInit then sets the EPIC operation mode to Mixed Mode (vs. Pass
+* Through or 8259 compatible mode).
+*
+* If IRQType (input) is Direct IRQs:
+* - IRQType is written to the SIE bit of the EPIC Interrupt
+* Configuration register (ICR).
+* - clkRatio is ignored.
+* If IRQType is Serial IRQs:
+* - both IRQType and clkRatio will be written to the ICR register
+*/
+
+void epicInit
+ (
+ unsigned int IRQType, /* Direct or Serial */
+ unsigned int clkRatio /* Clk Ratio for Serial IRQs */
+ )
+ {
+ ULONG tmp;
+
+ tmp = sysEUMBBARRead(EPIC_GLOBAL_REG);
+ tmp |= 0xa0000000; /* Set the Global Conf. register */
+ sysEUMBBARWrite(EPIC_GLOBAL_REG, tmp);
+ /*
+ * Wait for EPIC to reset - CLH
+ */
+ while( (sysEUMBBARRead(EPIC_GLOBAL_REG) & 0x80000000) == 1);
+ sysEUMBBARWrite(EPIC_GLOBAL_REG, 0x20000000);
+ tmp = sysEUMBBARRead(EPIC_INT_CONF_REG); /* Read interrupt conf. reg */
+
+ if (IRQType == EPIC_DIRECT_IRQ) /* direct mode */
+ sysEUMBBARWrite(EPIC_INT_CONF_REG, tmp & 0xf7ffffff);
+ else /* Serial mode */
+ {
+ tmp = (clkRatio << 28) | 0x08000000; /* Set clock ratio */
+ sysEUMBBARWrite(EPIC_INT_CONF_REG, tmp);
+ }
+
+ while (epicIntAck() != 0xff) /* Clear all pending interrupts */
+ epicEOI();
+}
+
+/****************************************************************************
+ * epicIntEnable - Enable an interrupt source
+ *
+ * This routine clears the mask bit of an external, an internal or
+ * a Timer register to enable the interrupt.
+ *
+ * RETURNS: None
+ */
+void epicIntEnable(int intVec)
+{
+ ULONG tmp;
+ ULONG srAddr;
+
+ srAddr = SrcVecTable[intVec].srcAddr; /* Retrieve src Vec/Prio register */
+ tmp = sysEUMBBARRead(srAddr);
+ tmp &= ~EPIC_VEC_PRI_MASK; /* Clear the mask bit */
+ tmp |= (EPIC_VEC_PRI_DFLT_PRI << 16); /* Set priority to Default - CLH */
+ tmp |= intVec; /* Set Vector number */
+ sysEUMBBARWrite(srAddr, tmp);
+
+ return;
+ }
+
+/****************************************************************************
+ * epicIntDisable - Disable an interrupt source
+ *
+ * This routine sets the mask bit of an external, an internal or
+ * a Timer register to disable the interrupt.
+ *
+ * RETURNS: OK or ERROR
+ *
+ */
+
+void epicIntDisable
+ (
+ int intVec /* Interrupt vector number */
+ )
+ {
+
+ ULONG tmp, srAddr;
+
+ srAddr = SrcVecTable[intVec].srcAddr;
+ tmp = sysEUMBBARRead(srAddr);
+ tmp |= 0x80000000; /* Set the mask bit */
+ sysEUMBBARWrite(srAddr, tmp);
+ return;
+ }
+
+/****************************************************************************
+ * epicIntSourceConfig - Set properties of an interrupt source
+ *
+ * This function sets interrupt properites (Polarity, Sense, Interrupt
+ * Prority, and Interrupt Vector) of an Interrupt Source. The properties
+ * can be set when the current source is not in-request or in-service,
+ * which is determined by the Activity bit. This routine return ERROR
+ * if the the Activity bit is 1 (in-request or in-service).
+ *
+ * This function assumes that the Source Vector/Priority register (input)
+ * is a valid address.
+ *
+ * RETURNS: OK or ERROR
+ */
+
+int epicIntSourceConfig
+ (
+ int Vect, /* interrupt source vector number */
+ int Polarity, /* interrupt source polarity */
+ int Sense, /* interrupt source Sense */
+ int Prio /* interrupt source priority */
+ )
+
+ {
+ ULONG tmp, newVal;
+ ULONG actBit, srAddr;
+
+ srAddr = SrcVecTable[Vect].srcAddr;
+ tmp = sysEUMBBARRead(srAddr);
+ actBit = (tmp & 40000000) >> 30; /* retrieve activity bit - bit 30 */
+ if (actBit == 1)
+ return ERROR;
+
+ tmp &= 0xff30ff00; /* Erase previously set P,S,Prio,Vector bits */
+ newVal = (Polarity << 23) | (Sense << 22) | (Prio << 16) | Vect;
+ sysEUMBBARWrite(srAddr, tmp | newVal );
+ return (OK);
+ }
+
+/****************************************************************************
+ * epicIntAck - acknowledge an interrupt
+ *
+ * This function reads the Interrupt acknowldge register and return
+ * the vector number of the highest pending interrupt.
+ *
+ * RETURNS: Interrupt Vector number.
+ */
+
+unsigned int epicIntAck(void)
+{
+ return(sysEUMBBARRead( EPIC_PROC_INT_ACK_REG ));
+}
+
+/****************************************************************************
+ * epicEOI - signal an end of interrupt
+ *
+ * This function writes 0x0 to the EOI register to signal end of interrupt.
+ * It is usually called after an interrupt routine is served.
+ *
+ * RETURNS: None
+ */
+
+void epicEOI(void)
+ {
+ sysEUMBBARWrite(EPIC_PROC_EOI_REG, 0x0);
+ }
+
+/****************************************************************************
+ * epicCurTaskPrioSet - sets the priority of the Processor Current Task
+ *
+ * This function should be called after epicInit() to lower the priority
+ * of the processor current task.
+ *
+ * RETURNS: OK or ERROR
+ */
+
+int epicCurTaskPrioSet
+ (
+ int prioNum /* New priority value */
+ )
+ {
+
+ if ( (prioNum < 0) || (prioNum > 0xF))
+ return ERROR;
+ sysEUMBBARWrite(EPIC_PROC_CTASK_PRI_REG, prioNum);
+ return OK;
+ }
+
+
+/************************************************************************
+ * function: epicIntTaskGet
+ *
+ * description: Get value of processor current interrupt task priority register
+ *
+ * note:
+ ***********************************************************************/
+unsigned char epicIntTaskGet()
+{
+ /* get the interrupt task priority register */
+ ULONG reg;
+ unsigned char rec;
+
+ reg = sysEUMBBARRead( EPIC_PROC_CTASK_PRI_REG );
+ rec = ( reg & 0x0F );
+ return rec;
+}
+
+
+/**************************************************************
+ * function: epicISR
+ *
+ * description: EPIC service routine called by the core exception
+ * at 0x500
+ *
+ * note:
+ **************************************************************/
+unsigned int epicISR(void)
+{
+ return 0;
+}
+
+
+/************************************************************
+ * function: epicModeGet
+ *
+ * description: query EPIC mode, return 0 if pass through mode
+ * return 1 if mixed mode
+ *
+ * note:
+ *************************************************************/
+unsigned int epicModeGet(void)
+{
+ ULONG val;
+
+ val = sysEUMBBARRead( EPIC_GLOBAL_REG );
+ return (( val & 0x20000000 ) >> 29);
+}
+
+
+/*********************************************
+ * function: epicConfigGet
+ *
+ * description: Get the EPIC interrupt Configuration
+ * return 0 if not error, otherwise return 1
+ *
+ * note:
+ ********************************************/
+void epicConfigGet( unsigned int *clkRatio, unsigned int *serEnable)
+{
+ ULONG val;
+
+ val = sysEUMBBARRead( EPIC_INT_CONF_REG );
+ *clkRatio = ( val & 0x70000000 ) >> 28;
+ *serEnable = ( val & 0x8000000 ) >> 27;
+}
+
+
+/*******************************************************************
+ * sysEUMBBARRead - Read a 32-bit EUMBBAR register
+ *
+ * This routine reads the content of a register in the Embedded
+ * Utilities Memory Block, and swaps to big endian before returning
+ * the value.
+ *
+ * RETURNS: The content of the specified EUMBBAR register.
+ */
+
+ULONG sysEUMBBARRead
+ (
+ ULONG regNum
+ )
+ {
+ ULONG temp;
+
+ temp = *(ULONG *) (CONFIG_SYS_EUMB_ADDR + regNum);
+ return ( LONGSWAP(temp));
+ }
+
+/*******************************************************************
+ * sysEUMBBARWrite - Write a 32-bit EUMBBAR register
+ *
+ * This routine swaps the value to little endian then writes it to
+ * a register in the Embedded Utilities Memory Block address space.
+ *
+ * RETURNS: N/A
+ */
+
+void sysEUMBBARWrite
+ (
+ ULONG regNum, /* EUMBBAR register address */
+ ULONG regVal /* Value to be written */
+ )
+ {
+
+ *(ULONG *) (CONFIG_SYS_EUMB_ADDR + regNum) = LONGSWAP(regVal);
+ return ;
+ }
+
+
+/********************************************************
+ * function: epicVendorId
+ *
+ * description: return the EPIC Vendor Identification
+ * register:
+ *
+ * siliccon version, device id, and vendor id
+ *
+ * note:
+ ********************************************************/
+void epicVendorId
+ (
+ unsigned int *step,
+ unsigned int *devId,
+ unsigned int *venId
+ )
+ {
+ ULONG val;
+ val = sysEUMBBARRead( EPIC_VENDOR_ID_REG );
+ *step = ( val & 0x00FF0000 ) >> 16;
+ *devId = ( val & 0x0000FF00 ) >> 8;
+ *venId = ( val & 0x000000FF );
+ }
+
+/**************************************************
+ * function: epicFeatures
+ *
+ * description: return the number of IRQ supported,
+ * number of CPU, and the version of the
+ * OpenEPIC
+ *
+ * note:
+ *************************************************/
+void epicFeatures
+ (
+ unsigned int *noIRQs,
+ unsigned int *noCPUs,
+ unsigned int *verId
+ )
+ {
+ ULONG val;
+
+ val = sysEUMBBARRead( EPIC_FEATURES_REG );
+ *noIRQs = ( val & 0x07FF0000 ) >> 16;
+ *noCPUs = ( val & 0x00001F00 ) >> 8;
+ *verId = ( val & 0x000000FF );
+}
+
+
+/*********************************************************
+ * function: epciTmFrequncySet
+ *
+ * description: Set the timer frequency reporting register
+ ********************************************************/
+void epicTmFrequencySet( unsigned int frq )
+{
+ sysEUMBBARWrite(EPIC_TM_FREQ_REG, frq);
+}
+
+/*******************************************************
+ * function: epicTmFrequncyGet
+ *
+ * description: Get the current value of the Timer Frequency
+ * Reporting register
+ *
+ ******************************************************/
+unsigned int epicTmFrequencyGet(void)
+{
+ return( sysEUMBBARRead(EPIC_TM_FREQ_REG)) ;
+}
+
+
+/****************************************************
+ * function: epicTmBaseSet
+ *
+ * description: Set the #n global timer base count register
+ * return 0 if no error, otherwise return 1.
+ *
+ * note:
+ ****************************************************/
+unsigned int epicTmBaseSet
+ (
+ ULONG srcAddr, /* Address of the Timer Base register */
+ unsigned int cnt, /* Base count */
+ unsigned int inhibit /* 1 - count inhibit */
+ )
+{
+
+ unsigned int val = 0x80000000;
+ /* First inhibit counting the timer */
+ sysEUMBBARWrite(srcAddr, val) ;
+
+ /* set the new value */
+ val = (cnt & 0x7fffffff) | ((inhibit & 0x1) << 31);
+ sysEUMBBARWrite(srcAddr, val) ;
+ return 0;
+}
+
+/***********************************************************************
+ * function: epicTmBaseGet
+ *
+ * description: Get the current value of the global timer base count register
+ * return 0 if no error, otherwise return 1.
+ *
+ * note:
+ ***********************************************************************/
+unsigned int epicTmBaseGet( ULONG srcAddr, unsigned int *val )
+{
+ *val = sysEUMBBARRead( srcAddr );
+ *val = *val & 0x7fffffff;
+ return 0;
+}
+
+/***********************************************************
+ * function: epicTmCountGet
+ *
+ * description: Get the value of a given global timer
+ * current count register
+ * return 0 if no error, otherwise return 1
+ * note:
+ **********************************************************/
+unsigned int epicTmCountGet( ULONG srcAddr, unsigned int *val )
+{
+ *val = sysEUMBBARRead( srcAddr );
+ *val = *val & 0x7fffffff;
+ return 0;
+}
+
+
+/***********************************************************
+ * function: epicTmInhibit
+ *
+ * description: Stop counting of a given global timer
+ * return 0 if no error, otherwise return 1
+ *
+ * note:
+ ***********************************************************/
+unsigned int epicTmInhibit( unsigned int srcAddr )
+{
+ ULONG val;
+
+ val = sysEUMBBARRead( srcAddr );
+ val |= 0x80000000;
+ sysEUMBBARWrite( srcAddr, val );
+ return 0;
+}
+
+/******************************************************************
+ * function: epicTmEnable
+ *
+ * description: Enable counting of a given global timer
+ * return 0 if no error, otherwise return 1
+ *
+ * note:
+ *****************************************************************/
+unsigned int epicTmEnable( ULONG srcAddr )
+{
+ ULONG val;
+
+ val = sysEUMBBARRead( srcAddr );
+ val &= 0x7fffffff;
+ sysEUMBBARWrite( srcAddr, val );
+ return 0;
+}
+
+void epicSourcePrint(int Vect)
+ {
+ ULONG srcVal;
+
+ srcVal = sysEUMBBARRead(SrcVecTable[Vect].srcAddr);
+ PRINT("%s\n", SrcVecTable[Vect].srcName);
+ PRINT("Address = 0x%lx\n", SrcVecTable[Vect].srcAddr);
+ PRINT("Vector = %ld\n", (srcVal & 0x000000FF) );
+ PRINT("Mask = %ld\n", srcVal >> 31);
+ PRINT("Activitiy = %ld\n", (srcVal & 40000000) >> 30);
+ PRINT("Polarity = %ld\n", (srcVal & 0x00800000) >> 23);
+ PRINT("Sense = %ld\n", (srcVal & 0x00400000) >> 22);
+ PRINT("Priority = %ld\n", (srcVal & 0x000F0000) >> 16);
+ }
diff --git a/arch/powerpc/cpu/mpc824x/drivers/epic/epic2.S b/arch/powerpc/cpu/mpc824x/drivers/epic/epic2.S
new file mode 100644
index 0000000..52d19aa
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/drivers/epic/epic2.S
@@ -0,0 +1,196 @@
+/**************************************
+ *
+ * copyright @ Motorola, 1999
+ *
+ **************************************/
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+#include <asm/processor.h>
+
+/*********************************************
+ * function: CoreExtIntEnable
+ *
+ * description: Enable 603e core external interrupt
+ *
+ * note: mtmsr is context-synchronization
+ **********************************************/
+ .text
+ .align 2
+ .global CoreExtIntEnable
+CoreExtIntEnable:
+ mfmsr r3
+
+ ori r3,r3,0x8000 /* enable external interrupt */
+ mtmsr r3
+
+ bclr 20, 0
+
+/*******************************************
+ * function: CoreExtIntDisable
+ *
+ * description: Disable 603e core external interrupt
+ *
+ * note:
+ *******************************************/
+ .text
+ .align 2
+ .global CoreExtIntDisable
+CoreExtIntDisable:
+ mfmsr r4
+
+ xor r3,r3,r3
+ or r3,r3,r4
+
+ andis. r4,r4,0xffff
+ andi. r3,r3,0x7fff /* disable external interrupt */
+
+ or r3,r3,r4
+ mtmsr r3
+
+ bclr 20, 0
+
+/*********************************************************
+ * function: epicEOI
+ *
+ * description: signal the EOI and restore machine status
+ * Input: r3 - value of eumbbar
+ * Output: r3 - value of eumbbar
+ * r4 - ISR vector value
+ * note:
+ ********************************************************/
+ .text
+ .align 2
+ .global epicEOI
+epicEOI:
+ lis r5,0x0006 /* Build End Of Interrupt Register offset */
+ ori r5,r5,0x00b0
+ xor r7,r7,r7 /* Clear r7 */
+ stwbrx r7,r5,r3 /* Save r7, writing to this register will
+ * intidate the end of processing the
+ * highest interrupt.
+ */
+ sync
+
+ /* ---RESTORE MACHINE STATE */
+ mfmsr r13 /* Clear Recoverable Interrupt bit in MSR */
+ or r7,r7,r13
+
+ andis. r7,r7,0xffff
+ andi. r13,r13,0x7ffd /* (and disable interrupts) */
+ or r13,r13,r7
+ mtmsr r13
+
+ lwz r13,0x1c(r1) /* pull ctr */
+ mtctr r13
+
+ lwz r13,0x18(r1) /* pull xer */
+ mtctr r13
+
+ lwz r13,0x14(r1) /* pull lr */
+ mtctr r13
+
+ lwz r13,0x10(r1) /* Pull SRR1 from stack */
+ mtspr SRR1,r13 /* Restore SRR1 */
+
+ lwz r13,0xc(r1) /* Pull SRR0 from stack */
+ mtspr SRR0,r13 /* Restore SRR0 */
+
+ lwz r13,0x8(r1) /* Pull User stack pointer from stack */
+ mtspr SPRG1,r13 /* Restore SPRG1 */
+
+ lwz r4,0x4(r1) /* vector value */
+ lwz r3,0x0(r1) /* eumbbar */
+ sync
+
+ addi r1,r1,0x20 /* Deallocate stack */
+ mtspr SPRG0,r1 /* Save updated Supervisor stack pointer */
+ mfspr r1,SPRG1 /* Restore User stack pointer */
+
+ bclr 20,0
+
+/***********************************************************
+ * function: exception routine called by exception vector
+ * at 0x500, external interrupt
+ *
+ * description: Kahlua EPIC controller
+ *
+ * input: r3 - content of eumbbar
+ * output: r3 - ISR return value
+ * r4 - Interrupt vector number
+ * note:
+ ***********************************************************/
+
+ .text
+ .align 2
+ .global epic_exception
+
+epic_exception:
+
+ /*---SAVE MACHINE STATE TO A STACK */
+ mtspr SPRG1,r1 /* Save User stack pointer to SPRG1 */
+ mfspr r1,SPRG0 /* Load Supervisor stack pointer into r1 */
+
+ stwu r3,-0x20(r1) /* Push the value of eumbbar onto stack */
+
+ mfspr r3,SPRG1 /* Push User stack pointer onto stack */
+ stw r3,0x8(r1)
+ mfspr r3,SRR0 /* Push SRR0 onto stack */
+ stw r1,0xc(r1)
+ mfspr r3,SRR1 /* Push SRR1 onto stack */
+ stw r3,0x10(r1)
+ mflr r3
+ stw r3,0x14(r1) /* Push LR */
+ mfxer r3
+ stw r3,0x18(r1) /* Push Xer */
+ mfctr r3
+ stw r3,0x1c(r1) /* Push CTR */
+
+ mtspr SPRG0,r1 /* Save updated Supervisor stack pointer
+ * value to SPRG0
+ */
+ mfmsr r3
+ ori r3,r3,0x0002 /* Set Recoverable Interrupt bit in MSR */
+ mtmsr r3
+
+ /* ---READ IN THE EUMBAR REGISTER */
+ lwz r6,0(r1) /* this is eumbbar */
+ sync
+
+ /* ---READ EPIC REGISTER: PROCESSOR INTERRUPT ACKNOWLEDGE REGISTER */
+ lis r5,0x0006 /* Build Interrupt Acknowledge Register
+ * offset
+ */
+ ori r5,r5,0x00a0
+ lwbrx r7,r5,r6 /* Load interrupt vector into r7 */
+ sync
+
+ /* --MASK OFF ALL BITS EXCEPT THE VECTOR */
+ xor r3,r3,r3
+ xor r4,r4,r4
+ or r3, r3, r6 /* eumbbar in r3 */
+ andi. r4,r7,0x00ff /* Mask off bits, vector in r4 */
+
+ stw r4,0x04(r1) /* save the vector value */
+
+ lis r5,epicISR@ha
+ ori r5,r5,epicISR@l
+ mtlr r5
+ blrl
+
+ xor r30,r30,r30
+ or r30,r30,r3 /* save the r3 which containts the return value from epicISR */
+
+ /* ---READ IN THE EUMBAR REGISTER */
+ lwz r3,0(r1)
+ sync
+
+ lis r5,epicEOI@ha
+ ori r5,r5,epicEOI@l
+ mtlr r5
+ blrl
+
+ xor r3,r3,r3
+ or r3,r3,r30 /* restore the ISR return value */
+
+ bclr 20,0
diff --git a/arch/powerpc/cpu/mpc824x/drivers/epic/epicutil.S b/arch/powerpc/cpu/mpc824x/drivers/epic/epicutil.S
new file mode 100644
index 0000000..4877050
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/drivers/epic/epicutil.S
@@ -0,0 +1,57 @@
+/**************************************
+ *
+ * copyright @ Motorola, 1999
+ *
+ *
+ * This file contains two commonly used
+ * lower level utility routines.
+ *
+ * The utility routines are also in other
+ * Kahlua device driver libraries. The
+ * need to be linked in only once.
+ **************************************/
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+/**********************************************************
+ * function: load_runtime_reg
+ *
+ * input: r3 - value of eumbbar
+ * r4 - register offset in embedded utility space
+ *
+ * output: r3 - register content
+ **********************************************************/
+ .text
+ .align 2
+ .global load_runtime_reg
+
+load_runtime_reg:
+
+ xor r5,r5,r5
+ or r5,r5,r3 /* save eumbbar */
+
+ lwbrx r3,r4,r5
+ sync
+
+ bclr 20, 0
+
+/****************************************************************
+ * function: store_runtime_reg
+ *
+ * input: r3 - value of eumbbar
+ * r4 - register offset in embedded utility space
+ * r5 - new value to be stored
+ *
+ ****************************************************************/
+ .text
+ .align 2
+ .global store_runtime_reg
+store_runtime_reg:
+
+ xor r0,r0,r0
+
+ stwbrx r5, r4, r3
+ sync
+
+ bclr 20,0
diff --git a/arch/powerpc/cpu/mpc824x/drivers/errors.h b/arch/powerpc/cpu/mpc824x/drivers/errors.h
new file mode 100644
index 0000000..20794a2
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/drivers/errors.h
@@ -0,0 +1,212 @@
+/* Copyright Motorola, Inc. 1993, 1994
+ ALL RIGHTS RESERVED
+
+ You are hereby granted a copyright license to use, modify, and
+ distribute the SOFTWARE so long as this entire notice is retained
+ without alteration in any modified and/or redistributed versions,
+ and that such modified versions are clearly identified as such.
+ No licenses are granted by implication, estoppel or otherwise under
+ any patents or trademarks of Motorola, Inc.
+
+ The SOFTWARE is provided on an "AS IS" basis and without warranty.
+ To the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS
+ ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
+ PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH
+ REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS
+ THEREOF) AND ANY ACCOMPANYING WRITTEN MATERIALS.
+
+ To the maximum extent permitted by applicable law, IN NO EVENT SHALL
+ MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
+ (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF
+ BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS
+ INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR
+ INABILITY TO USE THE SOFTWARE. Motorola assumes no responsibility
+ for the maintenance and support of the SOFTWARE.
+
+*/
+
+
+#include "config.h"
+
+/*
+ 1 2 3 4 5 6 7 8
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+*/
+/* List define statements here */
+
+/* These are for all the toolboxes and functions to use. These will help
+to standardize the error handling in the current project */
+
+ /* this is the "data type" for the error
+ messages in the system */
+#define STATUS unsigned int
+
+ /* this is a success status code */
+#define SUCCESS 1
+
+ /* likewise this is failure */
+#define FAILURE 0
+
+#define NUM_ERRORS 47
+
+/* This first section of "defines" are for error codes ONLY. The called
+ routine will return one of these error codes to the caller. If the final
+ returned code is "VALID", then everything is a-okay. However, if one
+ of the functions returns a non-valid status, that error code should be
+ propogated back to all the callers. At the end, the last caller will
+ call an error_processing function, and send in the status which was
+ returned. It's up to the error_processing function to determine which
+ error occured (as indicated by the status), and print an appropriate
+ message back to the user.
+*/
+/*----------------------------------------------------------------------*/
+/* these are specifically for the parser routines */
+
+#define UNKNOWN_COMMAND 0xfb00 /* "unrecognized command " */
+#define UNKNOWN_REGISTER 0xfb01 /* "unknown register "*/
+#define ILLEGAL_RD_STAGE 0xfb02 /* cannot specify reg. family in range*/
+#define ILLEGAL_REG_FAMILY 0xfb03 /* "cannot specify a range of special
+ or miscellaneous registers"*/
+#define RANGE_CROSS_FAMILY 0xfb04 /* "cannot specify a range across
+ register families" */
+#define UNIMPLEMENTED_STAGE 0xfb05 /* invalid rd or rmm parameter format */
+#define REG_NOT_WRITEABLE 0xfb06 /* "unknown operator in arguements"*/
+#define INVALID_FILENAME 0xfb07 /* "invalid download filename" */
+#define INVALID_BAUD_RATE 0xfb08 /* invalid baud rate from sb command */
+#define UNSUPPORTED_REGISTER 0xfb09 /* Special register is not supported */
+#define FOR_BOARD_ONLY 0xfb0a /* "Not available for Unix." */
+
+
+/*----------------------------------------------------------------------*/
+/* these are for the error checking toolbox */
+
+#define INVALID 0xfd00 /* NOT valid */
+#define VALID 0xfd01 /* valid */
+
+ /* This error is found in the fcn:
+ is_right_size_input() to indicate
+ that the input was not 8 characters
+ long. */
+#define INVALID_SIZE 0xfd02
+
+ /* This error is found in the fcn:
+ is_valid_address_range() to indicate
+ that the address given falls outside
+ of valid memory defined by MEM_START
+ to MEM_END.
+ */
+#define OUT_OF_BOUNDS_ADDRESS 0xfd03
+
+ /* This error is found in the fcn:
+ is_valid_hex_input() to indicate that
+ one of more of the characters entered
+ are not valid hex characters. Valid
+ hex characters are 0-9, A-F, a-f.
+ */
+#define INVALID_HEX_INPUT 0xfd04
+
+ /* This error is found in the fcn:
+ is_valid_register_number() to indicate
+ that a given register does not exist.
+ */
+#define REG_NOT_READABLE 0xfd05
+
+ /* This error is found in the fcn:
+ is_word_aligned_address() to indicate
+ that the given address is not word-
+ aligned. A word-aligned address ends
+ in 0x0,0x4,0x8,0xc.
+ */
+#define NOT_WORD_ALIGNED 0xfd07
+
+ /* This error is found in the fcn:
+ is_valid_address_range() to indicate
+ that the starting address is greater
+ than the ending address.
+ */
+#define REVERSED_ADDRESS 0xfd08
+
+ /* this error tells us that the address
+ specified as the destination is within
+ the source addresses */
+#define RANGE_OVERLAP 0xfd09
+
+
+#define ERROR 0xfd0a /* An error occured */
+#define INVALID_PARAM 0xfd0b /* "invalid input parameter " */
+
+
+#define INVALID_FLAG 0xfd0c /* invalid flag */
+
+/*----------------------------------------------------------------------*/
+/* these are for the getarg toolbox */
+
+#define INVALID_NUMBER_ARGS 0xFE00 /* invalid number of commd arguements */
+#define UNKNOWN_PARAMETER 0xFE01 /* "unknown type of parameter "*/
+
+
+/*----------------------------------------------------------------------*/
+/* these are for the tokenizer toolbox */
+
+#define ILLEGAL_CHARACTER 0xFF00 /* unrecognized char. in input stream*/
+#define TTL_NOT_SORTED 0xFF01 /* token translation list not sorted */
+#define TTL_NOT_DEFINED 0xFF02 /* token translation list not assigned*/
+#define INVALID_STRING 0xFF03 /* unable to extract string from input */
+#define BUFFER_EMPTY 0xFF04 /* "input buffer is empty" */
+#define INVALID_MODE 0xFF05 /* input buf is in an unrecognized mode*/
+#define TOK_INTERNAL_ERROR 0xFF06 /* "internal tokenizer error" */
+#define TOO_MANY_IBS 0xFF07 /* "too many open input buffers" */
+#define NO_OPEN_IBS 0xFF08 /* "no open input buffers" */
+
+
+/* these are for the read from screen toolbox */
+
+#define RESERVED_WORD 0xFC00 /* used a reserved word as an arguement*/
+
+
+/* these are for the breakpoint routines */
+
+#define FULL_BPDS 0xFA00 /* breakpoint data structure is full */
+
+
+/* THESE are for the downloader */
+
+#define NOT_IN_S_RECORD_FORMAT 0xf900 /* "not in S-Record Format" */
+#define UNREC_RECORD_TYPE 0xf901 /* "unrecognized record type" */
+#define CONVERSION_ERROR 0xf902 /* "ascii to int conversion error" */
+#define INVALID_MEMORY 0xf903 /* "bad s-record memory address " */
+
+
+/* these are for the compression and decompression stuff */
+
+#define COMP_UNK_CHARACTER 0xf800 /* "unknown compressed character " */
+
+#define COMP_UNKNOWN_STATE 0xf801 /* "unknown binary state" */
+
+#define NOT_IN_COMPRESSED_FORMAT 0xf802 /* not in compressed S-Record format */
+
+
+/* these are for the DUART handling things */
+
+ /* "unrecognized serial port configuration" */
+#define UNKNOWN_PORT_STATE 0xf700
+
+
+/* these are for the register toolbox */
+
+ /* "cannot find register in special
+ purpose register file " */
+#define SPR_NOT_FOUND 0xf600
+
+
+/* these are for the duart specific stuff */
+
+ /* "transparent mode needs access to
+ two serial ports" */
+#define TM_NEEDS_BOTH_PORTS 0xf500
+
+
+/*----------------------------------------------------------------------*/
+/* these are specifically for the flash routines */
+#define FLASH_ERROR 0xf100 /* general flash error */
diff --git a/arch/powerpc/cpu/mpc824x/drivers/i2c/i2c.c b/arch/powerpc/cpu/mpc824x/drivers/i2c/i2c.c
new file mode 100644
index 0000000..637ae4c
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/drivers/i2c/i2c.c
@@ -0,0 +1,270 @@
+/*
+ * (C) Copyright 2003
+ * Gleb Natapov <gnatapov@mrv.com>
+ * Some bits are taken from linux driver writen by adrian@humboldt.co.uk
+ *
+ * Hardware I2C driver for MPC107 PCI bridge.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#undef I2CDBG
+
+#ifdef CONFIG_HARD_I2C
+#include <i2c.h>
+
+#define TIMEOUT (CONFIG_SYS_HZ/4)
+
+#define I2C_Addr ((unsigned *)(CONFIG_SYS_EUMB_ADDR + 0x3000))
+
+#define I2CADR &I2C_Addr[0]
+#define I2CFDR &I2C_Addr[1]
+#define I2CCCR &I2C_Addr[2]
+#define I2CCSR &I2C_Addr[3]
+#define I2CCDR &I2C_Addr[4]
+
+#define MPC107_CCR_MEN 0x80
+#define MPC107_CCR_MIEN 0x40
+#define MPC107_CCR_MSTA 0x20
+#define MPC107_CCR_MTX 0x10
+#define MPC107_CCR_TXAK 0x08
+#define MPC107_CCR_RSTA 0x04
+
+#define MPC107_CSR_MCF 0x80
+#define MPC107_CSR_MAAS 0x40
+#define MPC107_CSR_MBB 0x20
+#define MPC107_CSR_MAL 0x10
+#define MPC107_CSR_SRW 0x04
+#define MPC107_CSR_MIF 0x02
+#define MPC107_CSR_RXAK 0x01
+
+#define I2C_READ 1
+#define I2C_WRITE 0
+
+/* taken from linux include/asm-ppc/io.h */
+inline unsigned in_le32 (volatile unsigned *addr)
+{
+ unsigned ret;
+
+ __asm__ __volatile__ ("lwbrx %0,0,%1;\n"
+ "twi 0,%0,0;\n"
+ "isync":"=r" (ret): "r" (addr), "m" (*addr));
+ return ret;
+}
+
+inline void out_le32 (volatile unsigned *addr, int val)
+{
+ __asm__ __volatile__ ("stwbrx %1,0,%2; eieio":"=m" (*addr):"r" (val),
+ "r" (addr));
+}
+
+#define writel(val, addr) out_le32(addr, val)
+#define readl(addr) in_le32(addr)
+
+void i2c_init (int speed, int slaveadd)
+{
+ /* stop I2C controller */
+ writel (0x0, I2CCCR);
+ /* set clock */
+ writel (0x1020, I2CFDR);
+ /* write slave address */
+ writel (slaveadd, I2CADR);
+ /* clear status register */
+ writel (0x0, I2CCSR);
+ /* start I2C controller */
+ writel (MPC107_CCR_MEN, I2CCCR);
+
+ return;
+}
+
+static __inline__ int i2c_wait4bus (void)
+{
+ ulong timeval = get_timer (0);
+
+ while (readl (I2CCSR) & MPC107_CSR_MBB)
+ if (get_timer (timeval) > TIMEOUT)
+ return -1;
+
+ return 0;
+}
+
+static __inline__ int i2c_wait (int write)
+{
+ u32 csr;
+ ulong timeval = get_timer (0);
+
+ do {
+ csr = readl (I2CCSR);
+
+ if (!(csr & MPC107_CSR_MIF))
+ continue;
+
+ writel (0x0, I2CCSR);
+
+ if (csr & MPC107_CSR_MAL) {
+#ifdef I2CDBG
+ printf ("i2c_wait: MAL\n");
+#endif
+ return -1;
+ }
+
+ if (!(csr & MPC107_CSR_MCF)) {
+#ifdef I2CDBG
+ printf ("i2c_wait: unfinished\n");
+#endif
+ return -1;
+ }
+
+ if (write == I2C_WRITE && (csr & MPC107_CSR_RXAK)) {
+#ifdef I2CDBG
+ printf ("i2c_wait: No RXACK\n");
+#endif
+ return -1;
+ }
+
+ return 0;
+ } while (get_timer (timeval) < TIMEOUT);
+
+#ifdef I2CDBG
+ printf ("i2c_wait: timed out\n");
+#endif
+ return -1;
+}
+
+static __inline__ int i2c_write_addr (u8 dev, u8 dir, int rsta)
+{
+ writel (MPC107_CCR_MEN | MPC107_CCR_MSTA | MPC107_CCR_MTX |
+ (rsta ? MPC107_CCR_RSTA : 0), I2CCCR);
+
+ writel ((dev << 1) | dir, I2CCDR);
+
+ if (i2c_wait (I2C_WRITE) < 0)
+ return 0;
+
+ return 1;
+}
+
+static __inline__ int __i2c_write (u8 * data, int length)
+{
+ int i;
+
+ writel (MPC107_CCR_MEN | MPC107_CCR_MSTA | MPC107_CCR_MTX, I2CCCR);
+
+ for (i = 0; i < length; i++) {
+ writel (data[i], I2CCDR);
+
+ if (i2c_wait (I2C_WRITE) < 0)
+ break;
+ }
+
+ return i;
+}
+
+static __inline__ int __i2c_read (u8 * data, int length)
+{
+ int i;
+
+ writel (MPC107_CCR_MEN | MPC107_CCR_MSTA |
+ ((length == 1) ? MPC107_CCR_TXAK : 0), I2CCCR);
+
+ /* dummy read */
+ readl (I2CCDR);
+
+ for (i = 0; i < length; i++) {
+ if (i2c_wait (I2C_READ) < 0)
+ break;
+
+ /* Generate ack on last next to last byte */
+ if (i == length - 2)
+ writel (MPC107_CCR_MEN | MPC107_CCR_MSTA |
+ MPC107_CCR_TXAK, I2CCCR);
+
+ /* Generate stop on last byte */
+ if (i == length - 1)
+ writel (MPC107_CCR_MEN | MPC107_CCR_TXAK, I2CCCR);
+
+ data[i] = readl (I2CCDR);
+ }
+
+ return i;
+}
+
+int i2c_read (u8 dev, uint addr, int alen, u8 * data, int length)
+{
+ int i = 0;
+ u8 *a = (u8 *) & addr;
+
+ if (i2c_wait4bus () < 0)
+ goto exit;
+
+ if (i2c_write_addr (dev, I2C_WRITE, 0) == 0)
+ goto exit;
+
+ if (__i2c_write (&a[4 - alen], alen) != alen)
+ goto exit;
+
+ if (i2c_write_addr (dev, I2C_READ, 1) == 0)
+ goto exit;
+
+ i = __i2c_read (data, length);
+
+exit:
+ writel (MPC107_CCR_MEN, I2CCCR);
+
+ return !(i == length);
+}
+
+int i2c_write (u8 dev, uint addr, int alen, u8 * data, int length)
+{
+ int i = 0;
+ u8 *a = (u8 *) & addr;
+
+ if (i2c_wait4bus () < 0)
+ goto exit;
+
+ if (i2c_write_addr (dev, I2C_WRITE, 0) == 0)
+ goto exit;
+
+ if (__i2c_write (&a[4 - alen], alen) != alen)
+ goto exit;
+
+ i = __i2c_write (data, length);
+
+exit:
+ writel (MPC107_CCR_MEN, I2CCCR);
+
+ return !(i == length);
+}
+
+int i2c_probe (uchar chip)
+{
+ int tmp;
+
+ /*
+ * Try to read the first location of the chip. The underlying
+ * driver doesn't appear to support sending just the chip address
+ * and looking for an <ACK> back.
+ */
+ udelay (10000);
+ return i2c_read (chip, 0, 1, (uchar *) &tmp, 1);
+}
+
+#endif /* CONFIG_HARD_I2C */
diff --git a/arch/powerpc/cpu/mpc824x/drivers/i2c_export.h b/arch/powerpc/cpu/mpc824x/drivers/i2c_export.h
new file mode 100644
index 0000000..6264d18
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/drivers/i2c_export.h
@@ -0,0 +1,103 @@
+#ifndef I2C_EXPORT_H
+#define I2C_EXPORT_H
+
+/****************************************************
+ *
+ * Copyright Motrola 1999
+ *
+ ****************************************************/
+
+/* These are the defined return values for the I2C_do_transaction function.
+ * Any non-zero value indicates failure. Failure modes can be added for
+ * more detailed error reporting.
+ */
+typedef enum _i2c_status
+{
+ I2C_SUCCESS = 0,
+ I2C_ERROR,
+} I2C_Status;
+
+/* These are the defined tasks for I2C_do_transaction.
+ * Modes for SLAVE_RCV and SLAVE_XMIT will be added.
+ */
+typedef enum _i2c_transaction_mode
+{
+ I2C_MASTER_RCV = 0,
+ I2C_MASTER_XMIT = 1,
+} I2C_TRANSACTION_MODE;
+
+typedef enum _i2c_interrupt_mode
+{
+ I2C_INT_DISABLE = 0,
+ I2C_INT_ENABLE = 1,
+} I2C_INTERRUPT_MODE;
+
+typedef enum _i2c_stop
+{
+ I2C_NO_STOP = 0,
+ I2C_STOP = 1,
+} I2C_STOP_MODE;
+
+typedef enum _i2c_restart
+{
+ I2C_NO_RESTART = 0,
+ I2C_RESTART = 1,
+} I2C_RESTART_MODE;
+
+/******************** App. API ********************
+ * The application API is for user level application
+ * to use the functionality provided by I2C driver.
+ * This is a "generic" I2C interface, it should contain
+ * nothing specific to the Kahlua implementation.
+ * Only the generic functions are exported by the library.
+ *
+ * Note: Its App.s responsibility to swap the data
+ * byte. In our API, we just transfer whatever
+ * we are given
+ **************************************************/
+
+
+/* Initialize I2C unit with the following:
+ * driver's slave address
+ * interrupt enabled
+ * optional pointer to application layer print function
+ *
+ * These parameters may be added:
+ * desired clock rate
+ * digital filter frequency sampling rate
+ *
+ * This function must be called before I2C unit can be used.
+ */
+extern I2C_Status I2C_Initialize(
+ unsigned char addr, /* driver's I2C slave address */
+ I2C_INTERRUPT_MODE en_int, /* 1 - enable I2C interrupt
+ * 0 - disable I2C interrupt
+ */
+ int (*app_print_function)(char *,...)); /* pointer to optional "printf"
+ * provided by application
+ */
+
+/* Perform the given I2C transaction, only MASTER_XMIT and MASTER_RCV
+ * are implemented. Both are only in polling mode.
+ *
+ * en_int controls interrupt/polling mode
+ * act is the type of transaction
+ * addr is the I2C address of the slave device
+ * len is the length of data to send or receive
+ * buffer is the address of the data buffer
+ * stop = I2C_NO_STOP, don't signal STOP at end of transaction
+ * I2C_STOP, signal STOP at end of transaction
+ * retry is the timeout retry value, currently ignored
+ * rsta = I2C_NO_RESTART, this is not continuation of existing transaction
+ * I2C_RESTART, this is a continuation of existing transaction
+ */
+extern I2C_Status I2C_do_transaction( I2C_INTERRUPT_MODE en_int,
+ I2C_TRANSACTION_MODE act,
+ unsigned char i2c_addr,
+ unsigned char data_addr,
+ int len,
+ char *buffer,
+ I2C_STOP_MODE stop,
+ int retry,
+ I2C_RESTART_MODE rsta);
+#endif
diff --git a/arch/powerpc/cpu/mpc824x/interrupts.c b/arch/powerpc/cpu/mpc824x/interrupts.c
new file mode 100644
index 0000000..139c52c
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/interrupts.c
@@ -0,0 +1,93 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Rob Taylor, Flying Pig Systems. robt@flyingpig.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc824x.h>
+#include <asm/processor.h>
+#include <asm/pci_io.h>
+#include <commproc.h>
+#include "drivers/epic.h"
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+ *decrementer_count = (get_bus_freq (0) / 4) / CONFIG_SYS_HZ;
+
+ /*
+ * It's all broken at the moment and I currently don't need
+ * interrupts. If you want to fix it, have a look at the epic
+ * drivers in dink32 v12. They do everthing and Motorola said
+ * I could use the dink source in this project as long as
+ * copyright notices remain intact.
+ */
+
+ epicInit (EPIC_DIRECT_IRQ, 0);
+ /* EPIC won't generate INT unless Current Task Pri < 15 */
+ epicCurTaskPrioSet(0);
+
+ return (0);
+}
+
+/****************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt (struct pt_regs *regs)
+{
+ register unsigned long temp;
+
+ pci_readl (CONFIG_SYS_EUMB_ADDR + EPIC_PROC_INT_ACK_REG, temp);
+ sync (); /* i'm not convinced this is needed, but dink source has it */
+ temp &= 0xff; /*get vector */
+
+ /*TODO: handle them -... */
+ epicEOI ();
+}
+
+/****************************************************************************/
+
+/*
+ * blank int handlers.
+ */
+
+void
+irq_install_handler (int vec, interrupt_handler_t * handler, void *arg)
+{
+}
+
+void irq_free_handler (int vec)
+{
+
+}
+
+/*TODO: some handlers for winbond and 87308 interrupts
+ and what about generic pci inteerupts?
+ vga?
+ */
+
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+ /* nothing to do here */
+ return;
+}
diff --git a/arch/powerpc/cpu/mpc824x/pci.c b/arch/powerpc/cpu/mpc824x/pci.c
new file mode 100644
index 0000000..72aaec7
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/pci.c
@@ -0,0 +1,78 @@
+/*
+ * arch/powerpc/kernel/mpc10x_common.c
+ *
+ * Common routines for the Motorola SPS MPC106, MPC107 and MPC8240 Host bridge,
+ * Mem ctlr, EPIC, etc.
+ *
+ * Author: Mark A. Greer
+ * mgreer@mvista.com
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_PCI
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+#include <mpc824x.h>
+
+void pci_mpc824x_init (struct pci_controller *hose)
+{
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ /* System memory space */
+ pci_set_region(hose->regions + 0,
+ CHRP_PCI_MEMORY_BUS,
+ CHRP_PCI_MEMORY_PHYS,
+ CHRP_PCI_MEMORY_SIZE,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ /* PCI memory space */
+ pci_set_region(hose->regions + 1,
+ CHRP_PCI_MEM_BUS,
+ CHRP_PCI_MEM_PHYS,
+ CHRP_PCI_MEM_SIZE,
+ PCI_REGION_MEM);
+
+ /* ISA/PCI memory space */
+ pci_set_region(hose->regions + 2,
+ CHRP_ISA_MEM_BUS,
+ CHRP_ISA_MEM_PHYS,
+ CHRP_ISA_MEM_SIZE,
+ PCI_REGION_MEM);
+
+ /* PCI I/O space */
+ pci_set_region(hose->regions + 3,
+ CHRP_PCI_IO_BUS,
+ CHRP_PCI_IO_PHYS,
+ CHRP_PCI_IO_SIZE,
+ PCI_REGION_IO);
+
+ /* ISA/PCI I/O space */
+ pci_set_region(hose->regions + 4,
+ CHRP_ISA_IO_BUS,
+ CHRP_ISA_IO_PHYS,
+ CHRP_ISA_IO_SIZE,
+ PCI_REGION_IO);
+
+ hose->region_count = 5;
+
+ pci_setup_indirect(hose,
+ CHRP_REG_ADDR,
+ CHRP_REG_DATA);
+
+ pci_register_hose(hose);
+
+ hose->last_busno = pci_hose_scan(hose);
+}
+
+#endif
diff --git a/arch/powerpc/cpu/mpc824x/speed.c b/arch/powerpc/cpu/mpc824x/speed.c
new file mode 100644
index 0000000..fdcb972
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/speed.c
@@ -0,0 +1,118 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002
+ * Gregory E. Allen, gallen@arlut.utexas.edu
+ * Applied Research Laboratories, The University of Texas at Austin
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc824x.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* ------------------------------------------------------------------------- */
+/* NOTE: This describes the proper use of this file.
+ *
+ * CONFIG_SYS_CLK_FREQ should be defined as the input frequency on
+ * PCI_SYNC_IN .
+ *
+ * CONFIG_PLL_PCI_TO_MEM_MULTIPLIER is only required on MPC8240
+ * boards. It should be defined as the PCI to Memory Multiplier as
+ * documented in the MPC8240 Hardware Specs.
+ *
+ * Other mpc824x boards don't need CONFIG_PLL_PCI_TO_MEM_MULTIPLIER
+ * because they can determine it from the PCR.
+ *
+ * Gary Milliorn <gary.milliorn@motorola.com> (who should know since
+ * he designed the Sandpoint) told us that the PCR is not in all revs
+ * of the MPC8240 CPU, so it's not guaranteeable and we cannot do
+ * away with CONFIG_PLL_PCI_TO_MEM_MULTIPLIER altogether.
+ */
+/* ------------------------------------------------------------------------- */
+
+/* This gives the PCI to Memory multiplier times 10 */
+/* The index is the value of PLL_CFG[0:4] */
+/* This is documented in the MPC8240/5 Hardware Specs */
+
+short pll_pci_to_mem_multiplier[] = {
+#if defined(CONFIG_MPC8240)
+ 30, 30, 10, 10, 20, 10, 0, 10,
+ 10, 0, 20, 0, 20, 0, 20, 0,
+ 30, 0, 15, 0, 20, 0, 20, 0,
+ 25, 0, 10, 0, 15, 15, 0, 0,
+#elif defined(CONFIG_MPC8245)
+ 30, 30, 10, 10, 20, 10, 10, 10,
+ 10, 20, 20, 15, 20, 15, 20, 30,
+ 30, 40, 15, 40, 20, 25, 20, 40,
+ 25, 20, 10, 20, 15, 15, 15, 0,
+#else
+#error Specific type of MPC824x must be defined (i.e. CONFIG_MPC8240)
+#endif
+};
+
+#define CU824_PLL_STATE_REG 0xFE80002F
+#define PCR 0x800000E2
+
+/* ------------------------------------------------------------------------- */
+
+/* compute the memory bus clock frequency */
+ulong get_bus_freq (ulong dummy)
+{
+ unsigned char pll_cfg;
+#if defined(CONFIG_MPC8240) && !defined(CONFIG_CU824)
+ return (CONFIG_SYS_CLK_FREQ) * (CONFIG_PLL_PCI_TO_MEM_MULTIPLIER);
+#elif defined(CONFIG_CU824)
+ pll_cfg = *(volatile unsigned char *) (CU824_PLL_STATE_REG);
+ pll_cfg &= 0x1f;
+#else
+ CONFIG_READ_BYTE(PCR, pll_cfg);
+ pll_cfg = (pll_cfg >> 3) & 0x1f;
+#endif
+ return ((CONFIG_SYS_CLK_FREQ) * pll_pci_to_mem_multiplier[pll_cfg] + 5) / 10;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+/* This gives the Memory to CPU Core multiplier times 10 */
+/* The index is the value of PLLRATIO in HID1 */
+/* This is documented in the MPC8240 Hardware Specs */
+/* This is not documented for MPC8245 ? FIXME */
+short pllratio_to_factor[] = {
+ 0, 0, 0, 10, 20, 20, 25, 45,
+ 30, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 10, 0, 0, 0, 45,
+ 30, 0, 40, 0, 0, 0, 35, 0,
+};
+
+/* compute the CPU and memory bus clock frequencies */
+int get_clocks (void)
+{
+ uint hid1 = mfspr(HID1);
+ hid1 = (hid1 >> (32-5)) & 0x1f;
+ gd->cpu_clk = (pllratio_to_factor[hid1] * get_bus_freq(0) + 5)
+ / 10;
+ gd->bus_clk = get_bus_freq(0);
+ return (0);
+}
diff --git a/arch/powerpc/cpu/mpc824x/start.S b/arch/powerpc/cpu/mpc824x/start.S
new file mode 100644
index 0000000..0b9d898
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/start.S
@@ -0,0 +1,745 @@
+/*
+ * Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2000,2001,2002 Wolfgang Denk <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* U-Boot - Startup Code for PowerPC based Embedded Boards
+ *
+ *
+ * The processor starts at 0x00000100 and the code is executed
+ * from flash. The code is organized to be at an other address
+ * in memory, but as long we don't jump around before relocating.
+ * board_init lies at a quite high address and when the cpu has
+ * jumped there, everything is ok.
+ * This works because the cpu gives the FLASH (CS0) the whole
+ * address space at startup, and board_init lies as a echo of
+ * the flash somewhere up there in the memorymap.
+ *
+ * board_init will change CS0 to be positioned at the correct
+ * address and (s)dram will be positioned at address 0
+ */
+#include <asm-offsets.h>
+#include <config.h>
+#include <mpc824x.h>
+#include <version.h>
+
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+#include <asm/u-boot.h>
+
+/* We don't want the MMU yet.
+*/
+#undef MSR_KERNEL
+/* FP, Machine Check and Recoverable Interr. */
+#define MSR_KERNEL ( MSR_FP | MSR_ME | MSR_RI )
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+ START_GOT
+ GOT_ENTRY(_GOT2_TABLE_)
+ GOT_ENTRY(_FIXUP_TABLE_)
+
+ GOT_ENTRY(_start)
+ GOT_ENTRY(_start_of_vectors)
+ GOT_ENTRY(_end_of_vectors)
+ GOT_ENTRY(transfer_to_handler)
+
+ GOT_ENTRY(__init_end)
+ GOT_ENTRY(__bss_end)
+ GOT_ENTRY(__bss_start)
+#if defined(CONFIG_FADS)
+ GOT_ENTRY(environment)
+#endif
+ END_GOT
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+ .text
+ .long 0x27051956 /* U-Boot Magic Number */
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION_STRING, "\0"
+
+ . = EXC_OFF_SYS_RESET
+ .globl _start
+_start:
+ /* Initialize machine status; enable machine check interrupt */
+ /*----------------------------------------------------------------------*/
+ li r3, MSR_KERNEL /* Set FP, ME, RI flags */
+ mtmsr r3
+ mtspr SRR1, r3 /* Make SRR1 match MSR */
+
+ addis r0,0,0x0000 /* lets make sure that r0 is really 0 */
+ mtspr HID0, r0 /* disable I and D caches */
+
+ mfspr r3, ICR /* clear Interrupt Cause Register */
+
+ mfmsr r3 /* turn off address translation */
+ addis r4,0,0xffff
+ ori r4,r4,0xffcf
+ and r3,r3,r4
+ mtmsr r3
+ isync
+ sync /* the MMU should be off... */
+
+
+in_flash:
+ /*
+ * Setup BATs - cannot be done in C since we don't have a stack yet
+ */
+ bl setup_bats
+
+ /* Enable MMU.
+ */
+ mfmsr r3
+ ori r3, r3, (MSR_IR | MSR_DR)
+ mtmsr r3
+
+ /* Enable and invalidate data cache.
+ */
+ mfspr r3, HID0
+ mr r2, r3
+ ori r3, r3, HID0_DCE | HID0_DCI
+ ori r2, r2, HID0_DCE
+ sync
+ mtspr HID0, r3
+ mtspr HID0, r2
+ sync
+
+ /* Allocate Initial RAM in data cache.
+ */
+ lis r3, CONFIG_SYS_INIT_RAM_ADDR@h
+ ori r3, r3, CONFIG_SYS_INIT_RAM_ADDR@l
+ li r2, 128
+ mtctr r2
+1:
+ dcbz r0, r3
+ addi r3, r3, 32
+ bdnz 1b
+
+ /* Lock way0 in data cache.
+ */
+ mfspr r3, 1011
+ lis r2, 0xffff
+ ori r2, r2, 0xff1f
+ and r3, r3, r2
+ ori r3, r3, 0x0080
+ sync
+ mtspr 1011, r3
+
+ /*
+ * Thisk the stack pointer *somewhere* sensible. Doesnt
+ * matter much where as we'll move it when we relocate
+ */
+ lis r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@h
+ ori r1, r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@l
+
+ li r0, 0 /* Make room for stack frame header and */
+ stwu r0, -4(r1) /* clear final stack frame so that */
+ stwu r0, -4(r1) /* stack backtraces terminate cleanly */
+
+ /* let the C-code set up the rest */
+ /* */
+ /* Be careful to keep code relocatable ! */
+ /*----------------------------------------------------------------------*/
+
+ GET_GOT /* initialize GOT access */
+
+ /* r3: IMMR */
+ bl cpu_init_f /* run low-level CPU init code (from Flash) */
+
+ bl board_init_f /* run 1st part of board init code (from Flash) */
+
+ /* NOTREACHED - board_init_f() does not return */
+
+
+ .globl _start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+ STD_EXCEPTION(EXC_OFF_MACH_CHCK, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. "Never" generated on the 860. */
+ STD_EXCEPTION(EXC_OFF_DATA_STOR, DataStorage, UnknownException)
+
+/* Instruction Storage exception. "Never" generated on the 860. */
+ STD_EXCEPTION(EXC_OFF_INS_STOR, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+ STD_EXCEPTION(EXC_OFF_EXTERNAL, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+ . = EXC_OFF_ALIGN
+Alignment:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+ . = EXC_OFF_PROGRAM
+ProgramCheck:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+ MSR_KERNEL, COPY_EE)
+
+ /* No FPU on MPC8xx. This exception is not supposed to happen.
+ */
+ STD_EXCEPTION(EXC_OFF_FPUNAVAIL, FPUnavailable, UnknownException)
+
+ /* I guess we could implement decrementer, and may have
+ * to someday for timekeeping.
+ */
+ STD_EXCEPTION(EXC_OFF_DECR, Decrementer, timer_interrupt)
+ STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+ STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+ STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+
+ STD_EXCEPTION(EXC_OFF_TRACE, SingleStep, UnknownException)
+
+ STD_EXCEPTION(EXC_OFF_FPUNASSIST, Trap_0e, UnknownException)
+ STD_EXCEPTION(EXC_OFF_PMI, Trap_0f, UnknownException)
+
+ STD_EXCEPTION(EXC_OFF_ITME, InstructionTransMiss, UnknownException)
+ STD_EXCEPTION(EXC_OFF_DLTME, DataLoadTransMiss, UnknownException)
+ STD_EXCEPTION(EXC_OFF_DSTME, DataStoreTransMiss, UnknownException)
+ STD_EXCEPTION(EXC_OFF_IABE, InstructionBreakpoint, DebugException)
+ STD_EXCEPTION(EXC_OFF_SMIE, SysManageInt, UnknownException)
+ STD_EXCEPTION(0x1500, Reserved5, UnknownException)
+ STD_EXCEPTION(0x1600, Reserved6, UnknownException)
+ STD_EXCEPTION(0x1700, Reserved7, UnknownException)
+ STD_EXCEPTION(0x1800, Reserved8, UnknownException)
+ STD_EXCEPTION(0x1900, Reserved9, UnknownException)
+ STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
+ STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
+ STD_EXCEPTION(0x1c00, ReservedC, UnknownException)
+ STD_EXCEPTION(0x1d00, ReservedD, UnknownException)
+ STD_EXCEPTION(0x1e00, ReservedE, UnknownException)
+ STD_EXCEPTION(0x1f00, ReservedF, UnknownException)
+
+ STD_EXCEPTION(EXC_OFF_RMTE, RunModeTrace, UnknownException)
+
+ .globl _end_of_vectors
+_end_of_vectors:
+
+
+ . = 0x3000
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+ .globl transfer_to_handler
+transfer_to_handler:
+ stw r22,_NIP(r21)
+ lis r22,MSR_POW@h
+ andc r23,r23,r22
+ stw r23,_MSR(r21)
+ SAVE_GPR(7, r21)
+ SAVE_4GPRS(8, r21)
+ SAVE_8GPRS(12, r21)
+ SAVE_8GPRS(24, r21)
+#if 0
+ andi. r23,r23,MSR_PR
+ mfspr r23,SPRG3 /* if from user, fix up tss.regs */
+ beq 2f
+ addi r24,r1,STACK_FRAME_OVERHEAD
+ stw r24,PT_REGS(r23)
+2: addi r2,r23,-TSS /* set r2 to current */
+ tovirt(r2,r2,r23)
+#endif
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ mtspr SPRG2,r22 /* r1 is now kernel sp */
+#if 0
+ addi r24,r2,TASK_STRUCT_SIZE /* check for kernel stack overflow */
+ cmplw 0,r1,r2
+ cmplw 1,r1,r24
+ crand 1,1,4
+ bgt stack_ovf /* if r2 < r1 < r2+TASK_STRUCT_SIZE */
+#endif
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ ori r20,r20,0x30 /* enable IR, DR */
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
+
+int_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+
+/* Cache functions.
+*/
+ .globl icache_enable
+icache_enable:
+ mfspr r5,HID0 /* turn on the I cache. */
+ ori r5,r5,0x8800 /* Instruction cache only! */
+ addis r6,0,0xFFFF
+ ori r6,r6,0xF7FF
+ and r6,r5,r6 /* clear the invalidate bit */
+ sync
+ mtspr HID0,r5
+ mtspr HID0,r6
+ isync
+ sync
+ blr
+
+ .globl icache_disable
+icache_disable:
+ mfspr r5,HID0
+ addis r6,0,0xFFFF
+ ori r6,r6,0x7FFF
+ and r5,r5,r6
+ sync
+ mtspr HID0,r5
+ isync
+ sync
+ blr
+
+ .globl icache_status
+icache_status:
+ mfspr r3, HID0
+ srwi r3, r3, 15 /* >>15 & 1=> select bit 16 */
+ andi. r3, r3, 1
+ blr
+
+ .globl dcache_enable
+dcache_enable:
+ mfspr r5,HID0 /* turn on the D cache. */
+ ori r5,r5,0x4400 /* Data cache only! */
+ mfspr r4, PVR /* read PVR */
+ srawi r3, r4, 16 /* shift off the least 16 bits */
+ cmpi 0, 0, r3, 0xC /* Check for Max pvr */
+ bne NotMax
+ ori r5,r5,0x0040 /* setting the DCFA bit, for Max rev 1 errata */
+NotMax:
+ addis r6,0,0xFFFF
+ ori r6,r6,0xFBFF
+ and r6,r5,r6 /* clear the invalidate bit */
+ sync
+ mtspr HID0,r5
+ mtspr HID0,r6
+ isync
+ sync
+ blr
+
+ .globl dcache_disable
+dcache_disable:
+ mfspr r5,HID0
+ addis r6,0,0xFFFF
+ ori r6,r6,0xBFFF
+ and r5,r5,r6
+ sync
+ mtspr HID0,r5
+ isync
+ sync
+ blr
+
+ .globl dcache_status
+dcache_status:
+ mfspr r3, HID0
+ srwi r3, r3, 14 /* >>14 & 1=> select bit 17 */
+ andi. r3, r3, 1
+ blr
+
+ .globl dc_read
+dc_read:
+/*TODO : who uses this, what should it do?
+*/
+ blr
+
+
+ .globl get_pvr
+get_pvr:
+ mfspr r3, PVR
+ blr
+
+
+/*------------------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+ .globl relocate_code
+relocate_code:
+
+ mr r1, r3 /* Set new stack pointer */
+ mr r9, r4 /* Save copy of Global Data pointer */
+ mr r10, r5 /* Save copy of Destination Address */
+
+ GET_GOT
+ mr r3, r5 /* Destination Address */
+#ifdef CONFIG_SYS_RAMBOOT
+ lis r4, CONFIG_SYS_SDRAM_BASE@h /* Source Address */
+ ori r4, r4, CONFIG_SYS_SDRAM_BASE@l
+#else
+ lis r4, CONFIG_SYS_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CONFIG_SYS_MONITOR_BASE@l
+#endif
+ lwz r5, GOT(__init_end)
+ sub r5, r5, r4
+ li r6, CONFIG_SYS_CACHELINE_SIZE /* Cache Line Size */
+
+ /*
+ * Fix GOT pointer:
+ *
+ * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+ *
+ * Offset:
+ */
+ sub r15, r10, r4
+
+ /* First our own GOT */
+ add r12, r12, r15
+ /* the the one used by the C code */
+ add r30, r30, r15
+
+ /*
+ * Now relocate code
+ */
+
+ cmplw cr1,r3,r4
+ addi r0,r5,3
+ srwi. r0,r0,2
+ beq cr1,4f /* In place copy is not necessary */
+ beq 7f /* Protect against 0 count */
+ mtctr r0
+ bge cr1,2f
+
+ la r8,-4(r4)
+ la r7,-4(r3)
+1: lwzu r0,4(r8)
+ stwu r0,4(r7)
+ bdnz 1b
+ b 4f
+
+2: slwi r0,r0,2
+ add r8,r4,r0
+ add r7,r3,r0
+3: lwzu r0,-4(r8)
+ stwu r0,-4(r7)
+ bdnz 3b
+
+4:
+/* Unlock the data cache and invalidate locked area */
+ xor r0, r0, r0
+ mtspr 1011, r0
+ lis r4, CONFIG_SYS_INIT_RAM_ADDR@h
+ ori r4, r4, CONFIG_SYS_INIT_RAM_ADDR@l
+ li r0, 128
+ mtctr r0
+41:
+ dcbi r0, r4
+ addi r4, r4, 32
+ bdnz 41b
+
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+ cmpwi r6,0
+ add r5,r3,r5
+ beq 7f /* Always flush prefetch queue in any case */
+ subi r0,r6,1
+ andc r3,r3,r0
+ mr r4,r3
+5: dcbst 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 5b
+ sync /* Wait for all dcbst to complete on bus */
+ mr r4,r3
+6: icbi 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 6b
+7: sync /* Wait for all icbi to complete on bus */
+ isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+ addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+ mtlr r0
+ blr
+
+in_ram:
+
+ /*
+ * Relocation Function, r12 point to got2+0x8000
+ *
+ * Adjust got2 pointers, no need to check for 0, this code
+ * already puts a few entries in the table.
+ */
+ li r0,__got2_entries@sectoff@l
+ la r3,GOT(_GOT2_TABLE_)
+ lwz r11,GOT(_GOT2_TABLE_)
+ mtctr r0
+ sub r11,r3,r11
+ addi r3,r3,-4
+1: lwzu r0,4(r3)
+ cmpwi r0,0
+ beq- 2f
+ add r0,r0,r11
+ stw r0,0(r3)
+2: bdnz 1b
+
+ /*
+ * Now adjust the fixups and the pointers to the fixups
+ * in case we need to move ourselves again.
+ */
+ li r0,__fixup_entries@sectoff@l
+ lwz r3,GOT(_FIXUP_TABLE_)
+ cmpwi r0,0
+ mtctr r0
+ addi r3,r3,-4
+ beq 4f
+3: lwzu r4,4(r3)
+ lwzux r0,r4,r11
+ cmpwi r0,0
+ add r0,r0,r11
+ stw r4,0(r3)
+ beq- 5f
+ stw r0,0(r4)
+5: bdnz 3b
+4:
+clear_bss:
+ /*
+ * Now clear BSS segment
+ */
+ lwz r3,GOT(__bss_start)
+ lwz r4,GOT(__bss_end)
+
+ cmplw 0, r3, r4
+ beq 6f
+
+ li r0, 0
+5:
+ stw r0, 0(r3)
+ addi r3, r3, 4
+ cmplw 0, r3, r4
+ blt 5b
+6:
+
+ mr r3, r9 /* Global Data pointer */
+ mr r4, r10 /* Destination Address */
+ bl board_init_r
+
+ /*
+ * Copy exception vector code to low memory
+ *
+ * r3: dest_addr
+ * r7: source address, r8: end address, r9: target address
+ */
+ .globl trap_init
+trap_init:
+ mflr r4 /* save link register */
+ GET_GOT
+ lwz r7, GOT(_start)
+ lwz r8, GOT(_end_of_vectors)
+
+ li r9, 0x100 /* reset vector always at 0x100 */
+
+ cmplw 0, r7, r8
+ bgelr /* return if r7>=r8 - just in case */
+1:
+ lwz r0, 0(r7)
+ stw r0, 0(r9)
+ addi r7, r7, 4
+ addi r9, r9, 4
+ cmplw 0, r7, r8
+ bne 1b
+
+ /*
+ * relocate `hdlr' and `int_return' entries
+ */
+ li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+ li r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 2b
+
+ li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+ li r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 3b
+
+ li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+ li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 4b
+
+ mtlr r4 /* restore link register */
+ blr
+
+ /* Setup the BAT registers.
+ */
+setup_bats:
+ lis r4, CONFIG_SYS_IBAT0L@h
+ ori r4, r4, CONFIG_SYS_IBAT0L@l
+ lis r3, CONFIG_SYS_IBAT0U@h
+ ori r3, r3, CONFIG_SYS_IBAT0U@l
+ mtspr IBAT0L, r4
+ mtspr IBAT0U, r3
+ isync
+
+ lis r4, CONFIG_SYS_DBAT0L@h
+ ori r4, r4, CONFIG_SYS_DBAT0L@l
+ lis r3, CONFIG_SYS_DBAT0U@h
+ ori r3, r3, CONFIG_SYS_DBAT0U@l
+ mtspr DBAT0L, r4
+ mtspr DBAT0U, r3
+ isync
+
+ lis r4, CONFIG_SYS_IBAT1L@h
+ ori r4, r4, CONFIG_SYS_IBAT1L@l
+ lis r3, CONFIG_SYS_IBAT1U@h
+ ori r3, r3, CONFIG_SYS_IBAT1U@l
+ mtspr IBAT1L, r4
+ mtspr IBAT1U, r3
+ isync
+
+ lis r4, CONFIG_SYS_DBAT1L@h
+ ori r4, r4, CONFIG_SYS_DBAT1L@l
+ lis r3, CONFIG_SYS_DBAT1U@h
+ ori r3, r3, CONFIG_SYS_DBAT1U@l
+ mtspr DBAT1L, r4
+ mtspr DBAT1U, r3
+ isync
+
+ lis r4, CONFIG_SYS_IBAT2L@h
+ ori r4, r4, CONFIG_SYS_IBAT2L@l
+ lis r3, CONFIG_SYS_IBAT2U@h
+ ori r3, r3, CONFIG_SYS_IBAT2U@l
+ mtspr IBAT2L, r4
+ mtspr IBAT2U, r3
+ isync
+
+ lis r4, CONFIG_SYS_DBAT2L@h
+ ori r4, r4, CONFIG_SYS_DBAT2L@l
+ lis r3, CONFIG_SYS_DBAT2U@h
+ ori r3, r3, CONFIG_SYS_DBAT2U@l
+ mtspr DBAT2L, r4
+ mtspr DBAT2U, r3
+ isync
+
+ lis r4, CONFIG_SYS_IBAT3L@h
+ ori r4, r4, CONFIG_SYS_IBAT3L@l
+ lis r3, CONFIG_SYS_IBAT3U@h
+ ori r3, r3, CONFIG_SYS_IBAT3U@l
+ mtspr IBAT3L, r4
+ mtspr IBAT3U, r3
+ isync
+
+ lis r4, CONFIG_SYS_DBAT3L@h
+ ori r4, r4, CONFIG_SYS_DBAT3L@l
+ lis r3, CONFIG_SYS_DBAT3U@h
+ ori r3, r3, CONFIG_SYS_DBAT3U@l
+ mtspr DBAT3L, r4
+ mtspr DBAT3U, r3
+ isync
+
+ /* Invalidate TLBs.
+ * -> for (val = 0; val < 0x20000; val+=0x1000)
+ * -> tlbie(val);
+ */
+ lis r3, 0
+ lis r5, 2
+
+1:
+ tlbie r3
+ addi r3, r3, 0x1000
+ cmp 0, 0, r3, r5
+ blt 1b
+
+ blr
diff --git a/arch/powerpc/cpu/mpc824x/traps.c b/arch/powerpc/cpu/mpc824x/traps.c
new file mode 100644
index 0000000..9bcdd8f
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/traps.c
@@ -0,0 +1,210 @@
+/*
+ * linux/arch/powerpc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM 0x00400000
+
+/*
+ * Trap & Exception support
+ */
+
+static void print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ printf("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ printf("\n");
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *)*sp;
+ }
+ printf("\n");
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ int i;
+
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+ regs->msr&MSR_IR ? 1 : 0,
+ regs->msr&MSR_DR ? 1 : 0);
+
+ printf("\n");
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0)
+ {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7)
+ {
+ printf("\n");
+ }
+ }
+}
+
+
+static void _exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup;
+
+ /* Probing PCI using config cycles cause this exception
+ * when a device is not present. Catch it and return to
+ * the PCI exception handler.
+ */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ return;
+ }
+
+ printf("Machine check in kernel mode.\n");
+ printf("Caused by (from msr): ");
+ printf("regs %p ",regs);
+ switch( regs->msr & 0x000F0000) {
+ case (0x80000000>>12):
+ printf("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (0x80000000>>13):
+ printf("Transfer error ack signal\n");
+ break;
+ case (0x80000000>>14):
+ printf("Data parity signal\n");
+ break;
+ case (0x80000000>>15):
+ printf("Address parity signal\n");
+ break;
+ default:
+ printf("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("machine check");
+}
+
+void AlignmentException(struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void ProgramCheckException(struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void SoftEmuException(struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Software Emulation Exception");
+}
+
+
+void UnknownException(struct pt_regs *regs)
+{
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+void DebugException(struct pt_regs *regs)
+{
+
+ printf("Debugger trap at @ %lx\n", regs->nip );
+ show_regs(regs);
+#if defined(CONFIG_CMD_BEDBUG)
+ do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading. If not present, return -1, otherwise
+ * return 0.
+ */
+int addr_probe(uint *addr)
+{
+#if 0
+ int retval;
+
+ __asm__ __volatile__( \
+ "1: lwz %0,0(%1)\n" \
+ " eieio\n" \
+ " li %0,0\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,-1\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r" (retval) : "r"(addr));
+
+ return (retval);
+#endif
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc824x/u-boot.lds b/arch/powerpc/cpu/mpc824x/u-boot.lds
new file mode 100644
index 0000000..4590fab
--- /dev/null
+++ b/arch/powerpc/cpu/mpc824x/u-boot.lds
@@ -0,0 +1,92 @@
+/*
+ * (C) Copyright 2001-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ .text :
+ {
+ arch/powerpc/cpu/mpc824x/start.o (.text*)
+ *(.text*)
+ . = ALIGN(16);
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ }
+
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x0FFF) & 0xFFFFF000;
+ _erotext = .;
+ PROVIDE (erotext = .);
+ .reloc :
+ {
+ _GOT2_TABLE_ = .;
+ KEEP(*(.got2))
+ KEEP(*(.got))
+ PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
+ _FIXUP_TABLE_ = .;
+ KEEP(*(.fixup))
+ }
+ __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
+ __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+ .data :
+ {
+ *(.data*)
+ *(.sdata*)
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+
+ . = .;
+
+ . = ALIGN(4);
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+
+ . = .;
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ . = ALIGN(4096);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(4096);
+ __init_end = .;
+
+ __bss_start = .;
+ .bss (NOLOAD) :
+ {
+ *(.bss*)
+ *(.sbss*)
+ *(COMMON)
+ . = ALIGN(4);
+ }
+ __bss_end = . ;
+ PROVIDE (end = .);
+}
diff --git a/arch/powerpc/cpu/mpc8260/Makefile b/arch/powerpc/cpu/mpc8260/Makefile
new file mode 100644
index 0000000..aa8b881
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/Makefile
@@ -0,0 +1,53 @@
+#
+# (C) Copyright 2000-2008
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(CPU).o
+
+START = start.o kgdb.o
+COBJS = traps.o serial_smc.o serial_scc.o cpu.o cpu_init.o speed.o \
+ interrupts.o ether_fcc.o i2c.o commproc.o \
+ bedbug_603e.o pci.o spi.o
+
+COBJS-$(CONFIG_ETHER_ON_SCC) = ether_scc.o
+
+COBJS += $(COBJS-y)
+
+SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
+START := $(addprefix $(obj),$(START))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(call cmd_link_o_target, $(OBJS) $(obj)kgdb.o)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/powerpc/cpu/mpc8260/bedbug_603e.c b/arch/powerpc/cpu/mpc8260/bedbug_603e.c
new file mode 100644
index 0000000..92f8957
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/bedbug_603e.c
@@ -0,0 +1,236 @@
+/*
+ * Bedbug Functions specific to the MPC603e core
+ */
+
+#include <common.h>
+#include <command.h>
+#include <linux/ctype.h>
+#include <bedbug/type.h>
+#include <bedbug/bedbug.h>
+#include <bedbug/regs.h>
+#include <bedbug/ppc.h>
+
+#if defined(CONFIG_CMD_BEDBUG) \
+ && (defined(CONFIG_MPC824X) || defined(CONFIG_MPC8260))
+
+#define MAX_BREAK_POINTS 1
+
+extern CPU_DEBUG_CTX bug_ctx;
+
+void bedbug603e_init __P((void));
+void bedbug603e_do_break __P((cmd_tbl_t*,int,int,char*const[]));
+void bedbug603e_break_isr __P((struct pt_regs*));
+int bedbug603e_find_empty __P((void));
+int bedbug603e_set __P((int,unsigned long));
+int bedbug603e_clear __P((int));
+
+
+/* ======================================================================
+ * Initialize the global bug_ctx structure for the processor. Clear all
+ * of the breakpoints.
+ * ====================================================================== */
+
+void bedbug603e_init( void )
+{
+ int i;
+ /* -------------------------------------------------- */
+
+ bug_ctx.hw_debug_enabled = 0;
+ bug_ctx.stopped = 0;
+ bug_ctx.current_bp = 0;
+ bug_ctx.regs = NULL;
+
+ bug_ctx.do_break = bedbug603e_do_break;
+ bug_ctx.break_isr = bedbug603e_break_isr;
+ bug_ctx.find_empty = bedbug603e_find_empty;
+ bug_ctx.set = bedbug603e_set;
+ bug_ctx.clear = bedbug603e_clear;
+
+ for( i = 1; i <= MAX_BREAK_POINTS; ++i )
+ (*bug_ctx.clear)( i );
+
+ puts ("BEDBUG:ready\n");
+ return;
+} /* bedbug_init_breakpoints */
+
+
+
+/* ======================================================================
+ * Set/clear/show the hardware breakpoint for the 603e. The "off"
+ * string will disable a specific breakpoint. The "show" string will
+ * display the current breakpoints. Otherwise an address will set a
+ * breakpoint at that address. Setting a breakpoint uses the CPU-specific
+ * set routine which will assign a breakpoint number.
+ * ====================================================================== */
+
+void bedbug603e_do_break (cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ long addr; /* Address to break at */
+ int which_bp; /* Breakpoint number */
+ /* -------------------------------------------------- */
+
+ if (argc < 2) {
+ cmd_usage(cmdtp);
+ return;
+ }
+
+ /* Turn off a breakpoint */
+
+ if( strcmp( argv[ 1 ], "off" ) == 0 )
+ {
+ if( bug_ctx.hw_debug_enabled == 0 )
+ {
+ puts ( "No breakpoints enabled\n" );
+ return;
+ }
+
+ which_bp = simple_strtoul( argv[ 2 ], NULL, 10 );
+
+ if( bug_ctx.clear )
+ (*bug_ctx.clear)( which_bp );
+
+ printf( "Breakpoint %d removed\n", which_bp );
+ return;
+ }
+
+ /* Show a list of breakpoints */
+
+ if( strcmp( argv[ 1 ], "show" ) == 0 )
+ {
+ for( which_bp = 1; which_bp <= MAX_BREAK_POINTS; ++which_bp )
+ {
+
+ addr = GET_IABR();
+
+ printf( "Breakpoint [%d]: ", which_bp );
+ if( (addr & 0x00000002) == 0 )
+ puts ( "NOT SET\n" );
+ else
+ disppc( (unsigned char *)(addr & 0xFFFFFFFC), 0, 1, bedbug_puts, F_RADHEX );
+ }
+ return;
+ }
+
+ /* Set a breakpoint at the address */
+
+ if(!(( isdigit( argv[ 1 ][ 0 ] )) ||
+ (( argv[ 1 ][ 0 ] >= 'a' ) && ( argv[ 1 ][ 0 ] <= 'f' )) ||
+ (( argv[ 1 ][ 0 ] >= 'A' ) && ( argv[ 1 ][ 0 ] <= 'F' )))) {
+ cmd_usage(cmdtp);
+ return;
+ }
+
+ addr = simple_strtoul( argv[ 1 ], NULL, 16 );
+
+ if(( bug_ctx.set ) && ( which_bp = (*bug_ctx.set)( 0, addr )) > 0 )
+ {
+ printf( "Breakpoint [%d]: ", which_bp );
+ disppc( (unsigned char *)addr, 0, 1, bedbug_puts, F_RADHEX );
+ }
+
+ return;
+} /* bedbug603e_do_break */
+
+
+
+/* ======================================================================
+ * Handle a breakpoint. Enter a mini main loop. Stay in the loop until
+ * the stopped flag in the debug context is cleared.
+ * ====================================================================== */
+
+void bedbug603e_break_isr( struct pt_regs *regs )
+{
+ unsigned long addr; /* Address stopped at */
+ /* -------------------------------------------------- */
+
+ bug_ctx.current_bp = 1;
+ addr = GET_IABR() & 0xFFFFFFFC;
+
+ bedbug_main_loop( addr, regs );
+ return;
+} /* bedbug603e_break_isr */
+
+
+
+/* ======================================================================
+ * See if the hardware breakpoint is available.
+ * ====================================================================== */
+
+int bedbug603e_find_empty( void )
+{
+ /* -------------------------------------------------- */
+
+ if( (GET_IABR() && 0x00000002) == 0 )
+ return 1;
+
+ return 0;
+} /* bedbug603e_find_empty */
+
+
+
+/* ======================================================================
+ * Set a breakpoint. If 'which_bp' is zero then find an unused breakpoint
+ * number, otherwise reassign the given breakpoint. If hardware debugging
+ * is not enabled, then turn it on via the MSR and DBCR0. Set the break
+ * address in the IABR register.
+ * ====================================================================== */
+
+int bedbug603e_set( int which_bp, unsigned long addr )
+{
+ /* -------------------------------------------------- */
+
+ if(( addr & 0x00000003 ) != 0 )
+ {
+ puts ( "Breakpoints must be on a 32 bit boundary\n" );
+ return 0;
+ }
+
+ /* Only look if which_bp == 0, else use which_bp */
+ if(( bug_ctx.find_empty ) && ( !which_bp ) &&
+ ( which_bp = (*bug_ctx.find_empty)()) == 0 )
+ {
+ puts ( "All breakpoints in use\n" );
+ return 0;
+ }
+
+ if( which_bp < 1 || which_bp > MAX_BREAK_POINTS )
+ {
+ printf( "Invalid break point # %d\n", which_bp );
+ return 0;
+ }
+
+ if( ! bug_ctx.hw_debug_enabled )
+ {
+ bug_ctx.hw_debug_enabled = 1;
+ }
+
+ SET_IABR( addr | 0x00000002 );
+
+ return which_bp;
+} /* bedbug603e_set */
+
+
+
+/* ======================================================================
+ * Disable a specific breakoint by setting the IABR register to zero.
+ * ====================================================================== */
+
+int bedbug603e_clear( int which_bp )
+{
+ /* -------------------------------------------------- */
+
+ if( which_bp < 1 || which_bp > MAX_BREAK_POINTS )
+ {
+ printf( "Invalid break point # (%d)\n", which_bp );
+ return -1;
+ }
+
+ SET_IABR( 0 );
+
+ return 0;
+} /* bedbug603e_clear */
+
+
+/* ====================================================================== */
+#endif
diff --git a/arch/powerpc/cpu/mpc8260/commproc.c b/arch/powerpc/cpu/mpc8260/commproc.c
new file mode 100644
index 0000000..484bd17
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/commproc.c
@@ -0,0 +1,178 @@
+/*
+ * This file is based on "arch/powerpc/8260_io/commproc.c" - here is it's
+ * copyright notice:
+ *
+ * General Purpose functions for the global management of the
+ * 8260 Communication Processor Module.
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
+ * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
+ * 2.3.99 Updates
+ *
+ * In addition to the individual control of the communication
+ * channels, there are a few functions that globally affect the
+ * communication processor.
+ *
+ * Buffer descriptors must be allocated from the dual ported memory
+ * space. The allocator for that is here. When the communication
+ * process is reset, we reclaim the memory available. There is
+ * currently no deallocator for this memory.
+ */
+#include <common.h>
+#include <asm/cpm_8260.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void
+m8260_cpm_reset(void)
+{
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ volatile ulong count;
+
+ /* Reclaim the DP memory for our use.
+ */
+ gd->arch.dp_alloc_base = CPM_DATAONLY_BASE;
+ gd->arch.dp_alloc_top = gd->arch.dp_alloc_base + CPM_DATAONLY_SIZE;
+
+ /*
+ * Reset CPM
+ */
+ immr->im_cpm.cp_cpcr = CPM_CR_RST;
+ count = 0;
+ do { /* Spin until command processed */
+ __asm__ __volatile__ ("eieio");
+ } while ((immr->im_cpm.cp_cpcr & CPM_CR_FLG) && ++count < 1000000);
+
+#ifdef CONFIG_HARD_I2C
+ immr->im_dprambase16[PROFF_I2C_BASE / sizeof(u16)] = 0;
+#endif
+}
+
+/* Allocate some memory from the dual ported ram.
+ * To help protocols with object alignment restrictions, we do that
+ * if they ask.
+ */
+uint
+m8260_cpm_dpalloc(uint size, uint align)
+{
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ uint retloc;
+ uint align_mask, off;
+ uint savebase;
+
+ align_mask = align - 1;
+ savebase = gd->arch.dp_alloc_base;
+
+ off = gd->arch.dp_alloc_base & align_mask;
+ if (off != 0)
+ gd->arch.dp_alloc_base += (align - off);
+
+ if ((off = size & align_mask) != 0)
+ size += align - off;
+
+ if ((gd->arch.dp_alloc_base + size) >= gd->arch.dp_alloc_top) {
+ gd->arch.dp_alloc_base = savebase;
+ panic("m8260_cpm_dpalloc: ran out of dual port ram!");
+ }
+
+ retloc = gd->arch.dp_alloc_base;
+ gd->arch.dp_alloc_base += size;
+
+ memset((void *)&immr->im_dprambase[retloc], 0, size);
+
+ return(retloc);
+}
+
+/* We also own one page of host buffer space for the allocation of
+ * UART "fifos" and the like.
+ */
+uint
+m8260_cpm_hostalloc(uint size, uint align)
+{
+ /* the host might not even have RAM yet - just use dual port RAM */
+ return (m8260_cpm_dpalloc(size, align));
+}
+
+/* Set a baud rate generator. This needs lots of work. There are
+ * eight BRGs, which can be connected to the CPM channels or output
+ * as clocks. The BRGs are in two different block of internal
+ * memory mapped space.
+ * The baud rate clock is the system clock divided by something.
+ * It was set up long ago during the initial boot phase and is
+ * is given to us.
+ * Baud rate clocks are zero-based in the driver code (as that maps
+ * to port numbers). Documentation uses 1-based numbering.
+ */
+#define BRG_INT_CLK gd->arch.brg_clk
+#define BRG_UART_CLK (BRG_INT_CLK / 16)
+
+/* This function is used by UARTs, or anything else that uses a 16x
+ * oversampled clock.
+ */
+void
+m8260_cpm_setbrg(uint brg, uint rate)
+{
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ volatile uint *bp;
+ uint cd = BRG_UART_CLK / rate;
+
+ if ((BRG_UART_CLK % rate) < (rate / 2))
+ cd--;
+ if (brg < 4) {
+ bp = (uint *)&immr->im_brgc1;
+ }
+ else {
+ bp = (uint *)&immr->im_brgc5;
+ brg -= 4;
+ }
+ bp += brg;
+ *bp = (cd << 1) | CPM_BRG_EN;
+}
+
+/* This function is used to set high speed synchronous baud rate
+ * clocks.
+ */
+void
+m8260_cpm_fastbrg(uint brg, uint rate, int div16)
+{
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ volatile uint *bp;
+
+ /* This is good enough to get SMCs running.....
+ */
+ if (brg < 4) {
+ bp = (uint *)&immr->im_brgc1;
+ }
+ else {
+ bp = (uint *)&immr->im_brgc5;
+ brg -= 4;
+ }
+ bp += brg;
+ *bp = (((((BRG_INT_CLK+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN;
+ if (div16)
+ *bp |= CPM_BRG_DIV16;
+}
+
+/* This function is used to set baud rate generators using an external
+ * clock source and 16x oversampling.
+ */
+
+void
+m8260_cpm_extcbrg(uint brg, uint rate, uint extclk, int pinsel)
+{
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ volatile uint *bp;
+
+ if (brg < 4) {
+ bp = (uint *)&immr->im_brgc1;
+ }
+ else {
+ bp = (uint *)&immr->im_brgc5;
+ brg -= 4;
+ }
+ bp += brg;
+ *bp = ((((((extclk/16)+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN;
+ if (pinsel == 0)
+ *bp |= CPM_BRG_EXTC_CLK3_9;
+ else
+ *bp |= CPM_BRG_EXTC_CLK5_15;
+}
diff --git a/arch/powerpc/cpu/mpc8260/config.mk b/arch/powerpc/cpu/mpc8260/config.mk
new file mode 100644
index 0000000..f091fa9
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/config.mk
@@ -0,0 +1,27 @@
+#
+# (C) Copyright 2000-2010
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_RELFLAGS += -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_8260 -DCONFIG_CPM2 -ffixed-r2 \
+ -mstring -mcpu=603e -mmultiple
diff --git a/arch/powerpc/cpu/mpc8260/cpu.c b/arch/powerpc/cpu/mpc8260/cpu.c
new file mode 100644
index 0000000..22e1a23
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/cpu.c
@@ -0,0 +1,337 @@
+/*
+ * (C) Copyright 2000-2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * CPU specific code for the MPC825x / MPC826x / MPC827x / MPC828x
+ *
+ * written or collected and sometimes rewritten by
+ * Magnus Damm <damm@bitsmart.com>
+ *
+ * modified by
+ * Wolfgang Denk <wd@denx.de>
+ *
+ * modified for 8260 by
+ * Murray Jensen <Murray.Jensen@cmst.csiro.au>
+ *
+ * added 8260 masks by
+ * Marius Groeger <mag@sysgo.de>
+ *
+ * added HiP7 (824x/827x/8280) processors support by
+ * Yuli Barcohen <yuli@arabellasw.com>
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc8260.h>
+#include <netdev.h>
+#include <asm/processor.h>
+#include <asm/cpm_8260.h>
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_GET_CPU_STR_F)
+extern int get_cpu_str_f (char *buf);
+#endif
+
+int checkcpu (void)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ ulong clock = gd->cpu_clk;
+ uint pvr = get_pvr ();
+ uint immr, rev, m, k;
+ char buf[32];
+
+ puts ("CPU: ");
+
+ switch (pvr) {
+ case PVR_8260:
+ case PVR_8260_HIP3:
+ k = 3;
+ break;
+ case PVR_8260_HIP4:
+ k = 4;
+ break;
+ case PVR_8260_HIP7R1:
+ case PVR_8260_HIP7RA:
+ case PVR_8260_HIP7:
+ k = 7;
+ break;
+ default:
+ return -1; /* whoops! not an MPC8260 */
+ }
+ rev = pvr & 0xff;
+
+ immr = immap->im_memctl.memc_immr;
+ if ((immr & IMMR_ISB_MSK) != CONFIG_SYS_IMMR)
+ return -1; /* whoops! someone moved the IMMR */
+
+#if defined(CONFIG_GET_CPU_STR_F)
+ get_cpu_str_f (buf);
+ printf ("%s (HiP%d Rev %02x, Mask ", buf, k, rev);
+#else
+ printf (CPU_ID_STR " (HiP%d Rev %02x, Mask ", k, rev);
+#endif
+
+ /*
+ * the bottom 16 bits of the immr are the Part Number and Mask Number
+ * (4-34); the 16 bits at PROFF_REVNUM (0x8af0) in dual port ram is the
+ * RISC Microcode Revision Number (13-10).
+ * For the 8260, Motorola doesn't include the Microcode Revision
+ * in the mask.
+ */
+ m = immr & (IMMR_PARTNUM_MSK | IMMR_MASKNUM_MSK);
+ k = immap->im_dprambase16[PROFF_REVNUM / sizeof(u16)];
+
+ switch (m) {
+ case 0x0000:
+ puts ("0.2 2J24M");
+ break;
+ case 0x0010:
+ puts ("A.0 K22A");
+ break;
+ case 0x0011:
+ puts ("A.1 1K22A-XC");
+ break;
+ case 0x0001:
+ puts ("B.1 1K23A");
+ break;
+ case 0x0021:
+ puts ("B.2 2K23A-XC");
+ break;
+ case 0x0023:
+ puts ("B.3 3K23A");
+ break;
+ case 0x0024:
+ puts ("C.2 6K23A");
+ break;
+ case 0x0060:
+ puts ("A.0(A) 2K25A");
+ break;
+ case 0x0062:
+ puts ("B.1 4K25A");
+ break;
+ case 0x0064:
+ puts ("C.0 5K25A");
+ break;
+ case 0x0A00:
+ puts ("0.0 0K49M");
+ break;
+ case 0x0A01:
+ puts ("0.1 1K49M");
+ break;
+ case 0x0A10:
+ puts ("1.0 1K49M");
+ break;
+ case 0x0C00:
+ puts ("0.0 0K50M");
+ break;
+ case 0x0C10:
+ puts ("1.0 1K50M");
+ break;
+ case 0x0D00:
+ puts ("0.0 0K50M");
+ break;
+ case 0x0D10:
+ puts ("1.0 1K50M");
+ break;
+ default:
+ printf ("unknown [immr=0x%04x,k=0x%04x]", m, k);
+ break;
+ }
+
+ printf (") at %s MHz\n", strmhz (buf, clock));
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+/* configures a UPM by writing into the UPM RAM array */
+/* uses bank 11 and a dummy physical address (=BRx_BA_MSK) */
+/* NOTE: the physical address chosen must not overlap into any other area */
+/* mapped by the memory controller because bank 11 has the lowest priority */
+
+void upmconfig (uint upm, uint * table, uint size)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile memctl8260_t *memctl = &immap->im_memctl;
+ volatile uchar *dummy = (uchar *) BRx_BA_MSK; /* set all BA bits */
+ uint i;
+
+ /* first set up bank 11 to reference the correct UPM at a dummy address */
+
+ memctl->memc_or11 = ORxU_AM_MSK; /* set all AM bits */
+
+ switch (upm) {
+
+ case UPMA:
+ memctl->memc_br11 =
+ ((uint)dummy & BRx_BA_MSK) | BRx_PS_32 | BRx_MS_UPMA |
+ BRx_V;
+ memctl->memc_mamr = MxMR_OP_WARR;
+ break;
+
+ case UPMB:
+ memctl->memc_br11 =
+ ((uint)dummy & BRx_BA_MSK) | BRx_PS_32 | BRx_MS_UPMB |
+ BRx_V;
+ memctl->memc_mbmr = MxMR_OP_WARR;
+ break;
+
+ case UPMC:
+ memctl->memc_br11 =
+ ((uint)dummy & BRx_BA_MSK) | BRx_PS_32 | BRx_MS_UPMC |
+ BRx_V;
+ memctl->memc_mcmr = MxMR_OP_WARR;
+ break;
+
+ default:
+ panic ("upmconfig passed invalid UPM number (%u)\n", upm);
+ break;
+
+ }
+
+ /*
+ * at this point, the dummy address is set up to access the selected UPM,
+ * the MAD pointer is zero, and the MxMR OP is set for writing to RAM
+ *
+ * now we simply load the mdr with each word and poke the dummy address.
+ * the MAD is incremented on each access.
+ */
+
+ for (i = 0; i < size; i++) {
+ memctl->memc_mdr = table[i];
+ *dummy = 0;
+ }
+
+ /* now kill bank 11 */
+ memctl->memc_br11 = 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if !defined(CONFIG_HAVE_OWN_RESET)
+int
+do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong msr, addr;
+
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+ immap->im_clkrst.car_rmr = RMR_CSRE; /* Checkstop Reset enable */
+
+ /* Interrupts and MMU off */
+ __asm__ __volatile__ ("mfmsr %0":"=r" (msr):);
+
+ msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR);
+ __asm__ __volatile__ ("mtmsr %0"::"r" (msr));
+
+ /*
+ * Trying to execute the next instruction at a non-existing address
+ * should cause a machine check, resulting in reset
+ */
+#ifdef CONFIG_SYS_RESET_ADDRESS
+ addr = CONFIG_SYS_RESET_ADDRESS;
+#else
+ /*
+ * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address, CONFIG_SYS_MONITOR_BASE
+ * - sizeof (ulong) is usually a valid address. Better pick an address
+ * known to be invalid on your system and assign it to CONFIG_SYS_RESET_ADDRESS.
+ */
+ addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong);
+#endif
+ ((void (*)(void)) addr) ();
+ return 1;
+
+}
+#endif /* CONFIG_HAVE_OWN_RESET */
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ *
+ */
+unsigned long get_tbclk (void)
+{
+ ulong tbclk;
+
+ tbclk = (gd->bus_clk + 3L) / 4L;
+
+ return (tbclk);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset (void)
+{
+ int re_enable = disable_interrupts ();
+
+ reset_8260_watchdog ((immap_t *) CONFIG_SYS_IMMR);
+ if (re_enable)
+ enable_interrupts ();
+}
+#endif /* CONFIG_WATCHDOG */
+
+/* ------------------------------------------------------------------------- */
+#if defined(CONFIG_OF_LIBFDT) && defined (CONFIG_OF_BOARD_SETUP)
+void ft_cpu_setup (void *blob, bd_t *bd)
+{
+#if defined(CONFIG_HAS_ETH0) || defined(CONFIG_HAS_ETH1) ||\
+ defined(CONFIG_HAS_ETH2) || defined(CONFIG_HAS_ETH3)
+ fdt_fixup_ethernet(blob);
+#endif
+
+ do_fixup_by_compat_u32(blob, "fsl,cpm2-brg",
+ "clock-frequency", bd->bi_brgfreq, 1);
+
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "bus-frequency", bd->bi_busfreq, 1);
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "timebase-frequency", OF_TBCLK, 1);
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "clock-frequency", bd->bi_intfreq, 1);
+ fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+}
+#endif /* CONFIG_OF_LIBFDT */
+
+/*
+ * Initializes on-chip ethernet controllers.
+ * to override, implement board_eth_init()
+ */
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(CONFIG_ETHER_ON_FCC)
+ fec_initialize(bis);
+#endif
+#if defined(CONFIG_ETHER_ON_SCC)
+ mpc82xx_scc_enet_initialize(bis);
+#endif
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc8260/cpu_init.c b/arch/powerpc/cpu/mpc8260/cpu_init.c
new file mode 100644
index 0000000..3964e60
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/cpu_init.c
@@ -0,0 +1,292 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8260.h>
+#include <asm/cpm_8260.h>
+#include <ioports.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_BOARD_GET_CPU_CLK_F)
+extern unsigned long board_get_cpu_clk_f (void);
+#endif
+
+static void config_8260_ioports (volatile immap_t * immr)
+{
+ int portnum;
+
+ for (portnum = 0; portnum < 4; portnum++) {
+ uint pmsk = 0,
+ ppar = 0,
+ psor = 0,
+ pdir = 0,
+ podr = 0,
+ pdat = 0;
+ iop_conf_t *iopc = (iop_conf_t *) & iop_conf_tab[portnum][0];
+ iop_conf_t *eiopc = iopc + 32;
+ uint msk = 1;
+
+ /*
+ * NOTE:
+ * index 0 refers to pin 31,
+ * index 31 refers to pin 0
+ */
+ while (iopc < eiopc) {
+ if (iopc->conf) {
+ pmsk |= msk;
+ if (iopc->ppar)
+ ppar |= msk;
+ if (iopc->psor)
+ psor |= msk;
+ if (iopc->pdir)
+ pdir |= msk;
+ if (iopc->podr)
+ podr |= msk;
+ if (iopc->pdat)
+ pdat |= msk;
+ }
+
+ msk <<= 1;
+ iopc++;
+ }
+
+ if (pmsk != 0) {
+ volatile ioport_t *iop = ioport_addr (immr, portnum);
+ uint tpmsk = ~pmsk;
+
+ /*
+ * the (somewhat confused) paragraph at the
+ * bottom of page 35-5 warns that there might
+ * be "unknown behaviour" when programming
+ * PSORx and PDIRx, if PPARx = 1, so I
+ * decided this meant I had to disable the
+ * dedicated function first, and enable it
+ * last.
+ */
+ iop->ppar &= tpmsk;
+ iop->psor = (iop->psor & tpmsk) | psor;
+ iop->podr = (iop->podr & tpmsk) | podr;
+ iop->pdat = (iop->pdat & tpmsk) | pdat;
+ iop->pdir = (iop->pdir & tpmsk) | pdir;
+ iop->ppar |= ppar;
+ }
+ }
+}
+
+#define SET_VAL_MASK(a, b, mask) ((a & mask) | (b & ~mask))
+/*
+ * Breath some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers,
+ * initialize the UPM's
+ */
+void cpu_init_f (volatile immap_t * immr)
+{
+#if !defined(CONFIG_COGENT) /* done in start.S for the cogent */
+ uint sccr;
+#endif
+#if defined(CONFIG_BOARD_GET_CPU_CLK_F)
+ unsigned long cpu_clk;
+#endif
+ volatile memctl8260_t *memctl = &immr->im_memctl;
+ extern void m8260_cpm_reset (void);
+
+ /* Pointer is writable since we allocated a register for it */
+ gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+ /* Clear initial global data */
+ memset ((void *) gd, 0, sizeof (gd_t));
+
+ /* RSR - Reset Status Register - clear all status (5-4) */
+ gd->arch.reset_status = immr->im_clkrst.car_rsr;
+ immr->im_clkrst.car_rsr = RSR_ALLBITS;
+
+ /* RMR - Reset Mode Register - contains checkstop reset enable (5-5) */
+ immr->im_clkrst.car_rmr = CONFIG_SYS_RMR;
+
+ /* BCR - Bus Configuration Register (4-25) */
+#if defined(CONFIG_SYS_BCR_60x) && (CONFIG_SYS_BCR_SINGLE)
+ if (immr->im_siu_conf.sc_bcr & BCR_EBM) {
+ immr->im_siu_conf.sc_bcr = SET_VAL_MASK(immr->im_siu_conf.sc_bcr, CONFIG_SYS_BCR_60x, 0x80000010);
+ } else {
+ immr->im_siu_conf.sc_bcr = SET_VAL_MASK(immr->im_siu_conf.sc_bcr, CONFIG_SYS_BCR_SINGLE, 0x80000010);
+ }
+#else
+ immr->im_siu_conf.sc_bcr = CONFIG_SYS_BCR;
+#endif
+
+ /* SIUMCR - contains debug pin configuration (4-31) */
+#if defined(CONFIG_SYS_SIUMCR_LOW) && (CONFIG_SYS_SIUMCR_HIGH)
+ cpu_clk = board_get_cpu_clk_f ();
+ if (cpu_clk >= 100000000) {
+ immr->im_siu_conf.sc_siumcr = SET_VAL_MASK(immr->im_siu_conf.sc_siumcr, CONFIG_SYS_SIUMCR_HIGH, 0x9f3cc000);
+ } else {
+ immr->im_siu_conf.sc_siumcr = SET_VAL_MASK(immr->im_siu_conf.sc_siumcr, CONFIG_SYS_SIUMCR_LOW, 0x9f3cc000);
+ }
+#else
+ immr->im_siu_conf.sc_siumcr = CONFIG_SYS_SIUMCR;
+#endif
+
+ config_8260_ioports (immr);
+
+ /* initialize time counter status and control register (4-40) */
+ immr->im_sit.sit_tmcntsc = CONFIG_SYS_TMCNTSC;
+
+ /* initialize the PIT (4-42) */
+ immr->im_sit.sit_piscr = CONFIG_SYS_PISCR;
+
+#if !defined(CONFIG_COGENT) /* done in start.S for the cogent */
+ /* System clock control register (9-8) */
+ sccr = immr->im_clkrst.car_sccr &
+ (SCCR_PCI_MODE | SCCR_PCI_MODCK | SCCR_PCIDF_MSK);
+ immr->im_clkrst.car_sccr = sccr |
+ (CONFIG_SYS_SCCR & ~(SCCR_PCI_MODE | SCCR_PCI_MODCK | SCCR_PCIDF_MSK) );
+#endif /* !CONFIG_COGENT */
+
+ /*
+ * Memory Controller:
+ */
+
+ /* Map banks 0 and 1 to the FLASH banks 0 and 1 at preliminary
+ * addresses - these have to be modified later when FLASH size
+ * has been determined
+ */
+
+#if defined(CONFIG_SYS_OR0_REMAP)
+ memctl->memc_or0 = CONFIG_SYS_OR0_REMAP;
+#endif
+#if defined(CONFIG_SYS_OR1_REMAP)
+ memctl->memc_or1 = CONFIG_SYS_OR1_REMAP;
+#endif
+
+ /* now restrict to preliminary range */
+ /* the PS came from the HRCW, don't change it */
+ memctl->memc_br0 = SET_VAL_MASK(memctl->memc_br0 , CONFIG_SYS_BR0_PRELIM, BRx_PS_MSK);
+ memctl->memc_or0 = CONFIG_SYS_OR0_PRELIM;
+
+#if defined(CONFIG_SYS_BR1_PRELIM) && defined(CONFIG_SYS_OR1_PRELIM)
+ memctl->memc_or1 = CONFIG_SYS_OR1_PRELIM;
+ memctl->memc_br1 = CONFIG_SYS_BR1_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR2_PRELIM) && defined(CONFIG_SYS_OR2_PRELIM)
+ memctl->memc_or2 = CONFIG_SYS_OR2_PRELIM;
+ memctl->memc_br2 = CONFIG_SYS_BR2_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR3_PRELIM) && defined(CONFIG_SYS_OR3_PRELIM)
+ memctl->memc_or3 = CONFIG_SYS_OR3_PRELIM;
+ memctl->memc_br3 = CONFIG_SYS_BR3_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR4_PRELIM) && defined(CONFIG_SYS_OR4_PRELIM)
+ memctl->memc_or4 = CONFIG_SYS_OR4_PRELIM;
+ memctl->memc_br4 = CONFIG_SYS_BR4_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR5_PRELIM) && defined(CONFIG_SYS_OR5_PRELIM)
+ memctl->memc_or5 = CONFIG_SYS_OR5_PRELIM;
+ memctl->memc_br5 = CONFIG_SYS_BR5_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR6_PRELIM) && defined(CONFIG_SYS_OR6_PRELIM)
+ memctl->memc_or6 = CONFIG_SYS_OR6_PRELIM;
+ memctl->memc_br6 = CONFIG_SYS_BR6_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR7_PRELIM) && defined(CONFIG_SYS_OR7_PRELIM)
+ memctl->memc_or7 = CONFIG_SYS_OR7_PRELIM;
+ memctl->memc_br7 = CONFIG_SYS_BR7_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR8_PRELIM) && defined(CONFIG_SYS_OR8_PRELIM)
+ memctl->memc_or8 = CONFIG_SYS_OR8_PRELIM;
+ memctl->memc_br8 = CONFIG_SYS_BR8_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR9_PRELIM) && defined(CONFIG_SYS_OR9_PRELIM)
+ memctl->memc_or9 = CONFIG_SYS_OR9_PRELIM;
+ memctl->memc_br9 = CONFIG_SYS_BR9_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR10_PRELIM) && defined(CONFIG_SYS_OR10_PRELIM)
+ memctl->memc_or10 = CONFIG_SYS_OR10_PRELIM;
+ memctl->memc_br10 = CONFIG_SYS_BR10_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_BR11_PRELIM) && defined(CONFIG_SYS_OR11_PRELIM)
+ memctl->memc_or11 = CONFIG_SYS_OR11_PRELIM;
+ memctl->memc_br11 = CONFIG_SYS_BR11_PRELIM;
+#endif
+
+ m8260_cpm_reset ();
+}
+
+/*
+ * initialize higher level parts of CPU like time base and timers
+ */
+int cpu_init_r (void)
+{
+ volatile immap_t *immr = (immap_t *) gd->bd->bi_immr_base;
+
+ immr->im_cpm.cp_rccr = CONFIG_SYS_RCCR;
+
+ return (0);
+}
+
+/*
+ * print out the reason for the reset
+ */
+int prt_8260_rsr (void)
+{
+ static struct {
+ ulong mask;
+ char *desc;
+ } bits[] = {
+ {
+ RSR_JTRS, "JTAG"}, {
+ RSR_CSRS, "Check Stop"}, {
+ RSR_SWRS, "Software Watchdog"}, {
+ RSR_BMRS, "Bus Monitor"}, {
+ RSR_ESRS, "External Soft"}, {
+ RSR_EHRS, "External Hard"}
+ };
+ static int n = sizeof bits / sizeof bits[0];
+ ulong rsr = gd->arch.reset_status;
+ int i;
+ char *sep;
+
+ puts (CPU_ID_STR " Reset Status:");
+
+ sep = " ";
+ for (i = 0; i < n; i++)
+ if (rsr & bits[i].mask) {
+ printf ("%s%s", sep, bits[i].desc);
+ sep = ", ";
+ }
+
+ puts ("\n\n");
+ return (0);
+}
diff --git a/arch/powerpc/cpu/mpc8260/ether_fcc.c b/arch/powerpc/cpu/mpc8260/ether_fcc.c
new file mode 100644
index 0000000..1853451
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/ether_fcc.c
@@ -0,0 +1,1188 @@
+/*
+ * MPC8260 FCC Fast Ethernet
+ *
+ * Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net)
+ *
+ * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * MPC8260 FCC Fast Ethernet
+ * Basic ET HW initialization and packet RX/TX routines
+ *
+ * This code will not perform the IO port configuration. This should be
+ * done in the iop_conf_t structure specific for the board.
+ *
+ * TODO:
+ * add a PHY driver to do the negotiation
+ * reflect negotiation results in FPSMR
+ * look for ways to configure the board specific stuff elsewhere, eg.
+ * config_xxx.h or the board directory
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/cpm_8260.h>
+#include <mpc8260.h>
+#include <command.h>
+#include <config.h>
+#include <net.h>
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#include <miiphy.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_ETHER_ON_FCC) && defined(CONFIG_CMD_NET)
+
+static struct ether_fcc_info_s
+{
+ int ether_index;
+ int proff_enet;
+ ulong cpm_cr_enet_sblock;
+ ulong cpm_cr_enet_page;
+ ulong cmxfcr_mask;
+ ulong cmxfcr_value;
+}
+ ether_fcc_info[] =
+{
+#ifdef CONFIG_ETHER_ON_FCC1
+{
+ 0,
+ PROFF_FCC1,
+ CPM_CR_FCC1_SBLOCK,
+ CPM_CR_FCC1_PAGE,
+ CONFIG_SYS_CMXFCR_MASK1,
+ CONFIG_SYS_CMXFCR_VALUE1
+},
+#endif
+
+#ifdef CONFIG_ETHER_ON_FCC2
+{
+ 1,
+ PROFF_FCC2,
+ CPM_CR_FCC2_SBLOCK,
+ CPM_CR_FCC2_PAGE,
+ CONFIG_SYS_CMXFCR_MASK2,
+ CONFIG_SYS_CMXFCR_VALUE2
+},
+#endif
+
+#ifdef CONFIG_ETHER_ON_FCC3
+{
+ 2,
+ PROFF_FCC3,
+ CPM_CR_FCC3_SBLOCK,
+ CPM_CR_FCC3_PAGE,
+ CONFIG_SYS_CMXFCR_MASK3,
+ CONFIG_SYS_CMXFCR_VALUE3
+},
+#endif
+};
+
+/*---------------------------------------------------------------------*/
+
+/* Maximum input DMA size. Must be a should(?) be a multiple of 4. */
+#define PKT_MAXDMA_SIZE 1520
+
+/* The FCC stores dest/src/type, data, and checksum for receive packets. */
+#define PKT_MAXBUF_SIZE 1518
+#define PKT_MINBUF_SIZE 64
+
+/* Maximum input buffer size. Must be a multiple of 32. */
+#define PKT_MAXBLR_SIZE 1536
+
+#define TOUT_LOOP 1000000
+
+#define TX_BUF_CNT 2
+#ifdef __GNUC__
+static char txbuf[TX_BUF_CNT][PKT_MAXBLR_SIZE] __attribute__ ((aligned(8)));
+#else
+#error "txbuf must be 64-bit aligned"
+#endif
+
+static uint rxIdx; /* index of the current RX buffer */
+static uint txIdx; /* index of the current TX buffer */
+
+/*
+ * FCC Ethernet Tx and Rx buffer descriptors.
+ * Provide for Double Buffering
+ * Note: PKTBUFSRX is defined in net.h
+ */
+
+typedef volatile struct rtxbd {
+ cbd_t rxbd[PKTBUFSRX];
+ cbd_t txbd[TX_BUF_CNT];
+} RTXBD;
+
+/* Good news: the FCC supports external BDs! */
+#ifdef __GNUC__
+static RTXBD rtx __attribute__ ((aligned(8)));
+#else
+#error "rtx must be 64-bit aligned"
+#endif
+
+static int fec_send(struct eth_device *dev, void *packet, int length)
+{
+ int i;
+ int result = 0;
+
+ if (length <= 0) {
+ printf("fec: bad packet size: %d\n", length);
+ goto out;
+ }
+
+ for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
+ if (i >= TOUT_LOOP) {
+ puts ("fec: tx buffer not ready\n");
+ goto out;
+ }
+ }
+
+ rtx.txbd[txIdx].cbd_bufaddr = (uint)packet;
+ rtx.txbd[txIdx].cbd_datlen = length;
+ rtx.txbd[txIdx].cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_LAST |
+ BD_ENET_TX_WRAP);
+
+ for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
+ if (i >= TOUT_LOOP) {
+ puts ("fec: tx error\n");
+ goto out;
+ }
+ }
+
+#ifdef ET_DEBUG
+ printf("cycles: %d status: %04x\n", i, rtx.txbd[txIdx].cbd_sc);
+#endif
+
+ /* return only status bits */
+ result = rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_STATS;
+
+out:
+ return result;
+}
+
+static int fec_recv(struct eth_device* dev)
+{
+ int length;
+
+ for (;;)
+ {
+ if (rtx.rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
+ length = -1;
+ break; /* nothing received - leave for() loop */
+ }
+ length = rtx.rxbd[rxIdx].cbd_datlen;
+
+ if (rtx.rxbd[rxIdx].cbd_sc & 0x003f) {
+ printf("fec: rx error %04x\n", rtx.rxbd[rxIdx].cbd_sc);
+ }
+ else {
+ /* Pass the packet up to the protocol layers. */
+ NetReceive(NetRxPackets[rxIdx], length - 4);
+ }
+
+
+ /* Give the buffer back to the FCC. */
+ rtx.rxbd[rxIdx].cbd_datlen = 0;
+
+ /* wrap around buffer index when necessary */
+ if ((rxIdx + 1) >= PKTBUFSRX) {
+ rtx.rxbd[PKTBUFSRX - 1].cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
+ rxIdx = 0;
+ }
+ else {
+ rtx.rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
+ rxIdx++;
+ }
+ }
+ return length;
+}
+
+
+static int fec_init(struct eth_device* dev, bd_t *bis)
+{
+ struct ether_fcc_info_s * info = dev->priv;
+ int i;
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8260_t *cp = &(immr->im_cpm);
+ fcc_enet_t *pram_ptr;
+ unsigned long mem_addr;
+
+#if 0
+ mii_discover_phy();
+#endif
+
+ /* 28.9 - (1-2): ioports have been set up already */
+
+ /* 28.9 - (3): connect FCC's tx and rx clocks */
+ immr->im_cpmux.cmx_uar = 0;
+ immr->im_cpmux.cmx_fcr = (immr->im_cpmux.cmx_fcr & ~info->cmxfcr_mask) |
+ info->cmxfcr_value;
+
+ /* 28.9 - (4): GFMR: disable tx/rx, CCITT CRC, Mode Ethernet */
+ immr->im_fcc[info->ether_index].fcc_gfmr =
+ FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32;
+
+ /* 28.9 - (5): FPSMR: enable full duplex, select CCITT CRC for Ethernet */
+ immr->im_fcc[info->ether_index].fcc_fpsmr = CONFIG_SYS_FCC_PSMR | FCC_PSMR_ENCRC;
+
+ /* 28.9 - (6): FDSR: Ethernet Syn */
+ immr->im_fcc[info->ether_index].fcc_fdsr = 0xD555;
+
+ /* reset indeces to current rx/tx bd (see eth_send()/eth_rx()) */
+ rxIdx = 0;
+ txIdx = 0;
+
+ /* Setup Receiver Buffer Descriptors */
+ for (i = 0; i < PKTBUFSRX; i++)
+ {
+ rtx.rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
+ rtx.rxbd[i].cbd_datlen = 0;
+ rtx.rxbd[i].cbd_bufaddr = (uint)NetRxPackets[i];
+ }
+ rtx.rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+ /* Setup Ethernet Transmitter Buffer Descriptors */
+ for (i = 0; i < TX_BUF_CNT; i++)
+ {
+ rtx.txbd[i].cbd_sc = (BD_ENET_TX_PAD | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+ rtx.txbd[i].cbd_datlen = 0;
+ rtx.txbd[i].cbd_bufaddr = (uint)&txbuf[i][0];
+ }
+ rtx.txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+ /* 28.9 - (7): initialise parameter ram */
+ pram_ptr = (fcc_enet_t *)&(immr->im_dprambase[info->proff_enet]);
+
+ /* clear whole structure to make sure all reserved fields are zero */
+ memset((void*)pram_ptr, 0, sizeof(fcc_enet_t));
+
+ /*
+ * common Parameter RAM area
+ *
+ * Allocate space in the reserved FCC area of DPRAM for the
+ * internal buffers. No one uses this space (yet), so we
+ * can do this. Later, we will add resource management for
+ * this area.
+ */
+ mem_addr = CPM_FCC_SPECIAL_BASE + ((info->ether_index) * 64);
+ pram_ptr->fen_genfcc.fcc_riptr = mem_addr;
+ pram_ptr->fen_genfcc.fcc_tiptr = mem_addr+32;
+ /*
+ * Set maximum bytes per receive buffer.
+ * It must be a multiple of 32.
+ */
+ pram_ptr->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE;
+ pram_ptr->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB |
+ CONFIG_SYS_CPMFCR_RAMTYPE) << 24;
+ pram_ptr->fen_genfcc.fcc_rbase = (unsigned int)(&rtx.rxbd[rxIdx]);
+ pram_ptr->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB |
+ CONFIG_SYS_CPMFCR_RAMTYPE) << 24;
+ pram_ptr->fen_genfcc.fcc_tbase = (unsigned int)(&rtx.txbd[txIdx]);
+
+ /* protocol-specific area */
+ pram_ptr->fen_cmask = 0xdebb20e3; /* CRC mask */
+ pram_ptr->fen_cpres = 0xffffffff; /* CRC preset */
+ pram_ptr->fen_retlim = 15; /* Retry limit threshold */
+ pram_ptr->fen_mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */
+ /*
+ * Set Ethernet station address.
+ *
+ * This is supplied in the board information structure, so we
+ * copy that into the controller.
+ * So, far we have only been given one Ethernet address. We make
+ * it unique by setting a few bits in the upper byte of the
+ * non-static part of the address.
+ */
+#define ea eth_get_dev()->enetaddr
+ pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4];
+ pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2];
+ pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0];
+#undef ea
+ pram_ptr->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */
+ /* pad pointer. use tiptr since we don't need a specific padding char */
+ pram_ptr->fen_padptr = pram_ptr->fen_genfcc.fcc_tiptr;
+ pram_ptr->fen_maxd1 = PKT_MAXDMA_SIZE; /* maximum DMA1 length */
+ pram_ptr->fen_maxd2 = PKT_MAXDMA_SIZE; /* maximum DMA2 length */
+ pram_ptr->fen_rfthr = 1;
+ pram_ptr->fen_rfcnt = 1;
+#if 0
+ printf("pram_ptr->fen_genfcc.fcc_rbase %08lx\n",
+ pram_ptr->fen_genfcc.fcc_rbase);
+ printf("pram_ptr->fen_genfcc.fcc_tbase %08lx\n",
+ pram_ptr->fen_genfcc.fcc_tbase);
+#endif
+
+ /* 28.9 - (8): clear out events in FCCE */
+ immr->im_fcc[info->ether_index].fcc_fcce = ~0x0;
+
+ /* 28.9 - (9): FCCM: mask all events */
+ immr->im_fcc[info->ether_index].fcc_fccm = 0;
+
+ /* 28.9 - (10-12): we don't use ethernet interrupts */
+
+ /* 28.9 - (13)
+ *
+ * Let's re-initialize the channel now. We have to do it later
+ * than the manual describes because we have just now finished
+ * the BD initialization.
+ */
+ cp->cp_cpcr = mk_cr_cmd(info->cpm_cr_enet_page,
+ info->cpm_cr_enet_sblock,
+ 0x0c,
+ CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ do {
+ __asm__ __volatile__ ("eieio");
+ } while (cp->cp_cpcr & CPM_CR_FLG);
+
+ /* 28.9 - (14): enable tx/rx in gfmr */
+ immr->im_fcc[info->ether_index].fcc_gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR;
+
+ return 1;
+}
+
+static void fec_halt(struct eth_device* dev)
+{
+ struct ether_fcc_info_s * info = dev->priv;
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+
+ /* write GFMR: disable tx/rx */
+ immr->im_fcc[info->ether_index].fcc_gfmr &=
+ ~(FCC_GFMR_ENT | FCC_GFMR_ENR);
+}
+
+int fec_initialize(bd_t *bis)
+{
+ struct eth_device* dev;
+ int i;
+
+ for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++)
+ {
+ dev = (struct eth_device*) malloc(sizeof *dev);
+ memset(dev, 0, sizeof *dev);
+
+ sprintf(dev->name, "FCC%d",
+ ether_fcc_info[i].ether_index + 1);
+ dev->priv = &ether_fcc_info[i];
+ dev->init = fec_init;
+ dev->halt = fec_halt;
+ dev->send = fec_send;
+ dev->recv = fec_recv;
+
+ eth_register(dev);
+
+#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) \
+ && defined(CONFIG_BITBANGMII)
+ miiphy_register(dev->name,
+ bb_miiphy_read, bb_miiphy_write);
+#endif
+ }
+
+ return 1;
+}
+
+#ifdef CONFIG_ETHER_LOOPBACK_TEST
+
+#define ELBT_BUFSZ 1024 /* must be multiple of 32 */
+
+#define ELBT_CRCSZ 4
+
+#define ELBT_NRXBD 4 /* must be at least 2 */
+#define ELBT_NTXBD 4
+
+#define ELBT_MAXRXERR 32
+#define ELBT_MAXTXERR 32
+
+#define ELBT_CLSWAIT 1000 /* msec to wait for further input frames */
+
+typedef
+ struct {
+ uint off;
+ char *lab;
+ }
+elbt_prdesc;
+
+typedef
+ struct {
+ uint _l, _f, m, bc, mc, lg, no, sh, cr, ov, cl;
+ uint badsrc, badtyp, badlen, badbit;
+ }
+elbt_rxeacc;
+
+static elbt_prdesc rxeacc_descs[] = {
+ { offsetof(elbt_rxeacc, _l), "Not Last in Frame" },
+ { offsetof(elbt_rxeacc, _f), "Not First in Frame" },
+ { offsetof(elbt_rxeacc, m), "Address Miss" },
+ { offsetof(elbt_rxeacc, bc), "Broadcast Address" },
+ { offsetof(elbt_rxeacc, mc), "Multicast Address" },
+ { offsetof(elbt_rxeacc, lg), "Frame Length Violation"},
+ { offsetof(elbt_rxeacc, no), "Non-Octet Alignment" },
+ { offsetof(elbt_rxeacc, sh), "Short Frame" },
+ { offsetof(elbt_rxeacc, cr), "CRC Error" },
+ { offsetof(elbt_rxeacc, ov), "Overrun" },
+ { offsetof(elbt_rxeacc, cl), "Collision" },
+ { offsetof(elbt_rxeacc, badsrc), "Bad Src Address" },
+ { offsetof(elbt_rxeacc, badtyp), "Bad Frame Type" },
+ { offsetof(elbt_rxeacc, badlen), "Bad Frame Length" },
+ { offsetof(elbt_rxeacc, badbit), "Data Compare Errors" },
+};
+static int rxeacc_ndesc = sizeof (rxeacc_descs) / sizeof (rxeacc_descs[0]);
+
+typedef
+ struct {
+ uint def, hb, lc, rl, rc, un, csl;
+ }
+elbt_txeacc;
+
+static elbt_prdesc txeacc_descs[] = {
+ { offsetof(elbt_txeacc, def), "Defer Indication" },
+ { offsetof(elbt_txeacc, hb), "Heartbeat" },
+ { offsetof(elbt_txeacc, lc), "Late Collision" },
+ { offsetof(elbt_txeacc, rl), "Retransmission Limit" },
+ { offsetof(elbt_txeacc, rc), "Retry Count" },
+ { offsetof(elbt_txeacc, un), "Underrun" },
+ { offsetof(elbt_txeacc, csl), "Carrier Sense Lost" },
+};
+static int txeacc_ndesc = sizeof (txeacc_descs) / sizeof (txeacc_descs[0]);
+
+typedef
+ struct {
+ uchar rxbufs[ELBT_NRXBD][ELBT_BUFSZ];
+ uchar txbufs[ELBT_NTXBD][ELBT_BUFSZ];
+ cbd_t rxbd[ELBT_NRXBD];
+ cbd_t txbd[ELBT_NTXBD];
+ enum { Idle, Running, Closing, Closed } state;
+ int proff, page, sblock;
+ uint clstime, nsent, ntxerr, nrcvd, nrxerr;
+ ushort rxerrs[ELBT_MAXRXERR], txerrs[ELBT_MAXTXERR];
+ elbt_rxeacc rxeacc;
+ elbt_txeacc txeacc;
+ } __attribute__ ((aligned(8)))
+elbt_chan;
+
+static uchar patbytes[ELBT_NTXBD] = {
+ 0xff, 0xaa, 0x55, 0x00
+};
+static uint patwords[ELBT_NTXBD] = {
+ 0xffffffff, 0xaaaaaaaa, 0x55555555, 0x00000000
+};
+
+#ifdef __GNUC__
+static elbt_chan elbt_chans[3] __attribute__ ((aligned(8)));
+#else
+#error "elbt_chans must be 64-bit aligned"
+#endif
+
+#define CPM_CR_GRACEFUL_STOP_TX ((ushort)0x0005)
+
+static elbt_prdesc epram_descs[] = {
+ { offsetof(fcc_enet_t, fen_crcec), "CRC Errors" },
+ { offsetof(fcc_enet_t, fen_alec), "Alignment Errors" },
+ { offsetof(fcc_enet_t, fen_disfc), "Discarded Frames" },
+ { offsetof(fcc_enet_t, fen_octc), "Octets" },
+ { offsetof(fcc_enet_t, fen_colc), "Collisions" },
+ { offsetof(fcc_enet_t, fen_broc), "Broadcast Frames" },
+ { offsetof(fcc_enet_t, fen_mulc), "Multicast Frames" },
+ { offsetof(fcc_enet_t, fen_uspc), "Undersize Frames" },
+ { offsetof(fcc_enet_t, fen_frgc), "Fragments" },
+ { offsetof(fcc_enet_t, fen_ospc), "Oversize Frames" },
+ { offsetof(fcc_enet_t, fen_jbrc), "Jabbers" },
+ { offsetof(fcc_enet_t, fen_p64c), "64 Octet Frames" },
+ { offsetof(fcc_enet_t, fen_p65c), "65-127 Octet Frames" },
+ { offsetof(fcc_enet_t, fen_p128c), "128-255 Octet Frames" },
+ { offsetof(fcc_enet_t, fen_p256c), "256-511 Octet Frames" },
+ { offsetof(fcc_enet_t, fen_p512c), "512-1023 Octet Frames" },
+ { offsetof(fcc_enet_t, fen_p1024c), "1024-1518 Octet Frames"},
+};
+static int epram_ndesc = sizeof (epram_descs) / sizeof (epram_descs[0]);
+
+/*
+ * given an elbt_prdesc array and an array of base addresses, print
+ * each prdesc down the screen with the values fetched from each
+ * base address across the screen
+ */
+static void
+print_desc (elbt_prdesc descs[], int ndesc, uchar *bases[], int nbase)
+{
+ elbt_prdesc *dp = descs, *edp = dp + ndesc;
+ int i;
+
+ printf ("%32s", "");
+
+ for (i = 0; i < nbase; i++)
+ printf (" Channel %d", i);
+
+ putc ('\n');
+
+ while (dp < edp) {
+
+ printf ("%-32s", dp->lab);
+
+ for (i = 0; i < nbase; i++) {
+ uint val = *(uint *)(bases[i] + dp->off);
+
+ printf (" %10u", val);
+ }
+
+ putc ('\n');
+
+ dp++;
+ }
+}
+
+/*
+ * return number of bits that are set in a value; value contains
+ * nbits (right-justified) bits.
+ */
+static uint __inline__
+nbs (uint value, uint nbits)
+{
+ uint cnt = 0;
+#if 1
+ uint pos = sizeof (uint) * 8;
+
+ __asm__ __volatile__ ("\
+ mtctr %2\n\
+1: rlwnm. %2,%1,%4,31,31\n\
+ beq 2f\n\
+ addi %0,%0,1\n\
+2: subi %4,%4,1\n\
+ bdnz 1b"
+ : "=r"(cnt)
+ : "r"(value), "r"(nbits), "r"(cnt), "r"(pos)
+ : "ctr", "cc" );
+#else
+ uint mask = 1;
+
+ do {
+ if (value & mask)
+ cnt++;
+ mask <<= 1;
+ } while (--nbits);
+#endif
+
+ return (cnt);
+}
+
+static ulong
+badbits (uchar *bp, int n, ulong pat)
+{
+ ulong *lp, cnt = 0;
+ int nl;
+
+ while (n > 0 && ((ulong)bp & (sizeof (ulong) - 1)) != 0) {
+ uchar diff;
+
+ diff = *bp++ ^ (uchar)pat;
+
+ if (diff)
+ cnt += nbs ((ulong)diff, 8);
+
+ n--;
+ }
+
+ lp = (ulong *)bp;
+ nl = n / sizeof (ulong);
+ n -= nl * sizeof (ulong);
+
+ while (nl > 0) {
+ ulong diff;
+
+ diff = *lp++ ^ pat;
+
+ if (diff)
+ cnt += nbs (diff, 32);
+
+ nl--;
+ }
+
+ bp = (uchar *)lp;
+
+ while (n > 0) {
+ uchar diff;
+
+ diff = *bp++ ^ (uchar)pat;
+
+ if (diff)
+ cnt += nbs ((ulong)diff, 8);
+
+ n--;
+ }
+
+ return (cnt);
+}
+
+static inline unsigned short
+swap16 (unsigned short x)
+{
+ return (((x & 0xff) << 8) | ((x & 0xff00) >> 8));
+}
+
+/* broadcast is not an error - we send them like that */
+#define BD_ENET_RX_ERRS (BD_ENET_RX_STATS & ~BD_ENET_RX_BC)
+
+void
+eth_loopback_test (void)
+{
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8260_t *cp = &(immr->im_cpm);
+ int c, nclosed;
+ ulong runtime, nmsec;
+ uchar *bases[3];
+
+ puts ("FCC Ethernet External loopback test\n");
+
+ eth_getenv_enetaddr("ethaddr", NetOurEther);
+
+ /*
+ * global initialisations for all FCC channels
+ */
+
+ /* 28.9 - (1-2): ioports have been set up already */
+
+#if defined(CONFIG_HYMOD)
+ /*
+ * Attention: this is board-specific
+ * 0, FCC1
+ * 1, FCC2
+ * 2, FCC3
+ */
+# define FCC_START_LOOP 0
+# define FCC_END_LOOP 2
+
+ /*
+ * Attention: this is board-specific
+ * - FCC1 Rx-CLK is CLK10
+ * - FCC1 Tx-CLK is CLK11
+ * - FCC2 Rx-CLK is CLK13
+ * - FCC2 Tx-CLK is CLK14
+ * - FCC3 Rx-CLK is CLK15
+ * - FCC3 Tx-CLK is CLK16
+ */
+
+ /* 28.9 - (3): connect FCC's tx and rx clocks */
+ immr->im_cpmux.cmx_uar = 0;
+ immr->im_cpmux.cmx_fcr = CMXFCR_RF1CS_CLK10|CMXFCR_TF1CS_CLK11|\
+ CMXFCR_RF2CS_CLK13|CMXFCR_TF2CS_CLK14|\
+ CMXFCR_RF3CS_CLK15|CMXFCR_TF3CS_CLK16;
+#elif defined(CONFIG_SACSng)
+ /*
+ * Attention: this is board-specific
+ * 1, FCC2
+ */
+# define FCC_START_LOOP 1
+# define FCC_END_LOOP 1
+
+ /*
+ * Attention: this is board-specific
+ * - FCC2 Rx-CLK is CLK13
+ * - FCC2 Tx-CLK is CLK14
+ */
+
+ /* 28.9 - (3): connect FCC's tx and rx clocks */
+ immr->im_cpmux.cmx_uar = 0;
+ immr->im_cpmux.cmx_fcr = CMXFCR_RF2CS_CLK13|CMXFCR_TF2CS_CLK14;
+#else
+#error "eth_loopback_test not supported on your board"
+#endif
+
+ puts ("Initialise FCC channels:");
+
+ for (c = FCC_START_LOOP; c <= FCC_END_LOOP; c++) {
+ elbt_chan *ecp = &elbt_chans[c];
+ volatile fcc_t *fcp = &immr->im_fcc[c];
+ volatile fcc_enet_t *fpp;
+ int i;
+ ulong addr;
+
+ /*
+ * initialise channel data
+ */
+
+ printf (" %d", c);
+
+ memset ((void *)ecp, 0, sizeof (*ecp));
+
+ ecp->state = Idle;
+
+ switch (c) {
+
+ case 0: /* FCC1 */
+ ecp->proff = PROFF_FCC1;
+ ecp->page = CPM_CR_FCC1_PAGE;
+ ecp->sblock = CPM_CR_FCC1_SBLOCK;
+ break;
+
+ case 1: /* FCC2 */
+ ecp->proff = PROFF_FCC2;
+ ecp->page = CPM_CR_FCC2_PAGE;
+ ecp->sblock = CPM_CR_FCC2_SBLOCK;
+ break;
+
+ case 2: /* FCC3 */
+ ecp->proff = PROFF_FCC3;
+ ecp->page = CPM_CR_FCC3_PAGE;
+ ecp->sblock = CPM_CR_FCC3_SBLOCK;
+ break;
+ }
+
+ /*
+ * set up tx buffers and bds
+ */
+
+ for (i = 0; i < ELBT_NTXBD; i++) {
+ cbd_t *bdp = &ecp->txbd[i];
+ uchar *bp = &ecp->txbufs[i][0];
+
+ bdp->cbd_bufaddr = (uint)bp;
+ /* room for crc */
+ bdp->cbd_datlen = ELBT_BUFSZ - ELBT_CRCSZ;
+ bdp->cbd_sc = BD_ENET_TX_READY | BD_ENET_TX_PAD | \
+ BD_ENET_TX_LAST | BD_ENET_TX_TC;
+
+ memset ((void *)bp, patbytes[i], ELBT_BUFSZ);
+ NetSetEther (bp, NetBcastAddr, 0x8000);
+ }
+ ecp->txbd[ELBT_NTXBD - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+ /*
+ * set up rx buffers and bds
+ */
+
+ for (i = 0; i < ELBT_NRXBD; i++) {
+ cbd_t *bdp = &ecp->rxbd[i];
+ uchar *bp = &ecp->rxbufs[i][0];
+
+ bdp->cbd_bufaddr = (uint)bp;
+ bdp->cbd_datlen = 0;
+ bdp->cbd_sc = BD_ENET_RX_EMPTY;
+
+ memset ((void *)bp, 0, ELBT_BUFSZ);
+ }
+ ecp->rxbd[ELBT_NRXBD - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+ /*
+ * set up the FCC channel hardware
+ */
+
+ /* 28.9 - (4): GFMR: disable tx/rx, CCITT CRC, Mode Ethernet */
+ fcp->fcc_gfmr = FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32;
+
+ /* 28.9 - (5): FPSMR: fd, enet CRC, Promis, RMON, Rx SHort */
+ fcp->fcc_fpsmr = FCC_PSMR_FDE | FCC_PSMR_LPB | \
+ FCC_PSMR_ENCRC | FCC_PSMR_PRO | \
+ FCC_PSMR_MON | FCC_PSMR_RSH;
+
+ /* 28.9 - (6): FDSR: Ethernet Syn */
+ fcp->fcc_fdsr = 0xD555;
+
+ /* 29.9 - (7): initialise parameter ram */
+ fpp = (fcc_enet_t *)&(immr->im_dprambase[ecp->proff]);
+
+ /* clear whole struct to make sure all resv fields are zero */
+ memset ((void *)fpp, 0, sizeof (fcc_enet_t));
+
+ /*
+ * common Parameter RAM area
+ *
+ * Allocate space in the reserved FCC area of DPRAM for the
+ * internal buffers. No one uses this space (yet), so we
+ * can do this. Later, we will add resource management for
+ * this area.
+ */
+ addr = CPM_FCC_SPECIAL_BASE + (c * 64);
+ fpp->fen_genfcc.fcc_riptr = addr;
+ fpp->fen_genfcc.fcc_tiptr = addr + 32;
+
+ /*
+ * Set maximum bytes per receive buffer.
+ * It must be a multiple of 32.
+ * buffers are in 60x bus memory.
+ */
+ fpp->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE;
+ fpp->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB) << 24;
+ fpp->fen_genfcc.fcc_rbase = (unsigned int)(&ecp->rxbd[0]);
+ fpp->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB) << 24;
+ fpp->fen_genfcc.fcc_tbase = (unsigned int)(&ecp->txbd[0]);
+
+ /* protocol-specific area */
+ fpp->fen_cmask = 0xdebb20e3; /* CRC mask */
+ fpp->fen_cpres = 0xffffffff; /* CRC preset */
+ fpp->fen_retlim = 15; /* Retry limit threshold */
+ fpp->fen_mflr = PKT_MAXBUF_SIZE;/* max frame length register */
+
+ /*
+ * Set Ethernet station address.
+ *
+ * This is supplied in the board information structure, so we
+ * copy that into the controller.
+ * So, far we have only been given one Ethernet address. We use
+ * the same address for all channels
+ */
+#define ea NetOurEther
+ fpp->fen_paddrh = (ea[5] << 8) + ea[4];
+ fpp->fen_paddrm = (ea[3] << 8) + ea[2];
+ fpp->fen_paddrl = (ea[1] << 8) + ea[0];
+#undef ea
+
+ fpp->fen_minflr = PKT_MINBUF_SIZE; /* min frame len register */
+ /*
+ * pad pointer. use tiptr since we don't need
+ * a specific padding char
+ */
+ fpp->fen_padptr = fpp->fen_genfcc.fcc_tiptr;
+ fpp->fen_maxd1 = PKT_MAXDMA_SIZE; /* max DMA1 length */
+ fpp->fen_maxd2 = PKT_MAXDMA_SIZE; /* max DMA2 length */
+ fpp->fen_rfthr = 1;
+ fpp->fen_rfcnt = 1;
+
+ /* 28.9 - (8): clear out events in FCCE */
+ fcp->fcc_fcce = ~0x0;
+
+ /* 28.9 - (9): FCCM: mask all events */
+ fcp->fcc_fccm = 0;
+
+ /* 28.9 - (10-12): we don't use ethernet interrupts */
+
+ /* 28.9 - (13)
+ *
+ * Let's re-initialize the channel now. We have to do it later
+ * than the manual describes because we have just now finished
+ * the BD initialization.
+ */
+ cp->cp_cpcr = mk_cr_cmd (ecp->page, ecp->sblock, \
+ 0x0c, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ do {
+ __asm__ __volatile__ ("eieio");
+ } while (cp->cp_cpcr & CPM_CR_FLG);
+ }
+
+ puts (" done\nStarting test... (Ctrl-C to Finish)\n");
+
+ /*
+ * Note: don't want serial output from here until the end of the
+ * test - the delays would probably stuff things up.
+ */
+
+ clear_ctrlc ();
+ runtime = get_timer (0);
+
+ do {
+ nclosed = 0;
+
+ for (c = FCC_START_LOOP; c <= FCC_END_LOOP; c++) {
+ volatile fcc_t *fcp = &immr->im_fcc[c];
+ elbt_chan *ecp = &elbt_chans[c];
+ int i;
+
+ switch (ecp->state) {
+
+ case Idle:
+ /*
+ * set the channel Running ...
+ */
+
+ /* 28.9 - (14): enable tx/rx in gfmr */
+ fcp->fcc_gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR;
+
+ ecp->state = Running;
+ break;
+
+ case Running:
+ /*
+ * (while Running only) check for
+ * termination of the test
+ */
+
+ (void)ctrlc ();
+
+ if (had_ctrlc ()) {
+ /*
+ * initiate a "graceful stop transmit"
+ * on the channel
+ */
+ cp->cp_cpcr = mk_cr_cmd (ecp->page, \
+ ecp->sblock, 0x0c, \
+ CPM_CR_GRACEFUL_STOP_TX) | \
+ CPM_CR_FLG;
+ do {
+ __asm__ __volatile__ ("eieio");
+ } while (cp->cp_cpcr & CPM_CR_FLG);
+
+ ecp->clstime = get_timer (0);
+ ecp->state = Closing;
+ }
+ /* fall through ... */
+
+ case Closing:
+ /*
+ * (while Running or Closing) poll the channel:
+ * - check for any non-READY tx buffers and
+ * make them ready
+ * - check for any non-EMPTY rx buffers and
+ * check that they were received correctly,
+ * adjust counters etc, then make empty
+ */
+
+ for (i = 0; i < ELBT_NTXBD; i++) {
+ cbd_t *bdp = &ecp->txbd[i];
+ ushort sc = bdp->cbd_sc;
+
+ if ((sc & BD_ENET_TX_READY) != 0)
+ continue;
+
+ /*
+ * this frame has finished
+ * transmitting
+ */
+ ecp->nsent++;
+
+ if (sc & BD_ENET_TX_STATS) {
+ ulong n;
+
+ /*
+ * we had an error on
+ * the transmission
+ */
+ n = ecp->ntxerr++;
+ if (n < ELBT_MAXTXERR)
+ ecp->txerrs[n] = sc;
+
+ if (sc & BD_ENET_TX_DEF)
+ ecp->txeacc.def++;
+ if (sc & BD_ENET_TX_HB)
+ ecp->txeacc.hb++;
+ if (sc & BD_ENET_TX_LC)
+ ecp->txeacc.lc++;
+ if (sc & BD_ENET_TX_RL)
+ ecp->txeacc.rl++;
+ if (sc & BD_ENET_TX_RCMASK)
+ ecp->txeacc.rc++;
+ if (sc & BD_ENET_TX_UN)
+ ecp->txeacc.un++;
+ if (sc & BD_ENET_TX_CSL)
+ ecp->txeacc.csl++;
+
+ bdp->cbd_sc &= \
+ ~BD_ENET_TX_STATS;
+ }
+
+ if (ecp->state == Closing)
+ ecp->clstime = get_timer (0);
+
+ /* make it ready again */
+ bdp->cbd_sc |= BD_ENET_TX_READY;
+ }
+
+ for (i = 0; i < ELBT_NRXBD; i++) {
+ cbd_t *bdp = &ecp->rxbd[i];
+ ushort sc = bdp->cbd_sc, mask;
+
+ if ((sc & BD_ENET_RX_EMPTY) != 0)
+ continue;
+
+ /* we have a new frame in this buffer */
+ ecp->nrcvd++;
+
+ mask = BD_ENET_RX_LAST|BD_ENET_RX_FIRST;
+ if ((sc & mask) != mask) {
+ /* somethings wrong here ... */
+ if (!(sc & BD_ENET_RX_LAST))
+ ecp->rxeacc._l++;
+ if (!(sc & BD_ENET_RX_FIRST))
+ ecp->rxeacc._f++;
+ }
+
+ if (sc & BD_ENET_RX_ERRS) {
+ ulong n;
+
+ /*
+ * we had some sort of error
+ * on the frame
+ */
+ n = ecp->nrxerr++;
+ if (n < ELBT_MAXRXERR)
+ ecp->rxerrs[n] = sc;
+
+ if (sc & BD_ENET_RX_MISS)
+ ecp->rxeacc.m++;
+ if (sc & BD_ENET_RX_BC)
+ ecp->rxeacc.bc++;
+ if (sc & BD_ENET_RX_MC)
+ ecp->rxeacc.mc++;
+ if (sc & BD_ENET_RX_LG)
+ ecp->rxeacc.lg++;
+ if (sc & BD_ENET_RX_NO)
+ ecp->rxeacc.no++;
+ if (sc & BD_ENET_RX_SH)
+ ecp->rxeacc.sh++;
+ if (sc & BD_ENET_RX_CR)
+ ecp->rxeacc.cr++;
+ if (sc & BD_ENET_RX_OV)
+ ecp->rxeacc.ov++;
+ if (sc & BD_ENET_RX_CL)
+ ecp->rxeacc.cl++;
+
+ bdp->cbd_sc &= \
+ ~BD_ENET_RX_ERRS;
+ }
+ else {
+ ushort datlen = bdp->cbd_datlen;
+ struct ethernet_hdr *ehp;
+ ushort prot;
+ int ours, tb, n, nbytes;
+
+ ehp = (struct ethernet_hdr *) \
+ &ecp->rxbufs[i][0];
+
+ ours = memcmp (ehp->et_src, \
+ NetOurEther, 6);
+
+ prot = swap16 (ehp->et_protlen);
+ tb = prot & 0x8000;
+ n = prot & 0x7fff;
+
+ nbytes = ELBT_BUFSZ -
+ ETHER_HDR_SIZE -
+ ELBT_CRCSZ;
+
+ /* check the frame is correct */
+ if (datlen != ELBT_BUFSZ)
+ ecp->rxeacc.badlen++;
+ else if (!ours)
+ ecp->rxeacc.badsrc++;
+ else if (!tb || n >= ELBT_NTXBD)
+ ecp->rxeacc.badtyp++;
+ else {
+ ulong patword = \
+ patwords[n];
+ uint nbb;
+
+ nbb = badbits(
+ ((uchar *)&ehp) +
+ ETHER_HDR_SIZE,
+ nbytes, patword);
+
+ ecp->rxeacc.badbit += \
+ nbb;
+ }
+ }
+
+ if (ecp->state == Closing)
+ ecp->clstime = get_timer (0);
+
+ /* make it empty again */
+ bdp->cbd_sc |= BD_ENET_RX_EMPTY;
+ }
+
+ if (ecp->state != Closing)
+ break;
+
+ /*
+ * (while Closing) check to see if
+ * waited long enough
+ */
+
+ if (get_timer (ecp->clstime) >= ELBT_CLSWAIT) {
+ /* write GFMR: disable tx/rx */
+ fcp->fcc_gfmr &= \
+ ~(FCC_GFMR_ENT | FCC_GFMR_ENR);
+ ecp->state = Closed;
+ }
+
+ break;
+
+ case Closed:
+ nclosed++;
+ break;
+ }
+ }
+
+ } while (nclosed < (FCC_END_LOOP - FCC_START_LOOP + 1));
+
+ runtime = get_timer (runtime);
+ if (runtime <= ELBT_CLSWAIT) {
+ printf ("Whoops! somehow elapsed time (%ld) is wrong (<= %d)\n",
+ runtime, ELBT_CLSWAIT);
+ return;
+ }
+ nmsec = runtime - ELBT_CLSWAIT;
+
+ printf ("Test Finished in %ldms (plus %dms close wait period)!\n\n",
+ nmsec, ELBT_CLSWAIT);
+
+ /*
+ * now print stats
+ */
+
+ for (c = FCC_START_LOOP; c <= FCC_END_LOOP; c++) {
+ elbt_chan *ecp = &elbt_chans[c];
+ uint rxpps, txpps, nerr;
+
+ rxpps = (ecp->nrcvd * 1000) / nmsec;
+ txpps = (ecp->nsent * 1000) / nmsec;
+
+ printf ("Channel %d: %d rcvd (%d pps, %d rxerrs), "
+ "%d sent (%d pps, %d txerrs)\n\n", c,
+ ecp->nrcvd, rxpps, ecp->nrxerr,
+ ecp->nsent, txpps, ecp->ntxerr);
+
+ if ((nerr = ecp->nrxerr) > 0) {
+ ulong i;
+
+ printf ("\tFirst %d rx errs:", nerr);
+ for (i = 0; i < nerr; i++)
+ printf (" %04x", ecp->rxerrs[i]);
+ putc ('\n');
+ }
+
+ if ((nerr = ecp->ntxerr) > 0) {
+ ulong i;
+
+ printf ("\tFirst %d tx errs:", nerr);
+ for (i = 0; i < nerr; i++)
+ printf (" %04x", ecp->txerrs[i]);
+ putc ('\n');
+ }
+ }
+
+ puts ("Receive Error Counts:\n");
+ for (c = FCC_START_LOOP; c <= FCC_END_LOOP; c++)
+ bases[c] = (uchar *)&elbt_chans[c].rxeacc;
+ print_desc (rxeacc_descs, rxeacc_ndesc, bases, 3);
+
+ puts ("\nTransmit Error Counts:\n");
+ for (c = FCC_START_LOOP; c <= FCC_END_LOOP; c++)
+ bases[c] = (uchar *)&elbt_chans[c].txeacc;
+ print_desc (txeacc_descs, txeacc_ndesc, bases, 3);
+
+ puts ("\nRMON(-like) Counters:\n");
+ for (c = FCC_START_LOOP; c <= FCC_END_LOOP; c++)
+ bases[c] = (uchar *)&immr->im_dprambase[elbt_chans[c].proff];
+ print_desc (epram_descs, epram_ndesc, bases, 3);
+}
+
+#endif /* CONFIG_ETHER_LOOPBACK_TEST */
+
+#endif
diff --git a/arch/powerpc/cpu/mpc8260/ether_scc.c b/arch/powerpc/cpu/mpc8260/ether_scc.c
new file mode 100644
index 0000000..3c71219
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/ether_scc.c
@@ -0,0 +1,383 @@
+/*
+ * MPC8260 SCC Ethernet
+ *
+ * Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net)
+ *
+ * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright (c) 2001
+ * Advent Networks, Inc. <http://www.adventnetworks.com>
+ * Jay Monkman <jtm@smoothsmoothie.com>
+ *
+ * Modified so that it plays nicely when more than one ETHERNET interface
+ * is in use a la ether_fcc.c.
+ * (C) Copyright 2008
+ * DENX Software Engineerin GmbH
+ * Gary Jennejohn <garyj@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/cpm_8260.h>
+#include <mpc8260.h>
+#include <malloc.h>
+#include <net.h>
+#include <command.h>
+#include <config.h>
+
+#if (CONFIG_ETHER_INDEX == 1)
+# define PROFF_ENET PROFF_SCC1
+# define CPM_CR_ENET_PAGE CPM_CR_SCC1_PAGE
+# define CPM_CR_ENET_SBLOCK CPM_CR_SCC1_SBLOCK
+# define CMXSCR_MASK (CMXSCR_SC1 |\
+ CMXSCR_RS1CS_MSK |\
+ CMXSCR_TS1CS_MSK)
+
+#elif (CONFIG_ETHER_INDEX == 2)
+# define PROFF_ENET PROFF_SCC2
+# define CPM_CR_ENET_PAGE CPM_CR_SCC2_PAGE
+# define CPM_CR_ENET_SBLOCK CPM_CR_SCC2_SBLOCK
+# define CMXSCR_MASK (CMXSCR_SC2 |\
+ CMXSCR_RS2CS_MSK |\
+ CMXSCR_TS2CS_MSK)
+
+#elif (CONFIG_ETHER_INDEX == 3)
+# define PROFF_ENET PROFF_SCC3
+# define CPM_CR_ENET_PAGE CPM_CR_SCC3_PAGE
+# define CPM_CR_ENET_SBLOCK CPM_CR_SCC3_SBLOCK
+# define CMXSCR_MASK (CMXSCR_SC3 |\
+ CMXSCR_RS3CS_MSK |\
+ CMXSCR_TS3CS_MSK)
+#elif (CONFIG_ETHER_INDEX == 4)
+# define PROFF_ENET PROFF_SCC4
+# define CPM_CR_ENET_PAGE CPM_CR_SCC4_PAGE
+# define CPM_CR_ENET_SBLOCK CPM_CR_SCC4_SBLOCK
+# define CMXSCR_MASK (CMXSCR_SC4 |\
+ CMXSCR_RS4CS_MSK |\
+ CMXSCR_TS4CS_MSK)
+
+#endif
+
+
+/* Ethernet Transmit and Receive Buffers */
+#define DBUF_LENGTH 1520
+
+#define TX_BUF_CNT 2
+
+#if !defined(CONFIG_SYS_SCC_TOUT_LOOP)
+ #define CONFIG_SYS_SCC_TOUT_LOOP 1000000
+#endif
+
+static char txbuf[TX_BUF_CNT][ DBUF_LENGTH ];
+
+static uint rxIdx; /* index of the current RX buffer */
+static uint txIdx; /* index of the current TX buffer */
+
+/*
+ * SCC Ethernet Tx and Rx buffer descriptors allocated at the
+ * immr->udata_bd address on Dual-Port RAM
+ * Provide for Double Buffering
+ */
+
+typedef volatile struct CommonBufferDescriptor {
+ cbd_t rxbd[PKTBUFSRX]; /* Rx BD */
+ cbd_t txbd[TX_BUF_CNT]; /* Tx BD */
+} RTXBD;
+
+static RTXBD *rtx;
+
+
+static int sec_send(struct eth_device *dev, void *packet, int length)
+{
+ int i;
+ int result = 0;
+
+ if (length <= 0) {
+ printf("scc: bad packet size: %d\n", length);
+ goto out;
+ }
+
+ for(i=0; rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
+ if (i >= CONFIG_SYS_SCC_TOUT_LOOP) {
+ puts ("scc: tx buffer not ready\n");
+ goto out;
+ }
+ }
+
+ rtx->txbd[txIdx].cbd_bufaddr = (uint)packet;
+ rtx->txbd[txIdx].cbd_datlen = length;
+ rtx->txbd[txIdx].cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_LAST |
+ BD_ENET_TX_WRAP);
+
+ for(i=0; rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
+ if (i >= CONFIG_SYS_SCC_TOUT_LOOP) {
+ puts ("scc: tx error\n");
+ goto out;
+ }
+ }
+
+ /* return only status bits */
+ result = rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_STATS;
+
+ out:
+ return result;
+}
+
+
+static int sec_rx(struct eth_device *dev)
+{
+ int length;
+
+ for (;;)
+ {
+ if (rtx->rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
+ length = -1;
+ break; /* nothing received - leave for() loop */
+ }
+
+ length = rtx->rxbd[rxIdx].cbd_datlen;
+
+ if (rtx->rxbd[rxIdx].cbd_sc & 0x003f)
+ {
+ printf("err: %x\n", rtx->rxbd[rxIdx].cbd_sc);
+ }
+ else
+ {
+ /* Pass the packet up to the protocol layers. */
+ NetReceive(NetRxPackets[rxIdx], length - 4);
+ }
+
+
+ /* Give the buffer back to the SCC. */
+ rtx->rxbd[rxIdx].cbd_datlen = 0;
+
+ /* wrap around buffer index when necessary */
+ if ((rxIdx + 1) >= PKTBUFSRX) {
+ rtx->rxbd[PKTBUFSRX - 1].cbd_sc = (BD_ENET_RX_WRAP |
+ BD_ENET_RX_EMPTY);
+ rxIdx = 0;
+ }
+ else {
+ rtx->rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
+ rxIdx++;
+ }
+ }
+ return length;
+}
+
+/**************************************************************
+ *
+ * SCC Ethernet Initialization Routine
+ *
+ *************************************************************/
+
+static int sec_init(struct eth_device *dev, bd_t *bis)
+{
+ int i;
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ scc_enet_t *pram_ptr;
+ uint dpaddr;
+ uchar ea[6];
+
+ rxIdx = 0;
+ txIdx = 0;
+
+ /*
+ * Assign static pointer to BD area.
+ * Avoid exhausting DPRAM, which would cause a panic.
+ */
+ if (rtx == NULL) {
+ dpaddr = m8260_cpm_dpalloc(sizeof(RTXBD) + 2, 16);
+ rtx = (RTXBD *)&immr->im_dprambase[dpaddr];
+ }
+
+ /* 24.21 - (1-3): ioports have been set up already */
+
+ /* 24.21 - (4,5): connect SCC's tx and rx clocks, use NMSI for SCC */
+ immr->im_cpmux.cmx_uar = 0;
+ immr->im_cpmux.cmx_scr = ( (immr->im_cpmux.cmx_scr & ~CMXSCR_MASK) |
+ CONFIG_SYS_CMXSCR_VALUE);
+
+
+ /* 24.21 (6) write RBASE and TBASE to parameter RAM */
+ pram_ptr = (scc_enet_t *)&(immr->im_dprambase[PROFF_ENET]);
+ pram_ptr->sen_genscc.scc_rbase = (unsigned int)(&rtx->rxbd[0]);
+ pram_ptr->sen_genscc.scc_tbase = (unsigned int)(&rtx->txbd[0]);
+
+ pram_ptr->sen_genscc.scc_rfcr = 0x18; /* Nrml Ops and Mot byte ordering */
+ pram_ptr->sen_genscc.scc_tfcr = 0x18; /* Mot byte ordering, Nrml access */
+
+ pram_ptr->sen_genscc.scc_mrblr = DBUF_LENGTH; /* max. package len 1520 */
+
+ pram_ptr->sen_cpres = ~(0x0); /* Preset CRC */
+ pram_ptr->sen_cmask = 0xdebb20e3; /* Constant Mask for CRC */
+
+
+ /* 24.21 - (7): Write INIT RX AND TX PARAMETERS to CPCR */
+ while(immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+ immr->im_cpm.cp_cpcr = mk_cr_cmd(CPM_CR_ENET_PAGE,
+ CPM_CR_ENET_SBLOCK,
+ 0x0c,
+ CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+ /* 24.21 - (8-18): Set up parameter RAM */
+ pram_ptr->sen_crcec = 0x0; /* Error Counter CRC (unused) */
+ pram_ptr->sen_alec = 0x0; /* Align Error Counter (unused) */
+ pram_ptr->sen_disfc = 0x0; /* Discard Frame Counter (unused) */
+
+ pram_ptr->sen_pads = 0x8888; /* Short Frame PAD Characters */
+
+ pram_ptr->sen_retlim = 15; /* Retry Limit Threshold */
+
+ pram_ptr->sen_maxflr = 1518; /* MAX Frame Length Register */
+ pram_ptr->sen_minflr = 64; /* MIN Frame Length Register */
+
+ pram_ptr->sen_maxd1 = DBUF_LENGTH; /* MAX DMA1 Length Register */
+ pram_ptr->sen_maxd2 = DBUF_LENGTH; /* MAX DMA2 Length Register */
+
+ pram_ptr->sen_gaddr1 = 0x0; /* Group Address Filter 1 (unused) */
+ pram_ptr->sen_gaddr2 = 0x0; /* Group Address Filter 2 (unused) */
+ pram_ptr->sen_gaddr3 = 0x0; /* Group Address Filter 3 (unused) */
+ pram_ptr->sen_gaddr4 = 0x0; /* Group Address Filter 4 (unused) */
+
+ eth_getenv_enetaddr("ethaddr", ea);
+ pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4];
+ pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2];
+ pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0];
+
+ pram_ptr->sen_pper = 0x0; /* Persistence (unused) */
+
+ pram_ptr->sen_iaddr1 = 0x0; /* Individual Address Filter 1 (unused) */
+ pram_ptr->sen_iaddr2 = 0x0; /* Individual Address Filter 2 (unused) */
+ pram_ptr->sen_iaddr3 = 0x0; /* Individual Address Filter 3 (unused) */
+ pram_ptr->sen_iaddr4 = 0x0; /* Individual Address Filter 4 (unused) */
+
+ pram_ptr->sen_taddrh = 0x0; /* Tmp Address (MSB) (unused) */
+ pram_ptr->sen_taddrm = 0x0; /* Tmp Address (unused) */
+ pram_ptr->sen_taddrl = 0x0; /* Tmp Address (LSB) (unused) */
+
+ /* 24.21 - (19): Initialize RxBD */
+ for (i = 0; i < PKTBUFSRX; i++)
+ {
+ rtx->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
+ rtx->rxbd[i].cbd_datlen = 0; /* Reset */
+ rtx->rxbd[i].cbd_bufaddr = (uint)NetRxPackets[i];
+ }
+
+ rtx->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+ /* 24.21 - (20): Initialize TxBD */
+ for (i = 0; i < TX_BUF_CNT; i++)
+ {
+ rtx->txbd[i].cbd_sc = (BD_ENET_TX_PAD |
+ BD_ENET_TX_LAST |
+ BD_ENET_TX_TC);
+ rtx->txbd[i].cbd_datlen = 0; /* Reset */
+ rtx->txbd[i].cbd_bufaddr = (uint)&txbuf[i][0];
+ }
+
+ rtx->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+ /* 24.21 - (21): Write 0xffff to SCCE */
+ immr->im_scc[CONFIG_ETHER_INDEX-1].scc_scce = ~(0x0);
+
+ /* 24.21 - (22): Write to SCCM to enable TXE, RXF, TXB events */
+ immr->im_scc[CONFIG_ETHER_INDEX-1].scc_sccm = (SCCE_ENET_TXE |
+ SCCE_ENET_RXF |
+ SCCE_ENET_TXB);
+
+ /* 24.21 - (23): we don't use ethernet interrupts */
+
+ /* 24.21 - (24): Clear GSMR_H to enable normal operations */
+ immr->im_scc[CONFIG_ETHER_INDEX-1].scc_gsmrh = 0;
+
+ /* 24.21 - (25): Clear GSMR_L to enable normal operations */
+ immr->im_scc[CONFIG_ETHER_INDEX-1].scc_gsmrl = (SCC_GSMRL_TCI |
+ SCC_GSMRL_TPL_48 |
+ SCC_GSMRL_TPP_10 |
+ SCC_GSMRL_MODE_ENET);
+
+ /* 24.21 - (26): Initialize DSR */
+ immr->im_scc[CONFIG_ETHER_INDEX-1].scc_dsr = 0xd555;
+
+ /* 24.21 - (27): Initialize PSMR2
+ *
+ * Settings:
+ * CRC = 32-Bit CCITT
+ * NIB = Begin searching for SFD 22 bits after RENA
+ * FDE = Full Duplex Enable
+ * BRO = Reject broadcast packets
+ * PROMISCOUS = Catch all packets regardless of dest. MAC adress
+ */
+ immr->im_scc[CONFIG_ETHER_INDEX-1].scc_psmr = SCC_PSMR_ENCRC |
+ SCC_PSMR_NIB22 |
+#if defined(CONFIG_SCC_ENET_FULL_DUPLEX)
+ SCC_PSMR_FDE |
+#endif
+#if defined(CONFIG_SCC_ENET_NO_BROADCAST)
+ SCC_PSMR_BRO |
+#endif
+#if defined(CONFIG_SCC_ENET_PROMISCOUS)
+ SCC_PSMR_PRO |
+#endif
+ 0;
+
+ /* 24.21 - (28): Write to GSMR_L to enable SCC */
+ immr->im_scc[CONFIG_ETHER_INDEX-1].scc_gsmrl |= (SCC_GSMRL_ENR |
+ SCC_GSMRL_ENT);
+
+ return 0;
+}
+
+
+static void sec_halt(struct eth_device *dev)
+{
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ immr->im_scc[CONFIG_ETHER_INDEX-1].scc_gsmrl &= ~(SCC_GSMRL_ENR |
+ SCC_GSMRL_ENT);
+}
+
+#if 0
+static void sec_restart(void)
+{
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ immr->im_cpm.cp_scc[CONFIG_ETHER_INDEX-1].scc_gsmrl |= (SCC_GSMRL_ENR |
+ SCC_GSMRL_ENT);
+}
+#endif
+
+int mpc82xx_scc_enet_initialize(bd_t *bis)
+{
+ struct eth_device *dev;
+
+ dev = (struct eth_device *) malloc(sizeof *dev);
+ memset(dev, 0, sizeof *dev);
+
+ sprintf(dev->name, "SCC");
+ dev->init = sec_init;
+ dev->halt = sec_halt;
+ dev->send = sec_send;
+ dev->recv = sec_rx;
+
+ eth_register(dev);
+
+ return 1;
+}
diff --git a/arch/powerpc/cpu/mpc8260/i2c.c b/arch/powerpc/cpu/mpc8260/i2c.c
new file mode 100644
index 0000000..e2341e9
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/i2c.c
@@ -0,0 +1,770 @@
+/*
+ * (C) Copyright 2000
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ *
+ * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_HARD_I2C)
+
+#include <asm/cpm_8260.h>
+#include <i2c.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_I2C_MULTI_BUS)
+static unsigned int i2c_bus_num __attribute__ ((section(".data"))) = 0;
+#endif /* CONFIG_I2C_MULTI_BUS */
+
+/* uSec to wait between polls of the i2c */
+#define DELAY_US 100
+/* uSec to wait for the CPM to start processing the buffer */
+#define START_DELAY_US 1000
+
+/*
+ * tx/rx per-byte timeout: we delay DELAY_US uSec between polls so the
+ * timeout will be (tx_length + rx_length) * DELAY_US * TOUT_LOOP
+ */
+#define TOUT_LOOP 5
+
+/*
+ * Set default values
+ */
+#ifndef CONFIG_SYS_I2C_SPEED
+#define CONFIG_SYS_I2C_SPEED 50000
+#endif
+
+
+typedef void (*i2c_ecb_t) (int, int, void *); /* error callback function */
+
+/* This structure keeps track of the bd and buffer space usage. */
+typedef struct i2c_state {
+ int rx_idx; /* index to next free Rx BD */
+ int tx_idx; /* index to next free Tx BD */
+ void *rxbd; /* pointer to next free Rx BD */
+ void *txbd; /* pointer to next free Tx BD */
+ int tx_space; /* number of Tx bytes left */
+ unsigned char *tx_buf; /* pointer to free Tx area */
+ i2c_ecb_t err_cb; /* error callback function */
+ void *cb_data; /* private data to be passed */
+} i2c_state_t;
+
+/* flags for i2c_send() and i2c_receive() */
+#define I2CF_ENABLE_SECONDARY 0x01 /* secondary_address is valid */
+#define I2CF_START_COND 0x02 /* tx: generate start condition */
+#define I2CF_STOP_COND 0x04 /* tx: generate stop condition */
+
+/* return codes */
+#define I2CERR_NO_BUFFERS 1 /* no more BDs or buffer space */
+#define I2CERR_MSG_TOO_LONG 2 /* tried to send/receive to much data */
+#define I2CERR_TIMEOUT 3 /* timeout in i2c_doio() */
+#define I2CERR_QUEUE_EMPTY 4 /* i2c_doio called without send/rcv */
+#define I2CERR_IO_ERROR 5 /* had an error during comms */
+
+/* error callback flags */
+#define I2CECB_RX_ERR 0x10 /* this is a receive error */
+#define I2CECB_RX_OV 0x02 /* receive overrun error */
+#define I2CECB_RX_MASK 0x0f /* mask for error bits */
+#define I2CECB_TX_ERR 0x20 /* this is a transmit error */
+#define I2CECB_TX_CL 0x01 /* transmit collision error */
+#define I2CECB_TX_UN 0x02 /* transmit underflow error */
+#define I2CECB_TX_NAK 0x04 /* transmit no ack error */
+#define I2CECB_TX_MASK 0x0f /* mask for error bits */
+#define I2CECB_TIMEOUT 0x40 /* this is a timeout error */
+
+#define ERROR_I2C_NONE 0
+#define ERROR_I2C_LENGTH 1
+
+#define I2C_WRITE_BIT 0x00
+#define I2C_READ_BIT 0x01
+
+#define I2C_RXTX_LEN 128 /* maximum tx/rx buffer length */
+
+
+#define NUM_RX_BDS 4
+#define NUM_TX_BDS 4
+#define MAX_TX_SPACE 256
+
+typedef struct I2C_BD {
+ unsigned short status;
+ unsigned short length;
+ unsigned char *addr;
+} I2C_BD;
+
+#define BD_I2C_TX_START 0x0400 /* special status for i2c: Start condition */
+
+#define BD_I2C_TX_CL 0x0001 /* collision error */
+#define BD_I2C_TX_UN 0x0002 /* underflow error */
+#define BD_I2C_TX_NAK 0x0004 /* no acknowledge error */
+#define BD_I2C_TX_ERR (BD_I2C_TX_NAK|BD_I2C_TX_UN|BD_I2C_TX_CL)
+
+#define BD_I2C_RX_ERR BD_SC_OV
+
+/*
+ * Returns the best value of I2BRG to meet desired clock speed of I2C with
+ * input parameters (clock speed, filter, and predivider value).
+ * It returns computer speed value and the difference between it and desired
+ * speed.
+ */
+static inline int
+i2c_roundrate(int hz, int speed, int filter, int modval,
+ int *brgval, int *totspeed)
+{
+ int moddiv = 1 << (5 - (modval & 3)), brgdiv, div;
+
+ debug("\t[I2C] trying hz=%d, speed=%d, filter=%d, modval=%d\n",
+ hz, speed, filter, modval);
+
+ div = moddiv * speed;
+ brgdiv = (hz + div - 1) / div;
+
+ debug("\t\tmoddiv=%d, brgdiv=%d\n", moddiv, brgdiv);
+
+ *brgval = ((brgdiv + 1) / 2) - 3 - (2 * filter);
+
+ if ((*brgval < 0) || (*brgval > 255)) {
+ debug("\t\trejected brgval=%d\n", *brgval);
+ return -1;
+ }
+
+ brgdiv = 2 * (*brgval + 3 + (2 * filter));
+ div = moddiv * brgdiv;
+ *totspeed = hz / div;
+
+ debug("\t\taccepted brgval=%d, totspeed=%d\n", *brgval, *totspeed);
+
+ return 0;
+}
+
+/*
+ * Sets the I2C clock predivider and divider to meet required clock speed.
+ */
+static int i2c_setrate(int hz, int speed)
+{
+ immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+ volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c;
+ int brgval,
+ modval, /* 0-3 */
+ bestspeed_diff = speed,
+ bestspeed_brgval = 0,
+ bestspeed_modval = 0,
+ bestspeed_filter = 0,
+ totspeed,
+ filter = 0; /* Use this fixed value */
+
+ for (modval = 0; modval < 4; modval++) {
+ if (i2c_roundrate(hz, speed, filter, modval, &brgval, &totspeed)
+ == 0) {
+ int diff = speed - totspeed;
+
+ if ((diff >= 0) && (diff < bestspeed_diff)) {
+ bestspeed_diff = diff;
+ bestspeed_modval = modval;
+ bestspeed_brgval = brgval;
+ bestspeed_filter = filter;
+ }
+ }
+ }
+
+ debug("[I2C] Best is:\n");
+ debug("[I2C] CPU=%dhz RATE=%d F=%d I2MOD=%08x I2BRG=%08x DIFF=%dhz\n",
+ hz, speed, bestspeed_filter, bestspeed_modval, bestspeed_brgval,
+ bestspeed_diff);
+
+ i2c->i2c_i2mod |= ((bestspeed_modval & 3) << 1) |
+ (bestspeed_filter << 3);
+ i2c->i2c_i2brg = bestspeed_brgval & 0xff;
+
+ debug("[I2C] i2mod=%08x i2brg=%08x\n", i2c->i2c_i2mod,
+ i2c->i2c_i2brg);
+
+ return 1;
+}
+
+void i2c_init(int speed, int slaveadd)
+{
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8260_t *cp = (cpm8260_t *)&immap->im_cpm;
+ volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c;
+ volatile iic_t *iip;
+ ulong rbase, tbase;
+ volatile I2C_BD *rxbd, *txbd;
+ uint dpaddr;
+
+#ifdef CONFIG_SYS_I2C_INIT_BOARD
+ /*
+ * call board specific i2c bus reset routine before accessing the
+ * environment, which might be in a chip on that bus. For details
+ * about this problem see doc/I2C_Edge_Conditions.
+ */
+ i2c_init_board();
+#endif
+
+ dpaddr = immap->im_dprambase16[PROFF_I2C_BASE / sizeof(u16)];
+ if (dpaddr == 0) {
+ /* need to allocate dual port ram */
+ dpaddr = m8260_cpm_dpalloc(64 +
+ (NUM_RX_BDS * sizeof(I2C_BD)) +
+ (NUM_TX_BDS * sizeof(I2C_BD)) +
+ MAX_TX_SPACE, 64);
+ immap->im_dprambase16[PROFF_I2C_BASE / sizeof(u16)] =
+ dpaddr;
+ }
+
+ /*
+ * initialise data in dual port ram:
+ *
+ * dpaddr -> parameter ram (64 bytes)
+ * rbase -> rx BD (NUM_RX_BDS * sizeof(I2C_BD) bytes)
+ * tbase -> tx BD (NUM_TX_BDS * sizeof(I2C_BD) bytes)
+ * tx buffer (MAX_TX_SPACE bytes)
+ */
+
+ iip = (iic_t *)&immap->im_dprambase[dpaddr];
+ memset((void *)iip, 0, sizeof(iic_t));
+
+ rbase = dpaddr + 64;
+ tbase = rbase + NUM_RX_BDS * sizeof(I2C_BD);
+
+ /* Disable interrupts */
+ i2c->i2c_i2mod = 0x00;
+ i2c->i2c_i2cmr = 0x00;
+ i2c->i2c_i2cer = 0xff;
+ i2c->i2c_i2add = slaveadd;
+
+ /*
+ * Set the I2C BRG Clock division factor from desired i2c rate
+ * and current CPU rate (we assume sccr dfbgr field is 0;
+ * divide BRGCLK by 1)
+ */
+ debug("[I2C] Setting rate...\n");
+ i2c_setrate(gd->arch.brg_clk, CONFIG_SYS_I2C_SPEED);
+
+ /* Set I2C controller in master mode */
+ i2c->i2c_i2com = 0x01;
+
+ /* Initialize Tx/Rx parameters */
+ iip->iic_rbase = rbase;
+ iip->iic_tbase = tbase;
+ rxbd = (I2C_BD *)((unsigned char *) &immap->
+ im_dprambase[iip->iic_rbase]);
+ txbd = (I2C_BD *)((unsigned char *) &immap->
+ im_dprambase[iip->iic_tbase]);
+
+ debug("[I2C] rbase = %04x\n", iip->iic_rbase);
+ debug("[I2C] tbase = %04x\n", iip->iic_tbase);
+ debug("[I2C] rxbd = %08x\n", (int) rxbd);
+ debug("[I2C] txbd = %08x\n", (int) txbd);
+
+ /* Set big endian byte order */
+ iip->iic_tfcr = 0x10;
+ iip->iic_rfcr = 0x10;
+
+ /* Set maximum receive size. */
+ iip->iic_mrblr = I2C_RXTX_LEN;
+
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_I2C_PAGE,
+ CPM_CR_I2C_SBLOCK,
+ 0x00, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ do {
+ __asm__ __volatile__("eieio");
+ } while (cp->cp_cpcr & CPM_CR_FLG);
+
+ /* Clear events and interrupts */
+ i2c->i2c_i2cer = 0xff;
+ i2c->i2c_i2cmr = 0x00;
+}
+
+static
+void i2c_newio(i2c_state_t *state)
+{
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+ volatile iic_t *iip;
+ uint dpaddr;
+
+ debug("[I2C] i2c_newio\n");
+
+ dpaddr = immap->im_dprambase16[PROFF_I2C_BASE / sizeof(u16)];
+ iip = (iic_t *)&immap->im_dprambase[dpaddr];
+ state->rx_idx = 0;
+ state->tx_idx = 0;
+ state->rxbd = (void *)&immap->im_dprambase[iip->iic_rbase];
+ state->txbd = (void *)&immap->im_dprambase[iip->iic_tbase];
+ state->tx_space = MAX_TX_SPACE;
+ state->tx_buf = (uchar *)state->txbd + NUM_TX_BDS * sizeof(I2C_BD);
+ state->err_cb = NULL;
+ state->cb_data = NULL;
+
+ debug("[I2C] rxbd = %08x\n", (int)state->rxbd);
+ debug("[I2C] txbd = %08x\n", (int)state->txbd);
+ debug("[I2C] tx_buf = %08x\n", (int)state->tx_buf);
+
+ /* clear the buffer memory */
+ memset((char *) state->tx_buf, 0, MAX_TX_SPACE);
+}
+
+static
+int i2c_send(i2c_state_t *state,
+ unsigned char address,
+ unsigned char secondary_address,
+ unsigned int flags, unsigned short size, unsigned char *dataout)
+{
+ volatile I2C_BD *txbd;
+ int i, j;
+
+ debug("[I2C] i2c_send add=%02d sec=%02d flag=%02d size=%d\n",
+ address, secondary_address, flags, size);
+
+ /* trying to send message larger than BD */
+ if (size > I2C_RXTX_LEN)
+ return I2CERR_MSG_TOO_LONG;
+
+ /* no more free bds */
+ if (state->tx_idx >= NUM_TX_BDS || state->tx_space < (2 + size))
+ return I2CERR_NO_BUFFERS;
+
+ txbd = (I2C_BD *)state->txbd;
+ txbd->addr = state->tx_buf;
+
+ debug("[I2C] txbd = %08x\n", (int) txbd);
+
+ if (flags & I2CF_START_COND) {
+ debug("[I2C] Formatting addresses...\n");
+ if (flags & I2CF_ENABLE_SECONDARY) {
+ /* Length of message plus dest addresses */
+ txbd->length = size + 2;
+ txbd->addr[0] = address << 1;
+ txbd->addr[1] = secondary_address;
+ i = 2;
+ } else {
+ /* Length of message plus dest address */
+ txbd->length = size + 1;
+ /* Write destination address to BD */
+ txbd->addr[0] = address << 1;
+ i = 1;
+ }
+ } else {
+ txbd->length = size; /* Length of message */
+ i = 0;
+ }
+
+ /* set up txbd */
+ txbd->status = BD_SC_READY;
+ if (flags & I2CF_START_COND)
+ txbd->status |= BD_I2C_TX_START;
+ if (flags & I2CF_STOP_COND)
+ txbd->status |= BD_SC_LAST | BD_SC_WRAP;
+
+ /* Copy data to send into buffer */
+ debug("[I2C] copy data...\n");
+ for (j = 0; j < size; i++, j++)
+ txbd->addr[i] = dataout[j];
+
+ debug("[I2C] txbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n",
+ txbd->length, txbd->status, txbd->addr[0], txbd->addr[1]);
+
+ /* advance state */
+ state->tx_buf += txbd->length;
+ state->tx_space -= txbd->length;
+ state->tx_idx++;
+ state->txbd = (void *) (txbd + 1);
+
+ return 0;
+}
+
+static
+int i2c_receive(i2c_state_t *state,
+ unsigned char address,
+ unsigned char secondary_address,
+ unsigned int flags,
+ unsigned short size_to_expect, unsigned char *datain)
+{
+ volatile I2C_BD *rxbd, *txbd;
+
+ debug("[I2C] i2c_receive %02d %02d %02d\n", address,
+ secondary_address, flags);
+
+ /* Expected to receive too much */
+ if (size_to_expect > I2C_RXTX_LEN)
+ return I2CERR_MSG_TOO_LONG;
+
+ /* no more free bds */
+ if (state->tx_idx >= NUM_TX_BDS || state->rx_idx >= NUM_RX_BDS
+ || state->tx_space < 2)
+ return I2CERR_NO_BUFFERS;
+
+ rxbd = (I2C_BD *) state->rxbd;
+ txbd = (I2C_BD *) state->txbd;
+
+ debug("[I2C] rxbd = %08x\n", (int) rxbd);
+ debug("[I2C] txbd = %08x\n", (int) txbd);
+
+ txbd->addr = state->tx_buf;
+
+ /* set up TXBD for destination address */
+ if (flags & I2CF_ENABLE_SECONDARY) {
+ txbd->length = 2;
+ txbd->addr[0] = address << 1; /* Write data */
+ txbd->addr[1] = secondary_address; /* Internal address */
+ txbd->status = BD_SC_READY;
+ } else {
+ txbd->length = 1 + size_to_expect;
+ txbd->addr[0] = (address << 1) | 0x01;
+ txbd->status = BD_SC_READY;
+ memset(&txbd->addr[1], 0, txbd->length);
+ }
+
+ /* set up rxbd for reception */
+ rxbd->status = BD_SC_EMPTY;
+ rxbd->length = size_to_expect;
+ rxbd->addr = datain;
+
+ txbd->status |= BD_I2C_TX_START;
+ if (flags & I2CF_STOP_COND) {
+ txbd->status |= BD_SC_LAST | BD_SC_WRAP;
+ rxbd->status |= BD_SC_WRAP;
+ }
+
+ debug("[I2C] txbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n",
+ txbd->length, txbd->status, txbd->addr[0], txbd->addr[1]);
+ debug("[I2C] rxbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n",
+ rxbd->length, rxbd->status, rxbd->addr[0], rxbd->addr[1]);
+
+ /* advance state */
+ state->tx_buf += txbd->length;
+ state->tx_space -= txbd->length;
+ state->tx_idx++;
+ state->txbd = (void *) (txbd + 1);
+ state->rx_idx++;
+ state->rxbd = (void *) (rxbd + 1);
+
+ return 0;
+}
+
+
+static
+int i2c_doio(i2c_state_t *state)
+{
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+ volatile iic_t *iip;
+ volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c;
+ volatile I2C_BD *txbd, *rxbd;
+ int n, i, b, rxcnt = 0, rxtimeo = 0, txcnt = 0, txtimeo = 0, rc = 0;
+ uint dpaddr;
+
+ debug("[I2C] i2c_doio\n");
+
+ if (state->tx_idx <= 0 && state->rx_idx <= 0) {
+ debug("[I2C] No I/O is queued\n");
+ return I2CERR_QUEUE_EMPTY;
+ }
+
+ dpaddr = immap->im_dprambase16[PROFF_I2C_BASE / sizeof(u16)];
+ iip = (iic_t *)&immap->im_dprambase[dpaddr];
+ iip->iic_rbptr = iip->iic_rbase;
+ iip->iic_tbptr = iip->iic_tbase;
+
+ /* Enable I2C */
+ debug("[I2C] Enabling I2C...\n");
+ i2c->i2c_i2mod |= 0x01;
+
+ /* Begin transmission */
+ i2c->i2c_i2com |= 0x80;
+
+ /* Loop until transmit & receive completed */
+
+ n = state->tx_idx;
+
+ if (n > 0) {
+
+ txbd = ((I2C_BD *) state->txbd) - n;
+ for (i = 0; i < n; i++) {
+ txtimeo += TOUT_LOOP * txbd->length;
+ txbd++;
+ }
+
+ txbd--; /* wait until last in list is done */
+
+ debug("[I2C] Transmitting...(txbd=0x%08lx)\n",
+ (ulong) txbd);
+
+ udelay(START_DELAY_US); /* give it time to start */
+ while ((txbd->status & BD_SC_READY) && (++txcnt < txtimeo)) {
+ udelay(DELAY_US);
+ if (ctrlc())
+ return -1;
+ __asm__ __volatile__("eieio");
+ }
+ }
+
+ n = state->rx_idx;
+
+ if (txcnt < txtimeo && n > 0) {
+
+ rxbd = ((I2C_BD *) state->rxbd) - n;
+ for (i = 0; i < n; i++) {
+ rxtimeo += TOUT_LOOP * rxbd->length;
+ rxbd++;
+ }
+
+ rxbd--; /* wait until last in list is done */
+
+ debug("[I2C] Receiving...(rxbd=0x%08lx)\n", (ulong) rxbd);
+
+ udelay(START_DELAY_US); /* give it time to start */
+ while ((rxbd->status & BD_SC_EMPTY) && (++rxcnt < rxtimeo)) {
+ udelay(DELAY_US);
+ if (ctrlc())
+ return -1;
+ __asm__ __volatile__("eieio");
+ }
+ }
+
+ /* Turn off I2C */
+ i2c->i2c_i2mod &= ~0x01;
+
+ n = state->tx_idx;
+
+ if (n > 0) {
+ for (i = 0; i < n; i++) {
+ txbd = ((I2C_BD *) state->txbd) - (n - i);
+ b = txbd->status & BD_I2C_TX_ERR;
+ if (b != 0) {
+ if (state->err_cb != NULL)
+ (*state->err_cb) (I2CECB_TX_ERR | b,
+ i, state->cb_data);
+ if (rc == 0)
+ rc = I2CERR_IO_ERROR;
+ }
+ }
+ }
+
+ n = state->rx_idx;
+
+ if (n > 0) {
+ for (i = 0; i < n; i++) {
+ rxbd = ((I2C_BD *) state->rxbd) - (n - i);
+ b = rxbd->status & BD_I2C_RX_ERR;
+ if (b != 0) {
+ if (state->err_cb != NULL)
+ (*state->err_cb) (I2CECB_RX_ERR | b,
+ i, state->cb_data);
+ if (rc == 0)
+ rc = I2CERR_IO_ERROR;
+ }
+ }
+ }
+
+ if ((txtimeo > 0 && txcnt >= txtimeo) ||
+ (rxtimeo > 0 && rxcnt >= rxtimeo)) {
+ if (state->err_cb != NULL)
+ (*state->err_cb) (I2CECB_TIMEOUT, -1, state->cb_data);
+ if (rc == 0)
+ rc = I2CERR_TIMEOUT;
+ }
+
+ return rc;
+}
+
+static void i2c_probe_callback(int flags, int xnum, void *data)
+{
+ /*
+ * the only acceptable errors are a transmit NAK or a receive
+ * overrun - tx NAK means the device does not exist, rx OV
+ * means the device must have responded to the slave address
+ * even though the transfer failed
+ */
+ if (flags == (I2CECB_TX_ERR | I2CECB_TX_NAK))
+ *(int *) data |= 1;
+ if (flags == (I2CECB_RX_ERR | I2CECB_RX_OV))
+ *(int *) data |= 2;
+}
+
+int i2c_probe(uchar chip)
+{
+ i2c_state_t state;
+ int rc, err_flag;
+ uchar buf[1];
+
+ i2c_newio(&state);
+
+ state.err_cb = i2c_probe_callback;
+ state.cb_data = (void *) &err_flag;
+ err_flag = 0;
+
+ rc = i2c_receive(&state, chip, 0, I2CF_START_COND | I2CF_STOP_COND, 1,
+ buf);
+
+ if (rc != 0)
+ return rc; /* probe failed */
+
+ rc = i2c_doio(&state);
+
+ if (rc == 0)
+ return 0; /* device exists - read succeeded */
+
+ if (rc == I2CERR_TIMEOUT)
+ return -1; /* device does not exist - timeout */
+
+ if (rc != I2CERR_IO_ERROR || err_flag == 0)
+ return rc; /* probe failed */
+
+ if (err_flag & 1)
+ return -1; /* device does not exist - had transmit NAK */
+
+ return 0; /* device exists - had receive overrun */
+}
+
+
+int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+ i2c_state_t state;
+ uchar xaddr[4];
+ int rc;
+
+ xaddr[0] = (addr >> 24) & 0xFF;
+ xaddr[1] = (addr >> 16) & 0xFF;
+ xaddr[2] = (addr >> 8) & 0xFF;
+ xaddr[3] = addr & 0xFF;
+
+#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
+ /*
+ * EEPROM chips that implement "address overflow" are ones
+ * like Catalyst 24WC04/08/16 which has 9/10/11 bits of address
+ * and the extra bits end up in the "chip address" bit slots.
+ * This makes a 24WC08 (1Kbyte) chip look like four 256 byte
+ * chips.
+ *
+ * Note that we consider the length of the address field to still
+ * be one byte because the extra address bits are hidden in the
+ * chip address.
+ */
+ chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
+#endif
+
+ i2c_newio(&state);
+
+ rc = i2c_send(&state, chip, 0, I2CF_START_COND, alen,
+ &xaddr[4 - alen]);
+ if (rc != 0) {
+ printf("i2c_read: i2c_send failed (%d)\n", rc);
+ return 1;
+ }
+
+ rc = i2c_receive(&state, chip, 0, I2CF_STOP_COND, len, buffer);
+ if (rc != 0) {
+ printf("i2c_read: i2c_receive failed (%d)\n", rc);
+ return 1;
+ }
+
+ rc = i2c_doio(&state);
+ if (rc != 0) {
+ printf("i2c_read: i2c_doio failed (%d)\n", rc);
+ return 1;
+ }
+ return 0;
+}
+
+int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+ i2c_state_t state;
+ uchar xaddr[4];
+ int rc;
+
+ xaddr[0] = (addr >> 24) & 0xFF;
+ xaddr[1] = (addr >> 16) & 0xFF;
+ xaddr[2] = (addr >> 8) & 0xFF;
+ xaddr[3] = addr & 0xFF;
+
+#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
+ /*
+ * EEPROM chips that implement "address overflow" are ones
+ * like Catalyst 24WC04/08/16 which has 9/10/11 bits of address
+ * and the extra bits end up in the "chip address" bit slots.
+ * This makes a 24WC08 (1Kbyte) chip look like four 256 byte
+ * chips.
+ *
+ * Note that we consider the length of the address field to still
+ * be one byte because the extra address bits are hidden in the
+ * chip address.
+ */
+ chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
+#endif
+
+ i2c_newio(&state);
+
+ rc = i2c_send(&state, chip, 0, I2CF_START_COND, alen,
+ &xaddr[4 - alen]);
+ if (rc != 0) {
+ printf("i2c_write: first i2c_send failed (%d)\n", rc);
+ return 1;
+ }
+
+ rc = i2c_send(&state, 0, 0, I2CF_STOP_COND, len, buffer);
+ if (rc != 0) {
+ printf("i2c_write: second i2c_send failed (%d)\n", rc);
+ return 1;
+ }
+
+ rc = i2c_doio(&state);
+ if (rc != 0) {
+ printf("i2c_write: i2c_doio failed (%d)\n", rc);
+ return 1;
+ }
+ return 0;
+}
+
+#if defined(CONFIG_I2C_MULTI_BUS)
+/*
+ * Functions for multiple I2C bus handling
+ */
+unsigned int i2c_get_bus_num(void)
+{
+ return i2c_bus_num;
+}
+
+int i2c_set_bus_num(unsigned int bus)
+{
+#if defined(CONFIG_I2C_MUX)
+ if (bus < CONFIG_SYS_MAX_I2C_BUS) {
+ i2c_bus_num = bus;
+ } else {
+ int ret;
+
+ ret = i2x_mux_select_mux(bus);
+ if (ret == 0)
+ i2c_bus_num = bus;
+ else
+ return ret;
+ }
+#else
+ if (bus >= CONFIG_SYS_MAX_I2C_BUS)
+ return -1;
+ i2c_bus_num = bus;
+#endif
+ return 0;
+}
+
+#endif /* CONFIG_I2C_MULTI_BUS */
+#endif /* CONFIG_HARD_I2C */
diff --git a/arch/powerpc/cpu/mpc8260/interrupts.c b/arch/powerpc/cpu/mpc8260/interrupts.c
new file mode 100644
index 0000000..79178cc
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/interrupts.c
@@ -0,0 +1,279 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 22-Oct-00
+ */
+
+#include <common.h>
+#include <command.h>
+#include <mpc8260.h>
+#include <mpc8260_irq.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/****************************************************************************/
+
+struct irq_action {
+ interrupt_handler_t *handler;
+ void *arg;
+ ulong count;
+};
+
+static struct irq_action irq_handlers[NR_IRQS];
+
+static ulong ppc_cached_irq_mask[NR_MASK_WORDS];
+
+/****************************************************************************/
+/* this section was ripped out of arch/powerpc/kernel/ppc8260_pic.c in the */
+/* Linux/PPC 2.4.x source. There was no copyright notice in that file. */
+
+/* The 8260 internal interrupt controller. It is usually
+ * the only interrupt controller.
+ * There are two 32-bit registers (high/low) for up to 64
+ * possible interrupts.
+ *
+ * Now, the fun starts.....Interrupt Numbers DO NOT MAP
+ * in a simple arithmetic fashion to mask or pending registers.
+ * That is, interrupt 4 does not map to bit position 4.
+ * We create two tables, indexed by vector number, to indicate
+ * which register to use and which bit in the register to use.
+ */
+static u_char irq_to_siureg[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static u_char irq_to_siubit[] = {
+ 31, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30,
+ 29, 30, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 31,
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 15, 14, 13, 12, 11, 10, 9, 8,
+ 7, 6, 5, 4, 3, 2, 1, 0
+};
+
+static void m8260_mask_irq (unsigned int irq_nr)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ int bit, word;
+ volatile uint *simr;
+
+ bit = irq_to_siubit[irq_nr];
+ word = irq_to_siureg[irq_nr];
+
+ simr = &(immr->im_intctl.ic_simrh);
+ ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+ simr[word] = ppc_cached_irq_mask[word];
+}
+
+static void m8260_unmask_irq (unsigned int irq_nr)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ int bit, word;
+ volatile uint *simr;
+
+ bit = irq_to_siubit[irq_nr];
+ word = irq_to_siureg[irq_nr];
+
+ simr = &(immr->im_intctl.ic_simrh);
+ ppc_cached_irq_mask[word] |= (1 << (31 - bit));
+ simr[word] = ppc_cached_irq_mask[word];
+}
+
+static void m8260_mask_and_ack (unsigned int irq_nr)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ int bit, word;
+ volatile uint *simr, *sipnr;
+
+ bit = irq_to_siubit[irq_nr];
+ word = irq_to_siureg[irq_nr];
+
+ simr = &(immr->im_intctl.ic_simrh);
+ sipnr = &(immr->im_intctl.ic_sipnrh);
+ ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+ simr[word] = ppc_cached_irq_mask[word];
+ sipnr[word] = 1 << (31 - bit);
+}
+
+static int m8260_get_irq (struct pt_regs *regs)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ int irq;
+ unsigned long bits;
+
+ /* For MPC8260, read the SIVEC register and shift the bits down
+ * to get the irq number. */
+ bits = immr->im_intctl.ic_sivec;
+ irq = bits >> 26;
+ return irq;
+}
+
+/* end of code ripped out of arch/powerpc/kernel/ppc8260_pic.c */
+/****************************************************************************/
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ *decrementer_count = (gd->bus_clk / 4) / CONFIG_SYS_HZ;
+
+ /* Initialize the default interrupt mapping priorities */
+ immr->im_intctl.ic_sicr = 0;
+ immr->im_intctl.ic_siprr = 0x05309770;
+ immr->im_intctl.ic_scprrh = 0x05309770;
+ immr->im_intctl.ic_scprrl = 0x05309770;
+
+ /* disable all interrupts and clear all pending bits */
+ immr->im_intctl.ic_simrh = ppc_cached_irq_mask[0] = 0;
+ immr->im_intctl.ic_simrl = ppc_cached_irq_mask[1] = 0;
+ immr->im_intctl.ic_sipnrh = 0xffffffff;
+ immr->im_intctl.ic_sipnrl = 0xffffffff;
+
+#ifdef CONFIG_HYMOD
+ /*
+ * ensure all external interrupt sources default to trigger on
+ * high-to-low transition (i.e. edge triggered active low)
+ */
+ immr->im_intctl.ic_siexr = -1;
+#endif
+
+ return (0);
+}
+
+/****************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt (struct pt_regs *regs)
+{
+ int irq, unmask = 1;
+
+ irq = m8260_get_irq (regs);
+
+ m8260_mask_and_ack (irq);
+
+ enable_interrupts ();
+
+ if (irq_handlers[irq].handler != NULL)
+ (*irq_handlers[irq].handler) (irq_handlers[irq].arg);
+ else {
+ printf ("\nBogus External Interrupt IRQ %d\n", irq);
+ /*
+ * turn off the bogus interrupt, otherwise it
+ * might repeat forever
+ */
+ unmask = 0;
+ }
+
+ if (unmask)
+ m8260_unmask_irq (irq);
+}
+
+/****************************************************************************/
+
+/*
+ * Install and free an interrupt handler.
+ */
+
+void
+irq_install_handler (int irq, interrupt_handler_t * handler, void *arg)
+{
+ if (irq < 0 || irq >= NR_IRQS) {
+ printf ("irq_install_handler: bad irq number %d\n", irq);
+ return;
+ }
+
+ if (irq_handlers[irq].handler != NULL)
+ printf ("irq_install_handler: 0x%08lx replacing 0x%08lx\n",
+ (ulong) handler, (ulong) irq_handlers[irq].handler);
+
+ irq_handlers[irq].handler = handler;
+ irq_handlers[irq].arg = arg;
+
+ m8260_unmask_irq (irq);
+}
+
+void irq_free_handler (int irq)
+{
+ if (irq < 0 || irq >= NR_IRQS) {
+ printf ("irq_free_handler: bad irq number %d\n", irq);
+ return;
+ }
+
+ m8260_mask_irq (irq);
+
+ irq_handlers[irq].handler = NULL;
+ irq_handlers[irq].arg = NULL;
+}
+
+/****************************************************************************/
+
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+ /* nothing to do here */
+ return;
+}
+
+/****************************************************************************/
+
+#if defined(CONFIG_CMD_IRQ)
+
+/* ripped this out of ppc4xx/interrupts.c */
+
+/*******************************************************************************
+*
+* irqinfo - print information about PCI devices
+*
+*/
+void
+do_irqinfo (cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char * const argv[])
+{
+ int irq, re_enable;
+
+ re_enable = disable_interrupts ();
+
+ puts ("\nInterrupt-Information:\n"
+ "Nr Routine Arg Count\n");
+
+ for (irq = 0; irq < 32; irq++)
+ if (irq_handlers[irq].handler != NULL)
+ printf ("%02d %08lx %08lx %ld\n", irq,
+ (ulong) irq_handlers[irq].handler,
+ (ulong) irq_handlers[irq].arg,
+ irq_handlers[irq].count);
+
+ if (re_enable)
+ enable_interrupts ();
+}
+
+#endif
diff --git a/arch/powerpc/cpu/mpc8260/kgdb.S b/arch/powerpc/cpu/mpc8260/kgdb.S
new file mode 100644
index 0000000..c5936c7
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/kgdb.S
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2000 Murray Jensen <Murray.Jensen@cmst.csiro.au>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <command.h>
+#include <mpc8260.h>
+#include <version.h>
+
+#define CONFIG_8260 1 /* needed for Linux kernel header files */
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#if defined(CONFIG_CMD_KGDB)
+
+ /*
+ * cache flushing routines for kgdb
+ */
+
+ .globl kgdb_flush_cache_all
+kgdb_flush_cache_all:
+ mfspr r3, HID0
+ ori r3, r3, HID0_ICFI|HID0_DCI /* Invalidate All */
+ SYNC
+ mtspr HID0, r3
+ blr
+
+ .globl kgdb_flush_cache_range
+kgdb_flush_cache_range:
+ li r5,CONFIG_SYS_CACHELINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,CONFIG_SYS_CACHELINE_SHIFT
+ beqlr
+ mtctr r4
+ mr r6,r3
+1: dcbst 0,r3
+ addi r3,r3,CONFIG_SYS_CACHELINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ mtctr r4
+2: icbi 0,r6
+ addi r6,r6,CONFIG_SYS_CACHELINE_SIZE
+ bdnz 2b
+ SYNC
+ blr
+
+#endif
diff --git a/arch/powerpc/cpu/mpc8260/pci.c b/arch/powerpc/cpu/mpc8260/pci.c
new file mode 100644
index 0000000..6a14ba4
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/pci.c
@@ -0,0 +1,466 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (c) 2005 MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ * Added support for PCI bridge on MPC8272ADS
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_PCI
+
+#include <pci.h>
+#include <mpc8260.h>
+#include <asm/m8260_pci.h>
+#include <asm/io.h>
+#ifdef CONFIG_OF_LIBFDT
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+
+#if defined CONFIG_MPC8266ADS || defined CONFIG_MPC8272 || defined CONFIG_PM826
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+/*
+ * Local->PCI map (from CPU) controlled by
+ * MPC826x master window
+ *
+ * 0x80000000 - 0xBFFFFFFF CPU2PCI space PCIBR0
+ * 0xF4000000 - 0xF7FFFFFF CPU2PCI space PCIBR1
+ *
+ * 0x80000000 - 0x9FFFFFFF 0x80000000 - 0x9FFFFFFF (Outbound ATU #1)
+ * PCI Mem with prefetch
+ *
+ * 0xA0000000 - 0xBFFFFFFF 0xA0000000 - 0xBFFFFFFF (Outbound ATU #2)
+ * PCI Mem w/o prefetch
+ *
+ * 0xF4000000 - 0xF7FFFFFF 0x00000000 - 0x03FFFFFF (Outbound ATU #3)
+ * 32-bit PCI IO
+ *
+ * PCI->Local map (from PCI)
+ * MPC826x slave window controlled by
+ *
+ * 0x00000000 - 0x1FFFFFFF 0x00000000 - 0x1FFFFFFF (Inbound ATU #1)
+ * MPC826x local memory
+ */
+
+/*
+ * Slave window that allows PCI masters to access MPC826x local memory.
+ * This window is set up using the first set of Inbound ATU registers
+ */
+
+#ifndef CONFIG_SYS_PCI_SLV_MEM_LOCAL
+#define PCI_SLV_MEM_LOCAL CONFIG_SYS_SDRAM_BASE /* Local base */
+#else
+#define PCI_SLV_MEM_LOCAL CONFIG_SYS_PCI_SLV_MEM_LOCAL
+#endif
+
+#ifndef CONFIG_SYS_PCI_SLV_MEM_BUS
+#define PCI_SLV_MEM_BUS 0x00000000 /* PCI base */
+#else
+#define PCI_SLV_MEM_BUS CONFIG_SYS_PCI_SLV_MEM_BUS
+#endif
+
+#ifndef CONFIG_SYS_PICMR0_MASK_ATTRIB
+#define PICMR0_MASK_ATTRIB (PICMR_MASK_512MB | PICMR_ENABLE | \
+ PICMR_PREFETCH_EN)
+#else
+#define PICMR0_MASK_ATTRIB CONFIG_SYS_PICMR0_MASK_ATTRIB
+#endif
+
+/*
+ * These are the windows that allow the CPU to access PCI address space.
+ * All three PCI master windows, which allow the CPU to access PCI
+ * prefetch, non prefetch, and IO space (see below), must all fit within
+ * these windows.
+ */
+
+/* PCIBR0 */
+#ifndef CONFIG_SYS_PCI_MSTR0_LOCAL
+#define PCI_MSTR0_LOCAL 0x80000000 /* Local base */
+#else
+#define PCI_MSTR0_LOCAL CONFIG_SYS_PCI_MSTR0_LOCAL
+#endif
+
+#ifndef CONFIG_SYS_PCIMSK0_MASK
+#define PCIMSK0_MASK PCIMSK_1GB /* Size of window */
+#else
+#define PCIMSK0_MASK CONFIG_SYS_PCIMSK0_MASK
+#endif
+
+/* PCIBR1 */
+#ifndef CONFIG_SYS_PCI_MSTR1_LOCAL
+#define PCI_MSTR1_LOCAL 0xF4000000 /* Local base */
+#else
+#define PCI_MSTR1_LOCAL CONFIG_SYS_PCI_MSTR1_LOCAL
+#endif
+
+#ifndef CONFIG_SYS_PCIMSK1_MASK
+#define PCIMSK1_MASK PCIMSK_64MB /* Size of window */
+#else
+#define PCIMSK1_MASK CONFIG_SYS_PCIMSK1_MASK
+#endif
+
+/*
+ * Master window that allows the CPU to access PCI Memory (prefetch).
+ * This window will be setup with the first set of Outbound ATU registers
+ * in the bridge.
+ */
+
+#ifndef CONFIG_SYS_PCI_MSTR_MEM_LOCAL
+#define PCI_MSTR_MEM_LOCAL 0x80000000 /* Local base */
+#else
+#define PCI_MSTR_MEM_LOCAL CONFIG_SYS_PCI_MSTR_MEM_LOCAL
+#endif
+
+#ifndef CONFIG_SYS_PCI_MSTR_MEM_BUS
+#define PCI_MSTR_MEM_BUS 0x80000000 /* PCI base */
+#else
+#define PCI_MSTR_MEM_BUS CONFIG_SYS_PCI_MSTR_MEM_BUS
+#endif
+
+#ifndef CONFIG_SYS_CPU_PCI_MEM_START
+#define CPU_PCI_MEM_START PCI_MSTR_MEM_LOCAL
+#else
+#define CPU_PCI_MEM_START CONFIG_SYS_CPU_PCI_MEM_START
+#endif
+
+#ifndef CONFIG_SYS_PCI_MSTR_MEM_SIZE
+#define PCI_MSTR_MEM_SIZE 0x10000000 /* 256MB */
+#else
+#define PCI_MSTR_MEM_SIZE CONFIG_SYS_PCI_MSTR_MEM_SIZE
+#endif
+
+#ifndef CONFIG_SYS_POCMR0_MASK_ATTRIB
+#define POCMR0_MASK_ATTRIB (POCMR_MASK_256MB | POCMR_ENABLE | POCMR_PREFETCH_EN)
+#else
+#define POCMR0_MASK_ATTRIB CONFIG_SYS_POCMR0_MASK_ATTRIB
+#endif
+
+/*
+ * Master window that allows the CPU to access PCI Memory (non-prefetch).
+ * This window will be setup with the second set of Outbound ATU registers
+ * in the bridge.
+ */
+
+#ifndef CONFIG_SYS_PCI_MSTR_MEMIO_LOCAL
+#define PCI_MSTR_MEMIO_LOCAL 0x90000000 /* Local base */
+#else
+#define PCI_MSTR_MEMIO_LOCAL CONFIG_SYS_PCI_MSTR_MEMIO_LOCAL
+#endif
+
+#ifndef CONFIG_SYS_PCI_MSTR_MEMIO_BUS
+#define PCI_MSTR_MEMIO_BUS 0x90000000 /* PCI base */
+#else
+#define PCI_MSTR_MEMIO_BUS CONFIG_SYS_PCI_MSTR_MEMIO_BUS
+#endif
+
+#ifndef CONFIG_SYS_CPU_PCI_MEMIO_START
+#define CPU_PCI_MEMIO_START PCI_MSTR_MEMIO_LOCAL
+#else
+#define CPU_PCI_MEMIO_START CONFIG_SYS_CPU_PCI_MEMIO_START
+#endif
+
+#ifndef CONFIG_SYS_PCI_MSTR_MEMIO_SIZE
+#define PCI_MSTR_MEMIO_SIZE 0x10000000 /* 256 MB */
+#else
+#define PCI_MSTR_MEMIO_SIZE CONFIG_SYS_PCI_MSTR_MEMIO_SIZE
+#endif
+
+#ifndef CONFIG_SYS_POCMR1_MASK_ATTRIB
+#define POCMR1_MASK_ATTRIB (POCMR_MASK_512MB | POCMR_ENABLE)
+#else
+#define POCMR1_MASK_ATTRIB CONFIG_SYS_POCMR1_MASK_ATTRIB
+#endif
+
+/*
+ * Master window that allows the CPU to access PCI IO space.
+ * This window will be setup with the third set of Outbound ATU registers
+ * in the bridge.
+ */
+
+#ifndef CONFIG_SYS_PCI_MSTR_IO_LOCAL
+#define PCI_MSTR_IO_LOCAL 0xA0000000 /* Local base */
+#else
+#define PCI_MSTR_IO_LOCAL CONFIG_SYS_PCI_MSTR_IO_LOCAL
+#endif
+
+#ifndef CONFIG_SYS_PCI_MSTR_IO_BUS
+#define PCI_MSTR_IO_BUS 0xA0000000 /* PCI base */
+#else
+#define PCI_MSTR_IO_BUS CONFIG_SYS_PCI_MSTR_IO_BUS
+#endif
+
+#ifndef CONFIG_SYS_CPU_PCI_IO_START
+#define CPU_PCI_IO_START PCI_MSTR_IO_LOCAL
+#else
+#define CPU_PCI_IO_START CONFIG_SYS_CPU_PCI_IO_START
+#endif
+
+#ifndef CONFIG_SYS_PCI_MSTR_IO_SIZE
+#define PCI_MSTR_IO_SIZE 0x10000000 /* 256MB */
+#else
+#define PCI_MSTR_IO_SIZE CONFIG_SYS_PCI_MSTR_IO_SIZE
+#endif
+
+#ifndef CONFIG_SYS_POCMR2_MASK_ATTRIB
+#define POCMR2_MASK_ATTRIB (POCMR_MASK_256MB | POCMR_ENABLE | POCMR_PCI_IO)
+#else
+#define POCMR2_MASK_ATTRIB CONFIG_SYS_POCMR2_MASK_ATTRIB
+#endif
+
+/* PCI bus configuration registers.
+ */
+
+#define PCI_CLASS_BRIDGE_CTLR 0x06
+
+
+static inline void pci_outl (u32 addr, u32 data)
+{
+ *(volatile u32 *) addr = cpu_to_le32 (data);
+}
+
+void pci_mpc8250_init (struct pci_controller *hose)
+{
+ u16 tempShort;
+
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ pci_dev_t host_devno = PCI_BDF (0, 0, 0);
+
+ pci_setup_indirect (hose, CONFIG_SYS_IMMR + PCI_CFG_ADDR_REG,
+ CONFIG_SYS_IMMR + PCI_CFG_DATA_REG);
+
+ /*
+ * Setting required to enable local bus for PCI (SIUMCR [LBPC]).
+ */
+#ifdef CONFIG_MPC8266ADS
+ immap->im_siu_conf.sc_siumcr =
+ (immap->im_siu_conf.sc_siumcr & ~SIUMCR_LBPC11)
+ | SIUMCR_LBPC01;
+#elif defined(CONFIG_ADSTYPE) && CONFIG_ADSTYPE == CONFIG_SYS_PQ2FADS
+/* nothing to do for this board here */
+#elif defined CONFIG_MPC8272
+ immap->im_siu_conf.sc_siumcr = (immap->im_siu_conf.sc_siumcr &
+ ~SIUMCR_BBD &
+ ~SIUMCR_ESE &
+ ~SIUMCR_PBSE &
+ ~SIUMCR_CDIS &
+ ~SIUMCR_DPPC11 &
+ ~SIUMCR_L2CPC11 &
+ ~SIUMCR_LBPC11 &
+ ~SIUMCR_APPC11 &
+ ~SIUMCR_CS10PC11 &
+ ~SIUMCR_BCTLC11 &
+ ~SIUMCR_MMR11)
+ | SIUMCR_DPPC11
+ | SIUMCR_L2CPC01
+ | SIUMCR_LBPC00
+ | SIUMCR_APPC10
+ | SIUMCR_CS10PC00
+ | SIUMCR_BCTLC00
+ | SIUMCR_MMR11;
+#elif defined(CONFIG_TQM8272)
+/* nothing to do for this Board here */
+#else
+ /*
+ * Setting required to enable IRQ1-IRQ7 (SIUMCR [DPPC]),
+ * and local bus for PCI (SIUMCR [LBPC]).
+ */
+ immap->im_siu_conf.sc_siumcr = (immap->im_siu_conf.sc_siumcr &
+ ~SIUMCR_LBPC11 &
+ ~SIUMCR_CS10PC11 &
+ ~SIUMCR_LBPC11) |
+ SIUMCR_LBPC01 |
+ SIUMCR_CS10PC01 |
+ SIUMCR_APPC10;
+#endif
+
+ /* Make PCI lowest priority */
+ /* Each 4 bits is a device bus request and the MS 4bits
+ is highest priority */
+ /* Bus 4bit value
+ --- ----------
+ CPM high 0b0000
+ CPM middle 0b0001
+ CPM low 0b0010
+ PCI reguest 0b0011
+ Reserved 0b0100
+ Reserved 0b0101
+ Internal Core 0b0110
+ External Master 1 0b0111
+ External Master 2 0b1000
+ External Master 3 0b1001
+ The rest are reserved */
+ immap->im_siu_conf.sc_ppc_alrh = 0x61207893;
+
+ /* Park bus on core while modifying PCI Bus accesses */
+ immap->im_siu_conf.sc_ppc_acr = 0x6;
+
+ /*
+ * Set up master windows that allow the CPU to access PCI space. These
+ * windows are set up using the two SIU PCIBR registers.
+ */
+ immap->im_memctl.memc_pcimsk0 = PCIMSK0_MASK;
+ immap->im_memctl.memc_pcibr0 = PCI_MSTR0_LOCAL | PCIBR_ENABLE;
+
+#if defined CONFIG_MPC8266ADS || defined CONFIG_MPC8272
+ immap->im_memctl.memc_pcimsk1 = PCIMSK1_MASK;
+ immap->im_memctl.memc_pcibr1 = PCI_MSTR1_LOCAL | PCIBR_ENABLE;
+#endif
+
+ /* Release PCI RST (by default the PCI RST signal is held low) */
+ immap->im_pci.pci_gcr = cpu_to_le32 (PCIGCR_PCI_BUS_EN);
+
+ /* give it some time */
+ {
+#if defined CONFIG_MPC8266ADS || defined CONFIG_MPC8272
+ /* Give the PCI cards more time to initialize before query
+ This might be good for other boards also
+ */
+ int i;
+
+ for (i = 0; i < 1000; ++i)
+#endif
+ udelay (1000);
+ }
+
+ /*
+ * Set up master window that allows the CPU to access PCI Memory (prefetch)
+ * space. This window is set up using the first set of Outbound ATU registers.
+ */
+ immap->im_pci.pci_potar0 = cpu_to_le32 (PCI_MSTR_MEM_BUS >> 12); /* PCI base */
+ immap->im_pci.pci_pobar0 = cpu_to_le32 (PCI_MSTR_MEM_LOCAL >> 12); /* Local base */
+ immap->im_pci.pci_pocmr0 = cpu_to_le32 (POCMR0_MASK_ATTRIB); /* Size & attribute */
+
+ /*
+ * Set up master window that allows the CPU to access PCI Memory (non-prefetch)
+ * space. This window is set up using the second set of Outbound ATU registers.
+ */
+ immap->im_pci.pci_potar1 = cpu_to_le32 (PCI_MSTR_MEMIO_BUS >> 12); /* PCI base */
+ immap->im_pci.pci_pobar1 = cpu_to_le32 (PCI_MSTR_MEMIO_LOCAL >> 12); /* Local base */
+ immap->im_pci.pci_pocmr1 = cpu_to_le32 (POCMR1_MASK_ATTRIB); /* Size & attribute */
+
+ /*
+ * Set up master window that allows the CPU to access PCI IO space. This window
+ * is set up using the third set of Outbound ATU registers.
+ */
+ immap->im_pci.pci_potar2 = cpu_to_le32 (PCI_MSTR_IO_BUS >> 12); /* PCI base */
+ immap->im_pci.pci_pobar2 = cpu_to_le32 (PCI_MSTR_IO_LOCAL >> 12); /* Local base */
+ immap->im_pci.pci_pocmr2 = cpu_to_le32 (POCMR2_MASK_ATTRIB); /* Size & attribute */
+
+ /*
+ * Set up slave window that allows PCI masters to access MPC826x local memory.
+ * This window is set up using the first set of Inbound ATU registers
+ */
+ immap->im_pci.pci_pitar0 = cpu_to_le32 (PCI_SLV_MEM_LOCAL >> 12); /* PCI base */
+ immap->im_pci.pci_pibar0 = cpu_to_le32 (PCI_SLV_MEM_BUS >> 12); /* Local base */
+ immap->im_pci.pci_picmr0 = cpu_to_le32 (PICMR0_MASK_ATTRIB); /* Size & attribute */
+
+ /* See above for description - puts PCI request as highest priority */
+#ifdef CONFIG_MPC8272
+ immap->im_siu_conf.sc_ppc_alrh = 0x01236745;
+#else
+ immap->im_siu_conf.sc_ppc_alrh = 0x03124567;
+#endif
+
+ /* Park the bus on the PCI */
+ immap->im_siu_conf.sc_ppc_acr = PPC_ACR_BUS_PARK_PCI;
+
+ /* Host mode - specify the bridge as a host-PCI bridge */
+
+ pci_hose_write_config_byte (hose, host_devno, PCI_CLASS_CODE,
+ PCI_CLASS_BRIDGE_CTLR);
+
+ /* Enable the host bridge to be a master on the PCI bus, and to act as a PCI memory target */
+ pci_hose_read_config_word (hose, host_devno, PCI_COMMAND, &tempShort);
+ pci_hose_write_config_word (hose, host_devno, PCI_COMMAND,
+ tempShort | PCI_COMMAND_MASTER |
+ PCI_COMMAND_MEMORY);
+
+ /* do some bridge init, should be done on all 8260 based bridges */
+ pci_hose_write_config_byte (hose, host_devno, PCI_CACHE_LINE_SIZE,
+ 0x08);
+ pci_hose_write_config_byte (hose, host_devno, PCI_LATENCY_TIMER,
+ 0xF8);
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ /* System memory space */
+#if defined CONFIG_MPC8266ADS || defined CONFIG_MPC8272 || defined CONFIG_PM826
+ pci_set_region (hose->regions + 0,
+ PCI_SLV_MEM_BUS,
+ PCI_SLV_MEM_LOCAL,
+ gd->ram_size, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+#else
+ pci_set_region (hose->regions + 0,
+ CONFIG_SYS_SDRAM_BASE,
+ CONFIG_SYS_SDRAM_BASE,
+ 0x4000000, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+#endif
+
+ /* PCI memory space */
+#if defined CONFIG_MPC8266ADS || defined CONFIG_MPC8272
+ pci_set_region (hose->regions + 1,
+ PCI_MSTR_MEMIO_BUS,
+ PCI_MSTR_MEMIO_LOCAL,
+ PCI_MSTR_MEMIO_SIZE, PCI_REGION_MEM);
+#else
+ pci_set_region (hose->regions + 1,
+ PCI_MSTR_MEM_BUS,
+ PCI_MSTR_MEM_LOCAL,
+ PCI_MSTR_MEM_SIZE, PCI_REGION_MEM);
+#endif
+
+ /* PCI I/O space */
+ pci_set_region (hose->regions + 2,
+ PCI_MSTR_IO_BUS,
+ PCI_MSTR_IO_LOCAL, PCI_MSTR_IO_SIZE, PCI_REGION_IO);
+
+ hose->region_count = 3;
+
+ pci_register_hose (hose);
+ /* Mask off master abort machine checks */
+ immap->im_pci.pci_emr &= cpu_to_le32 (~PCI_ERROR_PCI_NO_RSP);
+ eieio ();
+
+ hose->last_busno = pci_hose_scan (hose);
+
+
+ /* clear the error in the error status register */
+ immap->im_pci.pci_esr = cpu_to_le32 (PCI_ERROR_PCI_NO_RSP);
+
+ /* unmask master abort machine checks */
+ immap->im_pci.pci_emr |= cpu_to_le32 (PCI_ERROR_PCI_NO_RSP);
+}
+
+#if defined(CONFIG_OF_LIBFDT)
+void ft_pci_setup(void *blob, bd_t *bd)
+{
+ do_fixup_by_prop_u32(blob, "device_type", "pci", 4,
+ "clock-frequency", gd->pci_clk, 1);
+}
+#endif
+
+#endif /* CONFIG_PCI */
diff --git a/arch/powerpc/cpu/mpc8260/serial_scc.c b/arch/powerpc/cpu/mpc8260/serial_scc.c
new file mode 100644
index 0000000..ab2a2b2
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/serial_scc.c
@@ -0,0 +1,508 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00.
+ */
+
+/*
+ * Minimal serial functions needed to use one of the SCC ports
+ * as serial console interface.
+ */
+
+#include <common.h>
+#include <mpc8260.h>
+#include <asm/cpm_8260.h>
+#include <serial.h>
+#include <linux/compiler.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_CONS_ON_SCC)
+
+#if CONFIG_CONS_INDEX == 1 /* Console on SCC1 */
+
+#define SCC_INDEX 0
+#define PROFF_SCC PROFF_SCC1
+#define CMXSCR_MASK (CMXSCR_GR1|CMXSCR_SC1|\
+ CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK)
+#define CMXSCR_VALUE (CMXSCR_RS1CS_BRG1|CMXSCR_TS1CS_BRG1)
+#define CPM_CR_SCC_PAGE CPM_CR_SCC1_PAGE
+#define CPM_CR_SCC_SBLOCK CPM_CR_SCC1_SBLOCK
+
+#elif CONFIG_CONS_INDEX == 2 /* Console on SCC2 */
+
+#define SCC_INDEX 1
+#define PROFF_SCC PROFF_SCC2
+#define CMXSCR_MASK (CMXSCR_GR2|CMXSCR_SC2|\
+ CMXSCR_RS2CS_MSK|CMXSCR_TS2CS_MSK)
+#define CMXSCR_VALUE (CMXSCR_RS2CS_BRG2|CMXSCR_TS2CS_BRG2)
+#define CPM_CR_SCC_PAGE CPM_CR_SCC2_PAGE
+#define CPM_CR_SCC_SBLOCK CPM_CR_SCC2_SBLOCK
+
+#elif CONFIG_CONS_INDEX == 3 /* Console on SCC3 */
+
+#define SCC_INDEX 2
+#define PROFF_SCC PROFF_SCC3
+#define CMXSCR_MASK (CMXSCR_GR3|CMXSCR_SC3|\
+ CMXSCR_RS3CS_MSK|CMXSCR_TS3CS_MSK)
+#define CMXSCR_VALUE (CMXSCR_RS3CS_BRG3|CMXSCR_TS3CS_BRG3)
+#define CPM_CR_SCC_PAGE CPM_CR_SCC3_PAGE
+#define CPM_CR_SCC_SBLOCK CPM_CR_SCC3_SBLOCK
+
+#elif CONFIG_CONS_INDEX == 4 /* Console on SCC4 */
+
+#define SCC_INDEX 3
+#define PROFF_SCC PROFF_SCC4
+#define CMXSCR_MASK (CMXSCR_GR4|CMXSCR_SC4|\
+ CMXSCR_RS4CS_MSK|CMXSCR_TS4CS_MSK)
+#define CMXSCR_VALUE (CMXSCR_RS4CS_BRG4|CMXSCR_TS4CS_BRG4)
+#define CPM_CR_SCC_PAGE CPM_CR_SCC4_PAGE
+#define CPM_CR_SCC_SBLOCK CPM_CR_SCC4_SBLOCK
+
+#else
+
+#error "console not correctly defined"
+
+#endif
+
+static int mpc8260_scc_serial_init(void)
+{
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile scc_t *sp;
+ volatile scc_uart_t *up;
+ volatile cbd_t *tbdf, *rbdf;
+ volatile cpm8260_t *cp = &(im->im_cpm);
+ uint dpaddr;
+
+ /* initialize pointers to SCC */
+
+ sp = (scc_t *) &(im->im_scc[SCC_INDEX]);
+ up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC];
+
+ /* Disable transmitter/receiver.
+ */
+ sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+ /* put the SCC channel into NMSI (non multiplexd serial interface)
+ * mode and wire the selected SCC Tx and Rx clocks to BRGx (15-15).
+ */
+ im->im_cpmux.cmx_scr = (im->im_cpmux.cmx_scr&~CMXSCR_MASK)|CMXSCR_VALUE;
+
+ /* Set up the baud rate generator.
+ */
+ serial_setbrg ();
+
+ /* Allocate space for two buffer descriptors in the DP ram.
+ * damm: allocating space after the two buffers for rx/tx data
+ */
+
+ dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16);
+
+ /* Set the physical address of the host memory buffers in
+ * the buffer descriptors.
+ */
+ rbdf = (cbd_t *)&im->im_dprambase[dpaddr];
+ rbdf->cbd_bufaddr = (uint) (rbdf+2);
+ rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+ tbdf = rbdf + 1;
+ tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+ tbdf->cbd_sc = BD_SC_WRAP;
+
+ /* Set up the uart parameters in the parameter ram.
+ */
+ up->scc_genscc.scc_rbase = dpaddr;
+ up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t);
+ up->scc_genscc.scc_rfcr = CPMFCR_EB;
+ up->scc_genscc.scc_tfcr = CPMFCR_EB;
+ up->scc_genscc.scc_mrblr = 1;
+ up->scc_maxidl = 0;
+ up->scc_brkcr = 1;
+ up->scc_parec = 0;
+ up->scc_frmec = 0;
+ up->scc_nosec = 0;
+ up->scc_brkec = 0;
+ up->scc_uaddr1 = 0;
+ up->scc_uaddr2 = 0;
+ up->scc_toseq = 0;
+ up->scc_char1 = up->scc_char2 = up->scc_char3 = up->scc_char4 = 0x8000;
+ up->scc_char5 = up->scc_char6 = up->scc_char7 = up->scc_char8 = 0x8000;
+ up->scc_rccm = 0xc0ff;
+
+ /* Mask all interrupts and remove anything pending.
+ */
+ sp->scc_sccm = 0;
+ sp->scc_scce = 0xffff;
+
+ /* Set 8 bit FIFO, 16 bit oversampling and UART mode.
+ */
+ sp->scc_gsmrh = SCC_GSMRH_RFW; /* 8 bit FIFO */
+ sp->scc_gsmrl = \
+ SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16 | SCC_GSMRL_MODE_UART;
+
+ /* Set CTS flow control, 1 stop bit, 8 bit character length,
+ * normal async UART mode, no parity
+ */
+ sp->scc_psmr = SCU_PSMR_FLC | SCU_PSMR_CL;
+
+ /* execute the "Init Rx and Tx params" CP command.
+ */
+
+ while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
+ ;
+
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_SCC_PAGE, CPM_CR_SCC_SBLOCK,
+ 0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+ while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
+ ;
+
+ /* Enable transmitter/receiver.
+ */
+ sp->scc_gsmrl |= SCC_GSMRL_ENR | SCC_GSMRL_ENT;
+
+ return (0);
+}
+
+static void mpc8260_scc_serial_setbrg(void)
+{
+#if defined(CONFIG_CONS_USE_EXTC)
+ m8260_cpm_extcbrg(SCC_INDEX, gd->baudrate,
+ CONFIG_CONS_EXTC_RATE, CONFIG_CONS_EXTC_PINSEL);
+#else
+ m8260_cpm_setbrg(SCC_INDEX, gd->baudrate);
+#endif
+}
+
+static void mpc8260_scc_serial_putc(const char c)
+{
+ volatile scc_uart_t *up;
+ volatile cbd_t *tbdf;
+ volatile immap_t *im;
+
+ if (c == '\n')
+ serial_putc ('\r');
+
+ im = (immap_t *)CONFIG_SYS_IMMR;
+ up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC];
+ tbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_tbase];
+
+ /* Wait for last character to go.
+ */
+ while (tbdf->cbd_sc & BD_SC_READY)
+ ;
+
+ /* Load the character into the transmit buffer.
+ */
+ *(volatile char *)tbdf->cbd_bufaddr = c;
+ tbdf->cbd_datlen = 1;
+ tbdf->cbd_sc |= BD_SC_READY;
+}
+
+static int mpc8260_scc_serial_getc(void)
+{
+ volatile cbd_t *rbdf;
+ volatile scc_uart_t *up;
+ volatile immap_t *im;
+ unsigned char c;
+
+ im = (immap_t *)CONFIG_SYS_IMMR;
+ up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC];
+ rbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_rbase];
+
+ /* Wait for character to show up.
+ */
+ while (rbdf->cbd_sc & BD_SC_EMPTY)
+ ;
+
+ /* Grab the char and clear the buffer again.
+ */
+ c = *(volatile unsigned char *)rbdf->cbd_bufaddr;
+ rbdf->cbd_sc |= BD_SC_EMPTY;
+
+ return (c);
+}
+
+static int mpc8260_scc_serial_tstc(void)
+{
+ volatile cbd_t *rbdf;
+ volatile scc_uart_t *up;
+ volatile immap_t *im;
+
+ im = (immap_t *)CONFIG_SYS_IMMR;
+ up = (scc_uart_t *)&im->im_dprambase[PROFF_SCC];
+ rbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_rbase];
+
+ return ((rbdf->cbd_sc & BD_SC_EMPTY) == 0);
+}
+
+static struct serial_device mpc8260_scc_serial_drv = {
+ .name = "mpc8260_scc_uart",
+ .start = mpc8260_scc_serial_init,
+ .stop = NULL,
+ .setbrg = mpc8260_scc_serial_setbrg,
+ .putc = mpc8260_scc_serial_putc,
+ .puts = default_serial_puts,
+ .getc = mpc8260_scc_serial_getc,
+ .tstc = mpc8260_scc_serial_tstc,
+};
+
+void mpc8260_scc_serial_initialize(void)
+{
+ serial_register(&mpc8260_scc_serial_drv);
+}
+
+__weak struct serial_device *default_serial_console(void)
+{
+ return &mpc8260_scc_serial_drv;
+}
+#endif /* CONFIG_CONS_ON_SCC */
+
+#if defined(CONFIG_KGDB_ON_SCC)
+
+#if defined(CONFIG_CONS_ON_SCC) && CONFIG_KGDB_INDEX == CONFIG_CONS_INDEX
+#error Whoops! serial console and kgdb are on the same scc serial port
+#endif
+
+#if CONFIG_KGDB_INDEX == 1 /* KGDB Port on SCC1 */
+
+#define KGDB_SCC_INDEX 0
+#define KGDB_PROFF_SCC PROFF_SCC1
+#define KGDB_CMXSCR_MASK (CMXSCR_GR1|CMXSCR_SC1|\
+ CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK)
+#define KGDB_CMXSCR_VALUE (CMXSCR_RS1CS_BRG1|CMXSCR_TS1CS_BRG1)
+#define KGDB_CPM_CR_SCC_PAGE CPM_CR_SCC1_PAGE
+#define KGDB_CPM_CR_SCC_SBLOCK CPM_CR_SCC1_SBLOCK
+
+#elif CONFIG_KGDB_INDEX == 2 /* KGDB Port on SCC2 */
+
+#define KGDB_SCC_INDEX 1
+#define KGDB_PROFF_SCC PROFF_SCC2
+#define KGDB_CMXSCR_MASK (CMXSCR_GR2|CMXSCR_SC2|\
+ CMXSCR_RS2CS_MSK|CMXSCR_TS2CS_MSK)
+#define KGDB_CMXSCR_VALUE (CMXSCR_RS2CS_BRG2|CMXSCR_TS2CS_BRG2)
+#define KGDB_CPM_CR_SCC_PAGE CPM_CR_SCC2_PAGE
+#define KGDB_CPM_CR_SCC_SBLOCK CPM_CR_SCC2_SBLOCK
+
+#elif CONFIG_KGDB_INDEX == 3 /* KGDB Port on SCC3 */
+
+#define KGDB_SCC_INDEX 2
+#define KGDB_PROFF_SCC PROFF_SCC3
+#define KGDB_CMXSCR_MASK (CMXSCR_GR3|CMXSCR_SC3|\
+ CMXSCR_RS3CS_MSK|CMXSCR_TS3CS_MSK)
+#define KGDB_CMXSCR_VALUE (CMXSCR_RS3CS_BRG3|CMXSCR_TS3CS_BRG3)
+#define KGDB_CPM_CR_SCC_PAGE CPM_CR_SCC3_PAGE
+#define KGDB_CPM_CR_SCC_SBLOCK CPM_CR_SCC3_SBLOCK
+
+#elif CONFIG_KGDB_INDEX == 4 /* KGDB Port on SCC4 */
+
+#define KGDB_SCC_INDEX 3
+#define KGDB_PROFF_SCC PROFF_SCC4
+#define KGDB_CMXSCR_MASK (CMXSCR_GR4|CMXSCR_SC4|\
+ CMXSCR_RS4CS_MSK|CMXSCR_TS4CS_MSK)
+#define KGDB_CMXSCR_VALUE (CMXSCR_RS4CS_BRG4|CMXSCR_TS4CS_BRG4)
+#define KGDB_CPM_CR_SCC_PAGE CPM_CR_SCC4_PAGE
+#define KGDB_CPM_CR_SCC_SBLOCK CPM_CR_SCC4_SBLOCK
+
+#else
+
+#error "kgdb serial port not correctly defined"
+
+#endif
+
+void
+kgdb_serial_init (void)
+{
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile scc_t *sp;
+ volatile scc_uart_t *up;
+ volatile cbd_t *tbdf, *rbdf;
+ volatile cpm8260_t *cp = &(im->im_cpm);
+ uint dpaddr, speed = CONFIG_KGDB_BAUDRATE;
+ char *s, *e;
+
+ if ((s = getenv("kgdbrate")) != NULL && *s != '\0') {
+ ulong rate = simple_strtoul(s, &e, 10);
+ if (e > s && *e == '\0')
+ speed = rate;
+ }
+
+ /* initialize pointers to SCC */
+
+ sp = (scc_t *) &(im->im_scc[KGDB_SCC_INDEX]);
+ up = (scc_uart_t *)&im->im_dprambase[KGDB_PROFF_SCC];
+
+ /* Disable transmitter/receiver.
+ */
+ sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+ /* put the SCC channel into NMSI (non multiplexd serial interface)
+ * mode and wire the selected SCC Tx and Rx clocks to BRGx (15-15).
+ */
+ im->im_cpmux.cmx_scr = \
+ (im->im_cpmux.cmx_scr & ~KGDB_CMXSCR_MASK) | KGDB_CMXSCR_VALUE;
+
+ /* Set up the baud rate generator.
+ */
+#if defined(CONFIG_KGDB_USE_EXTC)
+ m8260_cpm_extcbrg(KGDB_SCC_INDEX, speed,
+ CONFIG_KGDB_EXTC_RATE, CONFIG_KGDB_EXTC_PINSEL);
+#else
+ m8260_cpm_setbrg(KGDB_SCC_INDEX, speed);
+#endif
+
+ /* Allocate space for two buffer descriptors in the DP ram.
+ * damm: allocating space after the two buffers for rx/tx data
+ */
+
+ dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16);
+
+ /* Set the physical address of the host memory buffers in
+ * the buffer descriptors.
+ */
+ rbdf = (cbd_t *)&im->im_dprambase[dpaddr];
+ rbdf->cbd_bufaddr = (uint) (rbdf+2);
+ rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+ tbdf = rbdf + 1;
+ tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+ tbdf->cbd_sc = BD_SC_WRAP;
+
+ /* Set up the uart parameters in the parameter ram.
+ */
+ up->scc_genscc.scc_rbase = dpaddr;
+ up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t);
+ up->scc_genscc.scc_rfcr = CPMFCR_EB;
+ up->scc_genscc.scc_tfcr = CPMFCR_EB;
+ up->scc_genscc.scc_mrblr = 1;
+ up->scc_maxidl = 0;
+ up->scc_brkcr = 1;
+ up->scc_parec = 0;
+ up->scc_frmec = 0;
+ up->scc_nosec = 0;
+ up->scc_brkec = 0;
+ up->scc_uaddr1 = 0;
+ up->scc_uaddr2 = 0;
+ up->scc_toseq = 0;
+ up->scc_char1 = up->scc_char2 = up->scc_char3 = up->scc_char4 = 0x8000;
+ up->scc_char5 = up->scc_char6 = up->scc_char7 = up->scc_char8 = 0x8000;
+ up->scc_rccm = 0xc0ff;
+
+ /* Mask all interrupts and remove anything pending.
+ */
+ sp->scc_sccm = 0;
+ sp->scc_scce = 0xffff;
+
+ /* Set 8 bit FIFO, 16 bit oversampling and UART mode.
+ */
+ sp->scc_gsmrh = SCC_GSMRH_RFW; /* 8 bit FIFO */
+ sp->scc_gsmrl = \
+ SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16 | SCC_GSMRL_MODE_UART;
+
+ /* Set CTS flow control, 1 stop bit, 8 bit character length,
+ * normal async UART mode, no parity
+ */
+ sp->scc_psmr = SCU_PSMR_FLC | SCU_PSMR_CL;
+
+ /* execute the "Init Rx and Tx params" CP command.
+ */
+
+ while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
+ ;
+
+ cp->cp_cpcr = mk_cr_cmd(KGDB_CPM_CR_SCC_PAGE, KGDB_CPM_CR_SCC_SBLOCK,
+ 0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+ while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
+ ;
+
+ /* Enable transmitter/receiver.
+ */
+ sp->scc_gsmrl |= SCC_GSMRL_ENR | SCC_GSMRL_ENT;
+
+ printf("SCC%d at %dbps ", CONFIG_KGDB_INDEX, speed);
+}
+
+void
+putDebugChar(const char c)
+{
+ volatile scc_uart_t *up;
+ volatile cbd_t *tbdf;
+ volatile immap_t *im;
+
+ if (c == '\n')
+ putDebugChar ('\r');
+
+ im = (immap_t *)CONFIG_SYS_IMMR;
+ up = (scc_uart_t *)&im->im_dprambase[KGDB_PROFF_SCC];
+ tbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_tbase];
+
+ /* Wait for last character to go.
+ */
+ while (tbdf->cbd_sc & BD_SC_READY)
+ ;
+
+ /* Load the character into the transmit buffer.
+ */
+ *(volatile char *)tbdf->cbd_bufaddr = c;
+ tbdf->cbd_datlen = 1;
+ tbdf->cbd_sc |= BD_SC_READY;
+}
+
+void
+putDebugStr (const char *s)
+{
+ while (*s) {
+ putDebugChar (*s++);
+ }
+}
+
+int
+getDebugChar(void)
+{
+ volatile cbd_t *rbdf;
+ volatile scc_uart_t *up;
+ volatile immap_t *im;
+ unsigned char c;
+
+ im = (immap_t *)CONFIG_SYS_IMMR;
+ up = (scc_uart_t *)&im->im_dprambase[KGDB_PROFF_SCC];
+ rbdf = (cbd_t *)&im->im_dprambase[up->scc_genscc.scc_rbase];
+
+ /* Wait for character to show up.
+ */
+ while (rbdf->cbd_sc & BD_SC_EMPTY)
+ ;
+
+ /* Grab the char and clear the buffer again.
+ */
+ c = *(volatile unsigned char *)rbdf->cbd_bufaddr;
+ rbdf->cbd_sc |= BD_SC_EMPTY;
+
+ return (c);
+}
+
+void
+kgdb_interruptible(int yes)
+{
+ return;
+}
+
+#endif /* CONFIG_KGDB_ON_SCC */
diff --git a/arch/powerpc/cpu/mpc8260/serial_smc.c b/arch/powerpc/cpu/mpc8260/serial_smc.c
new file mode 100644
index 0000000..9410e4c
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/serial_smc.c
@@ -0,0 +1,477 @@
+/*
+ * (C) Copyright 2000, 2001, 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00, with
+ * changes based on the file arch/powerpc/mbxboot/m8260_tty.c from the
+ * Linux/PPC sources (m8260_tty.c had no copyright info in it).
+ */
+
+/*
+ * Minimal serial functions needed to use one of the SMC ports
+ * as serial console interface.
+ */
+
+#include <common.h>
+#include <mpc8260.h>
+#include <asm/cpm_8260.h>
+#include <serial.h>
+#include <linux/compiler.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_CONS_ON_SMC)
+
+#if CONFIG_CONS_INDEX == 1 /* Console on SMC1 */
+
+#define SMC_INDEX 0
+#define PROFF_SMC_BASE PROFF_SMC1_BASE
+#define PROFF_SMC PROFF_SMC1
+#define CPM_CR_SMC_PAGE CPM_CR_SMC1_PAGE
+#define CPM_CR_SMC_SBLOCK CPM_CR_SMC1_SBLOCK
+#define CMXSMR_MASK (CMXSMR_SMC1|CMXSMR_SMC1CS_MSK)
+#define CMXSMR_VALUE CMXSMR_SMC1CS_BRG7
+
+#elif CONFIG_CONS_INDEX == 2 /* Console on SMC2 */
+
+#define SMC_INDEX 1
+#define PROFF_SMC_BASE PROFF_SMC2_BASE
+#define PROFF_SMC PROFF_SMC2
+#define CPM_CR_SMC_PAGE CPM_CR_SMC2_PAGE
+#define CPM_CR_SMC_SBLOCK CPM_CR_SMC2_SBLOCK
+#define CMXSMR_MASK (CMXSMR_SMC2|CMXSMR_SMC2CS_MSK)
+#define CMXSMR_VALUE CMXSMR_SMC2CS_BRG8
+
+#else
+
+#error "console not correctly defined"
+
+#endif
+
+#if !defined(CONFIG_SYS_SMC_RXBUFLEN)
+#define CONFIG_SYS_SMC_RXBUFLEN 1
+#define CONFIG_SYS_MAXIDLE 0
+#else
+#if !defined(CONFIG_SYS_MAXIDLE)
+#error "you must define CONFIG_SYS_MAXIDLE"
+#endif
+#endif
+
+typedef volatile struct serialbuffer {
+ cbd_t rxbd; /* Rx BD */
+ cbd_t txbd; /* Tx BD */
+ uint rxindex; /* index for next character to read */
+ volatile uchar rxbuf[CONFIG_SYS_SMC_RXBUFLEN];/* rx buffers */
+ volatile uchar txbuf; /* tx buffers */
+} serialbuffer_t;
+
+/* map rs_table index to baud rate generator index */
+static unsigned char brg_map[] = {
+ 6, /* BRG7 for SMC1 */
+ 7, /* BRG8 for SMC2 */
+ 0, /* BRG1 for SCC1 */
+ 1, /* BRG1 for SCC2 */
+ 2, /* BRG1 for SCC3 */
+ 3, /* BRG1 for SCC4 */
+};
+
+static int mpc8260_smc_serial_init(void)
+{
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile smc_t *sp;
+ volatile smc_uart_t *up;
+ volatile cpm8260_t *cp = &(im->im_cpm);
+ uint dpaddr;
+ volatile serialbuffer_t *rtx;
+
+ /* initialize pointers to SMC */
+
+ sp = (smc_t *) &(im->im_smc[SMC_INDEX]);
+ im->im_dprambase16[PROFF_SMC_BASE / sizeof(u16)] = PROFF_SMC;
+ up = (smc_uart_t *)&im->im_dprambase[PROFF_SMC];
+
+ /* Disable transmitter/receiver. */
+ sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+
+ /* NOTE: I/O port pins are set up via the iop_conf_tab[] table */
+
+ /* Allocate space for two buffer descriptors in the DP ram.
+ * damm: allocating space after the two buffers for rx/tx data
+ */
+
+ /* allocate size of struct serialbuffer with bd rx/tx,
+ * buffer rx/tx and rx index
+ */
+ dpaddr = m8260_cpm_dpalloc((sizeof(serialbuffer_t)), 16);
+
+ rtx = (serialbuffer_t *)&im->im_dprambase[dpaddr];
+
+ /* Set the physical address of the host memory buffers in
+ * the buffer descriptors.
+ */
+ rtx->rxbd.cbd_bufaddr = (uint) &rtx->rxbuf;
+ rtx->rxbd.cbd_sc = 0;
+
+ rtx->txbd.cbd_bufaddr = (uint) &rtx->txbuf;
+ rtx->txbd.cbd_sc = 0;
+
+ /* Set up the uart parameters in the parameter ram. */
+ up->smc_rbase = dpaddr;
+ up->smc_tbase = dpaddr+sizeof(cbd_t);
+ up->smc_rfcr = CPMFCR_EB;
+ up->smc_tfcr = CPMFCR_EB;
+ up->smc_brklen = 0;
+ up->smc_brkec = 0;
+ up->smc_brkcr = 0;
+
+ /* Set UART mode, 8 bit, no parity, one stop.
+ * Enable receive and transmit.
+ */
+ sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
+
+ /* Mask all interrupts and remove anything pending. */
+ sp->smc_smcm = 0;
+ sp->smc_smce = 0xff;
+
+ /* put the SMC channel into NMSI (non multiplexd serial interface)
+ * mode and wire either BRG7 to SMC1 or BRG8 to SMC2 (15-17).
+ */
+ im->im_cpmux.cmx_smr = (im->im_cpmux.cmx_smr&~CMXSMR_MASK)|CMXSMR_VALUE;
+
+ /* Set up the baud rate generator. */
+ serial_setbrg ();
+
+ /* Make the first buffer the only buffer. */
+ rtx->txbd.cbd_sc |= BD_SC_WRAP;
+ rtx->rxbd.cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+ /* single/multi character receive. */
+ up->smc_mrblr = CONFIG_SYS_SMC_RXBUFLEN;
+ up->smc_maxidl = CONFIG_SYS_MAXIDLE;
+ rtx->rxindex = 0;
+
+ /* Initialize Tx/Rx parameters. */
+
+ while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
+ ;
+
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC_PAGE, CPM_CR_SMC_SBLOCK,
+ 0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+ while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
+ ;
+
+ /* Enable transmitter/receiver. */
+ sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+
+ return (0);
+}
+
+static void mpc8260_smc_serial_setbrg(void)
+{
+#if defined(CONFIG_CONS_USE_EXTC)
+ m8260_cpm_extcbrg(brg_map[SMC_INDEX], gd->baudrate,
+ CONFIG_CONS_EXTC_RATE, CONFIG_CONS_EXTC_PINSEL);
+#else
+ m8260_cpm_setbrg(brg_map[SMC_INDEX], gd->baudrate);
+#endif
+}
+
+static void mpc8260_smc_serial_putc(const char c)
+{
+ volatile smc_uart_t *up;
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile serialbuffer_t *rtx;
+
+ if (c == '\n')
+ serial_putc ('\r');
+
+ up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]);
+
+ rtx = (serialbuffer_t *)&im->im_dprambase[up->smc_rbase];
+
+ /* Wait for last character to go. */
+ while (rtx->txbd.cbd_sc & BD_SC_READY & BD_SC_READY)
+ ;
+ rtx->txbuf = c;
+ rtx->txbd.cbd_datlen = 1;
+ rtx->txbd.cbd_sc |= BD_SC_READY;
+}
+
+static int mpc8260_smc_serial_getc(void)
+{
+ volatile smc_uart_t *up;
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile serialbuffer_t *rtx;
+ unsigned char c;
+
+ up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]);
+
+ rtx = (serialbuffer_t *)&im->im_dprambase[up->smc_rbase];
+
+ /* Wait for character to show up. */
+ while (rtx->rxbd.cbd_sc & BD_SC_EMPTY)
+ ;
+
+ /* the characters are read one by one,
+ * use the rxindex to know the next char to deliver
+ */
+ c = *(unsigned char *) (rtx->rxbd.cbd_bufaddr + rtx->rxindex);
+ rtx->rxindex++;
+
+ /* check if all char are readout, then make prepare for next receive */
+ if (rtx->rxindex >= rtx->rxbd.cbd_datlen) {
+ rtx->rxindex = 0;
+ rtx->rxbd.cbd_sc |= BD_SC_EMPTY;
+ }
+ return(c);
+}
+
+static int mpc8260_smc_serial_tstc(void)
+{
+ volatile smc_uart_t *up;
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile serialbuffer_t *rtx;
+
+ up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]);
+ rtx = (serialbuffer_t *)&im->im_dprambase[up->smc_rbase];
+
+ return !(rtx->rxbd.cbd_sc & BD_SC_EMPTY);
+}
+
+static struct serial_device mpc8260_smc_serial_drv = {
+ .name = "mpc8260_smc_uart",
+ .start = mpc8260_smc_serial_init,
+ .stop = NULL,
+ .setbrg = mpc8260_smc_serial_setbrg,
+ .putc = mpc8260_smc_serial_putc,
+ .puts = default_serial_puts,
+ .getc = mpc8260_smc_serial_getc,
+ .tstc = mpc8260_smc_serial_tstc,
+};
+
+void mpc8260_smc_serial_initialize(void)
+{
+ serial_register(&mpc8260_smc_serial_drv);
+}
+
+__weak struct serial_device *default_serial_console(void)
+{
+ return &mpc8260_smc_serial_drv;
+}
+#endif /* CONFIG_CONS_ON_SMC */
+
+#if defined(CONFIG_KGDB_ON_SMC)
+
+#if defined(CONFIG_CONS_ON_SMC) && CONFIG_KGDB_INDEX == CONFIG_CONS_INDEX
+#error Whoops! serial console and kgdb are on the same smc serial port
+#endif
+
+#if CONFIG_KGDB_INDEX == 1 /* KGDB Port on SMC1 */
+
+#define KGDB_SMC_INDEX 0
+#define KGDB_PROFF_SMC_BASE PROFF_SMC1_BASE
+#define KGDB_PROFF_SMC PROFF_SMC1
+#define KGDB_CPM_CR_SMC_PAGE CPM_CR_SMC1_PAGE
+#define KGDB_CPM_CR_SMC_SBLOCK CPM_CR_SMC1_SBLOCK
+#define KGDB_CMXSMR_MASK (CMXSMR_SMC1|CMXSMR_SMC1CS_MSK)
+#define KGDB_CMXSMR_VALUE CMXSMR_SMC1CS_BRG7
+
+#elif CONFIG_KGDB_INDEX == 2 /* KGDB Port on SMC2 */
+
+#define KGDB_SMC_INDEX 1
+#define KGDB_PROFF_SMC_BASE PROFF_SMC2_BASE
+#define KGDB_PROFF_SMC PROFF_SMC2
+#define KGDB_CPM_CR_SMC_PAGE CPM_CR_SMC2_PAGE
+#define KGDB_CPM_CR_SMC_SBLOCK CPM_CR_SMC2_SBLOCK
+#define KGDB_CMXSMR_MASK (CMXSMR_SMC2|CMXSMR_SMC2CS_MSK)
+#define KGDB_CMXSMR_VALUE CMXSMR_SMC2CS_BRG8
+
+#else
+
+#error "console not correctly defined"
+
+#endif
+
+void
+kgdb_serial_init (void)
+{
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile smc_t *sp;
+ volatile smc_uart_t *up;
+ volatile cbd_t *tbdf, *rbdf;
+ volatile cpm8260_t *cp = &(im->im_cpm);
+ uint dpaddr, speed = CONFIG_KGDB_BAUDRATE;
+ char *s, *e;
+
+ if ((s = getenv("kgdbrate")) != NULL && *s != '\0') {
+ ulong rate = simple_strtoul(s, &e, 10);
+ if (e > s && *e == '\0')
+ speed = rate;
+ }
+
+ /* initialize pointers to SMC */
+
+ sp = (smc_t *) &(im->im_smc[KGDB_SMC_INDEX]);
+ im->im_dprambase16[KGDB_PROFF_SMC_BASE / sizeof(u16)] = KGDB_PROFF_SMC;
+ up = (smc_uart_t *)&im->im_dprambase[KGDB_PROFF_SMC];
+
+ /* Disable transmitter/receiver. */
+ sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+
+ /* NOTE: I/O port pins are set up via the iop_conf_tab[] table */
+
+ /* Allocate space for two buffer descriptors in the DP ram.
+ * damm: allocating space after the two buffers for rx/tx data
+ */
+
+ dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16);
+
+ /* Set the physical address of the host memory buffers in
+ * the buffer descriptors.
+ */
+ rbdf = (cbd_t *)&im->im_dprambase[dpaddr];
+ rbdf->cbd_bufaddr = (uint) (rbdf+2);
+ rbdf->cbd_sc = 0;
+ tbdf = rbdf + 1;
+ tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+ tbdf->cbd_sc = 0;
+
+ /* Set up the uart parameters in the parameter ram. */
+ up->smc_rbase = dpaddr;
+ up->smc_tbase = dpaddr+sizeof(cbd_t);
+ up->smc_rfcr = CPMFCR_EB;
+ up->smc_tfcr = CPMFCR_EB;
+ up->smc_brklen = 0;
+ up->smc_brkec = 0;
+ up->smc_brkcr = 0;
+
+ /* Set UART mode, 8 bit, no parity, one stop.
+ * Enable receive and transmit.
+ */
+ sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
+
+ /* Mask all interrupts and remove anything pending. */
+ sp->smc_smcm = 0;
+ sp->smc_smce = 0xff;
+
+ /* put the SMC channel into NMSI (non multiplexd serial interface)
+ * mode and wire either BRG7 to SMC1 or BRG8 to SMC2 (15-17).
+ */
+ im->im_cpmux.cmx_smr =
+ (im->im_cpmux.cmx_smr & ~KGDB_CMXSMR_MASK) | KGDB_CMXSMR_VALUE;
+
+ /* Set up the baud rate generator. */
+#if defined(CONFIG_KGDB_USE_EXTC)
+ m8260_cpm_extcbrg(brg_map[KGDB_SMC_INDEX], speed,
+ CONFIG_KGDB_EXTC_RATE, CONFIG_KGDB_EXTC_PINSEL);
+#else
+ m8260_cpm_setbrg(brg_map[KGDB_SMC_INDEX], speed);
+#endif
+
+ /* Make the first buffer the only buffer. */
+ tbdf->cbd_sc |= BD_SC_WRAP;
+ rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+ /* Single character receive. */
+ up->smc_mrblr = 1;
+ up->smc_maxidl = 0;
+
+ /* Initialize Tx/Rx parameters. */
+
+ while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
+ ;
+
+ cp->cp_cpcr = mk_cr_cmd(KGDB_CPM_CR_SMC_PAGE, KGDB_CPM_CR_SMC_SBLOCK,
+ 0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+ while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
+ ;
+
+ /* Enable transmitter/receiver. */
+ sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+
+ printf("SMC%d at %dbps ", CONFIG_KGDB_INDEX, speed);
+}
+
+void
+putDebugChar(const char c)
+{
+ volatile cbd_t *tbdf;
+ volatile char *buf;
+ volatile smc_uart_t *up;
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+
+ if (c == '\n')
+ putDebugChar ('\r');
+
+ up = (smc_uart_t *)&(im->im_dprambase[KGDB_PROFF_SMC]);
+
+ tbdf = (cbd_t *)&im->im_dprambase[up->smc_tbase];
+
+ /* Wait for last character to go. */
+ buf = (char *)tbdf->cbd_bufaddr;
+ while (tbdf->cbd_sc & BD_SC_READY)
+ ;
+
+ *buf = c;
+ tbdf->cbd_datlen = 1;
+ tbdf->cbd_sc |= BD_SC_READY;
+}
+
+void
+putDebugStr (const char *s)
+{
+ while (*s) {
+ putDebugChar (*s++);
+ }
+}
+
+int
+getDebugChar(void)
+{
+ volatile cbd_t *rbdf;
+ volatile unsigned char *buf;
+ volatile smc_uart_t *up;
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ unsigned char c;
+
+ up = (smc_uart_t *)&(im->im_dprambase[KGDB_PROFF_SMC]);
+
+ rbdf = (cbd_t *)&im->im_dprambase[up->smc_rbase];
+
+ /* Wait for character to show up. */
+ buf = (unsigned char *)rbdf->cbd_bufaddr;
+ while (rbdf->cbd_sc & BD_SC_EMPTY)
+ ;
+ c = *buf;
+ rbdf->cbd_sc |= BD_SC_EMPTY;
+
+ return(c);
+}
+
+void
+kgdb_interruptible(int yes)
+{
+ return;
+}
+
+#endif /* CONFIG_KGDB_ON_SMC */
diff --git a/arch/powerpc/cpu/mpc8260/speed.c b/arch/powerpc/cpu/mpc8260/speed.c
new file mode 100644
index 0000000..7841e8a
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/speed.c
@@ -0,0 +1,244 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8260.h>
+#include <asm/processor.h>
+
+#if defined(CONFIG_BOARD_GET_CPU_CLK_F)
+extern unsigned long board_get_cpu_clk_f (void);
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* ------------------------------------------------------------------------- */
+
+/* Bus-to-Core Multiplier */
+#define _1x 2
+#define _1_5x 3
+#define _2x 4
+#define _2_5x 5
+#define _3x 6
+#define _3_5x 7
+#define _4x 8
+#define _4_5x 9
+#define _5x 10
+#define _5_5x 11
+#define _6x 12
+#define _6_5x 13
+#define _7x 14
+#define _7_5x 15
+#define _8x 16
+#define _byp -1
+#define _off -2
+#define _unk -3
+
+typedef struct {
+ int b2c_mult;
+ int vco_div;
+ char *freq_60x;
+ char *freq_core;
+} corecnf_t;
+
+/*
+ * this table based on "Errata to MPC8260 PowerQUICC II User's Manual",
+ * Rev. 1, 8/2000, page 10.
+ */
+corecnf_t corecnf_tab[] = {
+ { _1_5x, 4, " 33-100", " 33-100" }, /* 0x00 */
+ { _1x, 4, " 50-150", " 50-150" }, /* 0x01 */
+ { _1x, 8, " 25-75 ", " 25-75 " }, /* 0x02 */
+ { _byp, -1, " ?-? ", " ?-? " }, /* 0x03 */
+ { _2x, 2, " 50-150", "100-300" }, /* 0x04 */
+ { _2x, 4, " 25-75 ", " 50-150" }, /* 0x05 */
+ { _2_5x, 2, " 40-120", "100-240" }, /* 0x06 */
+ { _4_5x, 2, " 22-65 ", "100-300" }, /* 0x07 */
+ { _3x, 2, " 33-100", "100-300" }, /* 0x08 */
+ { _5_5x, 2, " 18-55 ", "100-300" }, /* 0x09 */
+ { _4x, 2, " 25-75 ", "100-300" }, /* 0x0A */
+ { _5x, 2, " 20-60 ", "100-300" }, /* 0x0B */
+ { _1_5x, 8, " 16-50 ", " 16-50 " }, /* 0x0C */
+ { _6x, 2, " 16-50 ", "100-300" }, /* 0x0D */
+ { _3_5x, 2, " 30-85 ", "100-300" }, /* 0x0E */
+ { _off, -1, " ?-? ", " ?-? " }, /* 0x0F */
+ { _3x, 4, " 16-50 ", " 50-150" }, /* 0x10 */
+ { _2_5x, 4, " 20-60 ", " 50-120" }, /* 0x11 */
+ { _6_5x, 2, " 15-46 ", "100-300" }, /* 0x12 */
+ { _byp, -1, " ?-? ", " ?-? " }, /* 0x13 */
+ { _7x, 2, " 14-43 ", "100-300" }, /* 0x14 */
+ { _2x, 4, " 25-75 ", " 50-150" }, /* 0x15 */
+ { _7_5x, 2, " 13-40 ", "100-300" }, /* 0x16 */
+ { _4_5x, 2, " 22-65 ", "100-300" }, /* 0x17 */
+ { _unk, -1, " ?-? ", " ?-? " }, /* 0x18 */
+ { _5_5x, 2, " 18-55 ", "100-300" }, /* 0x19 */
+ { _4x, 2, " 25-75 ", "100-300" }, /* 0x1A */
+ { _5x, 2, " 20-60 ", "100-300" }, /* 0x1B */
+ { _8x, 2, " 12-38 ", "100-300" }, /* 0x1C */
+ { _6x, 2, " 16-50 ", "100-300" }, /* 0x1D */
+ { _3_5x, 2, " 30-85 ", "100-300" }, /* 0x1E */
+ { _off, -1, " ?-? ", " ?-? " }, /* 0x1F */
+};
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ *
+ */
+
+int get_clocks (void)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ ulong clkin;
+ ulong sccr, dfbrg;
+ ulong scmr, corecnf, plldf, pllmf;
+ corecnf_t *cp;
+
+#if !defined(CONFIG_8260_CLKIN)
+#error clock measuring not implemented yet - define CONFIG_8260_CLKIN
+#else
+#if defined(CONFIG_BOARD_GET_CPU_CLK_F)
+ clkin = board_get_cpu_clk_f ();
+#else
+ clkin = CONFIG_8260_CLKIN;
+#endif
+#endif
+
+ sccr = immap->im_clkrst.car_sccr;
+ dfbrg = (sccr & SCCR_DFBRG_MSK) >> SCCR_DFBRG_SHIFT;
+
+ scmr = immap->im_clkrst.car_scmr;
+ corecnf = (scmr & SCMR_CORECNF_MSK) >> SCMR_CORECNF_SHIFT;
+ cp = &corecnf_tab[corecnf];
+
+ /* HiP7, HiP7 Rev01, HiP7 RevA */
+ if ((get_pvr () == PVR_8260_HIP7) ||
+ (get_pvr () == PVR_8260_HIP7R1) ||
+ (get_pvr () == PVR_8260_HIP7RA)) {
+ pllmf = (scmr & SCMR_PLLMF_MSKH7) >> SCMR_PLLMF_SHIFT;
+ gd->arch.vco_out = clkin * (pllmf + 1);
+ } else { /* HiP3, HiP4 */
+ pllmf = (scmr & SCMR_PLLMF_MSK) >> SCMR_PLLMF_SHIFT;
+ plldf = (scmr & SCMR_PLLDF) ? 1 : 0;
+ gd->arch.vco_out = (clkin * 2 * (pllmf + 1)) / (plldf + 1);
+ }
+
+ gd->arch.cpm_clk = gd->arch.vco_out / 2;
+ gd->bus_clk = clkin;
+ gd->arch.scc_clk = gd->arch.vco_out / 4;
+ gd->arch.brg_clk = gd->arch.vco_out / (1 << (2 * (dfbrg + 1)));
+
+ if (cp->b2c_mult > 0) {
+ gd->cpu_clk = (clkin * cp->b2c_mult) / 2;
+ } else {
+ gd->cpu_clk = clkin;
+ }
+
+#ifdef CONFIG_PCI
+ gd->pci_clk = clkin;
+
+ if (sccr & SCCR_PCI_MODE) {
+ uint pci_div;
+ uint pcidf = (sccr & SCCR_PCIDF_MSK) >> SCCR_PCIDF_SHIFT;
+
+ if (sccr & SCCR_PCI_MODCK) {
+ pci_div = 2;
+ if (pcidf == 9) {
+ pci_div *= 5;
+ } else if (pcidf == 0xB) {
+ pci_div *= 6;
+ } else {
+ pci_div *= (pcidf + 1);
+ }
+ } else {
+ pci_div = pcidf + 1;
+ }
+
+ gd->pci_clk = (gd->arch.cpm_clk * 2) / pci_div;
+ }
+#endif
+
+ return (0);
+}
+
+int prt_8260_clks (void)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ ulong sccr, dfbrg;
+ ulong scmr, corecnf, busdf, cpmdf, plldf, pllmf, pcidf;
+ corecnf_t *cp;
+
+ sccr = immap->im_clkrst.car_sccr;
+ dfbrg = (sccr & SCCR_DFBRG_MSK) >> SCCR_DFBRG_SHIFT;
+
+ scmr = immap->im_clkrst.car_scmr;
+ corecnf = (scmr & SCMR_CORECNF_MSK) >> SCMR_CORECNF_SHIFT;
+ busdf = (scmr & SCMR_BUSDF_MSK) >> SCMR_BUSDF_SHIFT;
+ cpmdf = (scmr & SCMR_CPMDF_MSK) >> SCMR_CPMDF_SHIFT;
+ plldf = (scmr & SCMR_PLLDF) ? 1 : 0;
+ pllmf = (scmr & SCMR_PLLMF_MSK) >> SCMR_PLLMF_SHIFT;
+ pcidf = (sccr & SCCR_PCIDF_MSK) >> SCCR_PCIDF_SHIFT;
+
+ cp = &corecnf_tab[corecnf];
+
+ puts (CPU_ID_STR " Clock Configuration\n - Bus-to-Core Mult ");
+
+ switch (cp->b2c_mult) {
+ case _byp:
+ puts ("BYPASS");
+ break;
+
+ case _off:
+ puts ("OFF");
+ break;
+
+ case _unk:
+ puts ("UNKNOWN");
+ break;
+
+ default:
+ printf ("%d%sx",
+ cp->b2c_mult / 2,
+ (cp->b2c_mult % 2) ? ".5" : "");
+ break;
+ }
+
+ printf (", VCO Div %d, 60x Bus Freq %s, Core Freq %s\n",
+ cp->vco_div, cp->freq_60x, cp->freq_core);
+
+ printf (" - dfbrg %ld, corecnf 0x%02lx, busdf %ld, cpmdf %ld, "
+ "plldf %ld, pllmf %ld, pcidf %ld\n",
+ dfbrg, corecnf, busdf, cpmdf,
+ plldf, pllmf, pcidf);
+
+ printf (" - vco_out %10ld, scc_clk %10ld, brg_clk %10ld\n",
+ gd->arch.vco_out, gd->arch.scc_clk, gd->arch.brg_clk);
+
+ printf (" - cpu_clk %10ld, cpm_clk %10ld, bus_clk %10ld\n",
+ gd->cpu_clk, gd->arch.cpm_clk, gd->bus_clk);
+#ifdef CONFIG_PCI
+ printf (" - pci_clk %10ld\n", gd->pci_clk);
+#endif
+ putc ('\n');
+
+ return (0);
+}
diff --git a/arch/powerpc/cpu/mpc8260/speed.h b/arch/powerpc/cpu/mpc8260/speed.h
new file mode 100644
index 0000000..3f32a14
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/speed.h
@@ -0,0 +1,54 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*-----------------------------------------------------------------------
+ * Timer value for timer 2, ICLK = 10
+ *
+ * SPEED_FCOUNT2 = GCLK / (16 * (TIMER_TMR_PS + 1))
+ * SPEED_TMR3_PS = (GCLK / (16 * SPEED_FCOUNT3)) - 1
+ *
+ * SPEED_FCOUNT2 timer 2 counting frequency
+ * GCLK CPU clock
+ * SPEED_TMR2_PS prescaler
+ */
+#define SPEED_TMR2_PS (250 - 1) /* divide by 250 */
+
+/*-----------------------------------------------------------------------
+ * Timer value for PIT
+ *
+ * PIT_TIME = SPEED_PITC / PITRTCLK
+ * PITRTCLK = 8192
+ */
+#define SPEED_PITC (82 << 16) /* start counting from 82 */
+
+/*
+ * The new value for PTA is calculated from
+ *
+ * PTA = (gclk * Trefresh) / (2 ^ (2 * DFBRG) * PTP * NCS)
+ *
+ * gclk CPU clock (not bus clock !)
+ * Trefresh Refresh cycle * 4 (four word bursts used)
+ * DFBRG For normal mode (no clock reduction) always 0
+ * PTP Prescaler (already adjusted for no. of banks and 4K / 8K refresh)
+ * NCS Number of SDRAM banks (chip selects) on this UPM.
+ */
diff --git a/arch/powerpc/cpu/mpc8260/spi.c b/arch/powerpc/cpu/mpc8260/spi.c
new file mode 100644
index 0000000..01b492e
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/spi.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2001 Navin Boppuri / Prashant Patel
+ * <nboppuri@trinetcommunication.com>,
+ * <pmpatel@trinetcommunication.com>
+ * Copyright (c) 2001 Gerd Mennchen <Gerd.Mennchen@icn.siemens.de>
+ * Copyright (c) 2001-2003 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * MPC8260 CPM SPI interface.
+ *
+ * Parts of this code are probably not portable and/or specific to
+ * the board which I used for the tests. Please send fixes/complaints
+ * to wd@denx.de
+ *
+ */
+
+#include <common.h>
+#include <asm/cpm_8260.h>
+#include <linux/ctype.h>
+#include <malloc.h>
+#include <post.h>
+#include <net.h>
+
+#if defined(CONFIG_SPI)
+
+/* Warning:
+ * You cannot enable DEBUG for early system initalization, i. e. when
+ * this driver is used to read environment parameters like "baudrate"
+ * from EEPROM which are used to initialize the serial port which is
+ * needed to print the debug messages...
+ */
+#undef DEBUG
+
+#define SPI_EEPROM_WREN 0x06
+#define SPI_EEPROM_RDSR 0x05
+#define SPI_EEPROM_READ 0x03
+#define SPI_EEPROM_WRITE 0x02
+
+/* ---------------------------------------------------------------
+ * Offset for initial SPI buffers in DPRAM:
+ * We need a 520 byte scratch DPRAM area to use at an early stage.
+ * It is used between the two initialization calls (spi_init_f()
+ * and spi_init_r()).
+ * The value 0x2000 makes it far enough from the start of the data
+ * area (as well as from the stack pointer).
+ * --------------------------------------------------------------- */
+#ifndef CONFIG_SYS_SPI_INIT_OFFSET
+#define CONFIG_SYS_SPI_INIT_OFFSET 0x2000
+#endif
+
+#define CPM_SPI_BASE 0x100
+
+#ifdef DEBUG
+
+#define DPRINT(a) printf a;
+/* -----------------------------------------------
+ * Helper functions to peek into tx and rx buffers
+ * ----------------------------------------------- */
+static const char * const hex_digit = "0123456789ABCDEF";
+
+static char quickhex (int i)
+{
+ return hex_digit[i];
+}
+
+static void memdump (void *pv, int num)
+{
+ int i;
+ unsigned char *pc = (unsigned char *) pv;
+
+ for (i = 0; i < num; i++)
+ printf ("%c%c ", quickhex (pc[i] >> 4), quickhex (pc[i] & 0x0f));
+ printf ("\t");
+ for (i = 0; i < num; i++)
+ printf ("%c", isprint (pc[i]) ? pc[i] : '.');
+ printf ("\n");
+}
+#else /* !DEBUG */
+
+#define DPRINT(a)
+
+#endif /* DEBUG */
+
+/* -------------------
+ * Function prototypes
+ * ------------------- */
+void spi_init (void);
+
+ssize_t spi_read (uchar *, int, uchar *, int);
+ssize_t spi_write (uchar *, int, uchar *, int);
+ssize_t spi_xfer (size_t);
+
+/* -------------------
+ * Variables
+ * ------------------- */
+
+#define MAX_BUFFER 0x104
+
+/* ----------------------------------------------------------------------
+ * Initially we place the RX and TX buffers at a fixed location in DPRAM!
+ * ---------------------------------------------------------------------- */
+static uchar *rxbuf =
+ (uchar *)&((immap_t *)CONFIG_SYS_IMMR)->im_dprambase
+ [CONFIG_SYS_SPI_INIT_OFFSET];
+static uchar *txbuf =
+ (uchar *)&((immap_t *)CONFIG_SYS_IMMR)->im_dprambase
+ [CONFIG_SYS_SPI_INIT_OFFSET+MAX_BUFFER];
+
+/* **************************************************************************
+ *
+ * Function: spi_init_f
+ *
+ * Description: Init SPI-Controller (ROM part)
+ *
+ * return: ---
+ *
+ * *********************************************************************** */
+void spi_init_f (void)
+{
+ unsigned int dpaddr;
+
+ volatile spi_t *spi;
+ volatile immap_t *immr;
+ volatile cpm8260_t *cp;
+ volatile cbd_t *tbdf, *rbdf;
+
+ immr = (immap_t *) CONFIG_SYS_IMMR;
+ cp = (cpm8260_t *) &immr->im_cpm;
+
+ immr->im_dprambase16[PROFF_SPI_BASE / sizeof(u16)] = PROFF_SPI;
+ spi = (spi_t *)&immr->im_dprambase[PROFF_SPI];
+
+/* 1 */
+ /* ------------------------------------------------
+ * Initialize Port D SPI pins
+ * (we are only in Master Mode !)
+ * ------------------------------------------------ */
+
+ /* --------------------------------------------
+ * GPIO or per. Function
+ * PPARD[16] = 1 [0x00008000] (SPIMISO)
+ * PPARD[17] = 1 [0x00004000] (SPIMOSI)
+ * PPARD[18] = 1 [0x00002000] (SPICLK)
+ * PPARD[12] = 0 [0x00080000] -> GPIO: (CS for ATC EEPROM)
+ * -------------------------------------------- */
+ immr->im_ioport.iop_ppard |= 0x0000E000; /* set bits */
+ immr->im_ioport.iop_ppard &= ~0x00080000; /* reset bit */
+
+ /* ----------------------------------------------
+ * In/Out or per. Function 0/1
+ * PDIRD[16] = 0 [0x00008000] -> PERI1: SPIMISO
+ * PDIRD[17] = 0 [0x00004000] -> PERI1: SPIMOSI
+ * PDIRD[18] = 0 [0x00002000] -> PERI1: SPICLK
+ * PDIRD[12] = 1 [0x00080000] -> GPIO OUT: CS for ATC EEPROM
+ * ---------------------------------------------- */
+ immr->im_ioport.iop_pdird &= ~0x0000E000;
+ immr->im_ioport.iop_pdird |= 0x00080000;
+
+ /* ----------------------------------------------
+ * special option reg.
+ * PSORD[16] = 1 [0x00008000] -> SPIMISO
+ * PSORD[17] = 1 [0x00004000] -> SPIMOSI
+ * PSORD[18] = 1 [0x00002000] -> SPICLK
+ * ---------------------------------------------- */
+ immr->im_ioport.iop_psord |= 0x0000E000;
+
+ /* Initialize the parameter ram.
+ * We need to make sure many things are initialized to zero
+ */
+ spi->spi_rstate = 0;
+ spi->spi_rdp = 0;
+ spi->spi_rbptr = 0;
+ spi->spi_rbc = 0;
+ spi->spi_rxtmp = 0;
+ spi->spi_tstate = 0;
+ spi->spi_tdp = 0;
+ spi->spi_tbptr = 0;
+ spi->spi_tbc = 0;
+ spi->spi_txtmp = 0;
+
+ /* Allocate space for one transmit and one receive buffer
+ * descriptor in the DP ram
+ */
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+ dpaddr = m8260_cpm_dpalloc (sizeof(cbd_t)*2, 8);
+#else
+ dpaddr = CPM_SPI_BASE;
+#endif
+
+/* 3 */
+ /* Set up the SPI parameters in the parameter ram */
+ spi->spi_rbase = dpaddr;
+ spi->spi_tbase = dpaddr + sizeof (cbd_t);
+
+ /***********IMPORTANT******************/
+
+ /*
+ * Setting transmit and receive buffer descriptor pointers
+ * initially to rbase and tbase. Only the microcode patches
+ * documentation talks about initializing this pointer. This
+ * is missing from the sample I2C driver. If you dont
+ * initialize these pointers, the kernel hangs.
+ */
+ spi->spi_rbptr = spi->spi_rbase;
+ spi->spi_tbptr = spi->spi_tbase;
+
+/* 4 */
+ /* Init SPI Tx + Rx Parameters */
+ while (cp->cp_cpcr & CPM_CR_FLG)
+ ;
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_SPI_PAGE, CPM_CR_SPI_SBLOCK,
+ 0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ while (cp->cp_cpcr & CPM_CR_FLG)
+ ;
+
+/* 6 */
+ /* Set to big endian. */
+ spi->spi_tfcr = CPMFCR_EB;
+ spi->spi_rfcr = CPMFCR_EB;
+
+/* 7 */
+ /* Set maximum receive size. */
+ spi->spi_mrblr = MAX_BUFFER;
+
+/* 8 + 9 */
+ /* tx and rx buffer descriptors */
+ tbdf = (cbd_t *) & immr->im_dprambase[spi->spi_tbase];
+ rbdf = (cbd_t *) & immr->im_dprambase[spi->spi_rbase];
+
+ tbdf->cbd_sc &= ~BD_SC_READY;
+ rbdf->cbd_sc &= ~BD_SC_EMPTY;
+
+ /* Set the bd's rx and tx buffer address pointers */
+ rbdf->cbd_bufaddr = (ulong) rxbuf;
+ tbdf->cbd_bufaddr = (ulong) txbuf;
+
+/* 10 + 11 */
+ immr->im_spi.spi_spie = SPI_EMASK; /* Clear all SPI events */
+ immr->im_spi.spi_spim = 0x00; /* Mask all SPI events */
+
+
+ return;
+}
+
+/* **************************************************************************
+ *
+ * Function: spi_init_r
+ *
+ * Description: Init SPI-Controller (RAM part) -
+ * The malloc engine is ready and we can move our buffers to
+ * normal RAM
+ *
+ * return: ---
+ *
+ * *********************************************************************** */
+void spi_init_r (void)
+{
+ volatile spi_t *spi;
+ volatile immap_t *immr;
+ volatile cbd_t *tbdf, *rbdf;
+
+ immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ spi = (spi_t *)&immr->im_dprambase[PROFF_SPI];
+
+ /* tx and rx buffer descriptors */
+ tbdf = (cbd_t *) & immr->im_dprambase[spi->spi_tbase];
+ rbdf = (cbd_t *) & immr->im_dprambase[spi->spi_rbase];
+
+ /* Allocate memory for RX and TX buffers */
+ rxbuf = (uchar *) malloc (MAX_BUFFER);
+ txbuf = (uchar *) malloc (MAX_BUFFER);
+
+ rbdf->cbd_bufaddr = (ulong) rxbuf;
+ tbdf->cbd_bufaddr = (ulong) txbuf;
+
+ return;
+}
+
+/****************************************************************************
+ * Function: spi_write
+ **************************************************************************** */
+ssize_t spi_write (uchar *addr, int alen, uchar *buffer, int len)
+{
+ int i;
+
+ memset(rxbuf, 0, MAX_BUFFER);
+ memset(txbuf, 0, MAX_BUFFER);
+ *txbuf = SPI_EEPROM_WREN; /* write enable */
+ spi_xfer(1);
+ memcpy(txbuf, addr, alen);
+ *txbuf = SPI_EEPROM_WRITE; /* WRITE memory array */
+ memcpy(alen + txbuf, buffer, len);
+ spi_xfer(alen + len);
+ /* ignore received data */
+ for (i = 0; i < 1000; i++) {
+ *txbuf = SPI_EEPROM_RDSR; /* read status */
+ txbuf[1] = 0;
+ spi_xfer(2);
+ if (!(rxbuf[1] & 1)) {
+ break;
+ }
+ udelay(1000);
+ }
+ if (i >= 1000) {
+ printf ("*** spi_write: Time out while writing!\n");
+ }
+
+ return len;
+}
+
+/****************************************************************************
+ * Function: spi_read
+ **************************************************************************** */
+ssize_t spi_read (uchar *addr, int alen, uchar *buffer, int len)
+{
+ memset(rxbuf, 0, MAX_BUFFER);
+ memset(txbuf, 0, MAX_BUFFER);
+ memcpy(txbuf, addr, alen);
+ *txbuf = SPI_EEPROM_READ; /* READ memory array */
+
+ /*
+ * There is a bug in 860T (?) that cuts the last byte of input
+ * if we're reading into DPRAM. The solution we choose here is
+ * to always read len+1 bytes (we have one extra byte at the
+ * end of the buffer).
+ */
+ spi_xfer(alen + len + 1);
+ memcpy(buffer, alen + rxbuf, len);
+
+ return len;
+}
+
+/****************************************************************************
+ * Function: spi_xfer
+ **************************************************************************** */
+ssize_t spi_xfer (size_t count)
+{
+ volatile immap_t *immr;
+ volatile spi_t *spi;
+ cbd_t *tbdf, *rbdf;
+ int tm;
+
+ DPRINT (("*** spi_xfer entered ***\n"));
+
+ immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ spi = (spi_t *)&immr->im_dprambase[PROFF_SPI];
+
+ tbdf = (cbd_t *) & immr->im_dprambase[spi->spi_tbase];
+ rbdf = (cbd_t *) & immr->im_dprambase[spi->spi_rbase];
+
+ /* Board-specific: Set CS for device (ATC EEPROM) */
+ immr->im_ioport.iop_pdatd &= ~0x00080000;
+
+ /* Setting tx bd status and data length */
+ tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP;
+ tbdf->cbd_datlen = count;
+
+ DPRINT (("*** spi_xfer: Bytes to be xferred: %d ***\n",
+ tbdf->cbd_datlen));
+
+ /* Setting rx bd status and data length */
+ rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+ rbdf->cbd_datlen = 0; /* rx length has no significance */
+
+ immr->im_spi.spi_spmode = SPMODE_REV |
+ SPMODE_MSTR |
+ SPMODE_EN |
+ SPMODE_LEN(8) | /* 8 Bits per char */
+ SPMODE_PM(0x8) ; /* medium speed */
+ immr->im_spi.spi_spie = SPI_EMASK; /* Clear all SPI events */
+ immr->im_spi.spi_spim = 0x00; /* Mask all SPI events */
+
+ /* start spi transfer */
+ DPRINT (("*** spi_xfer: Performing transfer ...\n"));
+ immr->im_spi.spi_spcom |= SPI_STR; /* Start transmit */
+
+ /* --------------------------------
+ * Wait for SPI transmit to get out
+ * or time out (1 second = 1000 ms)
+ * -------------------------------- */
+ for (tm=0; tm<1000; ++tm) {
+ if (immr->im_spi.spi_spie & SPI_TXB) { /* Tx Buffer Empty */
+ DPRINT (("*** spi_xfer: Tx buffer empty\n"));
+ break;
+ }
+ if ((tbdf->cbd_sc & BD_SC_READY) == 0) {
+ DPRINT (("*** spi_xfer: Tx BD done\n"));
+ break;
+ }
+ udelay (1000);
+ }
+ if (tm >= 1000) {
+ printf ("*** spi_xfer: Time out while xferring to/from SPI!\n");
+ }
+ DPRINT (("*** spi_xfer: ... transfer ended\n"));
+
+#ifdef DEBUG
+ printf ("\nspi_xfer: txbuf after xfer\n");
+ memdump ((void *) txbuf, 16); /* dump of txbuf before transmit */
+ printf ("spi_xfer: rxbuf after xfer\n");
+ memdump ((void *) rxbuf, 16); /* dump of rxbuf after transmit */
+ printf ("\n");
+#endif
+
+ /* Clear CS for device */
+ immr->im_ioport.iop_pdatd |= 0x00080000;
+
+ return count;
+}
+#endif /* CONFIG_SPI */
diff --git a/arch/powerpc/cpu/mpc8260/start.S b/arch/powerpc/cpu/mpc8260/start.S
new file mode 100644
index 0000000..bd8d7ac
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/start.S
@@ -0,0 +1,1008 @@
+/*
+ * Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2000, 2001,2002 Wolfgang Denk <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * U-Boot - Startup Code for MPC8260 PowerPC based Embedded Boards
+ */
+#include <asm-offsets.h>
+#include <config.h>
+#include <mpc8260.h>
+#include <version.h>
+
+#define CONFIG_8260 1 /* needed for Linux kernel header files */
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+#include <asm/u-boot.h>
+
+/* We don't want the MMU yet.
+*/
+#undef MSR_KERNEL
+/* Floating Point enable, Machine Check and Recoverable Interr. */
+#ifdef DEBUG
+#define MSR_KERNEL (MSR_FP|MSR_RI)
+#else
+#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI)
+#endif
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+ START_GOT
+ GOT_ENTRY(_GOT2_TABLE_)
+ GOT_ENTRY(_FIXUP_TABLE_)
+
+ GOT_ENTRY(_start)
+ GOT_ENTRY(_start_of_vectors)
+ GOT_ENTRY(_end_of_vectors)
+ GOT_ENTRY(transfer_to_handler)
+
+ GOT_ENTRY(__init_end)
+ GOT_ENTRY(__bss_end)
+ GOT_ENTRY(__bss_start)
+#if defined(CONFIG_HYMOD)
+ GOT_ENTRY(environment)
+#endif
+ END_GOT
+
+/*
+ * Version string - must be in data segment because MPC8260 uses the first
+ * 256 bytes for the Hard Reset Configuration Word table (see below).
+ * Similarly, can't have the U-Boot Magic Number as the first thing in
+ * the image - don't know how this will affect the image tools, but I guess
+ * I'll find out soon
+ */
+ .data
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION_STRING, "\0"
+
+/*
+ * Hard Reset Configuration Word (HRCW) table
+ *
+ * The Hard Reset Configuration Word (HRCW) sets a number of useful things
+ * such as whether there is an external memory controller, whether the
+ * PowerPC core is disabled (i.e. only the communications processor is
+ * active, accessed by another CPU on the bus), whether using external
+ * arbitration, external bus mode, boot port size, core initial prefix,
+ * internal space base, boot memory space, etc.
+ *
+ * These things dictate where the processor begins execution, where the
+ * boot ROM appears in memory, the memory controller setup when access
+ * boot ROM, etc. The HRCW is *extremely* important.
+ *
+ * The HRCW is read from the bus during reset. One CPU on the bus will
+ * be a hard reset configuration master, any others will be hard reset
+ * configuration slaves. The master reads eight HRCWs from flash during
+ * reset - the first it uses for itself, the other 7 it communicates to
+ * up to 7 configuration slaves by some complicated mechanism, which is
+ * not really important here.
+ *
+ * The configuration master performs 32 successive reads starting at address
+ * 0 and incrementing by 8 each read (i.e. on 64 bit boundaries) but only 8
+ * bits is read, and always from byte lane D[0-7] (so that port size of the
+ * boot device does not matter). The first four reads form the 32 bit HRCW
+ * for the master itself. The second four reads form the HRCW for the first
+ * slave, and so on, up to seven slaves. The 32 bit HRCW is formed by
+ * concatenating the four bytes, with the first read placed in byte 0 (the
+ * most significant byte), and so on with the fourth read placed in byte 3
+ * (the least significant byte).
+ */
+#define _HRCW_TABLE_ENTRY(w) \
+ .fill 8,1,(((w)>>24)&0xff); \
+ .fill 8,1,(((w)>>16)&0xff); \
+ .fill 8,1,(((w)>> 8)&0xff); \
+ .fill 8,1,(((w) )&0xff)
+ .text
+ .globl _hrcw_table
+_hrcw_table:
+ _HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_MASTER)
+ _HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE1)
+ _HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE2)
+ _HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE3)
+ _HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE4)
+ _HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE5)
+ _HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE6)
+ _HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_SLAVE7)
+/*
+ * After configuration, a system reset exception is executed using the
+ * vector at offset 0x100 relative to the base set by MSR[IP]. If MSR[IP]
+ * is 0, the base address is 0x00000000. If MSR[IP] is 1, the base address
+ * is 0xfff00000. In the case of a Power On Reset or Hard Reset, the value
+ * of MSR[IP] is determined by the CIP field in the HRCW.
+ *
+ * Other bits in the HRCW set up the Base Address and Port Size in BR0.
+ * This determines the location of the boot ROM (flash or EPROM) in the
+ * processor's address space at boot time. As long as the HRCW is set up
+ * so that we eventually end up executing the code below when the processor
+ * executes the reset exception, the actual values used should not matter.
+ *
+ * Once we have got here, the address mask in OR0 is cleared so that the
+ * bottom 32K of the boot ROM is effectively repeated all throughout the
+ * processor's address space, after which we can jump to the absolute
+ * address at which the boot ROM was linked at compile time, and proceed
+ * to initialise the memory controller without worrying if the rug will be
+ * pulled out from under us, so to speak (it will be fine as long as we
+ * configure BR0 with the same boot ROM link address).
+ */
+ . = EXC_OFF_SYS_RESET
+
+ .globl _start
+_start:
+#if defined(CONFIG_MPC8260ADS) && defined(CONFIG_SYS_DEFAULT_IMMR)
+ lis r3, CONFIG_SYS_DEFAULT_IMMR@h
+ nop
+ lwz r4, 0(r3)
+ nop
+ rlwinm r4, r4, 0, 8, 5
+ nop
+ oris r4, r4, 0x0200
+ nop
+ stw r4, 0(r3)
+ nop
+#endif /* CONFIG_MPC8260ADS && CONFIG_SYS_DEFAULT_IMMR */
+
+ mfmsr r5 /* save msr contents */
+
+#if defined(CONFIG_COGENT)
+ /* this is what the cogent EPROM does */
+ li r0, 0
+ mtmsr r0
+ isync
+ bl cogent_init_8260
+#endif /* CONFIG_COGENT */
+
+#if defined(CONFIG_SYS_DEFAULT_IMMR)
+ lis r3, CONFIG_SYS_IMMR@h
+ ori r3, r3, CONFIG_SYS_IMMR@l
+ lis r4, CONFIG_SYS_DEFAULT_IMMR@h
+ stw r3, 0x1A8(r4)
+#endif /* CONFIG_SYS_DEFAULT_IMMR */
+
+ /* Initialise the MPC8260 processor core */
+ /*--------------------------------------------------------------*/
+
+ bl init_8260_core
+
+#ifndef CONFIG_SYS_RAMBOOT
+ /* When booting from ROM (Flash or EPROM), clear the */
+ /* Address Mask in OR0 so ROM appears everywhere */
+ /*--------------------------------------------------------------*/
+
+ lis r3, (CONFIG_SYS_IMMR+IM_REGBASE)@h
+ lwz r4, IM_OR0@l(r3)
+ li r5, 0x7fff
+ and r4, r4, r5
+ stw r4, IM_OR0@l(r3)
+
+ /* Calculate absolute address in FLASH and jump there */
+ /*--------------------------------------------------------------*/
+
+ lis r3, CONFIG_SYS_MONITOR_BASE@h
+ ori r3, r3, CONFIG_SYS_MONITOR_BASE@l
+ addi r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
+ mtlr r3
+ blr
+
+in_flash:
+#endif /* CONFIG_SYS_RAMBOOT */
+
+ /* initialize some things that are hard to access from C */
+ /*--------------------------------------------------------------*/
+
+ lis r3, CONFIG_SYS_IMMR@h /* set up stack in internal DPRAM */
+ ori r1, r3, CONFIG_SYS_INIT_SP_OFFSET
+ li r0, 0 /* Make room for stack frame header and */
+ stwu r0, -4(r1) /* clear final stack frame so that */
+ stwu r0, -4(r1) /* stack backtraces terminate cleanly */
+
+ /* let the C-code set up the rest */
+ /* */
+ /* Be careful to keep code relocatable ! */
+ /*--------------------------------------------------------------*/
+
+ GET_GOT /* initialize GOT access */
+
+ /* r3: IMMR */
+ bl cpu_init_f /* run low-level CPU init code (in Flash)*/
+
+#ifdef DEBUG
+ bl init_debug /* set up debugging stuff */
+#endif
+
+ bl board_init_f /* run 1st part of board init code (in Flash)*/
+
+ /* NOTREACHED - board_init_f() does not return */
+
+/*
+ * Vector Table
+ */
+
+ .globl _start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. */
+ STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+ STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+ STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+ . = 0x600
+Alignment:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+ . = 0x700
+ProgramCheck:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+ MSR_KERNEL, COPY_EE)
+
+ STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+ /* I guess we could implement decrementer, and may have
+ * to someday for timekeeping.
+ */
+ STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+
+ STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+ STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+ STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+ STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+ STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+ STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+ STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException)
+#ifdef DEBUG
+ . = 0x1300
+ /*
+ * This exception occurs when the program counter matches the
+ * Instruction Address Breakpoint Register (IABR).
+ *
+ * I want the cpu to halt if this occurs so I can hunt around
+ * with the debugger and look at things.
+ *
+ * When DEBUG is defined, both machine check enable (in the MSR)
+ * and checkstop reset enable (in the reset mode register) are
+ * turned off and so a checkstop condition will result in the cpu
+ * halting.
+ *
+ * I force the cpu into a checkstop condition by putting an illegal
+ * instruction here (at least this is the theory).
+ *
+ * well - that didnt work, so just do an infinite loop!
+ */
+1: b 1b
+#else
+ STD_EXCEPTION(0x1300, InstructionBreakpoint, DebugException)
+#endif
+ STD_EXCEPTION(0x1400, SMI, UnknownException)
+
+ STD_EXCEPTION(0x1500, Trap_15, UnknownException)
+ STD_EXCEPTION(0x1600, Trap_16, UnknownException)
+ STD_EXCEPTION(0x1700, Trap_17, UnknownException)
+ STD_EXCEPTION(0x1800, Trap_18, UnknownException)
+ STD_EXCEPTION(0x1900, Trap_19, UnknownException)
+ STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
+ STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+ STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
+ STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
+ STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
+ STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
+ STD_EXCEPTION(0x2000, Trap_20, UnknownException)
+ STD_EXCEPTION(0x2100, Trap_21, UnknownException)
+ STD_EXCEPTION(0x2200, Trap_22, UnknownException)
+ STD_EXCEPTION(0x2300, Trap_23, UnknownException)
+ STD_EXCEPTION(0x2400, Trap_24, UnknownException)
+ STD_EXCEPTION(0x2500, Trap_25, UnknownException)
+ STD_EXCEPTION(0x2600, Trap_26, UnknownException)
+ STD_EXCEPTION(0x2700, Trap_27, UnknownException)
+ STD_EXCEPTION(0x2800, Trap_28, UnknownException)
+ STD_EXCEPTION(0x2900, Trap_29, UnknownException)
+ STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
+ STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
+ STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
+ STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
+ STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
+ STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
+
+
+ .globl _end_of_vectors
+_end_of_vectors:
+
+ . = 0x3000
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+ .globl transfer_to_handler
+transfer_to_handler:
+ stw r22,_NIP(r21)
+ lis r22,MSR_POW@h
+ andc r23,r23,r22
+ stw r23,_MSR(r21)
+ SAVE_GPR(7, r21)
+ SAVE_4GPRS(8, r21)
+ SAVE_8GPRS(12, r21)
+ SAVE_8GPRS(24, r21)
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
+
+int_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+
+#if defined(CONFIG_COGENT)
+
+/*
+ * This code initialises the MPC8260 processor core
+ * (conforms to PowerPC 603e spec)
+ */
+
+ .globl cogent_init_8260
+cogent_init_8260:
+
+ /* Taken from page 14 of CMA282 manual */
+ /*--------------------------------------------------------------*/
+
+ lis r4, (CONFIG_SYS_IMMR+IM_REGBASE)@h
+ lis r3, CONFIG_SYS_IMMR@h
+ stw r3, IM_IMMR@l(r4)
+ lwz r3, IM_IMMR@l(r4)
+ stw r3, 0(r0)
+ lis r3, CONFIG_SYS_SYPCR@h
+ ori r3, r3, CONFIG_SYS_SYPCR@l
+ stw r3, IM_SYPCR@l(r4)
+ lwz r3, IM_SYPCR@l(r4)
+ stw r3, 4(r0)
+ lis r3, CONFIG_SYS_SCCR@h
+ ori r3, r3, CONFIG_SYS_SCCR@l
+ stw r3, IM_SCCR@l(r4)
+ lwz r3, IM_SCCR@l(r4)
+ stw r3, 8(r0)
+
+ /* the rest of this was disassembled from the */
+ /* EPROM code that came with my CMA282 CPU module */
+ /*--------------------------------------------------------------*/
+
+ lis r1, 0x1234
+ ori r1, r1, 0x5678
+ stw r1, 0x20(r0)
+ lwz r1, 0x20(r0)
+ stw r1, 0x24(r0)
+ lwz r1, 0x24(r0)
+ lis r3, 0x0e80
+ ori r3, r3, 0
+ stw r1, 4(r3)
+ lwz r1, 4(r3)
+
+ /* Done! */
+ /*--------------------------------------------------------------*/
+
+ blr
+
+#endif /* CONFIG_COGENT */
+
+/*
+ * This code initialises the MPC8260 processor core
+ * (conforms to PowerPC 603e spec)
+ * Note: expects original MSR contents to be in r5.
+ */
+
+ .globl init_8260_core
+init_8260_core:
+
+ /* Initialize machine status; enable machine check interrupt */
+ /*--------------------------------------------------------------*/
+
+ li r3, MSR_KERNEL /* Set ME and RI flags */
+ rlwimi r3, r5, 0, 25, 25 /* preserve IP bit set by HRCW */
+#ifdef DEBUG
+ rlwimi r3, r5, 0, 21, 22 /* debugger might set SE & BE bits */
+#endif
+ SYNC /* Some chip revs need this... */
+ mtmsr r3
+ SYNC
+ mtspr SRR1, r3 /* Make SRR1 match MSR */
+
+ /* Initialise the SYPCR early, and reset the watchdog (if req) */
+ /*--------------------------------------------------------------*/
+
+ lis r3, (CONFIG_SYS_IMMR+IM_REGBASE)@h
+#if !defined(CONFIG_COGENT)
+ lis r4, CONFIG_SYS_SYPCR@h
+ ori r4, r4, CONFIG_SYS_SYPCR@l
+ stw r4, IM_SYPCR@l(r3)
+#endif /* !CONFIG_COGENT */
+#if defined(CONFIG_WATCHDOG)
+ li r4, 21868 /* = 0x556c */
+ sth r4, IM_SWSR@l(r3)
+ li r4, -21959 /* = 0xaa39 */
+ sth r4, IM_SWSR@l(r3)
+#endif /* CONFIG_WATCHDOG */
+
+ /* Initialize the Hardware Implementation-dependent Registers */
+ /* HID0 also contains cache control */
+ /*--------------------------------------------------------------*/
+
+ lis r3, CONFIG_SYS_HID0_INIT@h
+ ori r3, r3, CONFIG_SYS_HID0_INIT@l
+ SYNC
+ mtspr HID0, r3
+
+ lis r3, CONFIG_SYS_HID0_FINAL@h
+ ori r3, r3, CONFIG_SYS_HID0_FINAL@l
+ SYNC
+ mtspr HID0, r3
+
+ lis r3, CONFIG_SYS_HID2@h
+ ori r3, r3, CONFIG_SYS_HID2@l
+ mtspr HID2, r3
+
+ /* clear all BAT's */
+ /*--------------------------------------------------------------*/
+
+ li r0, 0
+ mtspr DBAT0U, r0
+ mtspr DBAT0L, r0
+ mtspr DBAT1U, r0
+ mtspr DBAT1L, r0
+ mtspr DBAT2U, r0
+ mtspr DBAT2L, r0
+ mtspr DBAT3U, r0
+ mtspr DBAT3L, r0
+ mtspr IBAT0U, r0
+ mtspr IBAT0L, r0
+ mtspr IBAT1U, r0
+ mtspr IBAT1L, r0
+ mtspr IBAT2U, r0
+ mtspr IBAT2L, r0
+ mtspr IBAT3U, r0
+ mtspr IBAT3L, r0
+ SYNC
+
+ /* invalidate all tlb's */
+ /* */
+ /* From the 603e User Manual: "The 603e provides the ability to */
+ /* invalidate a TLB entry. The TLB Invalidate Entry (tlbie) */
+ /* instruction invalidates the TLB entry indexed by the EA, and */
+ /* operates on both the instruction and data TLBs simultaneously*/
+ /* invalidating four TLB entries (both sets in each TLB). The */
+ /* index corresponds to bits 15-19 of the EA. To invalidate all */
+ /* entries within both TLBs, 32 tlbie instructions should be */
+ /* issued, incrementing this field by one each time." */
+ /* */
+ /* "Note that the tlbia instruction is not implemented on the */
+ /* 603e." */
+ /* */
+ /* bits 15-19 correspond to addresses 0x00000000 to 0x0001F000 */
+ /* incrementing by 0x1000 each time. The code below is sort of */
+ /* based on code in "flush_tlbs" from arch/powerpc/kernel/head.S */
+ /* */
+ /*--------------------------------------------------------------*/
+
+ li r3, 32
+ mtctr r3
+ li r3, 0
+1: tlbie r3
+ addi r3, r3, 0x1000
+ bdnz 1b
+ SYNC
+
+ /* Done! */
+ /*--------------------------------------------------------------*/
+
+ blr
+
+#ifdef DEBUG
+
+/*
+ * initialise things related to debugging.
+ *
+ * must be called after the global offset table (GOT) is initialised
+ * (GET_GOT) and after cpu_init_f() has executed.
+ */
+
+ .globl init_debug
+init_debug:
+
+ lis r3, (CONFIG_SYS_IMMR+IM_REGBASE)@h
+
+ /* Quick and dirty hack to enable the RAM and copy the */
+ /* vectors so that we can take exceptions. */
+ /*--------------------------------------------------------------*/
+ /* write Memory Refresh Prescaler */
+ li r4, CONFIG_SYS_MPTPR
+ sth r4, IM_MPTPR@l(r3)
+ /* write 60x Refresh Timer */
+ li r4, CONFIG_SYS_PSRT
+ stb r4, IM_PSRT@l(r3)
+ /* init the 60x SDRAM Mode Register */
+ lis r4, (CONFIG_SYS_PSDMR|PSDMR_OP_NORM)@h
+ ori r4, r4, (CONFIG_SYS_PSDMR|PSDMR_OP_NORM)@l
+ stw r4, IM_PSDMR@l(r3)
+ /* write Precharge All Banks command */
+ lis r4, (CONFIG_SYS_PSDMR|PSDMR_OP_PREA)@h
+ ori r4, r4, (CONFIG_SYS_PSDMR|PSDMR_OP_PREA)@l
+ stw r4, IM_PSDMR@l(r3)
+ stb r0, 0(0)
+ /* write eight CBR Refresh commands */
+ lis r4, (CONFIG_SYS_PSDMR|PSDMR_OP_CBRR)@h
+ ori r4, r4, (CONFIG_SYS_PSDMR|PSDMR_OP_CBRR)@l
+ stw r4, IM_PSDMR@l(r3)
+ stb r0, 0(0)
+ stb r0, 0(0)
+ stb r0, 0(0)
+ stb r0, 0(0)
+ stb r0, 0(0)
+ stb r0, 0(0)
+ stb r0, 0(0)
+ stb r0, 0(0)
+ /* write Mode Register Write command */
+ lis r4, (CONFIG_SYS_PSDMR|PSDMR_OP_MRW)@h
+ ori r4, r4, (CONFIG_SYS_PSDMR|PSDMR_OP_MRW)@l
+ stw r4, IM_PSDMR@l(r3)
+ stb r0, 0(0)
+ /* write Normal Operation command and enable Refresh */
+ lis r4, (CONFIG_SYS_PSDMR|PSDMR_OP_NORM|PSDMR_RFEN)@h
+ ori r4, r4, (CONFIG_SYS_PSDMR|PSDMR_OP_NORM|PSDMR_RFEN)@l
+ stw r4, IM_PSDMR@l(r3)
+ stb r0, 0(0)
+ /* RAM should now be operational */
+
+#define VEC_WRD_CNT ((_end_of_vectors - _start + EXC_OFF_SYS_RESET) / 4)
+ mflr r3
+ GET_GOT
+ mtlr r3
+ lwz r3, GOT(_end_of_vectors)
+ rlwinm r4, r3, 0, 18, 31 /* _end_of_vectors & 0x3FFF */
+ lis r5, VEC_WRD_CNT@h
+ ori r5, r5, VEC_WRD_CNT@l
+ mtctr r5
+1:
+ lwzu r5, -4(r3)
+ stwu r5, -4(r4)
+ bdnz 1b
+
+ /* Load the Instruction Address Breakpoint Register (IABR). */
+ /* */
+ /* The address to load is stored in the first word of dual port */
+ /* ram and should be preserved while the power is on, so you */
+ /* can plug addresses into that location then reset the cpu and */
+ /* this code will load that address into the IABR after the */
+ /* reset. */
+ /* */
+ /* When the program counter matches the contents of the IABR, */
+ /* an exception is generated (before the instruction at that */
+ /* location completes). The vector for this exception is 0x1300 */
+ /*--------------------------------------------------------------*/
+ lis r3, CONFIG_SYS_IMMR@h
+ lwz r3, 0(r3)
+ mtspr IABR, r3
+
+ /* Set the entire dual port RAM (where the initial stack */
+ /* resides) to a known value - makes it easier to see where */
+ /* the stack has been written */
+ /*--------------------------------------------------------------*/
+ lis r3, (CONFIG_SYS_IMMR + CONFIG_SYS_INIT_SP_OFFSET)@h
+ ori r3, r3, (CONFIG_SYS_IMMR + CONFIG_SYS_INIT_SP_OFFSET)@l
+ li r4, ((CONFIG_SYS_INIT_SP_OFFSET - 4) / 4)
+ mtctr r4
+ lis r4, 0xdeadbeaf@h
+ ori r4, r4, 0xdeadbeaf@l
+1:
+ stwu r4, -4(r3)
+ bdnz 1b
+
+ /* Done! */
+ /*--------------------------------------------------------------*/
+
+ blr
+#endif
+
+/* Cache functions.
+ *
+ * Note: requires that all cache bits in
+ * HID0 are in the low half word.
+ */
+ .globl icache_enable
+icache_enable:
+ mfspr r3, HID0
+ ori r3, r3, HID0_ICE
+ lis r4, 0
+ ori r4, r4, HID0_ILOCK
+ andc r3, r3, r4
+ ori r4, r3, HID0_ICFI
+ isync
+ mtspr HID0, r4 /* sets enable and invalidate, clears lock */
+ isync
+ mtspr HID0, r3 /* clears invalidate */
+ blr
+
+ .globl icache_disable
+icache_disable:
+ mfspr r3, HID0
+ lis r4, 0
+ ori r4, r4, HID0_ICE|HID0_ILOCK
+ andc r3, r3, r4
+ ori r4, r3, HID0_ICFI
+ isync
+ mtspr HID0, r4 /* sets invalidate, clears enable and lock */
+ isync
+ mtspr HID0, r3 /* clears invalidate */
+ blr
+
+ .globl icache_status
+icache_status:
+ mfspr r3, HID0
+ rlwinm r3, r3, HID0_ICE_BITPOS + 1, 31, 31
+ blr
+
+ .globl dcache_enable
+dcache_enable:
+ mfspr r3, HID0
+ ori r3, r3, HID0_DCE
+ lis r4, 0
+ ori r4, r4, HID0_DLOCK
+ andc r3, r3, r4
+ ori r4, r3, HID0_DCI
+ sync
+ mtspr HID0, r4 /* sets enable and invalidate, clears lock */
+ sync
+ mtspr HID0, r3 /* clears invalidate */
+ blr
+
+ .globl dcache_disable
+dcache_disable:
+ mfspr r3, HID0
+ lis r4, 0
+ ori r4, r4, HID0_DCE|HID0_DLOCK
+ andc r3, r3, r4
+ ori r4, r3, HID0_DCI
+ sync
+ mtspr HID0, r4 /* sets invalidate, clears enable and lock */
+ sync
+ mtspr HID0, r3 /* clears invalidate */
+ blr
+
+ .globl dcache_status
+dcache_status:
+ mfspr r3, HID0
+ rlwinm r3, r3, HID0_DCE_BITPOS + 1, 31, 31
+ blr
+
+ .globl get_pvr
+get_pvr:
+ mfspr r3, PVR
+ blr
+
+/*------------------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+ .globl relocate_code
+relocate_code:
+ mr r1, r3 /* Set new stack pointer */
+ mr r9, r4 /* Save copy of Global Data pointer */
+ mr r10, r5 /* Save copy of Destination Address */
+
+ GET_GOT
+ mr r3, r5 /* Destination Address */
+ lis r4, CONFIG_SYS_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CONFIG_SYS_MONITOR_BASE@l
+ lwz r5, GOT(__init_end)
+ sub r5, r5, r4
+ li r6, CONFIG_SYS_CACHELINE_SIZE /* Cache Line Size */
+
+ /*
+ * Fix GOT pointer:
+ *
+ * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+ *
+ * Offset:
+ */
+ sub r15, r10, r4
+
+ /* First our own GOT */
+ add r12, r12, r15
+ /* then the one used by the C code */
+ add r30, r30, r15
+
+ /*
+ * Now relocate code
+ */
+
+ cmplw cr1,r3,r4
+ addi r0,r5,3
+ srwi. r0,r0,2
+ beq cr1,4f /* In place copy is not necessary */
+ beq 7f /* Protect against 0 count */
+ mtctr r0
+ bge cr1,2f
+
+ la r8,-4(r4)
+ la r7,-4(r3)
+1: lwzu r0,4(r8)
+ stwu r0,4(r7)
+ bdnz 1b
+ b 4f
+
+2: slwi r0,r0,2
+ add r8,r4,r0
+ add r7,r3,r0
+3: lwzu r0,-4(r8)
+ stwu r0,-4(r7)
+ bdnz 3b
+
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4: cmpwi r6,0
+ add r5,r3,r5
+ beq 7f /* Always flush prefetch queue in any case */
+ subi r0,r6,1
+ andc r3,r3,r0
+ mfspr r7,HID0 /* don't do dcbst if dcache is disabled */
+ rlwinm r7,r7,HID0_DCE_BITPOS+1,31,31
+ cmpwi r7,0
+ beq 9f
+ mr r4,r3
+5: dcbst 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 5b
+ sync /* Wait for all dcbst to complete on bus */
+9: mfspr r7,HID0 /* don't do icbi if icache is disabled */
+ rlwinm r7,r7,HID0_ICE_BITPOS+1,31,31
+ cmpwi r7,0
+ beq 7f
+ mr r4,r3
+6: icbi 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 6b
+7: sync /* Wait for all icbi to complete on bus */
+ isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+ addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+ mtlr r0
+ blr
+
+in_ram:
+
+ /*
+ * Relocation Function, r12 point to got2+0x8000
+ *
+ * Adjust got2 pointers, no need to check for 0, this code
+ * already puts a few entries in the table.
+ */
+ li r0,__got2_entries@sectoff@l
+ la r3,GOT(_GOT2_TABLE_)
+ lwz r11,GOT(_GOT2_TABLE_)
+ mtctr r0
+ sub r11,r3,r11
+ addi r3,r3,-4
+1: lwzu r0,4(r3)
+ cmpwi r0,0
+ beq- 2f
+ add r0,r0,r11
+ stw r0,0(r3)
+2: bdnz 1b
+
+ /*
+ * Now adjust the fixups and the pointers to the fixups
+ * in case we need to move ourselves again.
+ */
+ li r0,__fixup_entries@sectoff@l
+ lwz r3,GOT(_FIXUP_TABLE_)
+ cmpwi r0,0
+ mtctr r0
+ addi r3,r3,-4
+ beq 4f
+3: lwzu r4,4(r3)
+ lwzux r0,r4,r11
+ cmpwi r0,0
+ add r0,r0,r11
+ stw r4,0(r3)
+ beq- 5f
+ stw r0,0(r4)
+5: bdnz 3b
+4:
+clear_bss:
+ /*
+ * Now clear BSS segment
+ */
+ lwz r3,GOT(__bss_start)
+#if defined(CONFIG_HYMOD)
+ /*
+ * For HYMOD - the environment is the very last item in flash.
+ * The real .bss stops just before environment starts, so only
+ * clear up to that point.
+ *
+ * taken from mods for FADS board
+ */
+ lwz r4,GOT(environment)
+#else
+ lwz r4,GOT(__bss_end)
+#endif
+
+ cmplw 0, r3, r4
+ beq 6f
+
+ li r0, 0
+5:
+ stw r0, 0(r3)
+ addi r3, r3, 4
+ cmplw 0, r3, r4
+ bne 5b
+6:
+
+ mr r3, r9 /* Global Data pointer */
+ mr r4, r10 /* Destination Address */
+ bl board_init_r
+
+ /*
+ * Copy exception vector code to low memory
+ *
+ * r3: dest_addr
+ * r7: source address, r8: end address, r9: target address
+ */
+ .globl trap_init
+trap_init:
+ mflr r4 /* save link register */
+ GET_GOT
+ lwz r7, GOT(_start)
+ lwz r8, GOT(_end_of_vectors)
+
+ li r9, 0x100 /* reset vector always at 0x100 */
+
+ cmplw 0, r7, r8
+ bgelr /* return if r7>=r8 - just in case */
+1:
+ lwz r0, 0(r7)
+ stw r0, 0(r9)
+ addi r7, r7, 4
+ addi r9, r9, 4
+ cmplw 0, r7, r8
+ bne 1b
+
+ /*
+ * relocate `hdlr' and `int_return' entries
+ */
+ li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+ li r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 2b
+
+ li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+ li r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 3b
+
+ li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+ li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 4b
+
+ mfmsr r3 /* now that the vectors have */
+ lis r7, MSR_IP@h /* relocated into low memory */
+ ori r7, r7, MSR_IP@l /* MSR[IP] can be turned off */
+ andc r3, r3, r7 /* (if it was on) */
+ SYNC /* Some chip revs need this... */
+ mtmsr r3
+ SYNC
+
+ mtlr r4 /* restore link register */
+ blr
diff --git a/arch/powerpc/cpu/mpc8260/traps.c b/arch/powerpc/cpu/mpc8260/traps.c
new file mode 100644
index 0000000..e1e6845
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/traps.c
@@ -0,0 +1,264 @@
+/*
+ * linux/arch/powerpc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+#include <asm/m8260_pci.h>
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM 0x02000000
+
+/*
+ * Trap & Exception support
+ */
+
+static void print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ puts ("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ putc ('\n');
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *)*sp;
+ }
+ putc ('\n');
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ int i;
+
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+ regs->msr&MSR_IR ? 1 : 0,
+ regs->msr&MSR_DR ? 1 : 0);
+
+ putc ('\n');
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0) {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7) {
+ putc ('\n');
+ }
+ }
+}
+
+
+static void _exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+#ifdef CONFIG_PCI
+void dump_pci (void)
+{
+
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+ printf ("PCI: err status %x err mask %x err ctrl %x\n",
+ le32_to_cpu (immap->im_pci.pci_esr),
+ le32_to_cpu (immap->im_pci.pci_emr),
+ le32_to_cpu (immap->im_pci.pci_ecr));
+ printf (" error address %x error data %x ctrl %x\n",
+ le32_to_cpu (immap->im_pci.pci_eacr),
+ le32_to_cpu (immap->im_pci.pci_edcr),
+ le32_to_cpu (immap->im_pci.pci_eccr));
+
+}
+#endif
+
+void MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup;
+
+ /* Probing PCI using config cycles cause this exception
+ * when a device is not present. Catch it and return to
+ * the PCI exception handler.
+ */
+#ifdef CONFIG_PCI
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+#ifdef DEBUG
+ dump_pci();
+#endif
+ /* clear the error in the error status register */
+ if(immap->im_pci.pci_esr & cpu_to_le32(PCI_ERROR_PCI_NO_RSP)) {
+ immap->im_pci.pci_esr = cpu_to_le32(PCI_ERROR_PCI_NO_RSP);
+ return;
+ }
+#endif
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ return;
+ }
+
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ puts ("Machine check in kernel mode.\n"
+ "Caused by (from msr): ");
+ printf("regs %p ",regs);
+ switch( regs->msr & 0x000F0000) {
+ case (0x80000000>>12):
+ puts ("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (0x80000000>>13):
+ puts ("Transfer error ack signal\n");
+ break;
+ case (0x80000000>>14):
+ puts ("Data parity signal\n");
+ break;
+ case (0x80000000>>15):
+ puts ("Address parity signal\n");
+ break;
+ default:
+ puts ("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+#ifdef CONFIG_PCI
+ dump_pci();
+#endif
+ panic("machine check");
+}
+
+void AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void ProgramCheckException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void SoftEmuException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Software Emulation Exception");
+}
+
+
+void UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+void DebugException(struct pt_regs *regs)
+{
+
+ printf("Debugger trap at @ %lx\n", regs->nip );
+ show_regs(regs);
+#if defined(CONFIG_CMD_BEDBUG)
+ do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading. If not present, return -1, otherwise
+ * return 0.
+ */
+int addr_probe(uint *addr)
+{
+#if 0
+ int retval;
+
+ __asm__ __volatile__( \
+ "1: lwz %0,0(%1)\n" \
+ " eieio\n" \
+ " li %0,0\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,-1\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r" (retval) : "r"(addr));
+
+ return (retval);
+#endif
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc8260/u-boot.lds b/arch/powerpc/cpu/mpc8260/u-boot.lds
new file mode 100644
index 0000000..eb1c611
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8260/u-boot.lds
@@ -0,0 +1,91 @@
+/*
+ * (C) Copyright 2001-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ .text :
+ {
+ arch/powerpc/cpu/mpc8260/start.o (.text*)
+ *(.text*)
+ . = ALIGN(16);
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ }
+
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x0FFF) & 0xFFFFF000;
+ _erotext = .;
+ PROVIDE (erotext = .);
+ .reloc :
+ {
+ _GOT2_TABLE_ = .;
+ KEEP(*(.got2))
+ KEEP(*(.got))
+ PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
+ _FIXUP_TABLE_ = .;
+ KEEP(*(.fixup))
+ }
+ __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
+ __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+ .data :
+ {
+ *(.data*)
+ *(.sdata*)
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+
+ . = .;
+
+ . = ALIGN(4);
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+
+ . = .;
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ . = ALIGN(4096);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(4096);
+ __init_end = .;
+
+ __bss_start = .;
+ .bss (NOLOAD) :
+ {
+ *(.bss*)
+ *(.sbss*)
+ *(COMMON)
+ . = ALIGN(4);
+ }
+ __bss_end = . ;
+ PROVIDE (end = .);
+}
diff --git a/arch/powerpc/cpu/mpc83xx/Makefile b/arch/powerpc/cpu/mpc83xx/Makefile
new file mode 100644
index 0000000..8a470b8
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/Makefile
@@ -0,0 +1,96 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# Copyright 2004 Freescale Semiconductor, Inc.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(CPU).o
+
+MINIMAL=
+
+ifdef CONFIG_SPL_BUILD
+ifdef CONFIG_SPL_INIT_MINIMAL
+MINIMAL=y
+endif
+endif
+
+START = start.o
+
+ifdef MINIMAL
+
+COBJS-y += spl_minimal.o
+
+else
+
+COBJS-y += traps.o
+COBJS-y += cpu.o
+COBJS-y += cpu_init.o
+COBJS-y += speed.o
+COBJS-y += interrupts.o
+COBJS-y += ecc.o
+COBJS-$(CONFIG_QE) += qe_io.o
+COBJS-$(CONFIG_FSL_SERDES) += serdes.o
+COBJS-$(CONFIG_PCI) += pci.o
+COBJS-$(CONFIG_PCIE) += pcie.o
+COBJS-$(CONFIG_OF_LIBFDT) += fdt.o
+
+# Stub implementations of cache management functions for USB
+COBJS-y += cache.o
+
+ifdef CONFIG_FSL_DDR2
+COBJS_LN-$(CONFIG_MPC8349) += ddr-gen2.o
+else
+COBJS-y += spd_sdram.o
+endif
+COBJS-$(CONFIG_FSL_DDR2) += law.o
+
+endif # not minimal
+
+COBJS := $(COBJS-y)
+SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) $(addprefix $(obj),$(COBJS_LN-y:.o=.c))
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS) $(COBJS_LN-y))
+START := $(addprefix $(obj),$(START))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+$(obj)ddr-gen1.c:
+ ln -sf $(SRCTREE)/arch/powerpc/cpu/mpc85xx/ddr-gen1.c $(obj)ddr-gen1.c
+
+$(obj)ddr-gen2.c:
+ ln -sf $(SRCTREE)/arch/powerpc/cpu/mpc85xx/ddr-gen2.c $(obj)ddr-gen2.c
+
+$(obj)ddr-gen3.c:
+ ln -sf $(SRCTREE)/arch/powerpc/cpu/mpc85xx/ddr-gen3.c $(obj)ddr-gen3.c
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/powerpc/cpu/mpc83xx/cache.c b/arch/powerpc/cpu/mpc83xx/cache.c
new file mode 100644
index 0000000..2a08b65
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/cache.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 Marek Vasut <marex@denx.de>
+ *
+ * This file contains stub implementation of
+ * invalidate_dcache_range()
+ * flush_dcache_range()
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+}
diff --git a/arch/powerpc/cpu/mpc83xx/config.mk b/arch/powerpc/cpu/mpc83xx/config.mk
new file mode 100644
index 0000000..a79729e
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/config.mk
@@ -0,0 +1,26 @@
+#
+# Copyright 2004 Freescale Semiconductor, Inc.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_RELFLAGS += -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_MPC83xx -DCONFIG_E300 \
+ -ffixed-r2 -msoft-float
diff --git a/arch/powerpc/cpu/mpc83xx/cpu.c b/arch/powerpc/cpu/mpc83xx/cpu.c
new file mode 100644
index 0000000..cc20234
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/cpu.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * CPU specific code for the MPC83xx family.
+ *
+ * Derived from the MPC8260 and MPC85xx.
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc83xx.h>
+#include <asm/processor.h>
+#include <libfdt.h>
+#include <tsec.h>
+#include <netdev.h>
+#include <fsl_esdhc.h>
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+#include <asm/immap_qe.h>
+#include <asm/io.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int checkcpu(void)
+{
+ volatile immap_t *immr;
+ ulong clock = gd->cpu_clk;
+ u32 pvr = get_pvr();
+ u32 spridr;
+ char buf[32];
+ int i;
+
+ const struct cpu_type {
+ char name[15];
+ u32 partid;
+ } cpu_type_list [] = {
+ CPU_TYPE_ENTRY(8308),
+ CPU_TYPE_ENTRY(8309),
+ CPU_TYPE_ENTRY(8311),
+ CPU_TYPE_ENTRY(8313),
+ CPU_TYPE_ENTRY(8314),
+ CPU_TYPE_ENTRY(8315),
+ CPU_TYPE_ENTRY(8321),
+ CPU_TYPE_ENTRY(8323),
+ CPU_TYPE_ENTRY(8343),
+ CPU_TYPE_ENTRY(8347_TBGA_),
+ CPU_TYPE_ENTRY(8347_PBGA_),
+ CPU_TYPE_ENTRY(8349),
+ CPU_TYPE_ENTRY(8358_TBGA_),
+ CPU_TYPE_ENTRY(8358_PBGA_),
+ CPU_TYPE_ENTRY(8360),
+ CPU_TYPE_ENTRY(8377),
+ CPU_TYPE_ENTRY(8378),
+ CPU_TYPE_ENTRY(8379),
+ };
+
+ immr = (immap_t *)CONFIG_SYS_IMMR;
+
+ puts("CPU: ");
+
+ switch (pvr & 0xffff0000) {
+ case PVR_E300C1:
+ printf("e300c1, ");
+ break;
+
+ case PVR_E300C2:
+ printf("e300c2, ");
+ break;
+
+ case PVR_E300C3:
+ printf("e300c3, ");
+ break;
+
+ case PVR_E300C4:
+ printf("e300c4, ");
+ break;
+
+ default:
+ printf("Unknown core, ");
+ }
+
+ spridr = immr->sysconf.spridr;
+
+ for (i = 0; i < ARRAY_SIZE(cpu_type_list); i++)
+ if (cpu_type_list[i].partid == PARTID_NO_E(spridr)) {
+ puts("MPC");
+ puts(cpu_type_list[i].name);
+ if (IS_E_PROCESSOR(spridr))
+ puts("E");
+ if ((SPR_FAMILY(spridr) == SPR_834X_FAMILY ||
+ SPR_FAMILY(spridr) == SPR_836X_FAMILY) &&
+ REVID_MAJOR(spridr) >= 2)
+ puts("A");
+ printf(", Rev: %d.%d", REVID_MAJOR(spridr),
+ REVID_MINOR(spridr));
+ break;
+ }
+
+ if (i == ARRAY_SIZE(cpu_type_list))
+ printf("(SPRIDR %08x unknown), ", spridr);
+
+ printf(" at %s MHz, ", strmhz(buf, clock));
+
+ printf("CSB: %s MHz\n", strmhz(buf, gd->arch.csb_clk));
+
+ return 0;
+}
+
+int
+do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong msr;
+#ifndef MPC83xx_RESET
+ ulong addr;
+#endif
+
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+ puts("Resetting the board.\n");
+
+#ifdef MPC83xx_RESET
+
+ /* Interrupts and MMU off */
+ __asm__ __volatile__ ("mfmsr %0":"=r" (msr):);
+
+ msr &= ~( MSR_EE | MSR_IR | MSR_DR);
+ __asm__ __volatile__ ("mtmsr %0"::"r" (msr));
+
+ /* enable Reset Control Reg */
+ immap->reset.rpr = 0x52535445;
+ __asm__ __volatile__ ("sync");
+ __asm__ __volatile__ ("isync");
+
+ /* confirm Reset Control Reg is enabled */
+ while(!((immap->reset.rcer) & RCER_CRE));
+
+ udelay(200);
+
+ /* perform reset, only one bit */
+ immap->reset.rcr = RCR_SWHR;
+
+#else /* ! MPC83xx_RESET */
+
+ immap->reset.rmr = RMR_CSRE; /* Checkstop Reset enable */
+
+ /* Interrupts and MMU off */
+ __asm__ __volatile__ ("mfmsr %0":"=r" (msr):);
+
+ msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR);
+ __asm__ __volatile__ ("mtmsr %0"::"r" (msr));
+
+ /*
+ * Trying to execute the next instruction at a non-existing address
+ * should cause a machine check, resulting in reset
+ */
+ addr = CONFIG_SYS_RESET_ADDRESS;
+
+ ((void (*)(void)) addr) ();
+#endif /* MPC83xx_RESET */
+
+ return 1;
+}
+
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ */
+
+unsigned long get_tbclk(void)
+{
+ ulong tbclk;
+
+ tbclk = (gd->bus_clk + 3L) / 4L;
+
+ return tbclk;
+}
+
+
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset (void)
+{
+ int re_enable = disable_interrupts();
+
+ /* Reset the 83xx watchdog */
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ immr->wdt.swsrr = 0x556c;
+ immr->wdt.swsrr = 0xaa39;
+
+ if (re_enable)
+ enable_interrupts ();
+}
+#endif
+
+/*
+ * Initializes on-chip ethernet controllers.
+ * to override, implement board_eth_init()
+ */
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(CONFIG_UEC_ETH)
+ uec_standard_init(bis);
+#endif
+
+#if defined(CONFIG_TSEC_ENET)
+ tsec_standard_init(bis);
+#endif
+ return 0;
+}
+
+/*
+ * Initializes on-chip MMC controllers.
+ * to override, implement board_mmc_init()
+ */
+int cpu_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FSL_ESDHC
+ return fsl_esdhc_mmc_init(bis);
+#else
+ return 0;
+#endif
+}
diff --git a/arch/powerpc/cpu/mpc83xx/cpu_init.c b/arch/powerpc/cpu/mpc83xx/cpu_init.c
new file mode 100644
index 0000000..5153351
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/cpu_init.c
@@ -0,0 +1,524 @@
+/*
+ * Copyright (C) 2004-2009 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc83xx.h>
+#include <ioports.h>
+#include <asm/io.h>
+#ifdef CONFIG_USB_EHCI_FSL
+#include <usb/ehci-fsl.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_QE
+extern qe_iop_conf_t qe_iop_conf_tab[];
+extern void qe_config_iopin(u8 port, u8 pin, int dir,
+ int open_drain, int assign);
+extern void qe_init(uint qe_base);
+extern void qe_reset(void);
+
+static void config_qe_ioports(void)
+{
+ u8 port, pin;
+ int dir, open_drain, assign;
+ int i;
+
+ for (i = 0; qe_iop_conf_tab[i].assign != QE_IOP_TAB_END; i++) {
+ port = qe_iop_conf_tab[i].port;
+ pin = qe_iop_conf_tab[i].pin;
+ dir = qe_iop_conf_tab[i].dir;
+ open_drain = qe_iop_conf_tab[i].open_drain;
+ assign = qe_iop_conf_tab[i].assign;
+ qe_config_iopin(port, pin, dir, open_drain, assign);
+ }
+}
+#endif
+
+/*
+ * Breathe some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers,
+ * initialize the UPM's
+ */
+void cpu_init_f (volatile immap_t * im)
+{
+ __be32 acr_mask =
+#ifdef CONFIG_SYS_ACR_PIPE_DEP /* Arbiter pipeline depth */
+ ACR_PIPE_DEP |
+#endif
+#ifdef CONFIG_SYS_ACR_RPTCNT /* Arbiter repeat count */
+ ACR_RPTCNT |
+#endif
+#ifdef CONFIG_SYS_ACR_APARK /* Arbiter address parking mode */
+ ACR_APARK |
+#endif
+#ifdef CONFIG_SYS_ACR_PARKM /* Arbiter parking master */
+ ACR_PARKM |
+#endif
+ 0;
+ __be32 acr_val =
+#ifdef CONFIG_SYS_ACR_PIPE_DEP /* Arbiter pipeline depth */
+ (CONFIG_SYS_ACR_PIPE_DEP << ACR_PIPE_DEP_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_ACR_RPTCNT /* Arbiter repeat count */
+ (CONFIG_SYS_ACR_RPTCNT << ACR_RPTCNT_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_ACR_APARK /* Arbiter address parking mode */
+ (CONFIG_SYS_ACR_APARK << ACR_APARK_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_ACR_PARKM /* Arbiter parking master */
+ (CONFIG_SYS_ACR_PARKM << ACR_PARKM_SHIFT) |
+#endif
+ 0;
+ __be32 spcr_mask =
+#ifdef CONFIG_SYS_SPCR_OPT /* Optimize transactions between CSB and other dev */
+ SPCR_OPT |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSECEP /* all eTSEC's Emergency priority */
+ SPCR_TSECEP |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSEC1EP /* TSEC1 Emergency priority */
+ SPCR_TSEC1EP |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSEC2EP /* TSEC2 Emergency priority */
+ SPCR_TSEC2EP |
+#endif
+ 0;
+ __be32 spcr_val =
+#ifdef CONFIG_SYS_SPCR_OPT
+ (CONFIG_SYS_SPCR_OPT << SPCR_OPT_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSECEP /* all eTSEC's Emergency priority */
+ (CONFIG_SYS_SPCR_TSECEP << SPCR_TSECEP_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSEC1EP /* TSEC1 Emergency priority */
+ (CONFIG_SYS_SPCR_TSEC1EP << SPCR_TSEC1EP_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SPCR_TSEC2EP /* TSEC2 Emergency priority */
+ (CONFIG_SYS_SPCR_TSEC2EP << SPCR_TSEC2EP_SHIFT) |
+#endif
+ 0;
+ __be32 sccr_mask =
+#ifdef CONFIG_SYS_SCCR_ENCCM /* Encryption clock mode */
+ SCCR_ENCCM |
+#endif
+#ifdef CONFIG_SYS_SCCR_PCICM /* PCI & DMA clock mode */
+ SCCR_PCICM |
+#endif
+#ifdef CONFIG_SYS_SCCR_PCIEXP1CM /* PCIE1 clock mode */
+ SCCR_PCIEXP1CM |
+#endif
+#ifdef CONFIG_SYS_SCCR_PCIEXP2CM /* PCIE2 clock mode */
+ SCCR_PCIEXP2CM |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSECCM /* all TSEC's clock mode */
+ SCCR_TSECCM |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC1CM /* TSEC1 clock mode */
+ SCCR_TSEC1CM |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC2CM /* TSEC2 clock mode */
+ SCCR_TSEC2CM |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC1ON /* TSEC1 clock switch */
+ SCCR_TSEC1ON |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC2ON /* TSEC2 clock switch */
+ SCCR_TSEC2ON |
+#endif
+#ifdef CONFIG_SYS_SCCR_USBMPHCM /* USB MPH clock mode */
+ SCCR_USBMPHCM |
+#endif
+#ifdef CONFIG_SYS_SCCR_USBDRCM /* USB DR clock mode */
+ SCCR_USBDRCM |
+#endif
+#ifdef CONFIG_SYS_SCCR_SATACM /* SATA controller clock mode */
+ SCCR_SATACM |
+#endif
+ 0;
+ __be32 sccr_val =
+#ifdef CONFIG_SYS_SCCR_ENCCM /* Encryption clock mode */
+ (CONFIG_SYS_SCCR_ENCCM << SCCR_ENCCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_PCICM /* PCI & DMA clock mode */
+ (CONFIG_SYS_SCCR_PCICM << SCCR_PCICM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_PCIEXP1CM /* PCIE1 clock mode */
+ (CONFIG_SYS_SCCR_PCIEXP1CM << SCCR_PCIEXP1CM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_PCIEXP2CM /* PCIE2 clock mode */
+ (CONFIG_SYS_SCCR_PCIEXP2CM << SCCR_PCIEXP2CM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSECCM /* all TSEC's clock mode */
+ (CONFIG_SYS_SCCR_TSECCM << SCCR_TSECCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC1CM /* TSEC1 clock mode */
+ (CONFIG_SYS_SCCR_TSEC1CM << SCCR_TSEC1CM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC2CM /* TSEC2 clock mode */
+ (CONFIG_SYS_SCCR_TSEC2CM << SCCR_TSEC2CM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC1ON /* TSEC1 clock switch */
+ (CONFIG_SYS_SCCR_TSEC1ON << SCCR_TSEC1ON_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_TSEC2ON /* TSEC2 clock switch */
+ (CONFIG_SYS_SCCR_TSEC2ON << SCCR_TSEC2ON_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_USBMPHCM /* USB MPH clock mode */
+ (CONFIG_SYS_SCCR_USBMPHCM << SCCR_USBMPHCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_USBDRCM /* USB DR clock mode */
+ (CONFIG_SYS_SCCR_USBDRCM << SCCR_USBDRCM_SHIFT) |
+#endif
+#ifdef CONFIG_SYS_SCCR_SATACM /* SATA controller clock mode */
+ (CONFIG_SYS_SCCR_SATACM << SCCR_SATACM_SHIFT) |
+#endif
+ 0;
+ __be32 lcrr_mask =
+#ifdef CONFIG_SYS_LCRR_DBYP /* PLL bypass */
+ LCRR_DBYP |
+#endif
+#ifdef CONFIG_SYS_LCRR_EADC /* external address delay */
+ LCRR_EADC |
+#endif
+#ifdef CONFIG_SYS_LCRR_CLKDIV /* system clock divider */
+ LCRR_CLKDIV |
+#endif
+ 0;
+ __be32 lcrr_val =
+#ifdef CONFIG_SYS_LCRR_DBYP /* PLL bypass */
+ CONFIG_SYS_LCRR_DBYP |
+#endif
+#ifdef CONFIG_SYS_LCRR_EADC
+ CONFIG_SYS_LCRR_EADC |
+#endif
+#ifdef CONFIG_SYS_LCRR_CLKDIV /* system clock divider */
+ CONFIG_SYS_LCRR_CLKDIV |
+#endif
+ 0;
+
+ /* Pointer is writable since we allocated a register for it */
+ gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+ /* Clear initial global data */
+ memset ((void *) gd, 0, sizeof (gd_t));
+
+ /* system performance tweaking */
+ clrsetbits_be32(&im->arbiter.acr, acr_mask, acr_val);
+
+ clrsetbits_be32(&im->sysconf.spcr, spcr_mask, spcr_val);
+
+ clrsetbits_be32(&im->clk.sccr, sccr_mask, sccr_val);
+
+ /* RSR - Reset Status Register - clear all status (4.6.1.3) */
+ gd->arch.reset_status = __raw_readl(&im->reset.rsr);
+ __raw_writel(~(RSR_RES), &im->reset.rsr);
+
+ /* AER - Arbiter Event Register - store status */
+ gd->arch.arbiter_event_attributes = __raw_readl(&im->arbiter.aeatr);
+ gd->arch.arbiter_event_address = __raw_readl(&im->arbiter.aeadr);
+
+ /*
+ * RMR - Reset Mode Register
+ * contains checkstop reset enable (4.6.1.4)
+ */
+ __raw_writel(RMR_CSRE & (1<<RMR_CSRE_SHIFT), &im->reset.rmr);
+
+ /* LCRR - Clock Ratio Register (10.3.1.16)
+ * write, read, and isync per MPC8379ERM rev.1 CLKDEV field description
+ */
+ clrsetbits_be32(&im->im_lbc.lcrr, lcrr_mask, lcrr_val);
+ __raw_readl(&im->im_lbc.lcrr);
+ isync();
+
+ /* Enable Time Base & Decrementer ( so we will have udelay() )*/
+ setbits_be32(&im->sysconf.spcr, SPCR_TBEN);
+
+ /* System General Purpose Register */
+#ifdef CONFIG_SYS_SICRH
+#if defined(CONFIG_MPC834x) || defined(CONFIG_MPC8313)
+ /* regarding to MPC34x manual rev.1 bits 28..29 must be preserved */
+ __raw_writel((im->sysconf.sicrh & 0x0000000C) | CONFIG_SYS_SICRH,
+ &im->sysconf.sicrh);
+#else
+ __raw_writel(CONFIG_SYS_SICRH, &im->sysconf.sicrh);
+#endif
+#endif
+#ifdef CONFIG_SYS_SICRL
+ __raw_writel(CONFIG_SYS_SICRL, &im->sysconf.sicrl);
+#endif
+#ifdef CONFIG_SYS_GPR1
+ __raw_writel(CONFIG_SYS_GPR1, &im->sysconf.gpr1);
+#endif
+#ifdef CONFIG_SYS_DDRCDR /* DDR control driver register */
+ __raw_writel(CONFIG_SYS_DDRCDR, &im->sysconf.ddrcdr);
+#endif
+#ifdef CONFIG_SYS_OBIR /* Output buffer impedance register */
+ __raw_writel(CONFIG_SYS_OBIR, &im->sysconf.obir);
+#endif
+
+#ifdef CONFIG_QE
+ /* Config QE ioports */
+ config_qe_ioports();
+#endif
+ /* Set up preliminary BR/OR regs */
+ init_early_memctl_regs();
+
+ /* Local Access window setup */
+#if defined(CONFIG_SYS_LBLAWBAR0_PRELIM) && defined(CONFIG_SYS_LBLAWAR0_PRELIM)
+ im->sysconf.lblaw[0].bar = CONFIG_SYS_LBLAWBAR0_PRELIM;
+ im->sysconf.lblaw[0].ar = CONFIG_SYS_LBLAWAR0_PRELIM;
+#else
+#error CONFIG_SYS_LBLAWBAR0_PRELIM & CONFIG_SYS_LBLAWAR0_PRELIM must be defined
+#endif
+
+#if defined(CONFIG_SYS_LBLAWBAR1_PRELIM) && defined(CONFIG_SYS_LBLAWAR1_PRELIM)
+ im->sysconf.lblaw[1].bar = CONFIG_SYS_LBLAWBAR1_PRELIM;
+ im->sysconf.lblaw[1].ar = CONFIG_SYS_LBLAWAR1_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR2_PRELIM) && defined(CONFIG_SYS_LBLAWAR2_PRELIM)
+ im->sysconf.lblaw[2].bar = CONFIG_SYS_LBLAWBAR2_PRELIM;
+ im->sysconf.lblaw[2].ar = CONFIG_SYS_LBLAWAR2_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR3_PRELIM) && defined(CONFIG_SYS_LBLAWAR3_PRELIM)
+ im->sysconf.lblaw[3].bar = CONFIG_SYS_LBLAWBAR3_PRELIM;
+ im->sysconf.lblaw[3].ar = CONFIG_SYS_LBLAWAR3_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR4_PRELIM) && defined(CONFIG_SYS_LBLAWAR4_PRELIM)
+ im->sysconf.lblaw[4].bar = CONFIG_SYS_LBLAWBAR4_PRELIM;
+ im->sysconf.lblaw[4].ar = CONFIG_SYS_LBLAWAR4_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR5_PRELIM) && defined(CONFIG_SYS_LBLAWAR5_PRELIM)
+ im->sysconf.lblaw[5].bar = CONFIG_SYS_LBLAWBAR5_PRELIM;
+ im->sysconf.lblaw[5].ar = CONFIG_SYS_LBLAWAR5_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR6_PRELIM) && defined(CONFIG_SYS_LBLAWAR6_PRELIM)
+ im->sysconf.lblaw[6].bar = CONFIG_SYS_LBLAWBAR6_PRELIM;
+ im->sysconf.lblaw[6].ar = CONFIG_SYS_LBLAWAR6_PRELIM;
+#endif
+#if defined(CONFIG_SYS_LBLAWBAR7_PRELIM) && defined(CONFIG_SYS_LBLAWAR7_PRELIM)
+ im->sysconf.lblaw[7].bar = CONFIG_SYS_LBLAWBAR7_PRELIM;
+ im->sysconf.lblaw[7].ar = CONFIG_SYS_LBLAWAR7_PRELIM;
+#endif
+#ifdef CONFIG_SYS_GPIO1_PRELIM
+ im->gpio[0].dat = CONFIG_SYS_GPIO1_DAT;
+ im->gpio[0].dir = CONFIG_SYS_GPIO1_DIR;
+#endif
+#ifdef CONFIG_SYS_GPIO2_PRELIM
+ im->gpio[1].dat = CONFIG_SYS_GPIO2_DAT;
+ im->gpio[1].dir = CONFIG_SYS_GPIO2_DIR;
+#endif
+#if defined(CONFIG_USB_EHCI_FSL) && defined(CONFIG_MPC831x)
+ uint32_t temp;
+ struct usb_ehci *ehci = (struct usb_ehci *)CONFIG_SYS_FSL_USB_ADDR;
+
+ /* Configure interface. */
+ setbits_be32(&ehci->control, REFSEL_16MHZ | UTMI_PHY_EN);
+
+ /* Wait for clock to stabilize */
+ do {
+ temp = __raw_readl(&ehci->control);
+ udelay(1000);
+ } while (!(temp & PHY_CLK_VALID));
+#endif
+}
+
+int cpu_init_r (void)
+{
+#ifdef CONFIG_QE
+ uint qe_base = CONFIG_SYS_IMMR + 0x00100000; /* QE immr base */
+
+ qe_init(qe_base);
+ qe_reset();
+#endif
+ return 0;
+}
+
+/*
+ * Print out the bus arbiter event
+ */
+#if defined(CONFIG_DISPLAY_AER_FULL)
+static int print_83xx_arb_event(int force)
+{
+ static char* event[] = {
+ "Address Time Out",
+ "Data Time Out",
+ "Address Only Transfer Type",
+ "External Control Word Transfer Type",
+ "Reserved Transfer Type",
+ "Transfer Error",
+ "reserved",
+ "reserved"
+ };
+ static char* master[] = {
+ "e300 Core Data Transaction",
+ "reserved",
+ "e300 Core Instruction Fetch",
+ "reserved",
+ "TSEC1",
+ "TSEC2",
+ "USB MPH",
+ "USB DR",
+ "Encryption Core",
+ "I2C Boot Sequencer",
+ "JTAG",
+ "reserved",
+ "eSDHC",
+ "PCI1",
+ "PCI2",
+ "DMA",
+ "QUICC Engine 00",
+ "QUICC Engine 01",
+ "QUICC Engine 10",
+ "QUICC Engine 11",
+ "reserved",
+ "reserved",
+ "reserved",
+ "reserved",
+ "SATA1",
+ "SATA2",
+ "SATA3",
+ "SATA4",
+ "reserved",
+ "PCI Express 1",
+ "PCI Express 2",
+ "TDM-DMAC"
+ };
+ static char *transfer[] = {
+ "Address-only, Clean Block",
+ "Address-only, lwarx reservation set",
+ "Single-beat or Burst write",
+ "reserved",
+ "Address-only, Flush Block",
+ "reserved",
+ "Burst write",
+ "reserved",
+ "Address-only, sync",
+ "Address-only, tlbsync",
+ "Single-beat or Burst read",
+ "Single-beat or Burst read",
+ "Address-only, Kill Block",
+ "Address-only, icbi",
+ "Burst read",
+ "reserved",
+ "Address-only, eieio",
+ "reserved",
+ "Single-beat write",
+ "reserved",
+ "ecowx - Illegal single-beat write",
+ "reserved",
+ "reserved",
+ "reserved",
+ "Address-only, TLB Invalidate",
+ "reserved",
+ "Single-beat or Burst read",
+ "reserved",
+ "eciwx - Illegal single-beat read",
+ "reserved",
+ "Burst read",
+ "reserved"
+ };
+
+ int etype = (gd->arch.arbiter_event_attributes & AEATR_EVENT)
+ >> AEATR_EVENT_SHIFT;
+ int mstr_id = (gd->arch.arbiter_event_attributes & AEATR_MSTR_ID)
+ >> AEATR_MSTR_ID_SHIFT;
+ int tbst = (gd->arch.arbiter_event_attributes & AEATR_TBST)
+ >> AEATR_TBST_SHIFT;
+ int tsize = (gd->arch.arbiter_event_attributes & AEATR_TSIZE)
+ >> AEATR_TSIZE_SHIFT;
+ int ttype = (gd->arch.arbiter_event_attributes & AEATR_TTYPE)
+ >> AEATR_TTYPE_SHIFT;
+
+ if (!force && !gd->arch.arbiter_event_address)
+ return 0;
+
+ puts("Arbiter Event Status:\n");
+ printf(" Event Address: 0x%08lX\n",
+ gd->arch.arbiter_event_address);
+ printf(" Event Type: 0x%1x = %s\n", etype, event[etype]);
+ printf(" Master ID: 0x%02x = %s\n", mstr_id, master[mstr_id]);
+ printf(" Transfer Size: 0x%1x = %d bytes\n", (tbst<<3) | tsize,
+ tbst ? (tsize ? tsize : 8) : 16 + 8 * tsize);
+ printf(" Transfer Type: 0x%02x = %s\n", ttype, transfer[ttype]);
+
+ return gd->arch.arbiter_event_address;
+}
+
+#elif defined(CONFIG_DISPLAY_AER_BRIEF)
+
+static int print_83xx_arb_event(int force)
+{
+ if (!force && !gd->arch.arbiter_event_address)
+ return 0;
+
+ printf("Arbiter Event Status: AEATR=0x%08lX, AEADR=0x%08lX\n",
+ gd->arch.arbiter_event_attributes,
+ gd->arch.arbiter_event_address);
+
+ return gd->arch.arbiter_event_address;
+}
+#endif /* CONFIG_DISPLAY_AER_xxxx */
+
+/*
+ * Figure out the cause of the reset
+ */
+int prt_83xx_rsr(void)
+{
+ static struct {
+ ulong mask;
+ char *desc;
+ } bits[] = {
+ {
+ RSR_SWSR, "Software Soft"}, {
+ RSR_SWHR, "Software Hard"}, {
+ RSR_JSRS, "JTAG Soft"}, {
+ RSR_CSHR, "Check Stop"}, {
+ RSR_SWRS, "Software Watchdog"}, {
+ RSR_BMRS, "Bus Monitor"}, {
+ RSR_SRS, "External/Internal Soft"}, {
+ RSR_HRS, "External/Internal Hard"}
+ };
+ static int n = sizeof bits / sizeof bits[0];
+ ulong rsr = gd->arch.reset_status;
+ int i;
+ char *sep;
+
+ puts("Reset Status:");
+
+ sep = " ";
+ for (i = 0; i < n; i++)
+ if (rsr & bits[i].mask) {
+ printf("%s%s", sep, bits[i].desc);
+ sep = ", ";
+ }
+ puts("\n");
+
+#if defined(CONFIG_DISPLAY_AER_FULL) || defined(CONFIG_DISPLAY_AER_BRIEF)
+ print_83xx_arb_event(rsr & RSR_BMRS);
+#endif
+ puts("\n");
+
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc83xx/ecc.c b/arch/powerpc/cpu/mpc83xx/ecc.c
new file mode 100644
index 0000000..717365c
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/ecc.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2007-2011 Freescale Semiconductor, Inc.
+ *
+ * Dave Liu <daveliu@freescale.com>
+ * based on the contribution of Marian Balakowicz <m8@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <common.h>
+#include <mpc83xx.h>
+#include <command.h>
+
+#if defined(CONFIG_DDR_ECC) && defined(CONFIG_DDR_ECC_CMD)
+void ecc_print_status(void)
+{
+ immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+#ifdef CONFIG_FSL_DDR2
+ ccsr_ddr_t *ddr = &immap->ddr;
+#else
+ ddr83xx_t *ddr = &immap->ddr;
+#endif
+
+ printf("\nECC mode: %s\n\n",
+ (ddr->sdram_cfg & SDRAM_CFG_ECC_EN) ? "ON" : "OFF");
+
+ /* Interrupts */
+ printf("Memory Error Interrupt Enable:\n");
+ printf(" Multiple-Bit Error Interrupt Enable: %d\n",
+ (ddr->err_int_en & ECC_ERR_INT_EN_MBEE) ? 1 : 0);
+ printf(" Single-Bit Error Interrupt Enable: %d\n",
+ (ddr->err_int_en & ECC_ERR_INT_EN_SBEE) ? 1 : 0);
+ printf(" Memory Select Error Interrupt Enable: %d\n\n",
+ (ddr->err_int_en & ECC_ERR_INT_EN_MSEE) ? 1 : 0);
+
+ /* Error disable */
+ printf("Memory Error Disable:\n");
+ printf(" Multiple-Bit Error Disable: %d\n",
+ (ddr->err_disable & ECC_ERROR_DISABLE_MBED) ? 1 : 0);
+ printf(" Sinle-Bit Error Disable: %d\n",
+ (ddr->err_disable & ECC_ERROR_DISABLE_SBED) ? 1 : 0);
+ printf(" Memory Select Error Disable: %d\n\n",
+ (ddr->err_disable & ECC_ERROR_DISABLE_MSED) ? 1 : 0);
+
+ /* Error injection */
+ printf("Memory Data Path Error Injection Mask High/Low: %08x %08x\n",
+ ddr->data_err_inject_hi, ddr->data_err_inject_lo);
+
+ printf("Memory Data Path Error Injection Mask ECC:\n");
+ printf(" ECC Mirror Byte: %d\n",
+ (ddr->ecc_err_inject & ECC_ERR_INJECT_EMB) ? 1 : 0);
+ printf(" ECC Injection Enable: %d\n",
+ (ddr->ecc_err_inject & ECC_ERR_INJECT_EIEN) ? 1 : 0);
+ printf(" ECC Error Injection Mask: 0x%02x\n\n",
+ ddr->ecc_err_inject & ECC_ERR_INJECT_EEIM);
+
+ /* SBE counter/threshold */
+ printf("Memory Single-Bit Error Management (0..255):\n");
+ printf(" Single-Bit Error Threshold: %d\n",
+ (ddr->err_sbe & ECC_ERROR_MAN_SBET) >> ECC_ERROR_MAN_SBET_SHIFT);
+ printf(" Single-Bit Error Counter: %d\n\n",
+ (ddr->err_sbe & ECC_ERROR_MAN_SBEC) >> ECC_ERROR_MAN_SBEC_SHIFT);
+
+ /* Error detect */
+ printf("Memory Error Detect:\n");
+ printf(" Multiple Memory Errors: %d\n",
+ (ddr->err_detect & ECC_ERROR_DETECT_MME) ? 1 : 0);
+ printf(" Multiple-Bit Error: %d\n",
+ (ddr->err_detect & ECC_ERROR_DETECT_MBE) ? 1 : 0);
+ printf(" Single-Bit Error: %d\n",
+ (ddr->err_detect & ECC_ERROR_DETECT_SBE) ? 1 : 0);
+ printf(" Memory Select Error: %d\n\n",
+ (ddr->err_detect & ECC_ERROR_DETECT_MSE) ? 1 : 0);
+
+ /* Capture data */
+ printf("Memory Error Address Capture: 0x%08x\n", ddr->capture_address);
+ printf("Memory Data Path Read Capture High/Low: %08x %08x\n",
+ ddr->capture_data_hi, ddr->capture_data_lo);
+ printf("Memory Data Path Read Capture ECC: 0x%02x\n\n",
+ ddr->capture_ecc & CAPTURE_ECC_ECE);
+
+ printf("Memory Error Attributes Capture:\n");
+ printf(" Data Beat Number: %d\n",
+ (ddr->capture_attributes & ECC_CAPT_ATTR_BNUM) >>
+ ECC_CAPT_ATTR_BNUM_SHIFT);
+ printf(" Transaction Size: %d\n",
+ (ddr->capture_attributes & ECC_CAPT_ATTR_TSIZ) >>
+ ECC_CAPT_ATTR_TSIZ_SHIFT);
+ printf(" Transaction Source: %d\n",
+ (ddr->capture_attributes & ECC_CAPT_ATTR_TSRC) >>
+ ECC_CAPT_ATTR_TSRC_SHIFT);
+ printf(" Transaction Type: %d\n",
+ (ddr->capture_attributes & ECC_CAPT_ATTR_TTYP) >>
+ ECC_CAPT_ATTR_TTYP_SHIFT);
+ printf(" Error Information Valid: %d\n\n",
+ ddr->capture_attributes & ECC_CAPT_ATTR_VLD);
+}
+
+int do_ecc(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+#ifdef CONFIG_FSL_DDR2
+ ccsr_ddr_t *ddr = &immap->ddr;
+#else
+ ddr83xx_t *ddr = &immap->ddr;
+#endif
+ volatile u32 val;
+ u64 *addr;
+ u32 count;
+ register u64 *i;
+ u32 ret[2];
+ u32 pattern[2];
+ u32 writeback[2];
+
+ /* The pattern is written into memory to generate error */
+ pattern[0] = 0xfedcba98UL;
+ pattern[1] = 0x76543210UL;
+
+ /* After injecting error, re-initialize the memory with the value */
+ writeback[0] = 0x01234567UL;
+ writeback[1] = 0x89abcdefUL;
+
+ if (argc > 4)
+ return cmd_usage(cmdtp);
+
+ if (argc == 2) {
+ if (strcmp(argv[1], "status") == 0) {
+ ecc_print_status();
+ return 0;
+ } else if (strcmp(argv[1], "captureclear") == 0) {
+ ddr->capture_address = 0;
+ ddr->capture_data_hi = 0;
+ ddr->capture_data_lo = 0;
+ ddr->capture_ecc = 0;
+ ddr->capture_attributes = 0;
+ return 0;
+ }
+ }
+ if (argc == 3) {
+ if (strcmp(argv[1], "sbecnt") == 0) {
+ val = simple_strtoul(argv[2], NULL, 10);
+ if (val > 255) {
+ printf("Incorrect Counter value, "
+ "should be 0..255\n");
+ return 1;
+ }
+
+ val = (val << ECC_ERROR_MAN_SBEC_SHIFT);
+ val |= (ddr->err_sbe & ECC_ERROR_MAN_SBET);
+
+ ddr->err_sbe = val;
+ return 0;
+ } else if (strcmp(argv[1], "sbethr") == 0) {
+ val = simple_strtoul(argv[2], NULL, 10);
+ if (val > 255) {
+ printf("Incorrect Counter value, "
+ "should be 0..255\n");
+ return 1;
+ }
+
+ val = (val << ECC_ERROR_MAN_SBET_SHIFT);
+ val |= (ddr->err_sbe & ECC_ERROR_MAN_SBEC);
+
+ ddr->err_sbe = val;
+ return 0;
+ } else if (strcmp(argv[1], "errdisable") == 0) {
+ val = ddr->err_disable;
+
+ if (strcmp(argv[2], "+sbe") == 0) {
+ val |= ECC_ERROR_DISABLE_SBED;
+ } else if (strcmp(argv[2], "+mbe") == 0) {
+ val |= ECC_ERROR_DISABLE_MBED;
+ } else if (strcmp(argv[2], "+mse") == 0) {
+ val |= ECC_ERROR_DISABLE_MSED;
+ } else if (strcmp(argv[2], "+all") == 0) {
+ val |= (ECC_ERROR_DISABLE_SBED |
+ ECC_ERROR_DISABLE_MBED |
+ ECC_ERROR_DISABLE_MSED);
+ } else if (strcmp(argv[2], "-sbe") == 0) {
+ val &= ~ECC_ERROR_DISABLE_SBED;
+ } else if (strcmp(argv[2], "-mbe") == 0) {
+ val &= ~ECC_ERROR_DISABLE_MBED;
+ } else if (strcmp(argv[2], "-mse") == 0) {
+ val &= ~ECC_ERROR_DISABLE_MSED;
+ } else if (strcmp(argv[2], "-all") == 0) {
+ val &= ~(ECC_ERROR_DISABLE_SBED |
+ ECC_ERROR_DISABLE_MBED |
+ ECC_ERROR_DISABLE_MSED);
+ } else {
+ printf("Incorrect err_disable field\n");
+ return 1;
+ }
+
+ ddr->err_disable = val;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+ return 0;
+ } else if (strcmp(argv[1], "errdetectclr") == 0) {
+ val = ddr->err_detect;
+
+ if (strcmp(argv[2], "mme") == 0) {
+ val |= ECC_ERROR_DETECT_MME;
+ } else if (strcmp(argv[2], "sbe") == 0) {
+ val |= ECC_ERROR_DETECT_SBE;
+ } else if (strcmp(argv[2], "mbe") == 0) {
+ val |= ECC_ERROR_DETECT_MBE;
+ } else if (strcmp(argv[2], "mse") == 0) {
+ val |= ECC_ERROR_DETECT_MSE;
+ } else if (strcmp(argv[2], "all") == 0) {
+ val |= (ECC_ERROR_DETECT_MME |
+ ECC_ERROR_DETECT_MBE |
+ ECC_ERROR_DETECT_SBE |
+ ECC_ERROR_DETECT_MSE);
+ } else {
+ printf("Incorrect err_detect field\n");
+ return 1;
+ }
+
+ ddr->err_detect = val;
+ return 0;
+ } else if (strcmp(argv[1], "injectdatahi") == 0) {
+ val = simple_strtoul(argv[2], NULL, 16);
+
+ ddr->data_err_inject_hi = val;
+ return 0;
+ } else if (strcmp(argv[1], "injectdatalo") == 0) {
+ val = simple_strtoul(argv[2], NULL, 16);
+
+ ddr->data_err_inject_lo = val;
+ return 0;
+ } else if (strcmp(argv[1], "injectecc") == 0) {
+ val = simple_strtoul(argv[2], NULL, 16);
+ if (val > 0xff) {
+ printf("Incorrect ECC inject mask, "
+ "should be 0x00..0xff\n");
+ return 1;
+ }
+ val |= (ddr->ecc_err_inject & ~ECC_ERR_INJECT_EEIM);
+
+ ddr->ecc_err_inject = val;
+ return 0;
+ } else if (strcmp(argv[1], "inject") == 0) {
+ val = ddr->ecc_err_inject;
+
+ if (strcmp(argv[2], "en") == 0)
+ val |= ECC_ERR_INJECT_EIEN;
+ else if (strcmp(argv[2], "dis") == 0)
+ val &= ~ECC_ERR_INJECT_EIEN;
+ else
+ printf("Incorrect command\n");
+
+ ddr->ecc_err_inject = val;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+ return 0;
+ } else if (strcmp(argv[1], "mirror") == 0) {
+ val = ddr->ecc_err_inject;
+
+ if (strcmp(argv[2], "en") == 0)
+ val |= ECC_ERR_INJECT_EMB;
+ else if (strcmp(argv[2], "dis") == 0)
+ val &= ~ECC_ERR_INJECT_EMB;
+ else
+ printf("Incorrect command\n");
+
+ ddr->ecc_err_inject = val;
+ return 0;
+ }
+ }
+ if (argc == 4) {
+ if (strcmp(argv[1], "testdw") == 0) {
+ addr = (u64 *) simple_strtoul(argv[2], NULL, 16);
+ count = simple_strtoul(argv[3], NULL, 16);
+
+ if ((u32) addr % 8) {
+ printf("Address not alligned on "
+ "double word boundary\n");
+ return 1;
+ }
+ disable_interrupts();
+
+ for (i = addr; i < addr + count; i++) {
+
+ /* enable injects */
+ ddr->ecc_err_inject |= ECC_ERR_INJECT_EIEN;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+
+ /* write memory location injecting errors */
+ ppcDWstore((u32 *) i, pattern);
+ __asm__ __volatile__("sync");
+
+ /* disable injects */
+ ddr->ecc_err_inject &= ~ECC_ERR_INJECT_EIEN;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+
+ /* read data, this generates ECC error */
+ ppcDWload((u32 *) i, ret);
+ __asm__ __volatile__("sync");
+
+ /* re-initialize memory, double word write the location again,
+ * generates new ECC code this time */
+ ppcDWstore((u32 *) i, writeback);
+ __asm__ __volatile__("sync");
+ }
+ enable_interrupts();
+ return 0;
+ }
+ if (strcmp(argv[1], "testword") == 0) {
+ addr = (u64 *) simple_strtoul(argv[2], NULL, 16);
+ count = simple_strtoul(argv[3], NULL, 16);
+
+ if ((u32) addr % 8) {
+ printf("Address not alligned on "
+ "double word boundary\n");
+ return 1;
+ }
+ disable_interrupts();
+
+ for (i = addr; i < addr + count; i++) {
+
+ /* enable injects */
+ ddr->ecc_err_inject |= ECC_ERR_INJECT_EIEN;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+
+ /* write memory location injecting errors */
+ *(u32 *) i = 0xfedcba98UL;
+ __asm__ __volatile__("sync");
+
+ /* sub double word write,
+ * bus will read-modify-write,
+ * generates ECC error */
+ *((u32 *) i + 1) = 0x76543210UL;
+ __asm__ __volatile__("sync");
+
+ /* disable injects */
+ ddr->ecc_err_inject &= ~ECC_ERR_INJECT_EIEN;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+
+ /* re-initialize memory,
+ * double word write the location again,
+ * generates new ECC code this time */
+ ppcDWstore((u32 *) i, writeback);
+ __asm__ __volatile__("sync");
+ }
+ enable_interrupts();
+ return 0;
+ }
+ }
+ return cmd_usage(cmdtp);
+}
+
+U_BOOT_CMD(ecc, 4, 0, do_ecc,
+ "support for DDR ECC features",
+ "status - print out status info\n"
+ "ecc captureclear - clear capture regs data\n"
+ "ecc sbecnt <val> - set Single-Bit Error counter\n"
+ "ecc sbethr <val> - set Single-Bit Threshold\n"
+ "ecc errdisable <flag> - clear/set disable Memory Error Disable, flag:\n"
+ " [-|+]sbe - Single-Bit Error\n"
+ " [-|+]mbe - Multiple-Bit Error\n"
+ " [-|+]mse - Memory Select Error\n"
+ " [-|+]all - all errors\n"
+ "ecc errdetectclr <flag> - clear Memory Error Detect, flag:\n"
+ " mme - Multiple Memory Errors\n"
+ " sbe - Single-Bit Error\n"
+ " mbe - Multiple-Bit Error\n"
+ " mse - Memory Select Error\n"
+ " all - all errors\n"
+ "ecc injectdatahi <hi> - set Memory Data Path Error Injection Mask High\n"
+ "ecc injectdatalo <lo> - set Memory Data Path Error Injection Mask Low\n"
+ "ecc injectecc <ecc> - set ECC Error Injection Mask\n"
+ "ecc inject <en|dis> - enable/disable error injection\n"
+ "ecc mirror <en|dis> - enable/disable mirror byte\n"
+ "ecc testdw <addr> <cnt> - test mem region with double word access:\n"
+ " - enables injects\n"
+ " - writes pattern injecting errors with double word access\n"
+ " - disables injects\n"
+ " - reads pattern back with double word access, generates error\n"
+ " - re-inits memory\n"
+ "ecc testword <addr> <cnt> - test mem region with word access:\n"
+ " - enables injects\n"
+ " - writes pattern injecting errors with word access\n"
+ " - writes pattern with word access, generates error\n"
+ " - disables injects\n" " - re-inits memory");
+#endif
diff --git a/arch/powerpc/cpu/mpc83xx/fdt.c b/arch/powerpc/cpu/mpc83xx/fdt.c
new file mode 100644
index 0000000..fe553a7
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/fdt.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2007 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+#include <asm/processor.h>
+
+extern void ft_qe_setup(void *blob);
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_BOOTCOUNT_LIMIT) && \
+ (defined(CONFIG_QE))
+#include <asm/immap_qe.h>
+
+void fdt_fixup_muram (void *blob)
+{
+ ulong data[2];
+
+ data[0] = 0;
+ data[1] = QE_MURAM_SIZE - 2 * sizeof(unsigned long);
+ do_fixup_by_compat(blob, "fsl,qe-muram-data", "reg",
+ data, sizeof (data), 0);
+}
+#endif
+
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+ immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ int spridr = immr->sysconf.spridr;
+
+ /*
+ * delete crypto node if not on an E-processor
+ * initial revisions of the MPC834xE/6xE have the original SEC 2.0.
+ * EA revisions got the SEC uprevved to 2.4 but since the default device
+ * tree contains SEC 2.0 properties we uprev them here.
+ */
+ if (!IS_E_PROCESSOR(spridr))
+ fdt_fixup_crypto_node(blob, 0);
+ else if (IS_E_PROCESSOR(spridr) &&
+ (SPR_FAMILY(spridr) == SPR_834X_FAMILY ||
+ SPR_FAMILY(spridr) == SPR_836X_FAMILY) &&
+ REVID_MAJOR(spridr) >= 2)
+ fdt_fixup_crypto_node(blob, 0x0204);
+
+#if defined(CONFIG_HAS_ETH0) || defined(CONFIG_HAS_ETH1) ||\
+ defined(CONFIG_HAS_ETH2) || defined(CONFIG_HAS_ETH3) ||\
+ defined(CONFIG_HAS_ETH4) || defined(CONFIG_HAS_ETH5)
+ fdt_fixup_ethernet(blob);
+#ifdef CONFIG_MPC8313
+ /*
+ * mpc8313e erratum IPIC1 swapped TSEC interrupt ID numbers on rev. 1
+ * h/w (see AN3545). The base device tree in use has rev. 1 ID numbers,
+ * so if on Rev. 2 (and higher) h/w, we fix them up here
+ */
+ if (REVID_MAJOR(immr->sysconf.spridr) >= 2) {
+ int nodeoffset, path;
+ const char *prop;
+
+ nodeoffset = fdt_path_offset(blob, "/aliases");
+ if (nodeoffset >= 0) {
+#if defined(CONFIG_HAS_ETH0)
+ prop = fdt_getprop(blob, nodeoffset, "ethernet0", NULL);
+ if (prop) {
+ u32 tmp[] = { 32, 0x8, 33, 0x8, 34, 0x8 };
+
+ path = fdt_path_offset(blob, prop);
+ prop = fdt_getprop(blob, path, "interrupts",
+ NULL);
+ if (prop)
+ fdt_setprop(blob, path, "interrupts",
+ &tmp, sizeof(tmp));
+ }
+#endif
+#if defined(CONFIG_HAS_ETH1)
+ prop = fdt_getprop(blob, nodeoffset, "ethernet1", NULL);
+ if (prop) {
+ u32 tmp[] = { 35, 0x8, 36, 0x8, 37, 0x8 };
+
+ path = fdt_path_offset(blob, prop);
+ prop = fdt_getprop(blob, path, "interrupts",
+ NULL);
+ if (prop)
+ fdt_setprop(blob, path, "interrupts",
+ &tmp, sizeof(tmp));
+ }
+#endif
+ }
+ }
+#endif
+#endif
+
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "timebase-frequency", (bd->bi_busfreq / 4), 1);
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "bus-frequency", bd->bi_busfreq, 1);
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "clock-frequency", gd->arch.core_clk, 1);
+ do_fixup_by_prop_u32(blob, "device_type", "soc", 4,
+ "bus-frequency", bd->bi_busfreq, 1);
+ do_fixup_by_compat_u32(blob, "fsl,soc",
+ "bus-frequency", bd->bi_busfreq, 1);
+ do_fixup_by_compat_u32(blob, "fsl,soc",
+ "clock-frequency", bd->bi_busfreq, 1);
+ do_fixup_by_compat_u32(blob, "fsl,immr",
+ "bus-frequency", bd->bi_busfreq, 1);
+ do_fixup_by_compat_u32(blob, "fsl,immr",
+ "clock-frequency", bd->bi_busfreq, 1);
+#ifdef CONFIG_QE
+ ft_qe_setup(blob);
+#endif
+
+#ifdef CONFIG_SYS_NS16550
+ do_fixup_by_compat_u32(blob, "ns16550",
+ "clock-frequency", CONFIG_SYS_NS16550_CLK, 1);
+#endif
+
+ fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+
+#if defined(CONFIG_BOOTCOUNT_LIMIT)
+ fdt_fixup_muram (blob);
+#endif
+}
diff --git a/arch/powerpc/cpu/mpc83xx/interrupts.c b/arch/powerpc/cpu/mpc83xx/interrupts.c
new file mode 100644
index 0000000..446af27
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/interrupts.c
@@ -0,0 +1,97 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright 2004 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <mpc83xx.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct irq_action {
+ interrupt_handler_t *handler;
+ void *arg;
+ ulong count;
+};
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ *decrementer_count = (gd->bus_clk / 4) / CONFIG_SYS_HZ;
+
+ /* Enable e300 time base */
+
+ immr->sysconf.spcr |= 0x00400000;
+
+ return 0;
+}
+
+
+/*
+ * Handle external interrupts
+ */
+
+void external_interrupt (struct pt_regs *regs)
+{
+}
+
+
+/*
+ * Install and free an interrupt handler.
+ */
+
+void
+irq_install_handler (int irq, interrupt_handler_t * handler, void *arg)
+{
+}
+
+
+void irq_free_handler (int irq)
+{
+}
+
+
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+ /* nothing to do here */
+ return;
+}
+
+
+#if defined(CONFIG_CMD_IRQ)
+
+/* ripped this out of ppc4xx/interrupts.c */
+
+/*
+ * irqinfo - print information about PCI devices
+ */
+
+void
+do_irqinfo(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char * const argv[])
+{
+}
+
+#endif
diff --git a/arch/powerpc/cpu/mpc83xx/law.c b/arch/powerpc/cpu/mpc83xx/law.c
new file mode 100644
index 0000000..66c88b6
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/law.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/fsl_law.h>
+#include <asm/mmu.h>
+
+int set_ddr_laws(u64 start, u64 sz, enum law_trgt_if id)
+{
+ immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+ law83xx_t *ecm = &immap->sysconf.ddrlaw[0];
+ u64 start_align, law_sz;
+ int law_sz_enc;
+
+ if (start == 0)
+ start_align = 1ull << (LAW_SIZE_2G + 1);
+ else
+ start_align = 1ull << (ffs64(start) - 1);
+ law_sz = min(start_align, sz);
+ law_sz_enc = __ilog2_u64(law_sz) - 1;
+
+ /*
+ * Set up LAWBAR for all of DDR.
+ */
+ ecm->bar = start & 0xfffff000;
+ ecm->ar = (LAWAR_EN | (id << 20) | (LAWAR_SIZE & law_sz_enc));
+ debug("DDR:bar=0x%08x\n", ecm->bar);
+ debug("DDR:ar=0x%08x\n", ecm->ar);
+
+ /* recalculate size based on what was actually covered by the law */
+ law_sz = 1ull << __ilog2_u64(law_sz);
+
+ /* do we still have anything to map */
+ sz = sz - law_sz;
+ if (sz) {
+ start += law_sz;
+
+ start_align = 1ull << (ffs64(start) - 1);
+ law_sz = min(start_align, sz);
+ law_sz_enc = __ilog2_u64(law_sz) - 1;
+ ecm = &immap->sysconf.ddrlaw[1];
+ ecm->bar = start & 0xfffff000;
+ ecm->ar = (LAWAR_EN | (id << 20) | (LAWAR_SIZE & law_sz_enc));
+ debug("DDR:bar=0x%08x\n", ecm->bar);
+ debug("DDR:ar=0x%08x\n", ecm->ar);
+ } else {
+ return 0;
+ }
+
+ /* do we still have anything to map */
+ sz = sz - law_sz;
+ if (sz)
+ return 1;
+
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc83xx/pci.c b/arch/powerpc/cpu/mpc83xx/pci.c
new file mode 100644
index 0000000..288d99f
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/pci.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) Freescale Semiconductor, Inc. 2007
+ *
+ * Author: Scott Wood <scottwood@freescale.com>,
+ * with some bits from older board-specific PCI initialization.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <pci.h>
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+
+#include <asm/mpc8349_pci.h>
+
+#define MAX_BUSES 2
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct pci_controller pci_hose[MAX_BUSES];
+static int pci_num_buses;
+
+static void pci_init_bus(int bus, struct pci_region *reg)
+{
+ volatile immap_t *immr = (volatile immap_t *)CONFIG_SYS_IMMR;
+ volatile pot83xx_t *pot = immr->ios.pot;
+ volatile pcictrl83xx_t *pci_ctrl = &immr->pci_ctrl[bus];
+ struct pci_controller *hose = &pci_hose[bus];
+ u32 dev;
+ u16 reg16;
+ int i;
+
+ if (bus == 1)
+ pot += 3;
+
+ /* Setup outbound translation windows */
+ for (i = 0; i < 3; i++, reg++, pot++) {
+ if (reg->size == 0)
+ break;
+
+ hose->regions[i] = *reg;
+ hose->region_count++;
+
+ pot->potar = reg->bus_start >> 12;
+ pot->pobar = reg->phys_start >> 12;
+ pot->pocmr = ~(reg->size - 1) >> 12;
+
+ if (reg->flags & PCI_REGION_IO)
+ pot->pocmr |= POCMR_IO;
+#ifdef CONFIG_83XX_PCI_STREAMING
+ else if (reg->flags & PCI_REGION_PREFETCH)
+ pot->pocmr |= POCMR_SE;
+#endif
+
+ if (bus == 1)
+ pot->pocmr |= POCMR_DST;
+
+ pot->pocmr |= POCMR_EN;
+ }
+
+ /* Point inbound translation at RAM */
+ pci_ctrl->pitar1 = 0;
+ pci_ctrl->pibar1 = 0;
+ pci_ctrl->piebar1 = 0;
+ pci_ctrl->piwar1 = PIWAR_EN | PIWAR_PF | PIWAR_RTT_SNOOP |
+ PIWAR_WTT_SNOOP | (__ilog2(gd->ram_size - 1));
+
+ i = hose->region_count++;
+ hose->regions[i].bus_start = 0;
+ hose->regions[i].phys_start = 0;
+ hose->regions[i].size = gd->ram_size;
+ hose->regions[i].flags = PCI_REGION_MEM | PCI_REGION_SYS_MEMORY;
+
+ hose->first_busno = pci_last_busno() + 1;
+ hose->last_busno = 0xff;
+
+ pci_setup_indirect(hose, CONFIG_SYS_IMMR + 0x8300 + bus * 0x80,
+ CONFIG_SYS_IMMR + 0x8304 + bus * 0x80);
+
+ pci_register_hose(hose);
+
+ /*
+ * Write to Command register
+ */
+ reg16 = 0xff;
+ dev = PCI_BDF(hose->first_busno, 0, 0);
+ pci_hose_read_config_word(hose, dev, PCI_COMMAND, &reg16);
+ reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+ pci_hose_write_config_word(hose, dev, PCI_COMMAND, reg16);
+
+ /*
+ * Clear non-reserved bits in status register.
+ */
+ pci_hose_write_config_word(hose, dev, PCI_STATUS, 0xffff);
+ pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
+ pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, 0x08);
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf("PCI: Bus Dev VenId DevId Class Int\n");
+#endif
+#ifndef CONFIG_PCISLAVE
+ /*
+ * Hose scan.
+ */
+ hose->last_busno = pci_hose_scan(hose);
+#endif
+}
+
+/*
+ * The caller must have already set OCCR, and the PCI_LAW BARs
+ * must have been set to cover all of the requested regions.
+ *
+ * If fewer than three regions are requested, then the region
+ * list is terminated with a region of size 0.
+ */
+void mpc83xx_pci_init(int num_buses, struct pci_region **reg)
+{
+ volatile immap_t *immr = (volatile immap_t *)CONFIG_SYS_IMMR;
+ int i;
+
+ if (num_buses > MAX_BUSES) {
+ printf("%d PCI buses requsted, %d supported\n",
+ num_buses, MAX_BUSES);
+
+ num_buses = MAX_BUSES;
+ }
+
+ pci_num_buses = num_buses;
+
+ /*
+ * Release PCI RST Output signal.
+ * Power on to RST high must be at least 100 ms as per PCI spec.
+ * On warm boots only 1 ms is required, but we play it safe.
+ */
+ udelay(100000);
+
+ for (i = 0; i < num_buses; i++)
+ immr->pci_ctrl[i].gcr = 1;
+
+ /*
+ * RST high to first config access must be at least 2^25 cycles
+ * as per PCI spec. This could be cut in half if we know we're
+ * running at 66MHz. This could be insufficiently long if we're
+ * running the PCI bus at significantly less than 33MHz.
+ */
+ udelay(1020000);
+
+ for (i = 0; i < num_buses; i++)
+ pci_init_bus(i, reg[i]);
+}
+
+#ifdef CONFIG_PCISLAVE
+
+#define PCI_FUNCTION_CONFIG 0x44
+#define PCI_FUNCTION_CFG_LOCK 0x20
+
+/*
+ * Unlock the configuration bit so that the host system can begin booting
+ *
+ * This should be used after you have:
+ * 1) Called mpc83xx_pci_init()
+ * 2) Set up your inbound translation windows to the appropriate size
+ */
+void mpc83xx_pcislave_unlock(int bus)
+{
+ struct pci_controller *hose = &pci_hose[bus];
+ u32 dev;
+ u16 reg16;
+
+ /* Unlock configuration lock in PCI function configuration register */
+ dev = PCI_BDF(hose->first_busno, 0, 0);
+ pci_hose_read_config_word (hose, dev, PCI_FUNCTION_CONFIG, &reg16);
+ reg16 &= ~(PCI_FUNCTION_CFG_LOCK);
+ pci_hose_write_config_word (hose, dev, PCI_FUNCTION_CONFIG, reg16);
+
+ /* The configuration bit is now unlocked, so we can scan the bus */
+ hose->last_busno = pci_hose_scan(hose);
+}
+#endif
+
+#if defined(CONFIG_OF_LIBFDT)
+void ft_pci_setup(void *blob, bd_t *bd)
+{
+ int nodeoffset;
+ int tmp[2];
+ const char *path;
+
+ if (pci_num_buses < 1)
+ return;
+
+ nodeoffset = fdt_path_offset(blob, "/aliases");
+ if (nodeoffset >= 0) {
+ path = fdt_getprop(blob, nodeoffset, "pci0", NULL);
+ if (path) {
+ tmp[0] = cpu_to_be32(pci_hose[0].first_busno);
+ tmp[1] = cpu_to_be32(pci_hose[0].last_busno);
+ do_fixup_by_path(blob, path, "bus-range",
+ &tmp, sizeof(tmp), 1);
+
+ tmp[0] = cpu_to_be32(gd->pci_clk);
+ do_fixup_by_path(blob, path, "clock-frequency",
+ &tmp, sizeof(tmp[0]), 1);
+ }
+
+ if (pci_num_buses < 2)
+ return;
+
+ path = fdt_getprop(blob, nodeoffset, "pci1", NULL);
+ if (path) {
+ tmp[0] = cpu_to_be32(pci_hose[1].first_busno);
+ tmp[1] = cpu_to_be32(pci_hose[1].last_busno);
+ do_fixup_by_path(blob, path, "bus-range",
+ &tmp, sizeof(tmp), 1);
+
+ tmp[0] = cpu_to_be32(gd->pci_clk);
+ do_fixup_by_path(blob, path, "clock-frequency",
+ &tmp, sizeof(tmp[0]), 1);
+ }
+ }
+}
+#endif /* CONFIG_OF_LIBFDT */
diff --git a/arch/powerpc/cpu/mpc83xx/pcie.c b/arch/powerpc/cpu/mpc83xx/pcie.c
new file mode 100644
index 0000000..609b133
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/pcie.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2007-2009 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008-2009 MontaVista Software, Inc.
+ *
+ * Authors: Tony Li <tony.li@freescale.com>
+ * Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <mpc83xx.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define PCIE_MAX_BUSES 2
+
+static struct {
+ u32 base;
+ u32 size;
+} mpc83xx_pcie_cfg_space[] = {
+ {
+ .base = CONFIG_SYS_PCIE1_CFG_BASE,
+ .size = CONFIG_SYS_PCIE1_CFG_SIZE,
+ },
+#if defined(CONFIG_SYS_PCIE2_CFG_BASE) && defined(CONFIG_SYS_PCIE2_CFG_SIZE)
+ {
+ .base = CONFIG_SYS_PCIE2_CFG_BASE,
+ .size = CONFIG_SYS_PCIE2_CFG_SIZE,
+ },
+#endif
+};
+
+#ifdef CONFIG_83XX_GENERIC_PCIE_REGISTER_HOSES
+
+/* private structure for mpc83xx pcie hose */
+static struct mpc83xx_pcie_priv {
+ u8 index;
+} pcie_priv[PCIE_MAX_BUSES] = {
+ {
+ /* pcie controller 1 */
+ .index = 0,
+ },
+ {
+ /* pcie controller 2 */
+ .index = 1,
+ },
+};
+
+static int mpc83xx_pcie_remap_cfg(struct pci_controller *hose, pci_dev_t dev)
+{
+ int bus = PCI_BUS(dev) - hose->first_busno;
+ immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ struct mpc83xx_pcie_priv *pcie_priv = hose->priv_data;
+ pex83xx_t *pex = &immr->pciexp[pcie_priv->index];
+ struct pex_outbound_window *out_win = &pex->bridge.pex_outbound_win[0];
+ u8 devfn = PCI_DEV(dev) << 3 | PCI_FUNC(dev);
+ u32 dev_base = bus << 24 | devfn << 16;
+
+ if (hose->indirect_type == INDIRECT_TYPE_NO_PCIE_LINK)
+ return -1;
+ /*
+ * Workaround for the HW bug: for Type 0 configure transactions the
+ * PCI-E controller does not check the device number bits and just
+ * assumes that the device number bits are 0.
+ */
+ if (devfn & 0xf8)
+ return -1;
+
+ out_le32(&out_win->tarl, dev_base);
+ return 0;
+}
+
+#define cfg_read(val, addr, type, op) \
+ do { *val = op((type)(addr)); } while (0)
+#define cfg_write(val, addr, type, op) \
+ do { op((type *)(addr), (val)); } while (0)
+
+#define cfg_read_err(val) do { *val = -1; } while (0)
+#define cfg_write_err(val) do { } while (0)
+
+#define PCIE_OP(rw, size, type, op) \
+static int pcie_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, \
+ type val) \
+{ \
+ int ret; \
+ \
+ ret = mpc83xx_pcie_remap_cfg(hose, dev); \
+ if (ret) { \
+ cfg_##rw##_err(val); \
+ return ret; \
+ } \
+ cfg_##rw(val, (void *)hose->cfg_addr + offset, type, op); \
+ return 0; \
+}
+
+PCIE_OP(read, byte, u8 *, in_8)
+PCIE_OP(read, word, u16 *, in_le16)
+PCIE_OP(read, dword, u32 *, in_le32)
+PCIE_OP(write, byte, u8, out_8)
+PCIE_OP(write, word, u16, out_le16)
+PCIE_OP(write, dword, u32, out_le32)
+
+static void mpc83xx_pcie_register_hose(int bus, struct pci_region *reg,
+ u8 link)
+{
+ extern void disable_addr_trans(void); /* start.S */
+ static struct pci_controller pcie_hose[PCIE_MAX_BUSES];
+ struct pci_controller *hose = &pcie_hose[bus];
+ int i;
+
+ /*
+ * There are no spare BATs to remap all PCI-E windows for U-Boot, so
+ * disable translations. In general, this is not great solution, and
+ * that's why we don't register PCI-E hoses by default.
+ */
+ disable_addr_trans();
+
+ for (i = 0; i < 2; i++, reg++) {
+ if (reg->size == 0)
+ break;
+
+ hose->regions[i] = *reg;
+ hose->region_count++;
+ }
+
+ i = hose->region_count++;
+ hose->regions[i].bus_start = 0;
+ hose->regions[i].phys_start = 0;
+ hose->regions[i].size = gd->ram_size;
+ hose->regions[i].flags = PCI_REGION_MEM | PCI_REGION_SYS_MEMORY;
+
+ i = hose->region_count++;
+ hose->regions[i].bus_start = CONFIG_SYS_IMMR;
+ hose->regions[i].phys_start = CONFIG_SYS_IMMR;
+ hose->regions[i].size = 0x100000;
+ hose->regions[i].flags = PCI_REGION_MEM | PCI_REGION_SYS_MEMORY;
+
+ hose->first_busno = pci_last_busno() + 1;
+ hose->last_busno = 0xff;
+
+ hose->cfg_addr = (unsigned int *)mpc83xx_pcie_cfg_space[bus].base;
+
+ hose->priv_data = &pcie_priv[bus];
+
+ pci_set_ops(hose,
+ pcie_read_config_byte,
+ pcie_read_config_word,
+ pcie_read_config_dword,
+ pcie_write_config_byte,
+ pcie_write_config_word,
+ pcie_write_config_dword);
+
+ if (!link)
+ hose->indirect_type = INDIRECT_TYPE_NO_PCIE_LINK;
+
+ pci_register_hose(hose);
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf("PCI: Bus Dev VenId DevId Class Int\n");
+#endif
+ /*
+ * Hose scan.
+ */
+ hose->last_busno = pci_hose_scan(hose);
+}
+
+#else
+
+static void mpc83xx_pcie_register_hose(int bus, struct pci_region *reg,
+ u8 link) {}
+
+#endif /* CONFIG_83XX_GENERIC_PCIE_REGISTER_HOSES */
+
+static void mpc83xx_pcie_init_bus(int bus, struct pci_region *reg)
+{
+ immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ pex83xx_t *pex = &immr->pciexp[bus];
+ struct pex_outbound_window *out_win;
+ struct pex_inbound_window *in_win;
+ void *hose_cfg_base;
+ unsigned int ram_sz;
+ unsigned int barl;
+ unsigned int tar;
+ u16 reg16;
+ int i;
+
+ /* Enable pex csb bridge inbound & outbound transactions */
+ out_le32(&pex->bridge.pex_csb_ctrl,
+ in_le32(&pex->bridge.pex_csb_ctrl) | PEX_CSB_CTRL_OBPIOE |
+ PEX_CSB_CTRL_IBPIOE);
+
+ /* Enable bridge outbound */
+ out_le32(&pex->bridge.pex_csb_obctrl, PEX_CSB_OBCTRL_PIOE |
+ PEX_CSB_OBCTRL_MEMWE | PEX_CSB_OBCTRL_IOWE |
+ PEX_CSB_OBCTRL_CFGWE);
+
+ out_win = &pex->bridge.pex_outbound_win[0];
+ out_le32(&out_win->ar, PEX_OWAR_EN | PEX_OWAR_TYPE_CFG |
+ mpc83xx_pcie_cfg_space[bus].size);
+ out_le32(&out_win->bar, mpc83xx_pcie_cfg_space[bus].base);
+ out_le32(&out_win->tarl, 0);
+ out_le32(&out_win->tarh, 0);
+
+ for (i = 0; i < 2; i++) {
+ u32 ar;
+
+ if (reg[i].size == 0)
+ break;
+
+ out_win = &pex->bridge.pex_outbound_win[i + 1];
+ out_le32(&out_win->bar, reg[i].phys_start);
+ out_le32(&out_win->tarl, reg[i].bus_start);
+ out_le32(&out_win->tarh, 0);
+ ar = PEX_OWAR_EN | (reg[i].size & PEX_OWAR_SIZE);
+ if (reg[i].flags & PCI_REGION_IO)
+ ar |= PEX_OWAR_TYPE_IO;
+ else
+ ar |= PEX_OWAR_TYPE_MEM;
+ out_le32(&out_win->ar, ar);
+ }
+
+ out_le32(&pex->bridge.pex_csb_ibctrl, PEX_CSB_IBCTRL_PIOE);
+
+ ram_sz = gd->ram_size;
+ barl = 0;
+ tar = 0;
+ i = 0;
+ while (ram_sz > 0) {
+ in_win = &pex->bridge.pex_inbound_win[i];
+ out_le32(&in_win->barl, barl);
+ out_le32(&in_win->barh, 0x0);
+ out_le32(&in_win->tar, tar);
+ if (ram_sz >= 0x10000000) {
+ /* The maxium windows size is 256M */
+ out_le32(&in_win->ar, PEX_IWAR_EN | PEX_IWAR_NSOV |
+ PEX_IWAR_TYPE_PF | 0x0FFFF000);
+ barl += 0x10000000;
+ tar += 0x10000000;
+ ram_sz -= 0x10000000;
+ } else {
+ /* The UM is not clear here.
+ * So, round up to even Mb boundary */
+
+ ram_sz = ram_sz >> (20 +
+ ((ram_sz & 0xFFFFF) ? 1 : 0));
+ if (!(ram_sz % 2))
+ ram_sz -= 1;
+ out_le32(&in_win->ar, PEX_IWAR_EN | PEX_IWAR_NSOV |
+ PEX_IWAR_TYPE_PF | (ram_sz << 20) | 0xFF000);
+ ram_sz = 0;
+ }
+ i++;
+ }
+
+ in_win = &pex->bridge.pex_inbound_win[i];
+ out_le32(&in_win->barl, CONFIG_SYS_IMMR);
+ out_le32(&in_win->barh, 0);
+ out_le32(&in_win->tar, CONFIG_SYS_IMMR);
+ out_le32(&in_win->ar, PEX_IWAR_EN |
+ PEX_IWAR_TYPE_NO_PF | PEX_IWAR_SIZE_1M);
+
+ /* Enable the host virtual INTX interrupts */
+ out_le32(&pex->bridge.pex_int_axi_misc_enb,
+ in_le32(&pex->bridge.pex_int_axi_misc_enb) | 0x1E0);
+
+ /* Hose configure header is memory-mapped */
+ hose_cfg_base = (void *)pex;
+
+ get_clocks();
+ /* Configure the PCIE controller core clock ratio */
+ out_le32(hose_cfg_base + PEX_GCLK_RATIO,
+ (((bus ? gd->arch.pciexp2_clk : gd->arch.pciexp1_clk)
+ / 1000000) * 16) / 333);
+ udelay(1000000);
+
+ /* Do Type 1 bridge configuration */
+ out_8(hose_cfg_base + PCI_PRIMARY_BUS, 0);
+ out_8(hose_cfg_base + PCI_SECONDARY_BUS, 1);
+ out_8(hose_cfg_base + PCI_SUBORDINATE_BUS, 255);
+
+ /*
+ * Write to Command register
+ */
+ reg16 = in_le16(hose_cfg_base + PCI_COMMAND);
+ reg16 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO |
+ PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
+ out_le16(hose_cfg_base + PCI_COMMAND, reg16);
+
+ /*
+ * Clear non-reserved bits in status register.
+ */
+ out_le16(hose_cfg_base + PCI_STATUS, 0xffff);
+ out_8(hose_cfg_base + PCI_LATENCY_TIMER, 0x80);
+ out_8(hose_cfg_base + PCI_CACHE_LINE_SIZE, 0x08);
+
+ printf("PCIE%d: ", bus);
+
+ reg16 = in_le16(hose_cfg_base + PCI_LTSSM);
+ if (reg16 >= PCI_LTSSM_L0)
+ printf("link\n");
+ else
+ printf("No link\n");
+
+ mpc83xx_pcie_register_hose(bus, reg, reg16 >= PCI_LTSSM_L0);
+}
+
+/*
+ * The caller must have already set SCCR, SERDES and the PCIE_LAW BARs
+ * must have been set to cover all of the requested regions.
+ */
+void mpc83xx_pcie_init(int num_buses, struct pci_region **reg)
+{
+ int i;
+
+ /*
+ * Release PCI RST Output signal.
+ * Power on to RST high must be at least 100 ms as per PCI spec.
+ * On warm boots only 1 ms is required, but we play it safe.
+ */
+ udelay(100000);
+
+ if (num_buses > ARRAY_SIZE(mpc83xx_pcie_cfg_space)) {
+ printf("Second PCIE host contoller not configured!\n");
+ num_buses = ARRAY_SIZE(mpc83xx_pcie_cfg_space);
+ }
+
+ for (i = 0; i < num_buses; i++)
+ mpc83xx_pcie_init_bus(i, reg[i]);
+}
diff --git a/arch/powerpc/cpu/mpc83xx/qe_io.c b/arch/powerpc/cpu/mpc83xx/qe_io.c
new file mode 100644
index 0000000..db94f00
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/qe_io.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2006 Freescale Semiconductor, Inc.
+ *
+ * Dave Liu <daveliu@freescale.com>
+ * based on source code of Shlomi Gridish
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "common.h"
+#include "asm/errno.h"
+#include "asm/io.h"
+#include "asm/immap_83xx.h"
+
+#define NUM_OF_PINS 32
+void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign)
+{
+ u32 pin_2bit_mask;
+ u32 pin_2bit_dir;
+ u32 pin_2bit_assign;
+ u32 pin_1bit_mask;
+ u32 tmp_val;
+ volatile immap_t *im = (volatile immap_t *)CONFIG_SYS_IMMR;
+ volatile qepio83xx_t *par_io = (volatile qepio83xx_t *)&im->qepio;
+
+ /* Caculate pin location and 2bit mask and dir */
+ pin_2bit_mask = (u32)(0x3 << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2));
+ pin_2bit_dir = (u32)(dir << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2));
+
+ /* Setup the direction */
+ tmp_val = (pin > (NUM_OF_PINS/2) - 1) ? \
+ in_be32(&par_io->ioport[port].dir2) :
+ in_be32(&par_io->ioport[port].dir1);
+
+ if (pin > (NUM_OF_PINS/2) -1) {
+ out_be32(&par_io->ioport[port].dir2, ~pin_2bit_mask & tmp_val);
+ out_be32(&par_io->ioport[port].dir2, pin_2bit_dir | tmp_val);
+ } else {
+ out_be32(&par_io->ioport[port].dir1, ~pin_2bit_mask & tmp_val);
+ out_be32(&par_io->ioport[port].dir1, pin_2bit_dir | tmp_val);
+ }
+
+ /* Calculate pin location for 1bit mask */
+ pin_1bit_mask = (u32)(1 << (NUM_OF_PINS - (pin+1)));
+
+ /* Setup the open drain */
+ tmp_val = in_be32(&par_io->ioport[port].podr);
+ if (open_drain) {
+ out_be32(&par_io->ioport[port].podr, pin_1bit_mask | tmp_val);
+ } else {
+ out_be32(&par_io->ioport[port].podr, ~pin_1bit_mask & tmp_val);
+ }
+
+ /* Setup the assignment */
+ tmp_val = (pin > (NUM_OF_PINS/2) - 1) ?
+ in_be32(&par_io->ioport[port].ppar2):
+ in_be32(&par_io->ioport[port].ppar1);
+ pin_2bit_assign = (u32)(assign
+ << (NUM_OF_PINS - (pin%(NUM_OF_PINS/2)+1)*2));
+
+ /* Clear and set 2 bits mask */
+ if (pin > (NUM_OF_PINS/2) - 1) {
+ out_be32(&par_io->ioport[port].ppar2, ~pin_2bit_mask & tmp_val);
+ out_be32(&par_io->ioport[port].ppar2, pin_2bit_assign | tmp_val);
+ } else {
+ out_be32(&par_io->ioport[port].ppar1, ~pin_2bit_mask & tmp_val);
+ out_be32(&par_io->ioport[port].ppar1, pin_2bit_assign | tmp_val);
+ }
+}
diff --git a/arch/powerpc/cpu/mpc83xx/serdes.c b/arch/powerpc/cpu/mpc83xx/serdes.c
new file mode 100644
index 0000000..2d5ee03
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/serdes.c
@@ -0,0 +1,154 @@
+/*
+ * Freescale SerDes initialization routine
+ *
+ * Copyright 2007,2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008 MontaVista Software, Inc.
+ *
+ * Author: Li Yang <leoli@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/fsl_mpc83xx_serdes.h>
+
+/* SerDes registers */
+#define FSL_SRDSCR0_OFFS 0x0
+#define FSL_SRDSCR0_DPP_1V2 0x00008800
+#define FSL_SRDSCR0_TXEQA_MASK 0x00007000
+#define FSL_SRDSCR0_TXEQA_SATA 0x00001000
+#define FSL_SRDSCR0_TXEQE_MASK 0x00000700
+#define FSL_SRDSCR0_TXEQE_SATA 0x00000100
+#define FSL_SRDSCR1_OFFS 0x4
+#define FSL_SRDSCR1_PLLBW 0x00000040
+#define FSL_SRDSCR2_OFFS 0x8
+#define FSL_SRDSCR2_VDD_1V2 0x00800000
+#define FSL_SRDSCR2_SEIC_MASK 0x00001c1c
+#define FSL_SRDSCR2_SEIC_SATA 0x00001414
+#define FSL_SRDSCR2_SEIC_PEX 0x00001010
+#define FSL_SRDSCR2_SEIC_SGMII 0x00000101
+#define FSL_SRDSCR3_OFFS 0xc
+#define FSL_SRDSCR3_KFR_SATA 0x10100000
+#define FSL_SRDSCR3_KPH_SATA 0x04040000
+#define FSL_SRDSCR3_SDFM_SATA_PEX 0x01010000
+#define FSL_SRDSCR3_SDTXL_SATA 0x00000505
+#define FSL_SRDSCR4_OFFS 0x10
+#define FSL_SRDSCR4_PROT_SATA 0x00000808
+#define FSL_SRDSCR4_PROT_PEX 0x00000101
+#define FSL_SRDSCR4_PROT_SGMII 0x00000505
+#define FSL_SRDSCR4_PLANE_X2 0x01000000
+#define FSL_SRDSRSTCTL_OFFS 0x20
+#define FSL_SRDSRSTCTL_RST 0x80000000
+#define FSL_SRDSRSTCTL_SATA_RESET 0xf
+
+void fsl_setup_serdes(u32 offset, char proto, u32 rfcks, char vdd)
+{
+ void *regs = (void *)CONFIG_SYS_IMMR + offset;
+ u32 tmp;
+
+ /* 1.0V corevdd */
+ if (vdd) {
+ /* DPPE/DPPA = 0 */
+ tmp = in_be32(regs + FSL_SRDSCR0_OFFS);
+ tmp &= ~FSL_SRDSCR0_DPP_1V2;
+ out_be32(regs + FSL_SRDSCR0_OFFS, tmp);
+
+ /* VDD = 0 */
+ tmp = in_be32(regs + FSL_SRDSCR2_OFFS);
+ tmp &= ~FSL_SRDSCR2_VDD_1V2;
+ out_be32(regs + FSL_SRDSCR2_OFFS, tmp);
+ }
+
+ /* protocol specific configuration */
+ switch (proto) {
+ case FSL_SERDES_PROTO_SATA:
+ /* Set and clear reset bits */
+ tmp = in_be32(regs + FSL_SRDSRSTCTL_OFFS);
+ tmp |= FSL_SRDSRSTCTL_SATA_RESET;
+ out_be32(regs + FSL_SRDSRSTCTL_OFFS, tmp);
+ udelay(1000);
+ tmp &= ~FSL_SRDSRSTCTL_SATA_RESET;
+ out_be32(regs + FSL_SRDSRSTCTL_OFFS, tmp);
+
+ /* Configure SRDSCR0 */
+ clrsetbits_be32(regs + FSL_SRDSCR0_OFFS,
+ FSL_SRDSCR0_TXEQA_MASK | FSL_SRDSCR0_TXEQE_MASK,
+ FSL_SRDSCR0_TXEQA_SATA | FSL_SRDSCR0_TXEQE_SATA);
+
+ /* Configure SRDSCR1 */
+ tmp = in_be32(regs + FSL_SRDSCR1_OFFS);
+ tmp &= ~FSL_SRDSCR1_PLLBW;
+ out_be32(regs + FSL_SRDSCR1_OFFS, tmp);
+
+ /* Configure SRDSCR2 */
+ tmp = in_be32(regs + FSL_SRDSCR2_OFFS);
+ tmp &= ~FSL_SRDSCR2_SEIC_MASK;
+ tmp |= FSL_SRDSCR2_SEIC_SATA;
+ out_be32(regs + FSL_SRDSCR2_OFFS, tmp);
+
+ /* Configure SRDSCR3 */
+ tmp = FSL_SRDSCR3_KFR_SATA | FSL_SRDSCR3_KPH_SATA |
+ FSL_SRDSCR3_SDFM_SATA_PEX |
+ FSL_SRDSCR3_SDTXL_SATA;
+ out_be32(regs + FSL_SRDSCR3_OFFS, tmp);
+
+ /* Configure SRDSCR4 */
+ tmp = rfcks | FSL_SRDSCR4_PROT_SATA;
+ out_be32(regs + FSL_SRDSCR4_OFFS, tmp);
+ break;
+ case FSL_SERDES_PROTO_PEX:
+ case FSL_SERDES_PROTO_PEX_X2:
+ /* Configure SRDSCR1 */
+ tmp = in_be32(regs + FSL_SRDSCR1_OFFS);
+ tmp |= FSL_SRDSCR1_PLLBW;
+ out_be32(regs + FSL_SRDSCR1_OFFS, tmp);
+
+ /* Configure SRDSCR2 */
+ tmp = in_be32(regs + FSL_SRDSCR2_OFFS);
+ tmp &= ~FSL_SRDSCR2_SEIC_MASK;
+ tmp |= FSL_SRDSCR2_SEIC_PEX;
+ out_be32(regs + FSL_SRDSCR2_OFFS, tmp);
+
+ /* Configure SRDSCR3 */
+ tmp = FSL_SRDSCR3_SDFM_SATA_PEX;
+ out_be32(regs + FSL_SRDSCR3_OFFS, tmp);
+
+ /* Configure SRDSCR4 */
+ tmp = rfcks | FSL_SRDSCR4_PROT_PEX;
+ if (proto == FSL_SERDES_PROTO_PEX_X2)
+ tmp |= FSL_SRDSCR4_PLANE_X2;
+ out_be32(regs + FSL_SRDSCR4_OFFS, tmp);
+ break;
+ case FSL_SERDES_PROTO_SGMII:
+ /* Configure SRDSCR1 */
+ tmp = in_be32(regs + FSL_SRDSCR1_OFFS);
+ tmp &= ~FSL_SRDSCR1_PLLBW;
+ out_be32(regs + FSL_SRDSCR1_OFFS, tmp);
+
+ /* Configure SRDSCR2 */
+ tmp = in_be32(regs + FSL_SRDSCR2_OFFS);
+ tmp &= ~FSL_SRDSCR2_SEIC_MASK;
+ tmp |= FSL_SRDSCR2_SEIC_SGMII;
+ out_be32(regs + FSL_SRDSCR2_OFFS, tmp);
+
+ /* Configure SRDSCR3 */
+ out_be32(regs + FSL_SRDSCR3_OFFS, 0);
+
+ /* Configure SRDSCR4 */
+ tmp = rfcks | FSL_SRDSCR4_PROT_SGMII;
+ out_be32(regs + FSL_SRDSCR4_OFFS, tmp);
+ break;
+ default:
+ return;
+ }
+
+ /* Do a software reset */
+ tmp = in_be32(regs + FSL_SRDSRSTCTL_OFFS);
+ tmp |= FSL_SRDSRSTCTL_RST;
+ out_be32(regs + FSL_SRDSRSTCTL_OFFS, tmp);
+}
diff --git a/arch/powerpc/cpu/mpc83xx/spd_sdram.c b/arch/powerpc/cpu/mpc83xx/spd_sdram.c
new file mode 100644
index 0000000..04d519a
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/spd_sdram.c
@@ -0,0 +1,943 @@
+/*
+ * (C) Copyright 2006-2007 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (C) 2004-2006 Freescale Semiconductor, Inc.
+ * (C) Copyright 2003 Motorola Inc.
+ * Xianghua Xiao (X.Xiao@motorola.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <i2c.h>
+#include <spd.h>
+#include <asm/mmu.h>
+#include <spd_sdram.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void board_add_ram_info(int use_default)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile ddr83xx_t *ddr = &immap->ddr;
+ char buf[32];
+
+ printf(" (DDR%d", ((ddr->sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK)
+ >> SDRAM_CFG_SDRAM_TYPE_SHIFT) - 1);
+
+#if defined(CONFIG_MPC8308) || defined(CONFIG_MPC831x)
+ if ((ddr->sdram_cfg & SDRAM_CFG_DBW_MASK) == SDRAM_CFG_DBW_16)
+ puts(", 16-bit");
+ else if ((ddr->sdram_cfg & SDRAM_CFG_DBW_MASK) == SDRAM_CFG_DBW_32)
+ puts(", 32-bit");
+ else
+ puts(", unknown width");
+#else
+ if (ddr->sdram_cfg & SDRAM_CFG_32_BE)
+ puts(", 32-bit");
+ else
+ puts(", 64-bit");
+#endif
+
+ if (ddr->sdram_cfg & SDRAM_CFG_ECC_EN)
+ puts(", ECC on");
+ else
+ puts(", ECC off");
+
+ printf(", %s MHz)", strmhz(buf, gd->mem_clk));
+
+#if defined(CONFIG_SYS_LB_SDRAM) && defined(CONFIG_SYS_LBC_SDRAM_SIZE)
+ puts("\nSDRAM: ");
+ print_size (CONFIG_SYS_LBC_SDRAM_SIZE * 1024 * 1024, " (local bus)");
+#endif
+}
+
+#ifdef CONFIG_SPD_EEPROM
+#ifndef CONFIG_SYS_READ_SPD
+#define CONFIG_SYS_READ_SPD i2c_read
+#endif
+#ifndef SPD_EEPROM_OFFSET
+#define SPD_EEPROM_OFFSET 0
+#endif
+#ifndef SPD_EEPROM_ADDR_LEN
+#define SPD_EEPROM_ADDR_LEN 1
+#endif
+
+/*
+ * Convert picoseconds into clock cycles (rounding up if needed).
+ */
+int
+picos_to_clk(int picos)
+{
+ unsigned int mem_bus_clk;
+ int clks;
+
+ mem_bus_clk = gd->mem_clk >> 1;
+ clks = picos / (1000000000 / (mem_bus_clk / 1000));
+ if (picos % (1000000000 / (mem_bus_clk / 1000)) != 0)
+ clks++;
+
+ return clks;
+}
+
+unsigned int banksize(unsigned char row_dens)
+{
+ return ((row_dens >> 2) | ((row_dens & 3) << 6)) << 24;
+}
+
+int read_spd(uint addr)
+{
+ return ((int) addr);
+}
+
+#undef SPD_DEBUG
+#ifdef SPD_DEBUG
+static void spd_debug(spd_eeprom_t *spd)
+{
+ printf ("\nDIMM type: %-18.18s\n", spd->mpart);
+ printf ("SPD size: %d\n", spd->info_size);
+ printf ("EEPROM size: %d\n", 1 << spd->chip_size);
+ printf ("Memory type: %d\n", spd->mem_type);
+ printf ("Row addr: %d\n", spd->nrow_addr);
+ printf ("Column addr: %d\n", spd->ncol_addr);
+ printf ("# of rows: %d\n", spd->nrows);
+ printf ("Row density: %d\n", spd->row_dens);
+ printf ("# of banks: %d\n", spd->nbanks);
+ printf ("Data width: %d\n",
+ 256 * spd->dataw_msb + spd->dataw_lsb);
+ printf ("Chip width: %d\n", spd->primw);
+ printf ("Refresh rate: %02X\n", spd->refresh);
+ printf ("CAS latencies: %02X\n", spd->cas_lat);
+ printf ("Write latencies: %02X\n", spd->write_lat);
+ printf ("tRP: %d\n", spd->trp);
+ printf ("tRCD: %d\n", spd->trcd);
+ printf ("\n");
+}
+#endif /* SPD_DEBUG */
+
+long int spd_sdram()
+{
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+ volatile ddr83xx_t *ddr = &immap->ddr;
+ volatile law83xx_t *ecm = &immap->sysconf.ddrlaw[0];
+ spd_eeprom_t spd;
+ unsigned int n_ranks;
+ unsigned int odt_rd_cfg, odt_wr_cfg;
+ unsigned char twr_clk, twtr_clk;
+ unsigned int sdram_type;
+ unsigned int memsize;
+ unsigned int law_size;
+ unsigned char caslat, caslat_ctrl;
+ unsigned int trfc, trfc_clk, trfc_low;
+ unsigned int trcd_clk, trtp_clk;
+ unsigned char cke_min_clk;
+ unsigned char add_lat, wr_lat;
+ unsigned char wr_data_delay;
+ unsigned char four_act;
+ unsigned char cpo;
+ unsigned char burstlen;
+ unsigned char odt_cfg, mode_odt_enable;
+ unsigned int max_bus_clk;
+ unsigned int max_data_rate, effective_data_rate;
+ unsigned int ddrc_clk;
+ unsigned int refresh_clk;
+ unsigned int sdram_cfg;
+ unsigned int ddrc_ecc_enable;
+ unsigned int pvr = get_pvr();
+
+ /*
+ * First disable the memory controller (could be enabled
+ * by the debugger)
+ */
+ clrsetbits_be32(&ddr->sdram_cfg, SDRAM_CFG_MEM_EN, 0);
+ sync();
+ isync();
+
+ /* Read SPD parameters with I2C */
+ CONFIG_SYS_READ_SPD(SPD_EEPROM_ADDRESS, SPD_EEPROM_OFFSET,
+ SPD_EEPROM_ADDR_LEN, (uchar *) &spd, sizeof(spd));
+#ifdef SPD_DEBUG
+ spd_debug(&spd);
+#endif
+ /* Check the memory type */
+ if (spd.mem_type != SPD_MEMTYPE_DDR && spd.mem_type != SPD_MEMTYPE_DDR2) {
+ debug("DDR: Module mem type is %02X\n", spd.mem_type);
+ return 0;
+ }
+
+ /* Check the number of physical bank */
+ if (spd.mem_type == SPD_MEMTYPE_DDR) {
+ n_ranks = spd.nrows;
+ } else {
+ n_ranks = (spd.nrows & 0x7) + 1;
+ }
+
+ if (n_ranks > 2) {
+ printf("DDR: The number of physical bank is %02X\n", n_ranks);
+ return 0;
+ }
+
+ /* Check if the number of row of the module is in the range of DDRC */
+ if (spd.nrow_addr < 12 || spd.nrow_addr > 15) {
+ printf("DDR: Row number is out of range of DDRC, row=%02X\n",
+ spd.nrow_addr);
+ return 0;
+ }
+
+ /* Check if the number of col of the module is in the range of DDRC */
+ if (spd.ncol_addr < 8 || spd.ncol_addr > 11) {
+ printf("DDR: Col number is out of range of DDRC, col=%02X\n",
+ spd.ncol_addr);
+ return 0;
+ }
+
+#ifdef CONFIG_SYS_DDRCDR_VALUE
+ /*
+ * Adjust DDR II IO voltage biasing. It just makes it work.
+ */
+ if(spd.mem_type == SPD_MEMTYPE_DDR2) {
+ immap->sysconf.ddrcdr = CONFIG_SYS_DDRCDR_VALUE;
+ }
+ udelay(50000);
+#endif
+
+ /*
+ * ODT configuration recommendation from DDR Controller Chapter.
+ */
+ odt_rd_cfg = 0; /* Never assert ODT */
+ odt_wr_cfg = 0; /* Never assert ODT */
+ if (spd.mem_type == SPD_MEMTYPE_DDR2) {
+ odt_wr_cfg = 1; /* Assert ODT on writes to CSn */
+ }
+
+ /* Setup DDR chip select register */
+#ifdef CONFIG_SYS_83XX_DDR_USES_CS0
+ ddr->csbnds[0].csbnds = (banksize(spd.row_dens) >> 24) - 1;
+ ddr->cs_config[0] = ( 1 << 31
+ | (odt_rd_cfg << 20)
+ | (odt_wr_cfg << 16)
+ | ((spd.nbanks == 8 ? 1 : 0) << 14)
+ | ((spd.nrow_addr - 12) << 8)
+ | (spd.ncol_addr - 8) );
+ debug("\n");
+ debug("cs0_bnds = 0x%08x\n",ddr->csbnds[0].csbnds);
+ debug("cs0_config = 0x%08x\n",ddr->cs_config[0]);
+
+ if (n_ranks == 2) {
+ ddr->csbnds[1].csbnds = ( (banksize(spd.row_dens) >> 8)
+ | ((banksize(spd.row_dens) >> 23) - 1) );
+ ddr->cs_config[1] = ( 1<<31
+ | (odt_rd_cfg << 20)
+ | (odt_wr_cfg << 16)
+ | ((spd.nbanks == 8 ? 1 : 0) << 14)
+ | ((spd.nrow_addr - 12) << 8)
+ | (spd.ncol_addr - 8) );
+ debug("cs1_bnds = 0x%08x\n",ddr->csbnds[1].csbnds);
+ debug("cs1_config = 0x%08x\n",ddr->cs_config[1]);
+ }
+
+#else
+ ddr->csbnds[2].csbnds = (banksize(spd.row_dens) >> 24) - 1;
+ ddr->cs_config[2] = ( 1 << 31
+ | (odt_rd_cfg << 20)
+ | (odt_wr_cfg << 16)
+ | ((spd.nbanks == 8 ? 1 : 0) << 14)
+ | ((spd.nrow_addr - 12) << 8)
+ | (spd.ncol_addr - 8) );
+ debug("\n");
+ debug("cs2_bnds = 0x%08x\n",ddr->csbnds[2].csbnds);
+ debug("cs2_config = 0x%08x\n",ddr->cs_config[2]);
+
+ if (n_ranks == 2) {
+ ddr->csbnds[3].csbnds = ( (banksize(spd.row_dens) >> 8)
+ | ((banksize(spd.row_dens) >> 23) - 1) );
+ ddr->cs_config[3] = ( 1<<31
+ | (odt_rd_cfg << 20)
+ | (odt_wr_cfg << 16)
+ | ((spd.nbanks == 8 ? 1 : 0) << 14)
+ | ((spd.nrow_addr - 12) << 8)
+ | (spd.ncol_addr - 8) );
+ debug("cs3_bnds = 0x%08x\n",ddr->csbnds[3].csbnds);
+ debug("cs3_config = 0x%08x\n",ddr->cs_config[3]);
+ }
+#endif
+
+ /*
+ * Figure out memory size in Megabytes.
+ */
+ memsize = n_ranks * banksize(spd.row_dens) / 0x100000;
+
+ /*
+ * First supported LAW size is 16M, at LAWAR_SIZE_16M == 23.
+ */
+ law_size = 19 + __ilog2(memsize);
+
+ /*
+ * Set up LAWBAR for all of DDR.
+ */
+ ecm->bar = CONFIG_SYS_DDR_SDRAM_BASE & 0xfffff000;
+ ecm->ar = (LAWAR_EN | LAWAR_TRGT_IF_DDR | (LAWAR_SIZE & law_size));
+ debug("DDR:bar=0x%08x\n", ecm->bar);
+ debug("DDR:ar=0x%08x\n", ecm->ar);
+
+ /*
+ * Find the largest CAS by locating the highest 1 bit
+ * in the spd.cas_lat field. Translate it to a DDR
+ * controller field value:
+ *
+ * CAS Lat DDR I DDR II Ctrl
+ * Clocks SPD Bit SPD Bit Value
+ * ------- ------- ------- -----
+ * 1.0 0 0001
+ * 1.5 1 0010
+ * 2.0 2 2 0011
+ * 2.5 3 0100
+ * 3.0 4 3 0101
+ * 3.5 5 0110
+ * 4.0 6 4 0111
+ * 4.5 1000
+ * 5.0 5 1001
+ */
+ caslat = __ilog2(spd.cas_lat);
+ if ((spd.mem_type == SPD_MEMTYPE_DDR)
+ && (caslat > 6)) {
+ printf("DDR I: Invalid SPD CAS Latency: 0x%x.\n", spd.cas_lat);
+ return 0;
+ } else if (spd.mem_type == SPD_MEMTYPE_DDR2
+ && (caslat < 2 || caslat > 5)) {
+ printf("DDR II: Invalid SPD CAS Latency: 0x%x.\n",
+ spd.cas_lat);
+ return 0;
+ }
+ debug("DDR: caslat SPD bit is %d\n", caslat);
+
+ max_bus_clk = 1000 *10 / (((spd.clk_cycle & 0xF0) >> 4) * 10
+ + (spd.clk_cycle & 0x0f));
+ max_data_rate = max_bus_clk * 2;
+
+ debug("DDR:Module maximum data rate is: %d MHz\n", max_data_rate);
+
+ ddrc_clk = gd->mem_clk / 1000000;
+ effective_data_rate = 0;
+
+ if (max_data_rate >= 460) { /* it is DDR2-800, 667, 533 */
+ if (spd.cas_lat & 0x08)
+ caslat = 3;
+ else
+ caslat = 4;
+ if (ddrc_clk <= 460 && ddrc_clk > 350)
+ effective_data_rate = 400;
+ else if (ddrc_clk <=350 && ddrc_clk > 280)
+ effective_data_rate = 333;
+ else if (ddrc_clk <= 280 && ddrc_clk > 230)
+ effective_data_rate = 266;
+ else
+ effective_data_rate = 200;
+ } else if (max_data_rate >= 390 && max_data_rate < 460) { /* it is DDR 400 */
+ if (ddrc_clk <= 460 && ddrc_clk > 350) {
+ /* DDR controller clk at 350~460 */
+ effective_data_rate = 400; /* 5ns */
+ caslat = caslat;
+ } else if (ddrc_clk <= 350 && ddrc_clk > 280) {
+ /* DDR controller clk at 280~350 */
+ effective_data_rate = 333; /* 6ns */
+ if (spd.clk_cycle2 == 0x60)
+ caslat = caslat - 1;
+ else
+ caslat = caslat;
+ } else if (ddrc_clk <= 280 && ddrc_clk > 230) {
+ /* DDR controller clk at 230~280 */
+ effective_data_rate = 266; /* 7.5ns */
+ if (spd.clk_cycle3 == 0x75)
+ caslat = caslat - 2;
+ else if (spd.clk_cycle2 == 0x75)
+ caslat = caslat - 1;
+ else
+ caslat = caslat;
+ } else if (ddrc_clk <= 230 && ddrc_clk > 90) {
+ /* DDR controller clk at 90~230 */
+ effective_data_rate = 200; /* 10ns */
+ if (spd.clk_cycle3 == 0xa0)
+ caslat = caslat - 2;
+ else if (spd.clk_cycle2 == 0xa0)
+ caslat = caslat - 1;
+ else
+ caslat = caslat;
+ }
+ } else if (max_data_rate >= 323) { /* it is DDR 333 */
+ if (ddrc_clk <= 350 && ddrc_clk > 280) {
+ /* DDR controller clk at 280~350 */
+ effective_data_rate = 333; /* 6ns */
+ caslat = caslat;
+ } else if (ddrc_clk <= 280 && ddrc_clk > 230) {
+ /* DDR controller clk at 230~280 */
+ effective_data_rate = 266; /* 7.5ns */
+ if (spd.clk_cycle2 == 0x75)
+ caslat = caslat - 1;
+ else
+ caslat = caslat;
+ } else if (ddrc_clk <= 230 && ddrc_clk > 90) {
+ /* DDR controller clk at 90~230 */
+ effective_data_rate = 200; /* 10ns */
+ if (spd.clk_cycle3 == 0xa0)
+ caslat = caslat - 2;
+ else if (spd.clk_cycle2 == 0xa0)
+ caslat = caslat - 1;
+ else
+ caslat = caslat;
+ }
+ } else if (max_data_rate >= 256) { /* it is DDR 266 */
+ if (ddrc_clk <= 350 && ddrc_clk > 280) {
+ /* DDR controller clk at 280~350 */
+ printf("DDR: DDR controller freq is more than "
+ "max data rate of the module\n");
+ return 0;
+ } else if (ddrc_clk <= 280 && ddrc_clk > 230) {
+ /* DDR controller clk at 230~280 */
+ effective_data_rate = 266; /* 7.5ns */
+ caslat = caslat;
+ } else if (ddrc_clk <= 230 && ddrc_clk > 90) {
+ /* DDR controller clk at 90~230 */
+ effective_data_rate = 200; /* 10ns */
+ if (spd.clk_cycle2 == 0xa0)
+ caslat = caslat - 1;
+ }
+ } else if (max_data_rate >= 190) { /* it is DDR 200 */
+ if (ddrc_clk <= 350 && ddrc_clk > 230) {
+ /* DDR controller clk at 230~350 */
+ printf("DDR: DDR controller freq is more than "
+ "max data rate of the module\n");
+ return 0;
+ } else if (ddrc_clk <= 230 && ddrc_clk > 90) {
+ /* DDR controller clk at 90~230 */
+ effective_data_rate = 200; /* 10ns */
+ caslat = caslat;
+ }
+ }
+
+ debug("DDR:Effective data rate is: %dMHz\n", effective_data_rate);
+ debug("DDR:The MSB 1 of CAS Latency is: %d\n", caslat);
+
+ /*
+ * Errata DDR6 work around: input enable 2 cycles earlier.
+ * including MPC834x Rev1.0/1.1 and MPC8360 Rev1.1/1.2.
+ */
+ if(PVR_MAJ(pvr) <= 1 && spd.mem_type == SPD_MEMTYPE_DDR){
+ if (caslat == 2)
+ ddr->debug_reg = 0x201c0000; /* CL=2 */
+ else if (caslat == 3)
+ ddr->debug_reg = 0x202c0000; /* CL=2.5 */
+ else if (caslat == 4)
+ ddr->debug_reg = 0x202c0000; /* CL=3.0 */
+
+ __asm__ __volatile__ ("sync");
+
+ debug("Errata DDR6 (debug_reg=0x%08x)\n", ddr->debug_reg);
+ }
+
+ /*
+ * Convert caslat clocks to DDR controller value.
+ * Force caslat_ctrl to be DDR Controller field-sized.
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR) {
+ caslat_ctrl = (caslat + 1) & 0x07;
+ } else {
+ caslat_ctrl = (2 * caslat - 1) & 0x0f;
+ }
+
+ debug("DDR: effective data rate is %d MHz\n", effective_data_rate);
+ debug("DDR: caslat SPD bit is %d, controller field is 0x%x\n",
+ caslat, caslat_ctrl);
+
+ /*
+ * Timing Config 0.
+ * Avoid writing for DDR I.
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR2) {
+ unsigned char taxpd_clk = 8; /* By the book. */
+ unsigned char tmrd_clk = 2; /* By the book. */
+ unsigned char act_pd_exit = 2; /* Empirical? */
+ unsigned char pre_pd_exit = 6; /* Empirical? */
+
+ ddr->timing_cfg_0 = (0
+ | ((act_pd_exit & 0x7) << 20) /* ACT_PD_EXIT */
+ | ((pre_pd_exit & 0x7) << 16) /* PRE_PD_EXIT */
+ | ((taxpd_clk & 0xf) << 8) /* ODT_PD_EXIT */
+ | ((tmrd_clk & 0xf) << 0) /* MRS_CYC */
+ );
+ debug("DDR: timing_cfg_0 = 0x%08x\n", ddr->timing_cfg_0);
+ }
+
+ /*
+ * For DDR I, WRREC(Twr) and WRTORD(Twtr) are not in SPD,
+ * use conservative value.
+ * For DDR II, they are bytes 36 and 37, in quarter nanos.
+ */
+
+ if (spd.mem_type == SPD_MEMTYPE_DDR) {
+ twr_clk = 3; /* Clocks */
+ twtr_clk = 1; /* Clocks */
+ } else {
+ twr_clk = picos_to_clk(spd.twr * 250);
+ twtr_clk = picos_to_clk(spd.twtr * 250);
+ if (twtr_clk < 2)
+ twtr_clk = 2;
+ }
+
+ /*
+ * Calculate Trfc, in picos.
+ * DDR I: Byte 42 straight up in ns.
+ * DDR II: Byte 40 and 42 swizzled some, in ns.
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR) {
+ trfc = spd.trfc * 1000; /* up to ps */
+ } else {
+ unsigned int byte40_table_ps[8] = {
+ 0,
+ 250,
+ 330,
+ 500,
+ 660,
+ 750,
+ 0,
+ 0
+ };
+
+ trfc = (((spd.trctrfc_ext & 0x1) * 256) + spd.trfc) * 1000
+ + byte40_table_ps[(spd.trctrfc_ext >> 1) & 0x7];
+ }
+ trfc_clk = picos_to_clk(trfc);
+
+ /*
+ * Trcd, Byte 29, from quarter nanos to ps and clocks.
+ */
+ trcd_clk = picos_to_clk(spd.trcd * 250) & 0x7;
+
+ /*
+ * Convert trfc_clk to DDR controller fields. DDR I should
+ * fit in the REFREC field (16-19) of TIMING_CFG_1, but the
+ * 83xx controller has an extended REFREC field of three bits.
+ * The controller automatically adds 8 clocks to this value,
+ * so preadjust it down 8 first before splitting it up.
+ */
+ trfc_low = (trfc_clk - 8) & 0xf;
+
+ ddr->timing_cfg_1 =
+ (((picos_to_clk(spd.trp * 250) & 0x07) << 28 ) | /* PRETOACT */
+ ((picos_to_clk(spd.tras * 1000) & 0x0f ) << 24 ) | /* ACTTOPRE */
+ (trcd_clk << 20 ) | /* ACTTORW */
+ (caslat_ctrl << 16 ) | /* CASLAT */
+ (trfc_low << 12 ) | /* REFEC */
+ ((twr_clk & 0x07) << 8) | /* WRRREC */
+ ((picos_to_clk(spd.trrd * 250) & 0x07) << 4) | /* ACTTOACT */
+ ((twtr_clk & 0x07) << 0) /* WRTORD */
+ );
+
+ /*
+ * Additive Latency
+ * For DDR I, 0.
+ * For DDR II, with ODT enabled, use "a value" less than ACTTORW,
+ * which comes from Trcd, and also note that:
+ * add_lat + caslat must be >= 4
+ */
+ add_lat = 0;
+ if (spd.mem_type == SPD_MEMTYPE_DDR2
+ && (odt_wr_cfg || odt_rd_cfg)
+ && (caslat < 4)) {
+ add_lat = 4 - caslat;
+ if ((add_lat + caslat) < 4) {
+ add_lat = 0;
+ }
+ }
+
+ /*
+ * Write Data Delay
+ * Historically 0x2 == 4/8 clock delay.
+ * Empirically, 0x3 == 6/8 clock delay is suggested for DDR I 266.
+ */
+ wr_data_delay = 2;
+#ifdef CONFIG_SYS_DDR_WRITE_DATA_DELAY
+ wr_data_delay = CONFIG_SYS_DDR_WRITE_DATA_DELAY;
+#endif
+
+ /*
+ * Write Latency
+ * Read to Precharge
+ * Minimum CKE Pulse Width.
+ * Four Activate Window
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR) {
+ /*
+ * This is a lie. It should really be 1, but if it is
+ * set to 1, bits overlap into the old controller's
+ * otherwise unused ACSM field. If we leave it 0, then
+ * the HW will magically treat it as 1 for DDR 1. Oh Yea.
+ */
+ wr_lat = 0;
+
+ trtp_clk = 2; /* By the book. */
+ cke_min_clk = 1; /* By the book. */
+ four_act = 1; /* By the book. */
+
+ } else {
+ wr_lat = caslat - 1;
+
+ /* Convert SPD value from quarter nanos to picos. */
+ trtp_clk = picos_to_clk(spd.trtp * 250);
+ if (trtp_clk < 2)
+ trtp_clk = 2;
+ trtp_clk += add_lat;
+
+ cke_min_clk = 3; /* By the book. */
+ four_act = picos_to_clk(37500); /* By the book. 1k pages? */
+ }
+
+ /*
+ * Empirically set ~MCAS-to-preamble override for DDR 2.
+ * Your milage will vary.
+ */
+ cpo = 0;
+ if (spd.mem_type == SPD_MEMTYPE_DDR2) {
+#ifdef CONFIG_SYS_DDR_CPO
+ cpo = CONFIG_SYS_DDR_CPO;
+#else
+ if (effective_data_rate == 266) {
+ cpo = 0x4; /* READ_LAT + 1/2 */
+ } else if (effective_data_rate == 333) {
+ cpo = 0x6; /* READ_LAT + 1 */
+ } else if (effective_data_rate == 400) {
+ cpo = 0x7; /* READ_LAT + 5/4 */
+ } else {
+ /* Automatic calibration */
+ cpo = 0x1f;
+ }
+#endif
+ }
+
+ ddr->timing_cfg_2 = (0
+ | ((add_lat & 0x7) << 28) /* ADD_LAT */
+ | ((cpo & 0x1f) << 23) /* CPO */
+ | ((wr_lat & 0x7) << 19) /* WR_LAT */
+ | ((trtp_clk & 0x7) << 13) /* RD_TO_PRE */
+ | ((wr_data_delay & 0x7) << 10) /* WR_DATA_DELAY */
+ | ((cke_min_clk & 0x7) << 6) /* CKE_PLS */
+ | ((four_act & 0x1f) << 0) /* FOUR_ACT */
+ );
+
+ debug("DDR:timing_cfg_1=0x%08x\n", ddr->timing_cfg_1);
+ debug("DDR:timing_cfg_2=0x%08x\n", ddr->timing_cfg_2);
+
+ /* Check DIMM data bus width */
+ if (spd.dataw_lsb < 64) {
+ if (spd.mem_type == SPD_MEMTYPE_DDR)
+ burstlen = 0x03; /* 32 bit data bus, burst len is 8 */
+ else
+ burstlen = 0x02; /* 32 bit data bus, burst len is 4 */
+ debug("\n DDR DIMM: data bus width is 32 bit");
+ } else {
+ burstlen = 0x02; /* Others act as 64 bit bus, burst len is 4 */
+ debug("\n DDR DIMM: data bus width is 64 bit");
+ }
+
+ /* Is this an ECC DDR chip? */
+ if (spd.config == 0x02)
+ debug(" with ECC\n");
+ else
+ debug(" without ECC\n");
+
+ /* Burst length is always 4 for 64 bit data bus, 8 for 32 bit data bus,
+ Burst type is sequential
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR) {
+ switch (caslat) {
+ case 1:
+ ddr->sdram_mode = 0x50 | burstlen; /* CL=1.5 */
+ break;
+ case 2:
+ ddr->sdram_mode = 0x20 | burstlen; /* CL=2.0 */
+ break;
+ case 3:
+ ddr->sdram_mode = 0x60 | burstlen; /* CL=2.5 */
+ break;
+ case 4:
+ ddr->sdram_mode = 0x30 | burstlen; /* CL=3.0 */
+ break;
+ default:
+ printf("DDR:only CL 1.5, 2.0, 2.5, 3.0 is supported\n");
+ return 0;
+ }
+ } else {
+ mode_odt_enable = 0x0; /* Default disabled */
+ if (odt_wr_cfg || odt_rd_cfg) {
+ /*
+ * Bits 6 and 2 in Extended MRS(1)
+ * Bit 2 == 0x04 == 75 Ohm, with 2 DIMM modules.
+ * Bit 6 == 0x40 == 150 Ohm, with 1 DIMM module.
+ */
+ mode_odt_enable = 0x40; /* 150 Ohm */
+ }
+
+ ddr->sdram_mode =
+ (0
+ | (1 << (16 + 10)) /* DQS Differential disable */
+#ifdef CONFIG_SYS_DDR_MODE_WEAK
+ | (1 << (16 + 1)) /* weak driver (~60%) */
+#endif
+ | (add_lat << (16 + 3)) /* Additive Latency in EMRS1 */
+ | (mode_odt_enable << 16) /* ODT Enable in EMRS1 */
+ | ((twr_clk - 1) << 9) /* Write Recovery Autopre */
+ | (caslat << 4) /* caslat */
+ | (burstlen << 0) /* Burst length */
+ );
+ }
+ debug("DDR:sdram_mode=0x%08x\n", ddr->sdram_mode);
+
+ /*
+ * Clear EMRS2 and EMRS3.
+ */
+ ddr->sdram_mode2 = 0;
+ debug("DDR: sdram_mode2 = 0x%08x\n", ddr->sdram_mode2);
+
+ switch (spd.refresh) {
+ case 0x00:
+ case 0x80:
+ refresh_clk = picos_to_clk(15625000);
+ break;
+ case 0x01:
+ case 0x81:
+ refresh_clk = picos_to_clk(3900000);
+ break;
+ case 0x02:
+ case 0x82:
+ refresh_clk = picos_to_clk(7800000);
+ break;
+ case 0x03:
+ case 0x83:
+ refresh_clk = picos_to_clk(31300000);
+ break;
+ case 0x04:
+ case 0x84:
+ refresh_clk = picos_to_clk(62500000);
+ break;
+ case 0x05:
+ case 0x85:
+ refresh_clk = picos_to_clk(125000000);
+ break;
+ default:
+ refresh_clk = 0x512;
+ break;
+ }
+
+ /*
+ * Set BSTOPRE to 0x100 for page mode
+ * If auto-charge is used, set BSTOPRE = 0
+ */
+ ddr->sdram_interval = ((refresh_clk & 0x3fff) << 16) | 0x100;
+ debug("DDR:sdram_interval=0x%08x\n", ddr->sdram_interval);
+
+ /*
+ * SDRAM Cfg 2
+ */
+ odt_cfg = 0;
+#ifndef CONFIG_NEVER_ASSERT_ODT_TO_CPU
+ if (odt_rd_cfg | odt_wr_cfg) {
+ odt_cfg = 0x2; /* ODT to IOs during reads */
+ }
+#endif
+ if (spd.mem_type == SPD_MEMTYPE_DDR2) {
+ ddr->sdram_cfg2 = (0
+ | (0 << 26) /* True DQS */
+ | (odt_cfg << 21) /* ODT only read */
+ | (1 << 12) /* 1 refresh at a time */
+ );
+
+ debug("DDR: sdram_cfg2 = 0x%08x\n", ddr->sdram_cfg2);
+ }
+
+#ifdef CONFIG_SYS_DDR_SDRAM_CLK_CNTL /* Optional platform specific value */
+ ddr->sdram_clk_cntl = CONFIG_SYS_DDR_SDRAM_CLK_CNTL;
+#endif
+ debug("DDR:sdram_clk_cntl=0x%08x\n", ddr->sdram_clk_cntl);
+
+ asm("sync;isync");
+
+ udelay(600);
+
+ /*
+ * Figure out the settings for the sdram_cfg register. Build up
+ * the value in 'sdram_cfg' before writing since the write into
+ * the register will actually enable the memory controller, and all
+ * settings must be done before enabling.
+ *
+ * sdram_cfg[0] = 1 (ddr sdram logic enable)
+ * sdram_cfg[1] = 1 (self-refresh-enable)
+ * sdram_cfg[5:7] = (SDRAM type = DDR SDRAM)
+ * 010 DDR 1 SDRAM
+ * 011 DDR 2 SDRAM
+ * sdram_cfg[12] = 0 (32_BE =0 , 64 bit bus mode)
+ * sdram_cfg[13] = 0 (8_BE =0, 4-beat bursts)
+ */
+ if (spd.mem_type == SPD_MEMTYPE_DDR)
+ sdram_type = SDRAM_CFG_SDRAM_TYPE_DDR1;
+ else
+ sdram_type = SDRAM_CFG_SDRAM_TYPE_DDR2;
+
+ sdram_cfg = (0
+ | SDRAM_CFG_MEM_EN /* DDR enable */
+ | SDRAM_CFG_SREN /* Self refresh */
+ | sdram_type /* SDRAM type */
+ );
+
+ /* sdram_cfg[3] = RD_EN - registered DIMM enable */
+ if (spd.mod_attr & 0x02)
+ sdram_cfg |= SDRAM_CFG_RD_EN;
+
+ /* The DIMM is 32bit width */
+ if (spd.dataw_lsb < 64) {
+ if (spd.mem_type == SPD_MEMTYPE_DDR)
+ sdram_cfg |= SDRAM_CFG_32_BE | SDRAM_CFG_8_BE;
+ if (spd.mem_type == SPD_MEMTYPE_DDR2)
+ sdram_cfg |= SDRAM_CFG_32_BE;
+ }
+
+ ddrc_ecc_enable = 0;
+
+#if defined(CONFIG_DDR_ECC)
+ /* Enable ECC with sdram_cfg[2] */
+ if (spd.config == 0x02) {
+ sdram_cfg |= 0x20000000;
+ ddrc_ecc_enable = 1;
+ /* disable error detection */
+ ddr->err_disable = ~ECC_ERROR_ENABLE;
+ /* set single bit error threshold to maximum value,
+ * reset counter to zero */
+ ddr->err_sbe = (255 << ECC_ERROR_MAN_SBET_SHIFT) |
+ (0 << ECC_ERROR_MAN_SBEC_SHIFT);
+ }
+
+ debug("DDR:err_disable=0x%08x\n", ddr->err_disable);
+ debug("DDR:err_sbe=0x%08x\n", ddr->err_sbe);
+#endif
+ debug(" DDRC ECC mode: %s\n", ddrc_ecc_enable ? "ON":"OFF");
+
+#if defined(CONFIG_DDR_2T_TIMING)
+ /*
+ * Enable 2T timing by setting sdram_cfg[16].
+ */
+ sdram_cfg |= SDRAM_CFG_2T_EN;
+#endif
+ /* Enable controller, and GO! */
+ ddr->sdram_cfg = sdram_cfg;
+ asm("sync;isync");
+ udelay(500);
+
+ debug("DDR:sdram_cfg=0x%08x\n", ddr->sdram_cfg);
+ return memsize; /*in MBytes*/
+}
+#endif /* CONFIG_SPD_EEPROM */
+
+#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)
+/*
+ * Use timebase counter, get_timer() is not availabe
+ * at this point of initialization yet.
+ */
+static __inline__ unsigned long get_tbms (void)
+{
+ unsigned long tbl;
+ unsigned long tbu1, tbu2;
+ unsigned long ms;
+ unsigned long long tmp;
+
+ ulong tbclk = get_tbclk();
+
+ /* get the timebase ticks */
+ do {
+ asm volatile ("mftbu %0":"=r" (tbu1):);
+ asm volatile ("mftb %0":"=r" (tbl):);
+ asm volatile ("mftbu %0":"=r" (tbu2):);
+ } while (tbu1 != tbu2);
+
+ /* convert ticks to ms */
+ tmp = (unsigned long long)(tbu1);
+ tmp = (tmp << 32);
+ tmp += (unsigned long long)(tbl);
+ ms = tmp/(tbclk/1000);
+
+ return ms;
+}
+
+/*
+ * Initialize all of memory for ECC, then enable errors.
+ */
+void ddr_enable_ecc(unsigned int dram_size)
+{
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+ volatile ddr83xx_t *ddr= &immap->ddr;
+ unsigned long t_start, t_end;
+ register u64 *p;
+ register uint size;
+ unsigned int pattern[2];
+
+ icache_enable();
+ t_start = get_tbms();
+ pattern[0] = 0xdeadbeef;
+ pattern[1] = 0xdeadbeef;
+
+#if defined(CONFIG_DDR_ECC_INIT_VIA_DMA)
+ dma_meminit(pattern[0], dram_size);
+#else
+ debug("ddr init: CPU FP write method\n");
+ size = dram_size;
+ for (p = 0; p < (u64*)(size); p++) {
+ ppcDWstore((u32*)p, pattern);
+ }
+ __asm__ __volatile__ ("sync");
+#endif
+
+ t_end = get_tbms();
+ icache_disable();
+
+ debug("\nREADY!!\n");
+ debug("ddr init duration: %ld ms\n", t_end - t_start);
+
+ /* Clear All ECC Errors */
+ if ((ddr->err_detect & ECC_ERROR_DETECT_MME) == ECC_ERROR_DETECT_MME)
+ ddr->err_detect |= ECC_ERROR_DETECT_MME;
+ if ((ddr->err_detect & ECC_ERROR_DETECT_MBE) == ECC_ERROR_DETECT_MBE)
+ ddr->err_detect |= ECC_ERROR_DETECT_MBE;
+ if ((ddr->err_detect & ECC_ERROR_DETECT_SBE) == ECC_ERROR_DETECT_SBE)
+ ddr->err_detect |= ECC_ERROR_DETECT_SBE;
+ if ((ddr->err_detect & ECC_ERROR_DETECT_MSE) == ECC_ERROR_DETECT_MSE)
+ ddr->err_detect |= ECC_ERROR_DETECT_MSE;
+
+ /* Disable ECC-Interrupts */
+ ddr->err_int_en &= ECC_ERR_INT_DISABLE;
+
+ /* Enable errors for ECC */
+ ddr->err_disable &= ECC_ERROR_ENABLE;
+
+ __asm__ __volatile__ ("sync");
+ __asm__ __volatile__ ("isync");
+}
+#endif /* CONFIG_DDR_ECC */
diff --git a/arch/powerpc/cpu/mpc83xx/speed.c b/arch/powerpc/cpu/mpc83xx/speed.c
new file mode 100644
index 0000000..6be0e3a
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/speed.c
@@ -0,0 +1,609 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc83xx.h>
+#include <command.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* ----------------------------------------------------------------- */
+
+typedef enum {
+ _unk,
+ _off,
+ _byp,
+ _x8,
+ _x4,
+ _x2,
+ _x1,
+ _1x,
+ _1_5x,
+ _2x,
+ _2_5x,
+ _3x
+} mult_t;
+
+typedef struct {
+ mult_t core_csb_ratio;
+ mult_t vco_divider;
+} corecnf_t;
+
+static corecnf_t corecnf_tab[] = {
+ {_byp, _byp}, /* 0x00 */
+ {_byp, _byp}, /* 0x01 */
+ {_byp, _byp}, /* 0x02 */
+ {_byp, _byp}, /* 0x03 */
+ {_byp, _byp}, /* 0x04 */
+ {_byp, _byp}, /* 0x05 */
+ {_byp, _byp}, /* 0x06 */
+ {_byp, _byp}, /* 0x07 */
+ {_1x, _x2}, /* 0x08 */
+ {_1x, _x4}, /* 0x09 */
+ {_1x, _x8}, /* 0x0A */
+ {_1x, _x8}, /* 0x0B */
+ {_1_5x, _x2}, /* 0x0C */
+ {_1_5x, _x4}, /* 0x0D */
+ {_1_5x, _x8}, /* 0x0E */
+ {_1_5x, _x8}, /* 0x0F */
+ {_2x, _x2}, /* 0x10 */
+ {_2x, _x4}, /* 0x11 */
+ {_2x, _x8}, /* 0x12 */
+ {_2x, _x8}, /* 0x13 */
+ {_2_5x, _x2}, /* 0x14 */
+ {_2_5x, _x4}, /* 0x15 */
+ {_2_5x, _x8}, /* 0x16 */
+ {_2_5x, _x8}, /* 0x17 */
+ {_3x, _x2}, /* 0x18 */
+ {_3x, _x4}, /* 0x19 */
+ {_3x, _x8}, /* 0x1A */
+ {_3x, _x8}, /* 0x1B */
+};
+
+/* ----------------------------------------------------------------- */
+
+/*
+ *
+ */
+int get_clocks(void)
+{
+ volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+ u32 pci_sync_in;
+ u8 spmf;
+ u8 clkin_div;
+ u32 sccr;
+ u32 corecnf_tab_index;
+ u8 corepll;
+ u32 lcrr;
+
+ u32 csb_clk;
+#if defined(CONFIG_MPC8308) || defined(CONFIG_MPC831x) || \
+ defined(CONFIG_MPC834x) || defined(CONFIG_MPC837x)
+ u32 tsec1_clk;
+ u32 tsec2_clk;
+ u32 usbdr_clk;
+#elif defined(CONFIG_MPC8309)
+ u32 usbdr_clk;
+#endif
+#ifdef CONFIG_MPC834x
+ u32 usbmph_clk;
+#endif
+ u32 core_clk;
+ u32 i2c1_clk;
+#if !defined(CONFIG_MPC832x)
+ u32 i2c2_clk;
+#endif
+#if defined(CONFIG_MPC8315)
+ u32 tdm_clk;
+#endif
+#if defined(CONFIG_FSL_ESDHC)
+ u32 sdhc_clk;
+#endif
+#if !defined(CONFIG_MPC8309)
+ u32 enc_clk;
+#endif
+ u32 lbiu_clk;
+ u32 lclk_clk;
+ u32 mem_clk;
+#if defined(CONFIG_MPC8360)
+ u32 mem_sec_clk;
+#endif
+#if defined(CONFIG_QE)
+ u32 qepmf;
+ u32 qepdf;
+ u32 qe_clk;
+ u32 brg_clk;
+#endif
+#if defined(CONFIG_MPC8308) || defined(CONFIG_MPC831x) || \
+ defined(CONFIG_MPC837x)
+ u32 pciexp1_clk;
+ u32 pciexp2_clk;
+#endif
+#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC8315)
+ u32 sata_clk;
+#endif
+
+ if ((im->sysconf.immrbar & IMMRBAR_BASE_ADDR) != (u32) im)
+ return -1;
+
+ clkin_div = ((im->clk.spmr & SPMR_CKID) >> SPMR_CKID_SHIFT);
+
+ if (im->reset.rcwh & HRCWH_PCI_HOST) {
+#if defined(CONFIG_83XX_CLKIN)
+ pci_sync_in = CONFIG_83XX_CLKIN / (1 + clkin_div);
+#else
+ pci_sync_in = 0xDEADBEEF;
+#endif
+ } else {
+#if defined(CONFIG_83XX_PCICLK)
+ pci_sync_in = CONFIG_83XX_PCICLK;
+#else
+ pci_sync_in = 0xDEADBEEF;
+#endif
+ }
+
+ spmf = (im->clk.spmr & SPMR_SPMF) >> SPMR_SPMF_SHIFT;
+ csb_clk = pci_sync_in * (1 + clkin_div) * spmf;
+
+ sccr = im->clk.sccr;
+
+#if defined(CONFIG_MPC8308) || defined(CONFIG_MPC831x) || \
+ defined(CONFIG_MPC834x) || defined(CONFIG_MPC837x)
+ switch ((sccr & SCCR_TSEC1CM) >> SCCR_TSEC1CM_SHIFT) {
+ case 0:
+ tsec1_clk = 0;
+ break;
+ case 1:
+ tsec1_clk = csb_clk;
+ break;
+ case 2:
+ tsec1_clk = csb_clk / 2;
+ break;
+ case 3:
+ tsec1_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_TSEC1CM value */
+ return -2;
+ }
+#endif
+
+#if defined(CONFIG_MPC830x) || defined(CONFIG_MPC831x) || \
+ defined(CONFIG_MPC834x) || defined(CONFIG_MPC837x)
+ switch ((sccr & SCCR_USBDRCM) >> SCCR_USBDRCM_SHIFT) {
+ case 0:
+ usbdr_clk = 0;
+ break;
+ case 1:
+ usbdr_clk = csb_clk;
+ break;
+ case 2:
+ usbdr_clk = csb_clk / 2;
+ break;
+ case 3:
+ usbdr_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_USBDRCM value */
+ return -3;
+ }
+#endif
+
+#if defined(CONFIG_MPC8308) || defined(CONFIG_MPC8315) || \
+ defined(CONFIG_MPC834x) || defined(CONFIG_MPC837x)
+ switch ((sccr & SCCR_TSEC2CM) >> SCCR_TSEC2CM_SHIFT) {
+ case 0:
+ tsec2_clk = 0;
+ break;
+ case 1:
+ tsec2_clk = csb_clk;
+ break;
+ case 2:
+ tsec2_clk = csb_clk / 2;
+ break;
+ case 3:
+ tsec2_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_TSEC2CM value */
+ return -4;
+ }
+#elif defined(CONFIG_MPC8313)
+ tsec2_clk = tsec1_clk;
+
+ if (!(sccr & SCCR_TSEC1ON))
+ tsec1_clk = 0;
+ if (!(sccr & SCCR_TSEC2ON))
+ tsec2_clk = 0;
+#endif
+
+#if defined(CONFIG_MPC834x)
+ switch ((sccr & SCCR_USBMPHCM) >> SCCR_USBMPHCM_SHIFT) {
+ case 0:
+ usbmph_clk = 0;
+ break;
+ case 1:
+ usbmph_clk = csb_clk;
+ break;
+ case 2:
+ usbmph_clk = csb_clk / 2;
+ break;
+ case 3:
+ usbmph_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_USBMPHCM value */
+ return -5;
+ }
+
+ if (usbmph_clk != 0 && usbdr_clk != 0 && usbmph_clk != usbdr_clk) {
+ /* if USB MPH clock is not disabled and
+ * USB DR clock is not disabled then
+ * USB MPH & USB DR must have the same rate
+ */
+ return -6;
+ }
+#endif
+#if !defined(CONFIG_MPC8309)
+ switch ((sccr & SCCR_ENCCM) >> SCCR_ENCCM_SHIFT) {
+ case 0:
+ enc_clk = 0;
+ break;
+ case 1:
+ enc_clk = csb_clk;
+ break;
+ case 2:
+ enc_clk = csb_clk / 2;
+ break;
+ case 3:
+ enc_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_ENCCM value */
+ return -7;
+ }
+#endif
+
+#if defined(CONFIG_FSL_ESDHC)
+ switch ((sccr & SCCR_SDHCCM) >> SCCR_SDHCCM_SHIFT) {
+ case 0:
+ sdhc_clk = 0;
+ break;
+ case 1:
+ sdhc_clk = csb_clk;
+ break;
+ case 2:
+ sdhc_clk = csb_clk / 2;
+ break;
+ case 3:
+ sdhc_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_SDHCCM value */
+ return -8;
+ }
+#endif
+#if defined(CONFIG_MPC8315)
+ switch ((sccr & SCCR_TDMCM) >> SCCR_TDMCM_SHIFT) {
+ case 0:
+ tdm_clk = 0;
+ break;
+ case 1:
+ tdm_clk = csb_clk;
+ break;
+ case 2:
+ tdm_clk = csb_clk / 2;
+ break;
+ case 3:
+ tdm_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_TDMCM value */
+ return -8;
+ }
+#endif
+
+#if defined(CONFIG_MPC834x)
+ i2c1_clk = tsec2_clk;
+#elif defined(CONFIG_MPC8360)
+ i2c1_clk = csb_clk;
+#elif defined(CONFIG_MPC832x)
+ i2c1_clk = enc_clk;
+#elif defined(CONFIG_MPC8308) || defined(CONFIG_MPC831x)
+ i2c1_clk = enc_clk;
+#elif defined(CONFIG_FSL_ESDHC)
+ i2c1_clk = sdhc_clk;
+#elif defined(CONFIG_MPC837x)
+ i2c1_clk = enc_clk;
+#elif defined(CONFIG_MPC8309)
+ i2c1_clk = csb_clk;
+#endif
+#if !defined(CONFIG_MPC832x)
+ i2c2_clk = csb_clk; /* i2c-2 clk is equal to csb clk */
+#endif
+
+#if defined(CONFIG_MPC8308) || defined(CONFIG_MPC831x) || \
+ defined(CONFIG_MPC837x)
+ switch ((sccr & SCCR_PCIEXP1CM) >> SCCR_PCIEXP1CM_SHIFT) {
+ case 0:
+ pciexp1_clk = 0;
+ break;
+ case 1:
+ pciexp1_clk = csb_clk;
+ break;
+ case 2:
+ pciexp1_clk = csb_clk / 2;
+ break;
+ case 3:
+ pciexp1_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_PCIEXP1CM value */
+ return -9;
+ }
+
+ switch ((sccr & SCCR_PCIEXP2CM) >> SCCR_PCIEXP2CM_SHIFT) {
+ case 0:
+ pciexp2_clk = 0;
+ break;
+ case 1:
+ pciexp2_clk = csb_clk;
+ break;
+ case 2:
+ pciexp2_clk = csb_clk / 2;
+ break;
+ case 3:
+ pciexp2_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_PCIEXP2CM value */
+ return -10;
+ }
+#endif
+
+#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC8315)
+ switch ((sccr & SCCR_SATA1CM) >> SCCR_SATA1CM_SHIFT) {
+ case 0:
+ sata_clk = 0;
+ break;
+ case 1:
+ sata_clk = csb_clk;
+ break;
+ case 2:
+ sata_clk = csb_clk / 2;
+ break;
+ case 3:
+ sata_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_SATACM value */
+ return -11;
+ }
+#endif
+
+ lbiu_clk = csb_clk *
+ (1 + ((im->clk.spmr & SPMR_LBIUCM) >> SPMR_LBIUCM_SHIFT));
+ lcrr = (im->im_lbc.lcrr & LCRR_CLKDIV) >> LCRR_CLKDIV_SHIFT;
+ switch (lcrr) {
+ case 2:
+ case 4:
+ case 8:
+ lclk_clk = lbiu_clk / lcrr;
+ break;
+ default:
+ /* unknown lcrr */
+ return -12;
+ }
+
+ mem_clk = csb_clk *
+ (1 + ((im->clk.spmr & SPMR_DDRCM) >> SPMR_DDRCM_SHIFT));
+ corepll = (im->clk.spmr & SPMR_COREPLL) >> SPMR_COREPLL_SHIFT;
+
+#if defined(CONFIG_MPC8360)
+ mem_sec_clk = csb_clk * (1 +
+ ((im->clk.spmr & SPMR_LBIUCM) >> SPMR_LBIUCM_SHIFT));
+#endif
+
+ corecnf_tab_index = ((corepll & 0x1F) << 2) | ((corepll & 0x60) >> 5);
+ if (corecnf_tab_index > (sizeof(corecnf_tab) / sizeof(corecnf_t))) {
+ /* corecnf_tab_index is too high, possibly worng value */
+ return -11;
+ }
+ switch (corecnf_tab[corecnf_tab_index].core_csb_ratio) {
+ case _byp:
+ case _x1:
+ case _1x:
+ core_clk = csb_clk;
+ break;
+ case _1_5x:
+ core_clk = (3 * csb_clk) / 2;
+ break;
+ case _2x:
+ core_clk = 2 * csb_clk;
+ break;
+ case _2_5x:
+ core_clk = (5 * csb_clk) / 2;
+ break;
+ case _3x:
+ core_clk = 3 * csb_clk;
+ break;
+ default:
+ /* unkown core to csb ratio */
+ return -13;
+ }
+
+#if defined(CONFIG_QE)
+ qepmf = (im->clk.spmr & SPMR_CEPMF) >> SPMR_CEPMF_SHIFT;
+ qepdf = (im->clk.spmr & SPMR_CEPDF) >> SPMR_CEPDF_SHIFT;
+ qe_clk = (pci_sync_in * qepmf) / (1 + qepdf);
+ brg_clk = qe_clk / 2;
+#endif
+
+ gd->arch.csb_clk = csb_clk;
+#if defined(CONFIG_MPC8308) || defined(CONFIG_MPC831x) || \
+ defined(CONFIG_MPC834x) || defined(CONFIG_MPC837x)
+ gd->arch.tsec1_clk = tsec1_clk;
+ gd->arch.tsec2_clk = tsec2_clk;
+ gd->arch.usbdr_clk = usbdr_clk;
+#elif defined(CONFIG_MPC8309)
+ gd->arch.usbdr_clk = usbdr_clk;
+#endif
+#if defined(CONFIG_MPC834x)
+ gd->arch.usbmph_clk = usbmph_clk;
+#endif
+#if defined(CONFIG_MPC8315)
+ gd->arch.tdm_clk = tdm_clk;
+#endif
+#if defined(CONFIG_FSL_ESDHC)
+ gd->arch.sdhc_clk = sdhc_clk;
+#endif
+ gd->arch.core_clk = core_clk;
+ gd->arch.i2c1_clk = i2c1_clk;
+#if !defined(CONFIG_MPC832x)
+ gd->arch.i2c2_clk = i2c2_clk;
+#endif
+#if !defined(CONFIG_MPC8309)
+ gd->arch.enc_clk = enc_clk;
+#endif
+ gd->arch.lbiu_clk = lbiu_clk;
+ gd->arch.lclk_clk = lclk_clk;
+ gd->mem_clk = mem_clk;
+#if defined(CONFIG_MPC8360)
+ gd->arch.mem_sec_clk = mem_sec_clk;
+#endif
+#if defined(CONFIG_QE)
+ gd->arch.qe_clk = qe_clk;
+ gd->arch.brg_clk = brg_clk;
+#endif
+#if defined(CONFIG_MPC8308) || defined(CONFIG_MPC831x) || \
+ defined(CONFIG_MPC837x)
+ gd->arch.pciexp1_clk = pciexp1_clk;
+ gd->arch.pciexp2_clk = pciexp2_clk;
+#endif
+#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC8315)
+ gd->arch.sata_clk = sata_clk;
+#endif
+ gd->pci_clk = pci_sync_in;
+ gd->cpu_clk = gd->arch.core_clk;
+ gd->bus_clk = gd->arch.csb_clk;
+ return 0;
+
+}
+
+/********************************************
+ * get_bus_freq
+ * return system bus freq in Hz
+ *********************************************/
+ulong get_bus_freq(ulong dummy)
+{
+ return gd->arch.csb_clk;
+}
+
+/********************************************
+ * get_ddr_freq
+ * return ddr bus freq in Hz
+ *********************************************/
+ulong get_ddr_freq(ulong dummy)
+{
+ return gd->mem_clk;
+}
+
+static int do_clocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char buf[32];
+
+ printf("Clock configuration:\n");
+ printf(" Core: %-4s MHz\n",
+ strmhz(buf, gd->arch.core_clk));
+ printf(" Coherent System Bus: %-4s MHz\n",
+ strmhz(buf, gd->arch.csb_clk));
+#if defined(CONFIG_QE)
+ printf(" QE: %-4s MHz\n",
+ strmhz(buf, gd->arch.qe_clk));
+ printf(" BRG: %-4s MHz\n",
+ strmhz(buf, gd->arch.brg_clk));
+#endif
+ printf(" Local Bus Controller:%-4s MHz\n",
+ strmhz(buf, gd->arch.lbiu_clk));
+ printf(" Local Bus: %-4s MHz\n",
+ strmhz(buf, gd->arch.lclk_clk));
+ printf(" DDR: %-4s MHz\n", strmhz(buf, gd->mem_clk));
+#if defined(CONFIG_MPC8360)
+ printf(" DDR Secondary: %-4s MHz\n",
+ strmhz(buf, gd->arch.mem_sec_clk));
+#endif
+#if !defined(CONFIG_MPC8309)
+ printf(" SEC: %-4s MHz\n",
+ strmhz(buf, gd->arch.enc_clk));
+#endif
+ printf(" I2C1: %-4s MHz\n",
+ strmhz(buf, gd->arch.i2c1_clk));
+#if !defined(CONFIG_MPC832x)
+ printf(" I2C2: %-4s MHz\n",
+ strmhz(buf, gd->arch.i2c2_clk));
+#endif
+#if defined(CONFIG_MPC8315)
+ printf(" TDM: %-4s MHz\n",
+ strmhz(buf, gd->arch.tdm_clk));
+#endif
+#if defined(CONFIG_FSL_ESDHC)
+ printf(" SDHC: %-4s MHz\n",
+ strmhz(buf, gd->arch.sdhc_clk));
+#endif
+#if defined(CONFIG_MPC8308) || defined(CONFIG_MPC831x) || \
+ defined(CONFIG_MPC834x) || defined(CONFIG_MPC837x)
+ printf(" TSEC1: %-4s MHz\n",
+ strmhz(buf, gd->arch.tsec1_clk));
+ printf(" TSEC2: %-4s MHz\n",
+ strmhz(buf, gd->arch.tsec2_clk));
+ printf(" USB DR: %-4s MHz\n",
+ strmhz(buf, gd->arch.usbdr_clk));
+#elif defined(CONFIG_MPC8309)
+ printf(" USB DR: %-4s MHz\n",
+ strmhz(buf, gd->arch.usbdr_clk));
+#endif
+#if defined(CONFIG_MPC834x)
+ printf(" USB MPH: %-4s MHz\n",
+ strmhz(buf, gd->arch.usbmph_clk));
+#endif
+#if defined(CONFIG_MPC8308) || defined(CONFIG_MPC831x) || \
+ defined(CONFIG_MPC837x)
+ printf(" PCIEXP1: %-4s MHz\n",
+ strmhz(buf, gd->arch.pciexp1_clk));
+ printf(" PCIEXP2: %-4s MHz\n",
+ strmhz(buf, gd->arch.pciexp2_clk));
+#endif
+#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC8315)
+ printf(" SATA: %-4s MHz\n",
+ strmhz(buf, gd->arch.sata_clk));
+#endif
+ return 0;
+}
+
+U_BOOT_CMD(clocks, 1, 0, do_clocks,
+ "print clock configuration",
+ " clocks"
+);
diff --git a/arch/powerpc/cpu/mpc83xx/spl_minimal.c b/arch/powerpc/cpu/mpc83xx/spl_minimal.c
new file mode 100644
index 0000000..d1648b7
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/spl_minimal.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2004-2008 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc83xx.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Breathe some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers,
+ * initialize the UPM's
+ */
+void cpu_init_f (volatile immap_t * im)
+{
+ int i;
+
+ /* Pointer is writable since we allocated a register for it */
+ gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+ /* Clear initial global data */
+ for (i = 0; i < sizeof(gd_t); i++)
+ ((char *)gd)[i] = 0;
+
+ /* system performance tweaking */
+
+#ifdef CONFIG_SYS_ACR_PIPE_DEP
+ /* Arbiter pipeline depth */
+ im->arbiter.acr = (im->arbiter.acr & ~ACR_PIPE_DEP) |
+ (CONFIG_SYS_ACR_PIPE_DEP << ACR_PIPE_DEP_SHIFT);
+#endif
+
+#ifdef CONFIG_SYS_ACR_RPTCNT
+ /* Arbiter repeat count */
+ im->arbiter.acr = (im->arbiter.acr & ~(ACR_RPTCNT)) |
+ (CONFIG_SYS_ACR_RPTCNT << ACR_RPTCNT_SHIFT);
+#endif
+
+#ifdef CONFIG_SYS_SPCR_OPT
+ /* Optimize transactions between CSB and other devices */
+ im->sysconf.spcr = (im->sysconf.spcr & ~SPCR_OPT) |
+ (CONFIG_SYS_SPCR_OPT << SPCR_OPT_SHIFT);
+#endif
+
+ /* Enable Time Base & Decrimenter (so we will have udelay()) */
+ im->sysconf.spcr |= SPCR_TBEN;
+
+ /* DDR control driver register */
+#ifdef CONFIG_SYS_DDRCDR
+ im->sysconf.ddrcdr = CONFIG_SYS_DDRCDR;
+#endif
+ /* Output buffer impedance register */
+#ifdef CONFIG_SYS_OBIR
+ im->sysconf.obir = CONFIG_SYS_OBIR;
+#endif
+
+ /*
+ * Memory Controller:
+ */
+
+ /* Map banks 0 and 1 to the FLASH banks 0 and 1 at preliminary
+ * addresses - these have to be modified later when FLASH size
+ * has been determined
+ */
+
+#if defined(CONFIG_SYS_NAND_BR_PRELIM) \
+ && defined(CONFIG_SYS_NAND_OR_PRELIM) \
+ && defined(CONFIG_SYS_NAND_LBLAWBAR_PRELIM) \
+ && defined(CONFIG_SYS_NAND_LBLAWAR_PRELIM)
+ set_lbc_br(0, CONFIG_SYS_NAND_BR_PRELIM);
+ set_lbc_or(0, CONFIG_SYS_NAND_OR_PRELIM);
+ im->sysconf.lblaw[0].bar = CONFIG_SYS_NAND_LBLAWBAR_PRELIM;
+ im->sysconf.lblaw[0].ar = CONFIG_SYS_NAND_LBLAWAR_PRELIM;
+#else
+#error CONFIG_SYS_NAND_BR_PRELIM, CONFIG_SYS_NAND_OR_PRELIM, CONFIG_SYS_NAND_LBLAWBAR_PRELIM & CONFIG_SYS_NAND_LBLAWAR_PRELIM must be defined
+#endif
+}
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ */
+unsigned long get_tbclk(void)
+{
+ return (gd->bus_clk + 3L) / 4L;
+}
+
+void puts(const char *str)
+{
+ while (*str)
+ putc(*str++);
+}
diff --git a/arch/powerpc/cpu/mpc83xx/start.S b/arch/powerpc/cpu/mpc83xx/start.S
new file mode 100644
index 0000000..1bfc971
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/start.S
@@ -0,0 +1,1211 @@
+/*
+ * Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2000, 2001,2002 Wolfgang Denk <wd@denx.de>
+ * Copyright Freescale Semiconductor, Inc. 2004, 2006, 2008.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * U-Boot - Startup Code for MPC83xx PowerPC based Embedded Boards
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <mpc83xx.h>
+#ifndef CONFIG_IDENT_STRING
+#define CONFIG_IDENT_STRING "MPC83XX"
+#endif
+#include <version.h>
+
+#define CONFIG_83XX 1 /* needed for Linux kernel header files*/
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+#include <asm/u-boot.h>
+
+/* We don't want the MMU yet.
+ */
+#undef MSR_KERNEL
+
+/*
+ * Floating Point enable, Machine Check and Recoverable Interr.
+ */
+#ifdef DEBUG
+#define MSR_KERNEL (MSR_FP|MSR_RI)
+#else
+#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI)
+#endif
+
+#if defined(CONFIG_NAND_SPL) || \
+ (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_INIT_MINIMAL))
+#define MINIMAL_SPL
+#endif
+
+#if !defined(CONFIG_SPL_BUILD) && !defined(CONFIG_NAND_SPL) && \
+ !defined(CONFIG_SYS_RAMBOOT)
+#define CONFIG_SYS_FLASHBOOT
+#endif
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+ START_GOT
+ GOT_ENTRY(_GOT2_TABLE_)
+ GOT_ENTRY(__bss_start)
+ GOT_ENTRY(__bss_end)
+
+#ifndef MINIMAL_SPL
+ GOT_ENTRY(_FIXUP_TABLE_)
+ GOT_ENTRY(_start)
+ GOT_ENTRY(_start_of_vectors)
+ GOT_ENTRY(_end_of_vectors)
+ GOT_ENTRY(transfer_to_handler)
+#endif
+ END_GOT
+
+/*
+ * The Hard Reset Configuration Word (HRCW) table is in the first 64
+ * (0x40) bytes of flash. It has 8 bytes, but each byte is repeated 8
+ * times so the processor can fetch it out of flash whether the flash
+ * is 8, 16, 32, or 64 bits wide (hardware trickery).
+ */
+ .text
+#define _HRCW_TABLE_ENTRY(w) \
+ .fill 8,1,(((w)>>24)&0xff); \
+ .fill 8,1,(((w)>>16)&0xff); \
+ .fill 8,1,(((w)>> 8)&0xff); \
+ .fill 8,1,(((w) )&0xff)
+
+ _HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_LOW)
+ _HRCW_TABLE_ENTRY(CONFIG_SYS_HRCW_HIGH)
+
+/*
+ * Magic number and version string - put it after the HRCW since it
+ * cannot be first in flash like it is in many other processors.
+ */
+ .long 0x27051956 /* U-Boot Magic Number */
+
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION_STRING, "\0"
+
+ .align 2
+
+ .globl enable_addr_trans
+enable_addr_trans:
+ /* enable address translation */
+ mfmsr r5
+ ori r5, r5, (MSR_IR | MSR_DR)
+ mtmsr r5
+ isync
+ blr
+
+ .globl disable_addr_trans
+disable_addr_trans:
+ /* disable address translation */
+ mflr r4
+ mfmsr r3
+ andi. r0, r3, (MSR_IR | MSR_DR)
+ beqlr
+ andc r3, r3, r0
+ mtspr SRR0, r4
+ mtspr SRR1, r3
+ rfi
+
+ .globl get_pvr
+get_pvr:
+ mfspr r3, PVR
+ blr
+
+ .globl ppcDWstore
+ppcDWstore:
+ lfd 1, 0(r4)
+ stfd 1, 0(r3)
+ blr
+
+ .globl ppcDWload
+ppcDWload:
+ lfd 1, 0(r3)
+ stfd 1, 0(r4)
+ blr
+
+#ifndef CONFIG_DEFAULT_IMMR
+#error CONFIG_DEFAULT_IMMR must be defined
+#endif /* CONFIG_SYS_DEFAULT_IMMR */
+#ifndef CONFIG_SYS_IMMR
+#define CONFIG_SYS_IMMR CONFIG_DEFAULT_IMMR
+#endif /* CONFIG_SYS_IMMR */
+
+/*
+ * After configuration, a system reset exception is executed using the
+ * vector at offset 0x100 relative to the base set by MSR[IP]. If
+ * MSR[IP] is 0, the base address is 0x00000000. If MSR[IP] is 1, the
+ * base address is 0xfff00000. In the case of a Power On Reset or Hard
+ * Reset, the value of MSR[IP] is determined by the CIP field in the
+ * HRCW.
+ *
+ * Other bits in the HRCW set up the Base Address and Port Size in BR0.
+ * This determines the location of the boot ROM (flash or EPROM) in the
+ * processor's address space at boot time. As long as the HRCW is set up
+ * so that we eventually end up executing the code below when the
+ * processor executes the reset exception, the actual values used should
+ * not matter.
+ *
+ * Once we have got here, the address mask in OR0 is cleared so that the
+ * bottom 32K of the boot ROM is effectively repeated all throughout the
+ * processor's address space, after which we can jump to the absolute
+ * address at which the boot ROM was linked at compile time, and proceed
+ * to initialise the memory controller without worrying if the rug will
+ * be pulled out from under us, so to speak (it will be fine as long as
+ * we configure BR0 with the same boot ROM link address).
+ */
+ . = EXC_OFF_SYS_RESET
+
+ .globl _start
+_start: /* time t 0 */
+ lis r4, CONFIG_DEFAULT_IMMR@h
+ nop
+
+ mfmsr r5 /* save msr contents */
+
+ /* 83xx manuals prescribe a specific sequence for updating IMMRBAR. */
+ bl 1f
+1: mflr r7
+
+ lis r3, CONFIG_SYS_IMMR@h
+ ori r3, r3, CONFIG_SYS_IMMR@l
+
+ lwz r6, IMMRBAR(r4)
+ isync
+
+ stw r3, IMMRBAR(r4)
+ lwz r6, 0(r7) /* Arbitrary external load */
+ isync
+
+ lwz r6, IMMRBAR(r3)
+ isync
+
+ /* Initialise the E300 processor core */
+ /*------------------------------------------*/
+
+#if (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_MPC83XX_WAIT_FOR_NAND)) || \
+ defined(CONFIG_NAND_SPL)
+ /* The FCM begins execution after only the first page
+ * is loaded. Wait for the rest before branching
+ * to another flash page.
+ */
+1: lwz r6, 0x50b0(r3)
+ andi. r6, r6, 1
+ beq 1b
+#endif
+
+ bl init_e300_core
+
+#ifdef CONFIG_SYS_FLASHBOOT
+
+ /* Inflate flash location so it appears everywhere, calculate */
+ /* the absolute address in final location of the FLASH, jump */
+ /* there and deflate the flash size back to minimal size */
+ /*------------------------------------------------------------*/
+ bl map_flash_by_law1
+ lis r4, (CONFIG_SYS_MONITOR_BASE)@h
+ ori r4, r4, (CONFIG_SYS_MONITOR_BASE)@l
+ addi r5, r4, in_flash - _start + EXC_OFF_SYS_RESET
+ mtlr r5
+ blr
+in_flash:
+#if 1 /* Remapping flash with LAW0. */
+ bl remap_flash_by_law0
+#endif
+#endif /* CONFIG_SYS_FLASHBOOT */
+
+ /* setup the bats */
+ bl setup_bats
+ sync
+
+ /*
+ * Cache must be enabled here for stack-in-cache trick.
+ * This means we need to enable the BATS.
+ * This means:
+ * 1) for the EVB, original gt regs need to be mapped
+ * 2) need to have an IBAT for the 0xf region,
+ * we are running there!
+ * Cache should be turned on after BATs, since by default
+ * everything is write-through.
+ * The init-mem BAT can be reused after reloc. The old
+ * gt-regs BAT can be reused after board_init_f calls
+ * board_early_init_f (EVB only).
+ */
+ /* enable address translation */
+ bl enable_addr_trans
+ sync
+
+ /* enable the data cache */
+ bl dcache_enable
+ sync
+#ifdef CONFIG_SYS_INIT_RAM_LOCK
+ bl lock_ram_in_cache
+ sync
+#endif
+
+ /* set up the stack pointer in our newly created
+ * cache-ram (r1) */
+ lis r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@h
+ ori r1, r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@l
+
+ li r0, 0 /* Make room for stack frame header and */
+ stwu r0, -4(r1) /* clear final stack frame so that */
+ stwu r0, -4(r1) /* stack backtraces terminate cleanly */
+
+
+ /* let the C-code set up the rest */
+ /* */
+ /* Be careful to keep code relocatable & stack humble */
+ /*------------------------------------------------------*/
+
+ GET_GOT /* initialize GOT access */
+
+ /* r3: IMMR */
+ lis r3, CONFIG_SYS_IMMR@h
+ /* run low-level CPU init code (in Flash)*/
+ bl cpu_init_f
+
+ /* run 1st part of board init code (in Flash)*/
+ bl board_init_f
+
+ /* NOTREACHED - board_init_f() does not return */
+
+#ifndef MINIMAL_SPL
+/*
+ * Vector Table
+ */
+
+ .globl _start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. */
+ STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+ STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+#ifndef FIXME
+ STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+#endif
+
+/* Alignment exception. */
+ . = 0x600
+Alignment:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+ . = 0x700
+ProgramCheck:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+ MSR_KERNEL, COPY_EE)
+
+ STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+ /* I guess we could implement decrementer, and may have
+ * to someday for timekeeping.
+ */
+ STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+
+ STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+ STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+ STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+ STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+ STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+ STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+ STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException)
+#ifdef DEBUG
+ . = 0x1300
+ /*
+ * This exception occurs when the program counter matches the
+ * Instruction Address Breakpoint Register (IABR).
+ *
+ * I want the cpu to halt if this occurs so I can hunt around
+ * with the debugger and look at things.
+ *
+ * When DEBUG is defined, both machine check enable (in the MSR)
+ * and checkstop reset enable (in the reset mode register) are
+ * turned off and so a checkstop condition will result in the cpu
+ * halting.
+ *
+ * I force the cpu into a checkstop condition by putting an illegal
+ * instruction here (at least this is the theory).
+ *
+ * well - that didnt work, so just do an infinite loop!
+ */
+1: b 1b
+#else
+ STD_EXCEPTION(0x1300, InstructionBreakpoint, DebugException)
+#endif
+ STD_EXCEPTION(0x1400, SMI, UnknownException)
+
+ STD_EXCEPTION(0x1500, Trap_15, UnknownException)
+ STD_EXCEPTION(0x1600, Trap_16, UnknownException)
+ STD_EXCEPTION(0x1700, Trap_17, UnknownException)
+ STD_EXCEPTION(0x1800, Trap_18, UnknownException)
+ STD_EXCEPTION(0x1900, Trap_19, UnknownException)
+ STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
+ STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+ STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
+ STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
+ STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
+ STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
+ STD_EXCEPTION(0x2000, Trap_20, UnknownException)
+ STD_EXCEPTION(0x2100, Trap_21, UnknownException)
+ STD_EXCEPTION(0x2200, Trap_22, UnknownException)
+ STD_EXCEPTION(0x2300, Trap_23, UnknownException)
+ STD_EXCEPTION(0x2400, Trap_24, UnknownException)
+ STD_EXCEPTION(0x2500, Trap_25, UnknownException)
+ STD_EXCEPTION(0x2600, Trap_26, UnknownException)
+ STD_EXCEPTION(0x2700, Trap_27, UnknownException)
+ STD_EXCEPTION(0x2800, Trap_28, UnknownException)
+ STD_EXCEPTION(0x2900, Trap_29, UnknownException)
+ STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
+ STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
+ STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
+ STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
+ STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
+ STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
+
+
+ .globl _end_of_vectors
+_end_of_vectors:
+
+ . = 0x3000
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+ .globl transfer_to_handler
+transfer_to_handler:
+ stw r22,_NIP(r21)
+ lis r22,MSR_POW@h
+ andc r23,r23,r22
+ stw r23,_MSR(r21)
+ SAVE_GPR(7, r21)
+ SAVE_4GPRS(8, r21)
+ SAVE_8GPRS(12, r21)
+ SAVE_8GPRS(24, r21)
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
+
+int_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+#endif /* !MINIMAL_SPL */
+
+/*
+ * This code initialises the E300 processor core
+ * (conforms to PowerPC 603e spec)
+ * Note: expects original MSR contents to be in r5.
+ */
+ .globl init_e300_core
+init_e300_core: /* time t 10 */
+ /* Initialize machine status; enable machine check interrupt */
+ /*-----------------------------------------------------------*/
+
+ li r3, MSR_KERNEL /* Set ME and RI flags */
+ rlwimi r3, r5, 0, 25, 25 /* preserve IP bit set by HRCW */
+#ifdef DEBUG
+ rlwimi r3, r5, 0, 21, 22 /* debugger might set SE & BE bits */
+#endif
+ SYNC /* Some chip revs need this... */
+ mtmsr r3
+ SYNC
+ mtspr SRR1, r3 /* Make SRR1 match MSR */
+
+
+ lis r3, CONFIG_SYS_IMMR@h
+#if defined(CONFIG_WATCHDOG)
+ /* Initialise the Watchdog values and reset it (if req) */
+ /*------------------------------------------------------*/
+ lis r4, CONFIG_SYS_WATCHDOG_VALUE
+ ori r4, r4, (SWCRR_SWEN | SWCRR_SWRI | SWCRR_SWPR)
+ stw r4, SWCRR(r3)
+
+ /* and reset it */
+
+ li r4, 0x556C
+ sth r4, SWSRR@l(r3)
+ li r4, -0x55C7
+ sth r4, SWSRR@l(r3)
+#else
+ /* Disable Watchdog */
+ /*-------------------*/
+ lwz r4, SWCRR(r3)
+ /* Check to see if its enabled for disabling
+ once disabled by SW you can't re-enable */
+ andi. r4, r4, 0x4
+ beq 1f
+ xor r4, r4, r4
+ stw r4, SWCRR(r3)
+1:
+#endif /* CONFIG_WATCHDOG */
+
+#if defined(CONFIG_MASK_AER_AO)
+ /* Write the Arbiter Event Enable to mask Address Only traps. */
+ /* This prevents the dcbz instruction from being trapped when */
+ /* HID0_ABE Address Broadcast Enable is set and the MEMORY */
+ /* COHERENCY bit is set in the WIMG bits, which is often */
+ /* needed for PCI operation. */
+ lwz r4, 0x0808(r3)
+ rlwinm r0, r4, 0, ~AER_AO
+ stw r0, 0x0808(r3)
+#endif /* CONFIG_MASK_AER_AO */
+
+ /* Initialize the Hardware Implementation-dependent Registers */
+ /* HID0 also contains cache control */
+ /* - force invalidation of data and instruction caches */
+ /*------------------------------------------------------*/
+
+ lis r3, CONFIG_SYS_HID0_INIT@h
+ ori r3, r3, (CONFIG_SYS_HID0_INIT | HID0_ICFI | HID0_DCFI)@l
+ SYNC
+ mtspr HID0, r3
+
+ lis r3, CONFIG_SYS_HID0_FINAL@h
+ ori r3, r3, (CONFIG_SYS_HID0_FINAL & ~(HID0_ICFI | HID0_DCFI))@l
+ SYNC
+ mtspr HID0, r3
+
+ lis r3, CONFIG_SYS_HID2@h
+ ori r3, r3, CONFIG_SYS_HID2@l
+ SYNC
+ mtspr HID2, r3
+
+ /* Done! */
+ /*------------------------------*/
+ blr
+
+ /* setup_bats - set them up to some initial state */
+ .globl setup_bats
+setup_bats:
+ addis r0, r0, 0x0000
+
+ /* IBAT 0 */
+ addis r4, r0, CONFIG_SYS_IBAT0L@h
+ ori r4, r4, CONFIG_SYS_IBAT0L@l
+ addis r3, r0, CONFIG_SYS_IBAT0U@h
+ ori r3, r3, CONFIG_SYS_IBAT0U@l
+ mtspr IBAT0L, r4
+ mtspr IBAT0U, r3
+
+ /* DBAT 0 */
+ addis r4, r0, CONFIG_SYS_DBAT0L@h
+ ori r4, r4, CONFIG_SYS_DBAT0L@l
+ addis r3, r0, CONFIG_SYS_DBAT0U@h
+ ori r3, r3, CONFIG_SYS_DBAT0U@l
+ mtspr DBAT0L, r4
+ mtspr DBAT0U, r3
+
+ /* IBAT 1 */
+ addis r4, r0, CONFIG_SYS_IBAT1L@h
+ ori r4, r4, CONFIG_SYS_IBAT1L@l
+ addis r3, r0, CONFIG_SYS_IBAT1U@h
+ ori r3, r3, CONFIG_SYS_IBAT1U@l
+ mtspr IBAT1L, r4
+ mtspr IBAT1U, r3
+
+ /* DBAT 1 */
+ addis r4, r0, CONFIG_SYS_DBAT1L@h
+ ori r4, r4, CONFIG_SYS_DBAT1L@l
+ addis r3, r0, CONFIG_SYS_DBAT1U@h
+ ori r3, r3, CONFIG_SYS_DBAT1U@l
+ mtspr DBAT1L, r4
+ mtspr DBAT1U, r3
+
+ /* IBAT 2 */
+ addis r4, r0, CONFIG_SYS_IBAT2L@h
+ ori r4, r4, CONFIG_SYS_IBAT2L@l
+ addis r3, r0, CONFIG_SYS_IBAT2U@h
+ ori r3, r3, CONFIG_SYS_IBAT2U@l
+ mtspr IBAT2L, r4
+ mtspr IBAT2U, r3
+
+ /* DBAT 2 */
+ addis r4, r0, CONFIG_SYS_DBAT2L@h
+ ori r4, r4, CONFIG_SYS_DBAT2L@l
+ addis r3, r0, CONFIG_SYS_DBAT2U@h
+ ori r3, r3, CONFIG_SYS_DBAT2U@l
+ mtspr DBAT2L, r4
+ mtspr DBAT2U, r3
+
+ /* IBAT 3 */
+ addis r4, r0, CONFIG_SYS_IBAT3L@h
+ ori r4, r4, CONFIG_SYS_IBAT3L@l
+ addis r3, r0, CONFIG_SYS_IBAT3U@h
+ ori r3, r3, CONFIG_SYS_IBAT3U@l
+ mtspr IBAT3L, r4
+ mtspr IBAT3U, r3
+
+ /* DBAT 3 */
+ addis r4, r0, CONFIG_SYS_DBAT3L@h
+ ori r4, r4, CONFIG_SYS_DBAT3L@l
+ addis r3, r0, CONFIG_SYS_DBAT3U@h
+ ori r3, r3, CONFIG_SYS_DBAT3U@l
+ mtspr DBAT3L, r4
+ mtspr DBAT3U, r3
+
+#ifdef CONFIG_HIGH_BATS
+ /* IBAT 4 */
+ addis r4, r0, CONFIG_SYS_IBAT4L@h
+ ori r4, r4, CONFIG_SYS_IBAT4L@l
+ addis r3, r0, CONFIG_SYS_IBAT4U@h
+ ori r3, r3, CONFIG_SYS_IBAT4U@l
+ mtspr IBAT4L, r4
+ mtspr IBAT4U, r3
+
+ /* DBAT 4 */
+ addis r4, r0, CONFIG_SYS_DBAT4L@h
+ ori r4, r4, CONFIG_SYS_DBAT4L@l
+ addis r3, r0, CONFIG_SYS_DBAT4U@h
+ ori r3, r3, CONFIG_SYS_DBAT4U@l
+ mtspr DBAT4L, r4
+ mtspr DBAT4U, r3
+
+ /* IBAT 5 */
+ addis r4, r0, CONFIG_SYS_IBAT5L@h
+ ori r4, r4, CONFIG_SYS_IBAT5L@l
+ addis r3, r0, CONFIG_SYS_IBAT5U@h
+ ori r3, r3, CONFIG_SYS_IBAT5U@l
+ mtspr IBAT5L, r4
+ mtspr IBAT5U, r3
+
+ /* DBAT 5 */
+ addis r4, r0, CONFIG_SYS_DBAT5L@h
+ ori r4, r4, CONFIG_SYS_DBAT5L@l
+ addis r3, r0, CONFIG_SYS_DBAT5U@h
+ ori r3, r3, CONFIG_SYS_DBAT5U@l
+ mtspr DBAT5L, r4
+ mtspr DBAT5U, r3
+
+ /* IBAT 6 */
+ addis r4, r0, CONFIG_SYS_IBAT6L@h
+ ori r4, r4, CONFIG_SYS_IBAT6L@l
+ addis r3, r0, CONFIG_SYS_IBAT6U@h
+ ori r3, r3, CONFIG_SYS_IBAT6U@l
+ mtspr IBAT6L, r4
+ mtspr IBAT6U, r3
+
+ /* DBAT 6 */
+ addis r4, r0, CONFIG_SYS_DBAT6L@h
+ ori r4, r4, CONFIG_SYS_DBAT6L@l
+ addis r3, r0, CONFIG_SYS_DBAT6U@h
+ ori r3, r3, CONFIG_SYS_DBAT6U@l
+ mtspr DBAT6L, r4
+ mtspr DBAT6U, r3
+
+ /* IBAT 7 */
+ addis r4, r0, CONFIG_SYS_IBAT7L@h
+ ori r4, r4, CONFIG_SYS_IBAT7L@l
+ addis r3, r0, CONFIG_SYS_IBAT7U@h
+ ori r3, r3, CONFIG_SYS_IBAT7U@l
+ mtspr IBAT7L, r4
+ mtspr IBAT7U, r3
+
+ /* DBAT 7 */
+ addis r4, r0, CONFIG_SYS_DBAT7L@h
+ ori r4, r4, CONFIG_SYS_DBAT7L@l
+ addis r3, r0, CONFIG_SYS_DBAT7U@h
+ ori r3, r3, CONFIG_SYS_DBAT7U@l
+ mtspr DBAT7L, r4
+ mtspr DBAT7U, r3
+#endif
+
+ isync
+
+ /* invalidate all tlb's
+ *
+ * From the 603e User Manual: "The 603e provides the ability to
+ * invalidate a TLB entry. The TLB Invalidate Entry (tlbie)
+ * instruction invalidates the TLB entry indexed by the EA, and
+ * operates on both the instruction and data TLBs simultaneously
+ * invalidating four TLB entries (both sets in each TLB). The
+ * index corresponds to bits 15-19 of the EA. To invalidate all
+ * entries within both TLBs, 32 tlbie instructions should be
+ * issued, incrementing this field by one each time."
+ *
+ * "Note that the tlbia instruction is not implemented on the
+ * 603e."
+ *
+ * bits 15-19 correspond to addresses 0x00000000 to 0x0001F000
+ * incrementing by 0x1000 each time. The code below is sort of
+ * based on code in "flush_tlbs" from arch/powerpc/kernel/head.S
+ *
+ */
+ lis r3, 0
+ lis r5, 2
+
+1:
+ tlbie r3
+ addi r3, r3, 0x1000
+ cmp 0, 0, r3, r5
+ blt 1b
+
+ blr
+
+/* Cache functions.
+ *
+ * Note: requires that all cache bits in
+ * HID0 are in the low half word.
+ */
+#ifndef MINIMAL_SPL
+ .globl icache_enable
+icache_enable:
+ mfspr r3, HID0
+ ori r3, r3, HID0_ICE
+ li r4, HID0_ICFI|HID0_ILOCK
+ andc r3, r3, r4
+ ori r4, r3, HID0_ICFI
+ isync
+ mtspr HID0, r4 /* sets enable and invalidate, clears lock */
+ isync
+ mtspr HID0, r3 /* clears invalidate */
+ blr
+
+ .globl icache_disable
+icache_disable:
+ mfspr r3, HID0
+ lis r4, 0
+ ori r4, r4, HID0_ICE|HID0_ICFI|HID0_ILOCK
+ andc r3, r3, r4
+ isync
+ mtspr HID0, r3 /* clears invalidate, enable and lock */
+ blr
+
+ .globl icache_status
+icache_status:
+ mfspr r3, HID0
+ rlwinm r3, r3, (31 - HID0_ICE_SHIFT + 1), 31, 31
+ blr
+#endif /* !MINIMAL_SPL */
+
+ .globl dcache_enable
+dcache_enable:
+ mfspr r3, HID0
+ li r5, HID0_DCFI|HID0_DLOCK
+ andc r3, r3, r5
+ ori r3, r3, HID0_DCE
+ sync
+ mtspr HID0, r3 /* enable, no invalidate */
+ blr
+
+ .globl dcache_disable
+dcache_disable:
+ mflr r4
+ bl flush_dcache /* uses r3 and r5 */
+ mfspr r3, HID0
+ li r5, HID0_DCE|HID0_DLOCK
+ andc r3, r3, r5
+ ori r5, r3, HID0_DCFI
+ sync
+ mtspr HID0, r5 /* sets invalidate, clears enable and lock */
+ sync
+ mtspr HID0, r3 /* clears invalidate */
+ mtlr r4
+ blr
+
+ .globl dcache_status
+dcache_status:
+ mfspr r3, HID0
+ rlwinm r3, r3, (31 - HID0_DCE_SHIFT + 1), 31, 31
+ blr
+
+ .globl flush_dcache
+flush_dcache:
+ lis r3, 0
+ lis r5, CONFIG_SYS_CACHELINE_SIZE
+1: cmp 0, 1, r3, r5
+ bge 2f
+ lwz r5, 0(r3)
+ lis r5, CONFIG_SYS_CACHELINE_SIZE
+ addi r3, r3, 0x4
+ b 1b
+2: blr
+
+/*-------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+ .globl relocate_code
+relocate_code:
+ mr r1, r3 /* Set new stack pointer */
+ mr r9, r4 /* Save copy of Global Data pointer */
+ mr r10, r5 /* Save copy of Destination Address */
+
+ GET_GOT
+ mr r3, r5 /* Destination Address */
+ lis r4, CONFIG_SYS_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CONFIG_SYS_MONITOR_BASE@l
+ lwz r5, GOT(__bss_start)
+ sub r5, r5, r4
+ li r6, CONFIG_SYS_CACHELINE_SIZE /* Cache Line Size */
+
+ /*
+ * Fix GOT pointer:
+ *
+ * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE)
+ * + Destination Address
+ *
+ * Offset:
+ */
+ sub r15, r10, r4
+
+ /* First our own GOT */
+ add r12, r12, r15
+ /* then the one used by the C code */
+ add r30, r30, r15
+
+ /*
+ * Now relocate code
+ */
+
+ cmplw cr1,r3,r4
+ addi r0,r5,3
+ srwi. r0,r0,2
+ beq cr1,4f /* In place copy is not necessary */
+ beq 7f /* Protect against 0 count */
+ mtctr r0
+ bge cr1,2f
+ la r8,-4(r4)
+ la r7,-4(r3)
+
+ /* copy */
+1: lwzu r0,4(r8)
+ stwu r0,4(r7)
+ bdnz 1b
+
+ addi r0,r5,3
+ srwi. r0,r0,2
+ mtctr r0
+ la r8,-4(r4)
+ la r7,-4(r3)
+
+ /* and compare */
+20: lwzu r20,4(r8)
+ lwzu r21,4(r7)
+ xor. r22, r20, r21
+ bne 30f
+ bdnz 20b
+ b 4f
+
+ /* compare failed */
+30: li r3, 0
+ blr
+
+2: slwi r0,r0,2 /* re copy in reverse order ... y do we needed it? */
+ add r8,r4,r0
+ add r7,r3,r0
+3: lwzu r0,-4(r8)
+ stwu r0,-4(r7)
+ bdnz 3b
+
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4: cmpwi r6,0
+ add r5,r3,r5
+ beq 7f /* Always flush prefetch queue in any case */
+ subi r0,r6,1
+ andc r3,r3,r0
+ mr r4,r3
+5: dcbst 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 5b
+ sync /* Wait for all dcbst to complete on bus */
+ mr r4,r3
+6: icbi 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 6b
+7: sync /* Wait for all icbi to complete on bus */
+ isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+ addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+ mtlr r0
+ blr
+
+in_ram:
+
+ /*
+ * Relocation Function, r12 point to got2+0x8000
+ *
+ * Adjust got2 pointers, no need to check for 0, this code
+ * already puts a few entries in the table.
+ */
+ li r0,__got2_entries@sectoff@l
+ la r3,GOT(_GOT2_TABLE_)
+ lwz r11,GOT(_GOT2_TABLE_)
+ mtctr r0
+ sub r11,r3,r11
+ addi r3,r3,-4
+1: lwzu r0,4(r3)
+ cmpwi r0,0
+ beq- 2f
+ add r0,r0,r11
+ stw r0,0(r3)
+2: bdnz 1b
+
+#ifndef MINIMAL_SPL
+ /*
+ * Now adjust the fixups and the pointers to the fixups
+ * in case we need to move ourselves again.
+ */
+ li r0,__fixup_entries@sectoff@l
+ lwz r3,GOT(_FIXUP_TABLE_)
+ cmpwi r0,0
+ mtctr r0
+ addi r3,r3,-4
+ beq 4f
+3: lwzu r4,4(r3)
+ lwzux r0,r4,r11
+ cmpwi r0,0
+ add r0,r0,r11
+ stw r4,0(r3)
+ beq- 5f
+ stw r0,0(r4)
+5: bdnz 3b
+4:
+#endif
+
+clear_bss:
+ /*
+ * Now clear BSS segment
+ */
+ lwz r3,GOT(__bss_start)
+#if defined(CONFIG_HYMOD)
+ /*
+ * For HYMOD - the environment is the very last item in flash.
+ * The real .bss stops just before environment starts, so only
+ * clear up to that point.
+ *
+ * taken from mods for FADS board
+ */
+ lwz r4,GOT(environment)
+#else
+ lwz r4,GOT(__bss_end)
+#endif
+
+ cmplw 0, r3, r4
+ beq 6f
+
+ li r0, 0
+5:
+ stw r0, 0(r3)
+ addi r3, r3, 4
+ cmplw 0, r3, r4
+ bne 5b
+6:
+
+ mr r3, r9 /* Global Data pointer */
+ mr r4, r10 /* Destination Address */
+ bl board_init_r
+
+#ifndef MINIMAL_SPL
+ /*
+ * Copy exception vector code to low memory
+ *
+ * r3: dest_addr
+ * r7: source address, r8: end address, r9: target address
+ */
+ .globl trap_init
+trap_init:
+ mflr r4 /* save link register */
+ GET_GOT
+ lwz r7, GOT(_start)
+ lwz r8, GOT(_end_of_vectors)
+
+ li r9, 0x100 /* reset vector always at 0x100 */
+
+ cmplw 0, r7, r8
+ bgelr /* return if r7>=r8 - just in case */
+1:
+ lwz r0, 0(r7)
+ stw r0, 0(r9)
+ addi r7, r7, 4
+ addi r9, r9, 4
+ cmplw 0, r7, r8
+ bne 1b
+
+ /*
+ * relocate `hdlr' and `int_return' entries
+ */
+ li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+ li r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 2b
+
+ li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+ li r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 3b
+
+ li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+ li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 4b
+
+ mfmsr r3 /* now that the vectors have */
+ lis r7, MSR_IP@h /* relocated into low memory */
+ ori r7, r7, MSR_IP@l /* MSR[IP] can be turned off */
+ andc r3, r3, r7 /* (if it was on) */
+ SYNC /* Some chip revs need this... */
+ mtmsr r3
+ SYNC
+
+ mtlr r4 /* restore link register */
+ blr
+
+#endif /* !MINIMAL_SPL */
+
+#ifdef CONFIG_SYS_INIT_RAM_LOCK
+lock_ram_in_cache:
+ /* Allocate Initial RAM in data cache.
+ */
+ lis r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@h
+ ori r3, r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@l
+ li r4, ((CONFIG_SYS_INIT_RAM_SIZE & ~31) + \
+ (CONFIG_SYS_INIT_RAM_ADDR & 31) + 31) / 32
+ mtctr r4
+1:
+ dcbz r0, r3
+ addi r3, r3, 32
+ bdnz 1b
+
+ /* Lock the data cache */
+ mfspr r0, HID0
+ ori r0, r0, HID0_DLOCK
+ sync
+ mtspr HID0, r0
+ sync
+ blr
+
+#ifndef MINIMAL_SPL
+.globl unlock_ram_in_cache
+unlock_ram_in_cache:
+ /* invalidate the INIT_RAM section */
+ lis r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@h
+ ori r3, r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@l
+ li r4, ((CONFIG_SYS_INIT_RAM_SIZE & ~31) + \
+ (CONFIG_SYS_INIT_RAM_ADDR & 31) + 31) / 32
+ mtctr r4
+1: icbi r0, r3
+ dcbi r0, r3
+ addi r3, r3, 32
+ bdnz 1b
+ sync /* Wait for all icbi to complete on bus */
+ isync
+
+ /* Unlock the data cache and invalidate it */
+ mfspr r3, HID0
+ li r5, HID0_DLOCK|HID0_DCFI
+ andc r3, r3, r5 /* no invalidate, unlock */
+ ori r5, r3, HID0_DCFI /* invalidate, unlock */
+ sync
+ mtspr HID0, r5 /* invalidate, unlock */
+ sync
+ mtspr HID0, r3 /* no invalidate, unlock */
+ blr
+#endif /* !MINIMAL_SPL */
+#endif /* CONFIG_SYS_INIT_RAM_LOCK */
+
+#ifdef CONFIG_SYS_FLASHBOOT
+map_flash_by_law1:
+ /* When booting from ROM (Flash or EPROM), clear the */
+ /* Address Mask in OR0 so ROM appears everywhere */
+ /*----------------------------------------------------*/
+ lis r3, (CONFIG_SYS_IMMR)@h /* r3 <= CONFIG_SYS_IMMR */
+ lwz r4, OR0@l(r3)
+ li r5, 0x7fff /* r5 <= 0x00007FFFF */
+ and r4, r4, r5
+ stw r4, OR0@l(r3) /* OR0 <= OR0 & 0x00007FFFF */
+
+ /* As MPC8349E User's Manual presented, when RCW[BMS] is set to 0,
+ * system will boot from 0x0000_0100, and the LBLAWBAR0[BASE_ADDR]
+ * reset value is 0x00000; when RCW[BMS] is set to 1, system will boot
+ * from 0xFFF0_0100, and the LBLAWBAR0[BASE_ADDR] reset value is
+ * 0xFF800. From the hard resetting to here, the processor fetched and
+ * executed the instructions one by one. There is not absolutely
+ * jumping happened. Laterly, the u-boot code has to do an absolutely
+ * jumping to tell the CPU instruction fetching component what the
+ * u-boot TEXT base address is. Because the TEXT base resides in the
+ * boot ROM memory space, to garantee the code can run smoothly after
+ * that jumping, we must map in the entire boot ROM by Local Access
+ * Window. Sometimes, we desire an non-0x00000 or non-0xFF800 starting
+ * address for boot ROM, such as 0xFE000000. In this case, the default
+ * LBIU Local Access Widow 0 will not cover this memory space. So, we
+ * need another window to map in it.
+ */
+ lis r4, (CONFIG_SYS_FLASH_BASE)@h
+ ori r4, r4, (CONFIG_SYS_FLASH_BASE)@l
+ stw r4, LBLAWBAR1(r3) /* LBLAWBAR1 <= CONFIG_SYS_FLASH_BASE */
+
+ /* Store 0x80000012 + log2(CONFIG_SYS_FLASH_SIZE) into LBLAWAR1 */
+ lis r4, (0x80000012)@h
+ ori r4, r4, (0x80000012)@l
+ li r5, CONFIG_SYS_FLASH_SIZE
+1: srawi. r5, r5, 1 /* r5 = r5 >> 1 */
+ addi r4, r4, 1
+ bne 1b
+
+ stw r4, LBLAWAR1(r3) /* LBLAWAR1 <= 8MB Flash Size */
+ /* Wait for HW to catch up */
+ lwz r4, LBLAWAR1(r3)
+ twi 0,r4,0
+ isync
+ blr
+
+ /* Though all the LBIU Local Access Windows and LBC Banks will be
+ * initialized in the C code, we'd better configure boot ROM's
+ * window 0 and bank 0 correctly at here.
+ */
+remap_flash_by_law0:
+ /* Initialize the BR0 with the boot ROM starting address. */
+ lwz r4, BR0(r3)
+ li r5, 0x7FFF
+ and r4, r4, r5
+ lis r5, (CONFIG_SYS_FLASH_BASE & 0xFFFF8000)@h
+ ori r5, r5, (CONFIG_SYS_FLASH_BASE & 0xFFFF8000)@l
+ or r5, r5, r4
+ stw r5, BR0(r3) /* r5 <= (CONFIG_SYS_FLASH_BASE & 0xFFFF8000) | (BR0 & 0x00007FFF) */
+
+ lwz r4, OR0(r3)
+ lis r5, ~((CONFIG_SYS_FLASH_SIZE << 4) - 1)
+ or r4, r4, r5
+ stw r4, OR0(r3)
+
+ lis r4, (CONFIG_SYS_FLASH_BASE)@h
+ ori r4, r4, (CONFIG_SYS_FLASH_BASE)@l
+ stw r4, LBLAWBAR0(r3) /* LBLAWBAR0 <= CONFIG_SYS_FLASH_BASE */
+
+ /* Store 0x80000012 + log2(CONFIG_SYS_FLASH_SIZE) into LBLAWAR0 */
+ lis r4, (0x80000012)@h
+ ori r4, r4, (0x80000012)@l
+ li r5, CONFIG_SYS_FLASH_SIZE
+1: srawi. r5, r5, 1 /* r5 = r5 >> 1 */
+ addi r4, r4, 1
+ bne 1b
+ stw r4, LBLAWAR0(r3) /* LBLAWAR0 <= Flash Size */
+
+
+ xor r4, r4, r4
+ stw r4, LBLAWBAR1(r3)
+ stw r4, LBLAWAR1(r3) /* Off LBIU LAW1 */
+ /* Wait for HW to catch up */
+ lwz r4, LBLAWAR1(r3)
+ twi 0,r4,0
+ isync
+ blr
+#endif /* CONFIG_SYS_FLASHBOOT */
diff --git a/arch/powerpc/cpu/mpc83xx/traps.c b/arch/powerpc/cpu/mpc83xx/traps.c
new file mode 100644
index 0000000..53a1062
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/traps.c
@@ -0,0 +1,257 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware
+ * exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+#include <asm/mpc8349_pci.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+#define END_OF_MEM (gd->bd->bi_memstart + gd->bd->bi_memsize)
+
+/*
+ * Trap & Exception support
+ */
+
+static void print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ puts ("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ putc ('\n');
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *)*sp;
+ }
+ putc ('\n');
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ int i;
+
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+ regs->msr&MSR_IR ? 1 : 0,
+ regs->msr&MSR_DR ? 1 : 0);
+
+ putc ('\n');
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0) {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7) {
+ putc ('\n');
+ }
+ }
+}
+
+
+static void _exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+#ifdef CONFIG_PCI
+void dump_pci (void)
+{
+/*
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ printf ("PCI: err status %x err mask %x err ctrl %x\n",
+ le32_to_cpu (immap->im_pci.pci_esr),
+ le32_to_cpu (immap->im_pci.pci_emr),
+ le32_to_cpu (immap->im_pci.pci_ecr));
+ printf (" error address %x error data %x ctrl %x\n",
+ le32_to_cpu (immap->im_pci.pci_eacr),
+ le32_to_cpu (immap->im_pci.pci_edcr),
+ le32_to_cpu (immap->im_pci.pci_eccr));
+*/
+}
+#endif
+
+void MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup;
+
+ /* Probing PCI using config cycles cause this exception
+ * when a device is not present. Catch it and return to
+ * the PCI exception handler.
+ */
+#ifdef CONFIG_PCI
+#if 0
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+#ifdef DEBUG
+ dump_pci();
+#endif
+ /* clear the error in the error status register */
+ if(immap->im_pci.pci_esr & cpu_to_le32(PCI_ERROR_PCI_NO_RSP)) {
+ immap->im_pci.pci_esr = cpu_to_le32(PCI_ERROR_PCI_NO_RSP);
+ return;
+ }
+#endif
+#endif /* CONFIG_PCI */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ return;
+ }
+
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ puts ("Machine check in kernel mode.\n"
+ "Caused by (from msr): ");
+ printf("regs %p ",regs);
+ switch( regs->msr & 0x000F0000) {
+ case (0x80000000>>12):
+ puts ("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (0x80000000>>13):
+ puts ("Transfer error ack signal\n");
+ break;
+ case (0x80000000>>14):
+ puts ("Data parity signal\n");
+ break;
+ case (0x80000000>>15):
+ puts ("Address parity signal\n");
+ break;
+ default:
+ puts ("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+#ifdef CONFIG_PCI
+ dump_pci();
+#endif
+ panic("machine check");
+}
+
+void AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void ProgramCheckException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void SoftEmuException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Software Emulation Exception");
+}
+
+
+void UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+void DebugException(struct pt_regs *regs)
+{
+ printf("Debugger trap at @ %lx\n", regs->nip );
+ show_regs(regs);
+#if defined(CONFIG_CMD_BEDBUG)
+ do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading. If not present, return -1, otherwise
+ * return 0.
+ */
+int addr_probe(uint *addr)
+{
+#if 0
+ int retval;
+
+ __asm__ __volatile__( \
+ "1: lwz %0,0(%1)\n" \
+ " eieio\n" \
+ " li %0,0\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,-1\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r" (retval) : "r"(addr));
+
+ return (retval);
+#endif
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc83xx/u-boot-spl.lds b/arch/powerpc/cpu/mpc83xx/u-boot-spl.lds
new file mode 100644
index 0000000..870b47d
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/u-boot-spl.lds
@@ -0,0 +1,55 @@
+/*
+ * (C) Copyright 2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+SECTIONS
+{
+ . = 0xfff00000;
+ .text : {
+ *(.text*)
+ . = ALIGN(16);
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ }
+
+ . = ALIGN(8);
+ .data : {
+ *(.data*)
+ *(.sdata*)
+ _GOT2_TABLE_ = .;
+ KEEP(*(.got2))
+ KEEP(*(.got))
+ PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
+ }
+ __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
+
+ . = ALIGN(8);
+ __bss_start = .;
+ .bss (NOLOAD) : {
+ *(.*bss)
+ }
+ __bss_end = .;
+}
+ENTRY(_start)
+ASSERT(__bss_end <= 0xfff01000, "NAND bootstrap too big");
diff --git a/arch/powerpc/cpu/mpc83xx/u-boot.lds b/arch/powerpc/cpu/mpc83xx/u-boot.lds
new file mode 100644
index 0000000..a9d8598
--- /dev/null
+++ b/arch/powerpc/cpu/mpc83xx/u-boot.lds
@@ -0,0 +1,91 @@
+/*
+ * (C) Copyright 2006-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ .text :
+ {
+ arch/powerpc/cpu/mpc83xx/start.o (.text*)
+ *(.text*)
+ . = ALIGN(16);
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ }
+
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x0FFF) & 0xFFFFF000;
+ _erotext = .;
+ PROVIDE (erotext = .);
+ .reloc :
+ {
+ _GOT2_TABLE_ = .;
+ KEEP(*(.got2))
+ KEEP(*(.got))
+ PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
+ _FIXUP_TABLE_ = .;
+ KEEP(*(.fixup))
+ }
+ __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
+ __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+ .data :
+ {
+ *(.data*)
+ *(.sdata*)
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+
+ . = .;
+
+ . = ALIGN(4);
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+
+ . = .;
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ . = ALIGN(4096);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(4096);
+ __init_end = .;
+
+ __bss_start = .;
+ .bss (NOLOAD) :
+ {
+ *(.bss*)
+ *(.sbss*)
+ *(COMMON)
+ . = ALIGN(4);
+ }
+ __bss_end = . ;
+ PROVIDE (end = .);
+}
+ENTRY(_start)
diff --git a/arch/powerpc/cpu/mpc85xx/Makefile b/arch/powerpc/cpu/mpc85xx/Makefile
new file mode 100644
index 0000000..4669883
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/Makefile
@@ -0,0 +1,182 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# (C) Copyright 2002,2003 Motorola Inc.
+# Xianghua Xiao,X.Xiao@motorola.com
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(CPU).o
+
+MINIMAL=
+
+ifdef CONFIG_SPL_BUILD
+ifdef CONFIG_SPL_INIT_MINIMAL
+MINIMAL=y
+endif
+endif
+
+START = start.o resetvec.o
+
+ifdef MINIMAL
+
+COBJS-y += cpu_init_early.o tlb.o spl_minimal.o
+
+else
+
+SOBJS-$(CONFIG_MP) += release.o
+SOBJS = $(SOBJS-y)
+
+COBJS-$(CONFIG_CMD_ERRATA) += cmd_errata.o
+COBJS-$(CONFIG_CPM2) += commproc.o
+
+# supports ddr1
+COBJS-$(CONFIG_MPC8540) += ddr-gen1.o
+COBJS-$(CONFIG_MPC8560) += ddr-gen1.o
+COBJS-$(CONFIG_MPC8541) += ddr-gen1.o
+COBJS-$(CONFIG_MPC8555) += ddr-gen1.o
+
+# supports ddr1/2
+COBJS-$(CONFIG_MPC8548) += ddr-gen2.o
+COBJS-$(CONFIG_MPC8568) += ddr-gen2.o
+COBJS-$(CONFIG_MPC8544) += ddr-gen2.o
+
+# supports ddr1/2/3
+COBJS-$(CONFIG_MPC8572) += ddr-gen3.o
+COBJS-$(CONFIG_MPC8536) += ddr-gen3.o
+COBJS-$(CONFIG_MPC8569) += ddr-gen3.o
+COBJS-$(CONFIG_P1010) += ddr-gen3.o
+COBJS-$(CONFIG_P1011) += ddr-gen3.o
+COBJS-$(CONFIG_P1012) += ddr-gen3.o
+COBJS-$(CONFIG_P1013) += ddr-gen3.o
+COBJS-$(CONFIG_P1014) += ddr-gen3.o
+COBJS-$(CONFIG_P1020) += ddr-gen3.o
+COBJS-$(CONFIG_P1021) += ddr-gen3.o
+COBJS-$(CONFIG_P1022) += ddr-gen3.o
+COBJS-$(CONFIG_P1023) += ddr-gen3.o
+COBJS-$(CONFIG_P1024) += ddr-gen3.o
+COBJS-$(CONFIG_P1025) += ddr-gen3.o
+COBJS-$(CONFIG_P2010) += ddr-gen3.o
+COBJS-$(CONFIG_P2020) += ddr-gen3.o
+COBJS-$(CONFIG_PPC_P2041) += ddr-gen3.o
+COBJS-$(CONFIG_PPC_P3041) += ddr-gen3.o
+COBJS-$(CONFIG_PPC_P4080) += ddr-gen3.o
+COBJS-$(CONFIG_PPC_P5020) += ddr-gen3.o
+COBJS-$(CONFIG_PPC_P5040) += ddr-gen3.o
+COBJS-$(CONFIG_PPC_T4240) += ddr-gen3.o
+COBJS-$(CONFIG_PPC_T4160) += ddr-gen3.o
+COBJS-$(CONFIG_PPC_B4420) += ddr-gen3.o
+COBJS-$(CONFIG_PPC_B4860) += ddr-gen3.o
+COBJS-$(CONFIG_BSC9131) += ddr-gen3.o
+COBJS-$(CONFIG_BSC9132) += ddr-gen3.o
+COBJS-$(CONFIG_PPC_T1040) += ddr-gen3.o
+
+COBJS-$(CONFIG_CPM2) += ether_fcc.o
+COBJS-$(CONFIG_OF_LIBFDT) += fdt.o
+COBJS-$(CONFIG_FSL_CORENET) += liodn.o
+COBJS-$(CONFIG_MP) += mp.o
+COBJS-$(CONFIG_PCI) += pci.o
+COBJS-$(CONFIG_SYS_DPAA_QBMAN) += portals.o
+
+# various SoC specific assignments
+COBJS-$(CONFIG_PPC_P2041) += p2041_ids.o
+COBJS-$(CONFIG_PPC_P3041) += p3041_ids.o
+COBJS-$(CONFIG_PPC_P4080) += p4080_ids.o
+COBJS-$(CONFIG_PPC_P5020) += p5020_ids.o
+COBJS-$(CONFIG_PPC_P5040) += p5040_ids.o
+COBJS-$(CONFIG_PPC_T4240) += t4240_ids.o
+COBJS-$(CONFIG_PPC_T4160) += t4240_ids.o
+COBJS-$(CONFIG_PPC_B4420) += b4860_ids.o
+COBJS-$(CONFIG_PPC_B4860) += b4860_ids.o
+COBJS-$(CONFIG_PPC_T1040) += t1040_ids.o
+
+COBJS-$(CONFIG_QE) += qe_io.o
+COBJS-$(CONFIG_CPM2) += serial_scc.o
+COBJS-$(CONFIG_SYS_FSL_QORIQ_CHASSIS1) += fsl_corenet_serdes.o
+COBJS-$(CONFIG_SYS_FSL_QORIQ_CHASSIS2) += fsl_corenet2_serdes.o
+
+# SoC specific SERDES support
+COBJS-$(CONFIG_MPC8536) += mpc8536_serdes.o
+COBJS-$(CONFIG_MPC8544) += mpc8544_serdes.o
+COBJS-$(CONFIG_MPC8548) += mpc8548_serdes.o
+COBJS-$(CONFIG_MPC8568) += mpc8568_serdes.o
+COBJS-$(CONFIG_MPC8569) += mpc8569_serdes.o
+COBJS-$(CONFIG_MPC8572) += mpc8572_serdes.o
+COBJS-$(CONFIG_P1010) += p1010_serdes.o
+COBJS-$(CONFIG_P1011) += p1021_serdes.o
+COBJS-$(CONFIG_P1012) += p1021_serdes.o
+COBJS-$(CONFIG_P1013) += p1022_serdes.o
+COBJS-$(CONFIG_P1014) += p1010_serdes.o
+COBJS-$(CONFIG_P1017) += p1023_serdes.o
+COBJS-$(CONFIG_P1020) += p1021_serdes.o
+COBJS-$(CONFIG_P1021) += p1021_serdes.o
+COBJS-$(CONFIG_P1022) += p1022_serdes.o
+COBJS-$(CONFIG_P1023) += p1023_serdes.o
+COBJS-$(CONFIG_P1024) += p1021_serdes.o
+COBJS-$(CONFIG_P1025) += p1021_serdes.o
+COBJS-$(CONFIG_P2010) += p2020_serdes.o
+COBJS-$(CONFIG_P2020) += p2020_serdes.o
+COBJS-$(CONFIG_PPC_P2041) += p2041_serdes.o
+COBJS-$(CONFIG_PPC_P3041) += p3041_serdes.o
+COBJS-$(CONFIG_PPC_P4080) += p4080_serdes.o
+COBJS-$(CONFIG_PPC_P5020) += p5020_serdes.o
+COBJS-$(CONFIG_PPC_P5040) += p5040_serdes.o
+COBJS-$(CONFIG_PPC_T4240) += t4240_serdes.o
+COBJS-$(CONFIG_PPC_T4160) += t4240_serdes.o
+COBJS-$(CONFIG_PPC_B4420) += b4860_serdes.o
+COBJS-$(CONFIG_PPC_B4860) += b4860_serdes.o
+COBJS-$(CONFIG_BSC9132) += bsc9132_serdes.o
+COBJS-$(CONFIG_PPC_T1040) += t1040_serdes.o
+
+COBJS-y += cpu.o
+COBJS-y += cpu_init.o
+COBJS-y += cpu_init_early.o
+COBJS-y += interrupts.o
+COBJS-y += speed.o
+COBJS-y += tlb.o
+COBJS-y += traps.o
+
+# Stub implementations of cache management functions for USB
+COBJS-y += cache.o
+
+endif # not minimal
+
+COBJS = $(COBJS-y)
+
+SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
+START := $(addprefix $(obj),$(START))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/powerpc/cpu/mpc85xx/b4860_ids.c b/arch/powerpc/cpu/mpc85xx/b4860_ids.c
new file mode 100644
index 0000000..0f4e82e
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/b4860_ids.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_portals.h>
+#include <asm/fsl_liodn.h>
+
+#ifdef CONFIG_SYS_DPAA_QBMAN
+struct qportal_info qp_info[CONFIG_SYS_QMAN_NUM_PORTALS] = {
+ /* dqrr liodn, frame data liodn, liodn off, sdest */
+ SET_QP_INFO(1, 27, 1, 0),
+ SET_QP_INFO(2, 28, 1, 0),
+ SET_QP_INFO(3, 29, 1, 1),
+ SET_QP_INFO(4, 30, 1, 1),
+ SET_QP_INFO(5, 31, 1, 2),
+ SET_QP_INFO(6, 32, 1, 2),
+ SET_QP_INFO(7, 33, 1, 3),
+ SET_QP_INFO(8, 34, 1, 3),
+ SET_QP_INFO(9, 35, 1, 0),
+ SET_QP_INFO(10, 36, 1, 0),
+ SET_QP_INFO(11, 37, 1, 1),
+ SET_QP_INFO(12, 38, 1, 1),
+ SET_QP_INFO(13, 39, 1, 2),
+ SET_QP_INFO(14, 40, 1, 2),
+ SET_QP_INFO(15, 41, 1, 3),
+ SET_QP_INFO(16, 42, 1, 3),
+ SET_QP_INFO(17, 43, 1, 0),
+ SET_QP_INFO(18, 44, 1, 0),
+ SET_QP_INFO(19, 45, 1, 1),
+ SET_QP_INFO(20, 46, 1, 1),
+ SET_QP_INFO(21, 47, 1, 2),
+ SET_QP_INFO(22, 48, 1, 2),
+ SET_QP_INFO(23, 49, 1, 3),
+ SET_QP_INFO(24, 50, 1, 3),
+ SET_QP_INFO(25, 51, 1, 0),
+};
+#endif
+
+#ifdef CONFIG_SYS_SRIO
+struct srio_liodn_id_table srio_liodn_tbl[] = {
+ SET_SRIO_LIODN_1(1, 307),
+ SET_SRIO_LIODN_1(2, 387),
+};
+int srio_liodn_tbl_sz = ARRAY_SIZE(srio_liodn_tbl);
+#endif
+
+struct liodn_id_table liodn_tbl[] = {
+#ifdef CONFIG_SYS_DPAA_QBMAN
+ SET_QMAN_LIODN(62),
+ SET_BMAN_LIODN(63),
+#endif
+
+ SET_SDHC_LIODN(1, 552),
+
+ SET_USB_LIODN(1, "fsl-usb2-mph", 553),
+
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 1, 148),
+
+ SET_DMA_LIODN(1, 147),
+ SET_DMA_LIODN(2, 227),
+
+#ifndef CONFIG_PPC_B4420
+ SET_GUTS_LIODN("fsl,rapidio-delta", 199, rio1liodnr, 0),
+ SET_GUTS_LIODN(NULL, 200, rio2liodnr, 0),
+ SET_GUTS_LIODN(NULL, 201, rio1maintliodnr, 0),
+ SET_GUTS_LIODN(NULL, 202, rio2maintliodnr, 0),
+#endif
+
+ /* SET_NEXUS_LIODN(557), -- not yet implemented */
+};
+int liodn_tbl_sz = ARRAY_SIZE(liodn_tbl);
+
+#ifdef CONFIG_SYS_DPAA_FMAN
+struct liodn_id_table fman1_liodn_tbl[] = {
+ SET_FMAN_RX_1G_LIODN(1, 0, 88),
+ SET_FMAN_RX_1G_LIODN(1, 1, 89),
+ SET_FMAN_RX_1G_LIODN(1, 2, 90),
+ SET_FMAN_RX_1G_LIODN(1, 3, 91),
+ SET_FMAN_RX_1G_LIODN(1, 4, 92),
+ SET_FMAN_RX_1G_LIODN(1, 5, 93),
+#ifndef CONFIG_PPC_B4420
+ SET_FMAN_RX_10G_LIODN(1, 0, 94),
+ SET_FMAN_RX_10G_LIODN(1, 1, 95),
+#endif
+};
+int fman1_liodn_tbl_sz = ARRAY_SIZE(fman1_liodn_tbl);
+#endif
+
+struct liodn_id_table sec_liodn_tbl[] = {
+ SET_SEC_JR_LIODN_ENTRY(0, 454, 458),
+ SET_SEC_JR_LIODN_ENTRY(1, 455, 459),
+ SET_SEC_JR_LIODN_ENTRY(2, 456, 460),
+ SET_SEC_JR_LIODN_ENTRY(3, 457, 461),
+ SET_SEC_RTIC_LIODN_ENTRY(a, 453),
+ SET_SEC_RTIC_LIODN_ENTRY(b, 549),
+ SET_SEC_RTIC_LIODN_ENTRY(c, 550),
+ SET_SEC_RTIC_LIODN_ENTRY(d, 551),
+ SET_SEC_DECO_LIODN_ENTRY(0, 541, 610),
+ SET_SEC_DECO_LIODN_ENTRY(1, 542, 611),
+ SET_SEC_DECO_LIODN_ENTRY(2, 543, 612),
+ SET_SEC_DECO_LIODN_ENTRY(3, 544, 613),
+ SET_SEC_DECO_LIODN_ENTRY(4, 545, 614),
+ SET_SEC_DECO_LIODN_ENTRY(5, 546, 615),
+ SET_SEC_DECO_LIODN_ENTRY(6, 547, 616),
+ SET_SEC_DECO_LIODN_ENTRY(7, 548, 617),
+};
+int sec_liodn_tbl_sz = ARRAY_SIZE(sec_liodn_tbl);
+
+#ifdef CONFIG_SYS_DPAA_RMAN
+struct liodn_id_table rman_liodn_tbl[] = {
+ /* Set RMan block 0-3 liodn offset */
+ SET_RMAN_LIODN(0, 678),
+ SET_RMAN_LIODN(1, 679),
+ SET_RMAN_LIODN(2, 680),
+ SET_RMAN_LIODN(3, 681),
+};
+int rman_liodn_tbl_sz = ARRAY_SIZE(rman_liodn_tbl);
+#endif
+
+struct liodn_id_table liodn_bases[] = {
+ [FSL_HW_PORTAL_SEC] = SET_LIODN_BASE_2(462, 558),
+#ifdef CONFIG_SYS_DPAA_FMAN
+ [FSL_HW_PORTAL_FMAN1] = SET_LIODN_BASE_1(973),
+#endif
+#ifdef CONFIG_SYS_DPAA_RMAN
+ [FSL_HW_PORTAL_RMAN] = SET_LIODN_BASE_1(922),
+#endif
+};
diff --git a/arch/powerpc/cpu/mpc85xx/b4860_serdes.c b/arch/powerpc/cpu/mpc85xx/b4860_serdes.c
new file mode 100644
index 0000000..bd32342
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/b4860_serdes.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_serdes.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include "fsl_corenet2_serdes.h"
+
+struct serdes_config {
+ u8 protocol;
+ u8 lanes[SRDS_MAX_LANES];
+};
+
+#ifdef CONFIG_PPC_B4860
+static struct serdes_config serdes1_cfg_tbl[] = {
+ /* SerDes 1 */
+ {0x0D, {CPRI8, CPRI7, CPRI6, CPRI5,
+ CPRI4, CPRI3, CPRI2, CPRI1}},
+ {0x0E, {CPRI8, CPRI7, CPRI6, CPRI5,
+ CPRI4, CPRI3, CPRI2, CPRI1}},
+ {0x12, {CPRI8, CPRI7, CPRI6, CPRI5,
+ CPRI4, CPRI3, CPRI2, CPRI1}},
+ {0x2a, {SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6,
+ CPRI6, CPRI5, CPRI4, CPRI3, CPRI2, CPRI1}},
+ {0x2C, {SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6,
+ CPRI6, CPRI5, CPRI4, CPRI3, CPRI2, CPRI1}},
+ {0x2D, {SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6,
+ CPRI6, CPRI5, CPRI4, CPRI3, CPRI2, CPRI1}},
+ {0x2E, {SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6,
+ CPRI6, CPRI5, CPRI4, CPRI3, CPRI2, CPRI1}},
+ {0x30, {AURORA, AURORA,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4,
+ CPRI4, CPRI3, CPRI2, CPRI1}},
+ {0x32, {AURORA, AURORA,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4,
+ CPRI4, CPRI3, CPRI2, CPRI1}},
+ {0x33, {AURORA, AURORA,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4,
+ CPRI4, CPRI3, CPRI2, CPRI1}},
+ {0x34, {AURORA, AURORA,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4,
+ CPRI4, CPRI3, CPRI2, CPRI1}},
+ {0x3E, {CPRI8, CPRI7, CPRI6, CPRI5,
+ CPRI4, CPRI3, CPRI2, CPRI1}},
+ {}
+};
+static struct serdes_config serdes2_cfg_tbl[] = {
+ /* SerDes 2 */
+ {0x18, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4,
+ AURORA, AURORA, SRIO1, SRIO1}},
+ {0x1D, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4,
+ AURORA, AURORA, SRIO1, SRIO1}},
+ {0x2B, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SRIO2, SRIO2,
+ AURORA, AURORA, SRIO1, SRIO1}},
+ {0x30, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SRIO2, SRIO2,
+ AURORA, AURORA,
+ SRIO1, SRIO1}},
+ {0x49, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, AURORA,
+ SRIO1, SRIO1, SRIO1, SRIO1}},
+ {0x4A, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, AURORA,
+ SRIO1, SRIO1, SRIO1, SRIO1}},
+ {0x4C, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, AURORA,
+ SRIO1, SRIO1, SRIO1, SRIO1}},
+ {0x4E, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, AURORA,
+ SRIO1, SRIO1, SRIO1, SRIO1}},
+ {0x7A, {SRIO2, SRIO2, SRIO2, SRIO2,
+ SRIO1, SRIO1, SRIO1, SRIO1}},
+ {0x84, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SRIO2, SRIO2, AURORA, AURORA,
+ XFI_FM1_MAC9, XFI_FM1_MAC10}},
+ {0x85, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SRIO2, SRIO2, AURORA, AURORA,
+ XFI_FM1_MAC9, XFI_FM1_MAC10}},
+ {0x87, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SRIO2, SRIO2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4,
+ XFI_FM1_MAC9, XFI_FM1_MAC10}},
+ {0x8D, {SRIO2, SRIO2, SRIO2, SRIO2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4,
+ XFI_FM1_MAC9, XFI_FM1_MAC10}},
+ {0x93, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4,
+ XAUI_FM1_MAC10, XAUI_FM1_MAC10,
+ XAUI_FM1_MAC10, XAUI_FM1_MAC10}},
+ {0x9E, {PCIE1, PCIE1, PCIE1, PCIE1,
+ XAUI_FM1_MAC10, XAUI_FM1_MAC10,
+ XAUI_FM1_MAC10, XAUI_FM1_MAC10}},
+ {0x9A, {PCIE1, PCIE1,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4,
+ XAUI_FM1_MAC10, XAUI_FM1_MAC10,
+ XAUI_FM1_MAC10, XAUI_FM1_MAC10}},
+ {0xB2, {PCIE1, PCIE1, PCIE1, PCIE1,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4,
+ XFI_FM1_MAC9, XFI_FM1_MAC10}},
+ {0xC3, {XAUI_FM1_MAC9, XAUI_FM1_MAC9,
+ XAUI_FM1_MAC9, XAUI_FM1_MAC9,
+ SRIO1, SRIO1, SRIO1, SRIO1}},
+ {0x98, {XAUI_FM1_MAC9, XAUI_FM1_MAC9,
+ XAUI_FM1_MAC9, XAUI_FM1_MAC9,
+ XAUI_FM1_MAC10, XAUI_FM1_MAC10,
+ XAUI_FM1_MAC10, XAUI_FM1_MAC10}},
+ {}
+};
+#endif
+
+#ifdef CONFIG_PPC_B4420
+static struct serdes_config serdes1_cfg_tbl[] = {
+ {0x0D, {NONE, NONE, CPRI6, CPRI5,
+ CPRI4, CPRI3, NONE, NONE} },
+ {0x0E, {NONE, NONE, CPRI8, CPRI5,
+ CPRI4, CPRI3, NONE, NONE} },
+ {0x0F, {NONE, NONE, CPRI6, CPRI5,
+ CPRI4, CPRI3, NONE, NONE} },
+ {0x18, {NONE, NONE,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4,
+ NONE, NONE, NONE, NONE} },
+ {0x1B, {NONE, NONE,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4,
+ NONE, NONE, NONE, NONE} },
+ {0x1E, {NONE, NONE, AURORA, AURORA,
+ NONE, NONE, NONE, NONE} },
+ {0x21, {NONE, NONE, AURORA, AURORA,
+ NONE, NONE, NONE, NONE} },
+ {0x3E, {NONE, NONE, CPRI6, CPRI5,
+ CPRI4, CPRI3, NONE, NONE} },
+ {}
+};
+static struct serdes_config serdes2_cfg_tbl[] = {
+ {0x49, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, AURORA,
+ NONE, NONE, NONE, NONE} },
+ {0x4A, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, AURORA,
+ NONE, NONE, NONE, NONE} },
+ {0x6F, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ AURORA, AURORA, NONE, NONE, NONE, NONE} },
+ {0x70, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ AURORA, AURORA, NONE, NONE, NONE, NONE} },
+ {0x9A, {PCIE1, PCIE1,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4,
+ NONE, NONE, NONE, NONE} },
+ {0x9E, {PCIE1, PCIE1, PCIE1, PCIE1,
+ NONE, NONE, NONE, NONE} },
+ {}
+};
+#endif
+
+static struct serdes_config *serdes_cfg_tbl[] = {
+ serdes1_cfg_tbl,
+ serdes2_cfg_tbl,
+};
+
+enum srds_prtcl serdes_get_prtcl(int serdes, int cfg, int lane)
+{
+ struct serdes_config *ptr;
+
+ if (serdes >= ARRAY_SIZE(serdes_cfg_tbl))
+ return 0;
+
+ ptr = serdes_cfg_tbl[serdes];
+ while (ptr->protocol) {
+ if (ptr->protocol == cfg)
+ return ptr->lanes[lane];
+ ptr++;
+ }
+
+ return 0;
+}
+
+int is_serdes_prtcl_valid(int serdes, u32 prtcl)
+{
+ int i;
+ struct serdes_config *ptr;
+
+ if (serdes >= ARRAY_SIZE(serdes_cfg_tbl))
+ return 0;
+
+ ptr = serdes_cfg_tbl[serdes];
+ while (ptr->protocol) {
+ if (ptr->protocol == prtcl)
+ break;
+ ptr++;
+ }
+
+ if (!ptr->protocol)
+ return 0;
+
+ for (i = 0; i < SRDS_MAX_LANES; i++) {
+ if (ptr->lanes[i] != NONE)
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc85xx/bsc9132_serdes.c b/arch/powerpc/cpu/mpc85xx/bsc9132_serdes.c
new file mode 100644
index 0000000..300a4db
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/bsc9132_serdes.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ * Author: Prabhakar Kushwaha <prabhakar@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+#define SRDS1_MAX_LANES 4
+
+static u32 serdes1_prtcl_map;
+
+static u8 serdes1_cfg_tbl[][SRDS1_MAX_LANES] = {
+ [0] = {NONE, NONE, NONE, NONE},
+ [1] = {PCIE1, PCIE2, CPRI2, CPRI1},
+ [2] = {PCIE1, PCIE2, CPRI2, CPRI1},
+ [3] = {PCIE1, PCIE2, CPRI2, CPRI1},
+ [4] = {PCIE1, PCIE2, CPRI2, CPRI1},
+ [5] = {PCIE1, PCIE2, CPRI2, CPRI1},
+ [6] = {PCIE1, PCIE2, SGMII_TSEC1, CPRI1},
+ [7] = {PCIE1, PCIE2, SGMII_TSEC1, CPRI1},
+ [8] = {PCIE1, PCIE2, SGMII_TSEC1, CPRI1},
+ [9] = {PCIE1, PCIE2, SGMII_TSEC1, CPRI1},
+ [10] = {PCIE1, PCIE2, SGMII_TSEC1, CPRI1},
+ [11] = {PCIE1, PCIE2, SGMII_TSEC1, SGMII_TSEC2},
+ [12] = {PCIE1, SGMII_TSEC2, CPRI2, CPRI1},
+ [13] = {PCIE1, SGMII_TSEC2, CPRI2, CPRI1},
+ [14] = {PCIE1, SGMII_TSEC2, CPRI2, CPRI1},
+ [15] = {PCIE1, SGMII_TSEC2, CPRI2, CPRI1},
+ [16] = {PCIE1, SGMII_TSEC2, CPRI2, CPRI1},
+ [17] = {PCIE1, SGMII_TSEC2, SGMII_TSEC1, CPRI1},
+ [18] = {PCIE1, SGMII_TSEC2, SGMII_TSEC1, CPRI1},
+ [19] = {PCIE1, SGMII_TSEC2, SGMII_TSEC1, CPRI1},
+ [20] = {PCIE1, SGMII_TSEC2, SGMII_TSEC1, CPRI1},
+ [21] = {PCIE1, SGMII_TSEC2, SGMII_TSEC1, CPRI1},
+ [22] = {PCIE1, PCIE2, CPRI2, CPRI1},
+ [23] = {PCIE1, PCIE2, CPRI2, CPRI1},
+ [24] = {PCIE1, PCIE2, CPRI2, CPRI1},
+ [25] = {PCIE1, PCIE2, CPRI2, CPRI1},
+ [26] = {PCIE1, PCIE2, CPRI2, CPRI1},
+ [27] = {PCIE1, PCIE2, SGMII_TSEC1, CPRI1},
+ [28] = {PCIE1, PCIE2, SGMII_TSEC1, CPRI1},
+ [29] = {PCIE1, PCIE2, SGMII_TSEC1, CPRI1},
+ [30] = {PCIE1, PCIE2, SGMII_TSEC1, CPRI1},
+ [31] = {PCIE1, PCIE2, SGMII_TSEC1, CPRI1},
+ [32] = {PCIE1, PCIE2, SGMII_TSEC1, SGMII_TSEC2},
+ [33] = {PCIE1, SGMII_TSEC2, CPRI2, CPRI1},
+ [34] = {PCIE1, SGMII_TSEC2, CPRI2, CPRI1},
+ [35] = {PCIE1, SGMII_TSEC2, CPRI2, CPRI1},
+ [36] = {PCIE1, SGMII_TSEC2, CPRI2, CPRI1},
+ [37] = {PCIE1, SGMII_TSEC2, CPRI2, CPRI1},
+ [38] = {PCIE1, SGMII_TSEC2, SGMII_TSEC1, CPRI1},
+ [39] = {PCIE1, SGMII_TSEC2, SGMII_TSEC1, CPRI1},
+ [40] = {PCIE1, SGMII_TSEC2, SGMII_TSEC1, CPRI1},
+ [41] = {PCIE1, SGMII_TSEC2, SGMII_TSEC1, CPRI1},
+ [42] = {PCIE1, SGMII_TSEC2, SGMII_TSEC1, CPRI1},
+ [43] = {SGMII_TSEC1, SGMII_TSEC2, CPRI2, CPRI1},
+ [44] = {SGMII_TSEC1, SGMII_TSEC2, CPRI2, CPRI1},
+ [45] = {SGMII_TSEC1, SGMII_TSEC2, CPRI2, CPRI1},
+ [46] = {SGMII_TSEC1, SGMII_TSEC2, CPRI2, CPRI1},
+ [47] = {SGMII_TSEC1, SGMII_TSEC2, CPRI2, CPRI1},
+};
+
+int is_serdes_configured(enum srds_prtcl prtcl)
+{
+ return (1 << prtcl) & serdes1_prtcl_map;
+}
+
+void fsl_serdes_init(void)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 pordevsr = in_be32(&gur->pordevsr);
+ u32 srds_cfg = (pordevsr & MPC85xx_PORDEVSR_IO_SEL) >>
+ MPC85xx_PORDEVSR_IO_SEL_SHIFT;
+ int lane;
+
+ debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg);
+
+ if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);
+ return;
+ }
+
+ for (lane = 0; lane < SRDS1_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes1_cfg_tbl[srds_cfg][lane];
+ serdes1_prtcl_map |= (1 << lane_prtcl);
+ }
+}
diff --git a/arch/powerpc/cpu/mpc85xx/cache.c b/arch/powerpc/cpu/mpc85xx/cache.c
new file mode 100644
index 0000000..2a08b65
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/cache.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 Marek Vasut <marex@denx.de>
+ *
+ * This file contains stub implementation of
+ * invalidate_dcache_range()
+ * flush_dcache_range()
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+}
diff --git a/arch/powerpc/cpu/mpc85xx/cmd_errata.c b/arch/powerpc/cpu/mpc85xx/cmd_errata.c
new file mode 100644
index 0000000..a7ed877
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/cmd_errata.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <linux/compiler.h>
+#include <asm/processor.h>
+#include "fsl_corenet_serdes.h"
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_A004849
+/*
+ * This work-around is implemented in PBI, so just check to see if the
+ * work-around was actually applied. To do this, we check for specific data
+ * at specific addresses in DCSR.
+ *
+ * Array offsets[] contains a list of offsets within DCSR. According to the
+ * erratum document, the value at each offset should be 2.
+ */
+static void check_erratum_a4849(uint32_t svr)
+{
+ void __iomem *dcsr = (void *)CONFIG_SYS_DCSRBAR + 0xb0000;
+ unsigned int i;
+
+#if defined(CONFIG_PPC_P2041) || defined(CONFIG_PPC_P3041)
+ static const uint8_t offsets[] = {
+ 0x50, 0x54, 0x58, 0x90, 0x94, 0x98
+ };
+#endif
+#ifdef CONFIG_PPC_P4080
+ static const uint8_t offsets[] = {
+ 0x60, 0x64, 0x68, 0x6c, 0xa0, 0xa4, 0xa8, 0xac
+ };
+#endif
+ uint32_t x108; /* The value that should be at offset 0x108 */
+
+ for (i = 0; i < ARRAY_SIZE(offsets); i++) {
+ if (in_be32(dcsr + offsets[i]) != 2) {
+ printf("Work-around for Erratum A004849 is not enabled\n");
+ return;
+ }
+ }
+
+#if defined(CONFIG_PPC_P2041) || defined(CONFIG_PPC_P3041)
+ x108 = 0x12;
+#endif
+
+#ifdef CONFIG_PPC_P4080
+ /*
+ * For P4080, the erratum document says that the value at offset 0x108
+ * should be 0x12 on rev2, or 0x1c on rev3.
+ */
+ if (SVR_MAJ(svr) == 2)
+ x108 = 0x12;
+ if (SVR_MAJ(svr) == 3)
+ x108 = 0x1c;
+#endif
+
+ if (in_be32(dcsr + 0x108) != x108) {
+ printf("Work-around for Erratum A004849 is not enabled\n");
+ return;
+ }
+
+ /* Everything matches, so the erratum work-around was applied */
+
+ printf("Work-around for Erratum A004849 enabled\n");
+}
+#endif
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_A004580
+/*
+ * This work-around is implemented in PBI, so just check to see if the
+ * work-around was actually applied. To do this, we check for specific data
+ * at specific addresses in the SerDes register block.
+ *
+ * The work-around says that for each SerDes lane, write BnTTLCRy0 =
+ * 0x1B00_0001, Register 2 = 0x0088_0000, and Register 3 = 0x4000_0000.
+
+ */
+static void check_erratum_a4580(uint32_t svr)
+{
+ const serdes_corenet_t __iomem *srds_regs =
+ (void *)CONFIG_SYS_FSL_CORENET_SERDES_ADDR;
+ unsigned int lane;
+
+ for (lane = 0; lane < SRDS_MAX_LANES; lane++) {
+ if (serdes_lane_enabled(lane)) {
+ const struct serdes_lane __iomem *srds_lane =
+ &srds_regs->lane[serdes_get_lane_idx(lane)];
+
+ /*
+ * Verify that the values we were supposed to write in
+ * the PBI are actually there. Also, the lower 15
+ * bits of res4[3] should be the same as the upper 15
+ * bits of res4[1].
+ */
+ if ((in_be32(&srds_lane->ttlcr0) != 0x1b000001) ||
+ (in_be32(&srds_lane->res4[1]) != 0x880000) ||
+ (in_be32(&srds_lane->res4[3]) != 0x40000044)) {
+ printf("Work-around for Erratum A004580 is "
+ "not enabled\n");
+ return;
+ }
+ }
+ }
+
+ /* Everything matches, so the erratum work-around was applied */
+
+ printf("Work-around for Erratum A004580 enabled\n");
+}
+#endif
+
+static int do_errata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_CPU_A011
+ extern int enable_cpu_a011_workaround;
+#endif
+ __maybe_unused u32 svr = get_svr();
+
+#if defined(CONFIG_FSL_SATA_V2) && defined(CONFIG_FSL_SATA_ERRATUM_A001)
+ if (IS_SVR_REV(svr, 1, 0)) {
+ switch (SVR_SOC_VER(svr)) {
+ case SVR_P1013:
+ case SVR_P1022:
+ puts("Work-around for Erratum SATA A001 enabled\n");
+ }
+ }
+#endif
+
+#if defined(CONFIG_SYS_P4080_ERRATUM_SERDES8)
+ puts("Work-around for Erratum SERDES8 enabled\n");
+#endif
+#if defined(CONFIG_SYS_P4080_ERRATUM_SERDES9)
+ puts("Work-around for Erratum SERDES9 enabled\n");
+#endif
+#if defined(CONFIG_SYS_P4080_ERRATUM_SERDES_A005)
+ puts("Work-around for Erratum SERDES-A005 enabled\n");
+#endif
+#if defined(CONFIG_SYS_P4080_ERRATUM_CPU22)
+ if (SVR_MAJ(svr) < 3)
+ puts("Work-around for Erratum CPU22 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_CPU_A011
+ /*
+ * NMG_CPU_A011 applies to P4080 rev 1.0, 2.0, fixed in 3.0
+ * also applies to P3041 rev 1.0, 1.1, P2041 rev 1.0, 1.1
+ * The SVR has been checked by cpu_init_r().
+ */
+ if (enable_cpu_a011_workaround)
+ puts("Work-around for Erratum CPU-A011 enabled\n");
+#endif
+#if defined(CONFIG_SYS_FSL_ERRATUM_CPU_A003999)
+ puts("Work-around for Erratum CPU-A003999 enabled\n");
+#endif
+#if defined(CONFIG_SYS_FSL_ERRATUM_DDR_A003474)
+ puts("Work-around for Erratum DDR-A003473 enabled\n");
+#endif
+#if defined(CONFIG_SYS_FSL_ERRATUM_DDR_MSYNC_IN)
+ puts("Work-around for DDR MSYNC_IN Erratum enabled\n");
+#endif
+#if defined(CONFIG_SYS_FSL_ERRATUM_ESDHC111)
+ puts("Work-around for Erratum ESDHC111 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_A004468
+ puts("Work-around for Erratum A004468 enabled\n");
+#endif
+#if defined(CONFIG_SYS_FSL_ERRATUM_ESDHC135)
+ puts("Work-around for Erratum ESDHC135 enabled\n");
+#endif
+#if defined(CONFIG_SYS_FSL_ERRATUM_ESDHC13)
+ if (SVR_MAJ(svr) < 3)
+ puts("Work-around for Erratum ESDHC13 enabled\n");
+#endif
+#if defined(CONFIG_SYS_FSL_ERRATUM_ESDHC_A001)
+ puts("Work-around for Erratum ESDHC-A001 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_CPC_A002
+ puts("Work-around for Erratum CPC-A002 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_CPC_A003
+ puts("Work-around for Erratum CPC-A003 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_ELBC_A001
+ puts("Work-around for Erratum ELBC-A001 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_DDR_A003
+ puts("Work-around for Erratum DDR-A003 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_DDR_115
+ puts("Work-around for Erratum DDR115 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134
+ puts("Work-around for Erratum DDR111 enabled\n");
+ puts("Work-around for Erratum DDR134 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_IFC_A002769
+ puts("Work-around for Erratum IFC-A002769 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_P1010_A003549
+ puts("Work-around for Erratum P1010-A003549 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_IFC_A003399
+ puts("Work-around for Erratum IFC A-003399 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_DDR120
+ if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0))
+ puts("Work-around for Erratum NMG DDR120 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_LBC103
+ puts("Work-around for Erratum NMG_LBC103 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
+ if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0))
+ puts("Work-around for Erratum NMG ETSEC129 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_A004510
+ puts("Work-around for Erratum A004510 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_SRIO_A004034
+ puts("Work-around for Erratum SRIO-A004034 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_A_004934
+ puts("Work-around for Erratum A004934 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_A005871
+ if (IS_SVR_REV(svr, 1, 0))
+ puts("Work-around for Erratum A005871 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_A004849
+ /* This work-around is implemented in PBI, so just check for it */
+ check_erratum_a4849(svr);
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_A004580
+ /* This work-around is implemented in PBI, so just check for it */
+ check_erratum_a4580(svr);
+#endif
+#ifdef CONFIG_SYS_P4080_ERRATUM_PCIE_A003
+ puts("Work-around for Erratum PCIe-A003 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_USB14
+ puts("Work-around for Erratum USB14 enabled\n");
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_A006593
+ puts("Work-around for Erratum A006593 enabled\n");
+#endif
+ return 0;
+}
+
+U_BOOT_CMD(
+ errata, 1, 0, do_errata,
+ "Report errata workarounds",
+ ""
+);
diff --git a/arch/powerpc/cpu/mpc85xx/commproc.c b/arch/powerpc/cpu/mpc85xx/commproc.c
new file mode 100644
index 0000000..37e7062
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/commproc.c
@@ -0,0 +1,186 @@
+/*
+ * Adapted for Motorola MPC8560 chips
+ * Xianghua Xiao <x.xiao@motorola.com>
+ *
+ * This file is based on "arch/powerpc/8260_io/commproc.c" - here is it's
+ * copyright notice:
+ *
+ * General Purpose functions for the global management of the
+ * 8220 Communication Processor Module.
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
+ * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
+ * 2.3.99 Updates
+ * Copyright (c) 2003 Motorola,Inc.
+ *
+ * In addition to the individual control of the communication
+ * channels, there are a few functions that globally affect the
+ * communication processor.
+ *
+ * Buffer descriptors must be allocated from the dual ported memory
+ * space. The allocator for that is here. When the communication
+ * process is reset, we reclaim the memory available. There is
+ * currently no deallocator for this memory.
+ */
+#include <common.h>
+#include <asm/cpm_85xx.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * because we have stack and init data in dual port ram
+ * we must reduce the size
+ */
+#undef CPM_DATAONLY_SIZE
+#define CPM_DATAONLY_SIZE ((uint)(8 * 1024) - CPM_DATAONLY_BASE)
+
+void
+m8560_cpm_reset(void)
+{
+ volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+ volatile ulong count;
+
+ gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+ /* Reclaim the DP memory for our use.
+ */
+ gd->arch.dp_alloc_base = CPM_DATAONLY_BASE;
+ gd->arch.dp_alloc_top = gd->arch.dp_alloc_base + CPM_DATAONLY_SIZE;
+
+ /*
+ * Reset CPM
+ */
+ cpm->im_cpm_cp.cpcr = CPM_CR_RST;
+ count = 0;
+ do { /* Spin until command processed */
+ __asm__ __volatile__ ("eieio");
+ } while ((cpm->im_cpm_cp.cpcr & CPM_CR_FLG) && ++count < 1000000);
+}
+
+/* Allocate some memory from the dual ported ram.
+ * To help protocols with object alignment restrictions, we do that
+ * if they ask.
+ */
+uint
+m8560_cpm_dpalloc(uint size, uint align)
+{
+ volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+ uint retloc;
+ uint align_mask, off;
+ uint savebase;
+
+ align_mask = align - 1;
+ savebase = gd->arch.dp_alloc_base;
+
+ off = gd->arch.dp_alloc_base & align_mask;
+ if (off != 0)
+ gd->arch.dp_alloc_base += (align - off);
+
+ if ((off = size & align_mask) != 0)
+ size += align - off;
+
+ if ((gd->arch.dp_alloc_base + size) >= gd->arch.dp_alloc_top) {
+ gd->arch.dp_alloc_base = savebase;
+ panic("m8560_cpm_dpalloc: ran out of dual port ram!");
+ }
+
+ retloc = gd->arch.dp_alloc_base;
+ gd->arch.dp_alloc_base += size;
+
+ memset((void *)&(cpm->im_dprambase[retloc]), 0, size);
+
+ return(retloc);
+}
+
+/* We also own one page of host buffer space for the allocation of
+ * UART "fifos" and the like.
+ */
+uint
+m8560_cpm_hostalloc(uint size, uint align)
+{
+ /* the host might not even have RAM yet - just use dual port RAM */
+ return (m8560_cpm_dpalloc(size, align));
+}
+
+/* Set a baud rate generator. This needs lots of work. There are
+ * eight BRGs, which can be connected to the CPM channels or output
+ * as clocks. The BRGs are in two different block of internal
+ * memory mapped space.
+ * The baud rate clock is the system clock divided by something.
+ * It was set up long ago during the initial boot phase and is
+ * is given to us.
+ * Baud rate clocks are zero-based in the driver code (as that maps
+ * to port numbers). Documentation uses 1-based numbering.
+ */
+#define BRG_INT_CLK gd->arch.brg_clk
+#define BRG_UART_CLK ((BRG_INT_CLK + 15) / 16)
+
+/* This function is used by UARTS, or anything else that uses a 16x
+ * oversampled clock.
+ */
+void
+m8560_cpm_setbrg(uint brg, uint rate)
+{
+ volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+ volatile uint *bp;
+
+ /* This is good enough to get SMCs running.....
+ */
+ if (brg < 4) {
+ bp = (uint *)&(cpm->im_cpm_brg1.brgc1);
+ }
+ else {
+ bp = (uint *)&(cpm->im_cpm_brg2.brgc5);
+ brg -= 4;
+ }
+ bp += brg;
+ *bp = (((((BRG_UART_CLK+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN;
+}
+
+/* This function is used to set high speed synchronous baud rate
+ * clocks.
+ */
+void
+m8560_cpm_fastbrg(uint brg, uint rate, int div16)
+{
+ volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+ volatile uint *bp;
+
+ /* This is good enough to get SMCs running.....
+ */
+ if (brg < 4) {
+ bp = (uint *)&(cpm->im_cpm_brg1.brgc1);
+ }
+ else {
+ bp = (uint *)&(cpm->im_cpm_brg2.brgc5);
+ brg -= 4;
+ }
+ bp += brg;
+ *bp = (((((BRG_INT_CLK+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN;
+ if (div16)
+ *bp |= CPM_BRG_DIV16;
+}
+
+/* This function is used to set baud rate generators using an external
+ * clock source and 16x oversampling.
+ */
+
+void
+m8560_cpm_extcbrg(uint brg, uint rate, uint extclk, int pinsel)
+{
+ volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+ volatile uint *bp;
+
+ if (brg < 4) {
+ bp = (uint *)&(cpm->im_cpm_brg1.brgc1);
+ }
+ else {
+ bp = (uint *)&(cpm->im_cpm_brg2.brgc5);
+ brg -= 4;
+ }
+ bp += brg;
+ *bp = ((((((extclk/16)+rate-1)/rate)-1)&0xfff)<<1)|CPM_BRG_EN;
+ if (pinsel == 0)
+ *bp |= CPM_BRG_EXTC_CLK3_9;
+ else
+ *bp |= CPM_BRG_EXTC_CLK5_15;
+}
diff --git a/arch/powerpc/cpu/mpc85xx/config.mk b/arch/powerpc/cpu/mpc85xx/config.mk
new file mode 100644
index 0000000..f36d823
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2002,2003 Motorola Inc.
+# Xianghua Xiao, X.Xiao@motorola.com
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_RELFLAGS += -meabi
+
+PLATFORM_CPPFLAGS += -ffixed-r2 -Wa,-me500 -msoft-float -mno-string
+
+# -mspe=yes is needed to have -mno-spe accepted by a buggy GCC;
+# see "[PATCH,rs6000] make -mno-spe work as expected" on
+# http://gcc.gnu.org/ml/gcc-patches/2008-04/msg00311.html
+PF_CPPFLAGS_SPE := $(call cc-option,-mspe=yes) \
+ $(call cc-option,-mno-spe)
+PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_SPE)
diff --git a/arch/powerpc/cpu/mpc85xx/cpu.c b/arch/powerpc/cpu/mpc85xx/cpu.c
new file mode 100644
index 0000000..fbee753
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/cpu.c
@@ -0,0 +1,618 @@
+/*
+ * Copyright 2004,2007-2011 Freescale Semiconductor, Inc.
+ * (C) Copyright 2002, 2003 Motorola Inc.
+ * Xianghua Xiao (X.Xiao@motorola.com)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <fsl_esdhc.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <asm/mmu.h>
+#include <asm/fsl_ifc.h>
+#include <asm/fsl_law.h>
+#include <asm/fsl_lbc.h>
+#include <post.h>
+#include <asm/processor.h>
+#include <asm/fsl_ddr_sdram.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Default board reset function
+ */
+static void
+__board_reset(void)
+{
+ /* Do nothing */
+}
+void board_reset(void) __attribute__((weak, alias("__board_reset")));
+
+int checkcpu (void)
+{
+ sys_info_t sysinfo;
+ uint pvr, svr;
+ uint ver;
+ uint major, minor;
+ struct cpu_type *cpu;
+ char buf1[32], buf2[32];
+#if (defined(CONFIG_DDR_CLK_FREQ) || \
+ defined(CONFIG_FSL_CORENET)) && !defined(CONFIG_SYS_FSL_QORIQ_CHASSIS2)
+ volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+#endif /* CONFIG_FSL_CORENET */
+
+ /*
+ * Cornet platforms use ddr sync bit in RCW to indicate sync vs async
+ * mode. Previous platform use ddr ratio to do the same. This
+ * information is only for display here.
+ */
+#ifdef CONFIG_FSL_CORENET
+#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2
+ u32 ddr_sync = 0; /* only async mode is supported */
+#else
+ u32 ddr_sync = ((gur->rcwsr[5]) & FSL_CORENET_RCWSR5_DDR_SYNC)
+ >> FSL_CORENET_RCWSR5_DDR_SYNC_SHIFT;
+#endif /* CONFIG_SYS_FSL_QORIQ_CHASSIS2 */
+#else /* CONFIG_FSL_CORENET */
+#ifdef CONFIG_DDR_CLK_FREQ
+ u32 ddr_ratio = ((gur->porpllsr) & MPC85xx_PORPLLSR_DDR_RATIO)
+ >> MPC85xx_PORPLLSR_DDR_RATIO_SHIFT;
+#else
+ u32 ddr_ratio = 0;
+#endif /* CONFIG_DDR_CLK_FREQ */
+#endif /* CONFIG_FSL_CORENET */
+
+ unsigned int i, core, nr_cores = cpu_numcores();
+ u32 mask = cpu_mask();
+
+ svr = get_svr();
+ major = SVR_MAJ(svr);
+ minor = SVR_MIN(svr);
+
+ if (cpu_numcores() > 1) {
+#ifndef CONFIG_MP
+ puts("Unicore software on multiprocessor system!!\n"
+ "To enable mutlticore build define CONFIG_MP\n");
+#endif
+ volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR);
+ printf("CPU%d: ", pic->whoami);
+ } else {
+ puts("CPU: ");
+ }
+
+ cpu = gd->arch.cpu;
+
+ puts(cpu->name);
+ if (IS_E_PROCESSOR(svr))
+ puts("E");
+
+ printf(", Version: %d.%d, (0x%08x)\n", major, minor, svr);
+
+ pvr = get_pvr();
+ ver = PVR_VER(pvr);
+ major = PVR_MAJ(pvr);
+ minor = PVR_MIN(pvr);
+
+ printf("Core: ");
+ switch(ver) {
+ case PVR_VER_E500_V1:
+ case PVR_VER_E500_V2:
+ puts("e500");
+ break;
+ case PVR_VER_E500MC:
+ puts("e500mc");
+ break;
+ case PVR_VER_E5500:
+ puts("e5500");
+ break;
+ case PVR_VER_E6500:
+ puts("e6500");
+ break;
+ default:
+ puts("Unknown");
+ break;
+ }
+
+ printf(", Version: %d.%d, (0x%08x)\n", major, minor, pvr);
+
+ if (nr_cores > CONFIG_MAX_CPUS) {
+ panic("\nUnexpected number of cores: %d, max is %d\n",
+ nr_cores, CONFIG_MAX_CPUS);
+ }
+
+ get_sys_info(&sysinfo);
+
+ puts("Clock Configuration:");
+ for_each_cpu(i, core, nr_cores, mask) {
+ if (!(i & 3))
+ printf ("\n ");
+ printf("CPU%d:%-4s MHz, ", core,
+ strmhz(buf1, sysinfo.freqProcessor[core]));
+ }
+ printf("\n CCB:%-4s MHz,\n", strmhz(buf1, sysinfo.freqSystemBus));
+
+#ifdef CONFIG_FSL_CORENET
+ if (ddr_sync == 1) {
+ printf(" DDR:%-4s MHz (%s MT/s data rate) "
+ "(Synchronous), ",
+ strmhz(buf1, sysinfo.freqDDRBus/2),
+ strmhz(buf2, sysinfo.freqDDRBus));
+ } else {
+ printf(" DDR:%-4s MHz (%s MT/s data rate) "
+ "(Asynchronous), ",
+ strmhz(buf1, sysinfo.freqDDRBus/2),
+ strmhz(buf2, sysinfo.freqDDRBus));
+ }
+#else
+ switch (ddr_ratio) {
+ case 0x0:
+ printf(" DDR:%-4s MHz (%s MT/s data rate), ",
+ strmhz(buf1, sysinfo.freqDDRBus/2),
+ strmhz(buf2, sysinfo.freqDDRBus));
+ break;
+ case 0x7:
+ printf(" DDR:%-4s MHz (%s MT/s data rate) "
+ "(Synchronous), ",
+ strmhz(buf1, sysinfo.freqDDRBus/2),
+ strmhz(buf2, sysinfo.freqDDRBus));
+ break;
+ default:
+ printf(" DDR:%-4s MHz (%s MT/s data rate) "
+ "(Asynchronous), ",
+ strmhz(buf1, sysinfo.freqDDRBus/2),
+ strmhz(buf2, sysinfo.freqDDRBus));
+ break;
+ }
+#endif
+
+#if defined(CONFIG_FSL_LBC)
+ if (sysinfo.freqLocalBus > LCRR_CLKDIV) {
+ printf("LBC:%-4s MHz\n", strmhz(buf1, sysinfo.freqLocalBus));
+ } else {
+ printf("LBC: unknown (LCRR[CLKDIV] = 0x%02lx)\n",
+ sysinfo.freqLocalBus);
+ }
+#endif
+
+#if defined(CONFIG_FSL_IFC)
+ printf("IFC:%-4s MHz\n", strmhz(buf1, sysinfo.freqLocalBus));
+#endif
+
+#ifdef CONFIG_CPM2
+ printf("CPM: %s MHz\n", strmhz(buf1, sysinfo.freqSystemBus));
+#endif
+
+#ifdef CONFIG_QE
+ printf(" QE:%-4s MHz\n", strmhz(buf1, sysinfo.freqQE));
+#endif
+
+#ifdef CONFIG_SYS_DPAA_FMAN
+ for (i = 0; i < CONFIG_SYS_NUM_FMAN; i++) {
+ printf(" FMAN%d: %s MHz\n", i + 1,
+ strmhz(buf1, sysinfo.freqFMan[i]));
+ }
+#endif
+
+#ifdef CONFIG_SYS_DPAA_QBMAN
+ printf(" QMAN: %s MHz\n", strmhz(buf1, sysinfo.freqQMAN));
+#endif
+
+#ifdef CONFIG_SYS_DPAA_PME
+ printf(" PME: %s MHz\n", strmhz(buf1, sysinfo.freqPME));
+#endif
+
+ puts("L1: D-cache 32 kB enabled\n I-cache 32 kB enabled\n");
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+/* Everything after the first generation of PQ3 parts has RSTCR */
+#if defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
+ defined(CONFIG_MPC8555) || defined(CONFIG_MPC8560)
+ unsigned long val, msr;
+
+ /*
+ * Initiate hard reset in debug control register DBCR0
+ * Make sure MSR[DE] = 1. This only resets the core.
+ */
+ msr = mfmsr ();
+ msr |= MSR_DE;
+ mtmsr (msr);
+
+ val = mfspr(DBCR0);
+ val |= 0x70000000;
+ mtspr(DBCR0,val);
+#else
+ volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ /* Attempt board-specific reset */
+ board_reset();
+
+ /* Next try asserting HRESET_REQ */
+ out_be32(&gur->rstcr, 0x2);
+ udelay(100);
+#endif
+
+ return 1;
+}
+
+
+/*
+ * Get timebase clock frequency
+ */
+#ifndef CONFIG_SYS_FSL_TBCLK_DIV
+#define CONFIG_SYS_FSL_TBCLK_DIV 8
+#endif
+unsigned long get_tbclk (void)
+{
+ unsigned long tbclk_div = CONFIG_SYS_FSL_TBCLK_DIV;
+
+ return (gd->bus_clk + (tbclk_div >> 1)) / tbclk_div;
+}
+
+
+#if defined(CONFIG_WATCHDOG)
+void
+reset_85xx_watchdog(void)
+{
+ /*
+ * Clear TSR(WIS) bit by writing 1
+ */
+ mtspr(SPRN_TSR, TSR_WIS);
+}
+
+void
+watchdog_reset(void)
+{
+ int re_enable = disable_interrupts();
+
+ reset_85xx_watchdog();
+ if (re_enable)
+ enable_interrupts();
+}
+#endif /* CONFIG_WATCHDOG */
+
+/*
+ * Initializes on-chip MMC controllers.
+ * to override, implement board_mmc_init()
+ */
+int cpu_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FSL_ESDHC
+ return fsl_esdhc_mmc_init(bis);
+#else
+ return 0;
+#endif
+}
+
+/*
+ * Print out the state of various machine registers.
+ * Currently prints out LAWs, BR0/OR0 for LBC, CSPR/CSOR/Timing
+ * parameters for IFC and TLBs
+ */
+void mpc85xx_reginfo(void)
+{
+ print_tlbcam();
+ print_laws();
+#if defined(CONFIG_FSL_LBC)
+ print_lbc_regs();
+#endif
+#ifdef CONFIG_FSL_IFC
+ print_ifc_regs();
+#endif
+
+}
+
+/* Common ddr init for non-corenet fsl 85xx platforms */
+#ifndef CONFIG_FSL_CORENET
+#if (defined(CONFIG_SYS_RAMBOOT) || defined(CONFIG_SPL)) && \
+ !defined(CONFIG_SYS_INIT_L2_ADDR)
+phys_size_t initdram(int board_type)
+{
+#if defined(CONFIG_SPD_EEPROM) || defined(CONFIG_DDR_SPD)
+ return fsl_ddr_sdram_size();
+#else
+ return (phys_size_t)CONFIG_SYS_SDRAM_SIZE * 1024 * 1024;
+#endif
+}
+#else /* CONFIG_SYS_RAMBOOT */
+phys_size_t initdram(int board_type)
+{
+ phys_size_t dram_size = 0;
+
+#if defined(CONFIG_SYS_FSL_ERRATUM_DDR_MSYNC_IN)
+ {
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ unsigned int x = 10;
+ unsigned int i;
+
+ /*
+ * Work around to stabilize DDR DLL
+ */
+ out_be32(&gur->ddrdllcr, 0x81000000);
+ asm("sync;isync;msync");
+ udelay(200);
+ while (in_be32(&gur->ddrdllcr) != 0x81000100) {
+ setbits_be32(&gur->devdisr, 0x00010000);
+ for (i = 0; i < x; i++)
+ ;
+ clrbits_be32(&gur->devdisr, 0x00010000);
+ x++;
+ }
+ }
+#endif
+
+#if defined(CONFIG_SPD_EEPROM) || \
+ defined(CONFIG_DDR_SPD) || \
+ defined(CONFIG_SYS_DDR_RAW_TIMING)
+ dram_size = fsl_ddr_sdram();
+#else
+ dram_size = fixed_sdram();
+#endif
+ dram_size = setup_ddr_tlbs(dram_size / 0x100000);
+ dram_size *= 0x100000;
+
+#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)
+ /*
+ * Initialize and enable DDR ECC.
+ */
+ ddr_enable_ecc(dram_size);
+#endif
+
+#if defined(CONFIG_FSL_LBC)
+ /* Some boards also have sdram on the lbc */
+ lbc_sdram_init();
+#endif
+
+ debug("DDR: ");
+ return dram_size;
+}
+#endif /* CONFIG_SYS_RAMBOOT */
+#endif
+
+#if CONFIG_POST & CONFIG_SYS_POST_MEMORY
+
+/* Board-specific functions defined in each board's ddr.c */
+void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
+ unsigned int ctrl_num);
+void read_tlbcam_entry(int idx, u32 *valid, u32 *tsize, unsigned long *epn,
+ phys_addr_t *rpn);
+unsigned int
+ setup_ddr_tlbs_phys(phys_addr_t p_addr, unsigned int memsize_in_meg);
+
+void clear_ddr_tlbs_phys(phys_addr_t p_addr, unsigned int memsize_in_meg);
+
+static void dump_spd_ddr_reg(void)
+{
+ int i, j, k, m;
+ u8 *p_8;
+ u32 *p_32;
+ ccsr_ddr_t *ddr[CONFIG_NUM_DDR_CONTROLLERS];
+ generic_spd_eeprom_t
+ spd[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR];
+
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
+ fsl_ddr_get_spd(spd[i], i);
+
+ puts("SPD data of all dimms (zero vaule is omitted)...\n");
+ puts("Byte (hex) ");
+ k = 1;
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++)
+ printf("Dimm%d ", k++);
+ }
+ puts("\n");
+ for (k = 0; k < sizeof(generic_spd_eeprom_t); k++) {
+ m = 0;
+ printf("%3d (0x%02x) ", k, k);
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+ p_8 = (u8 *) &spd[i][j];
+ if (p_8[k]) {
+ printf("0x%02x ", p_8[k]);
+ m++;
+ } else
+ puts(" ");
+ }
+ }
+ if (m)
+ puts("\n");
+ else
+ puts("\r");
+ }
+
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ switch (i) {
+ case 0:
+ ddr[i] = (void *)CONFIG_SYS_MPC8xxx_DDR_ADDR;
+ break;
+#if defined(CONFIG_SYS_MPC8xxx_DDR2_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 1)
+ case 1:
+ ddr[i] = (void *)CONFIG_SYS_MPC8xxx_DDR2_ADDR;
+ break;
+#endif
+#if defined(CONFIG_SYS_MPC8xxx_DDR3_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 2)
+ case 2:
+ ddr[i] = (void *)CONFIG_SYS_MPC8xxx_DDR3_ADDR;
+ break;
+#endif
+#if defined(CONFIG_SYS_MPC8xxx_DDR4_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 3)
+ case 3:
+ ddr[i] = (void *)CONFIG_SYS_MPC8xxx_DDR4_ADDR;
+ break;
+#endif
+ default:
+ printf("%s unexpected controller number = %u\n",
+ __func__, i);
+ return;
+ }
+ }
+ printf("DDR registers dump for all controllers "
+ "(zero vaule is omitted)...\n");
+ puts("Offset (hex) ");
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
+ printf(" Base + 0x%04x", (u32)ddr[i] & 0xFFFF);
+ puts("\n");
+ for (k = 0; k < sizeof(ccsr_ddr_t)/4; k++) {
+ m = 0;
+ printf("%6d (0x%04x)", k * 4, k * 4);
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ p_32 = (u32 *) ddr[i];
+ if (p_32[k]) {
+ printf(" 0x%08x", p_32[k]);
+ m++;
+ } else
+ puts(" ");
+ }
+ if (m)
+ puts("\n");
+ else
+ puts("\r");
+ }
+ puts("\n");
+}
+
+/* invalid the TLBs for DDR and setup new ones to cover p_addr */
+static int reset_tlb(phys_addr_t p_addr, u32 size, phys_addr_t *phys_offset)
+{
+ u32 vstart = CONFIG_SYS_DDR_SDRAM_BASE;
+ unsigned long epn;
+ u32 tsize, valid, ptr;
+ int ddr_esel;
+
+ clear_ddr_tlbs_phys(p_addr, size>>20);
+
+ /* Setup new tlb to cover the physical address */
+ setup_ddr_tlbs_phys(p_addr, size>>20);
+
+ ptr = vstart;
+ ddr_esel = find_tlb_idx((void *)ptr, 1);
+ if (ddr_esel != -1) {
+ read_tlbcam_entry(ddr_esel, &valid, &tsize, &epn, phys_offset);
+ } else {
+ printf("TLB error in function %s\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * slide the testing window up to test another area
+ * for 32_bit system, the maximum testable memory is limited to
+ * CONFIG_MAX_MEM_MAPPED
+ */
+int arch_memory_test_advance(u32 *vstart, u32 *size, phys_addr_t *phys_offset)
+{
+ phys_addr_t test_cap, p_addr;
+ phys_size_t p_size = min(gd->ram_size, CONFIG_MAX_MEM_MAPPED);
+
+#if !defined(CONFIG_PHYS_64BIT) || \
+ !defined(CONFIG_SYS_INIT_RAM_ADDR_PHYS) || \
+ (CONFIG_SYS_INIT_RAM_ADDR_PHYS < 0x100000000ull)
+ test_cap = p_size;
+#else
+ test_cap = gd->ram_size;
+#endif
+ p_addr = (*vstart) + (*size) + (*phys_offset);
+ if (p_addr < test_cap - 1) {
+ p_size = min(test_cap - p_addr, CONFIG_MAX_MEM_MAPPED);
+ if (reset_tlb(p_addr, p_size, phys_offset) == -1)
+ return -1;
+ *vstart = CONFIG_SYS_DDR_SDRAM_BASE;
+ *size = (u32) p_size;
+ printf("Testing 0x%08llx - 0x%08llx\n",
+ (u64)(*vstart) + (*phys_offset),
+ (u64)(*vstart) + (*phys_offset) + (*size) - 1);
+ } else
+ return 1;
+
+ return 0;
+}
+
+/* initialization for testing area */
+int arch_memory_test_prepare(u32 *vstart, u32 *size, phys_addr_t *phys_offset)
+{
+ phys_size_t p_size = min(gd->ram_size, CONFIG_MAX_MEM_MAPPED);
+
+ *vstart = CONFIG_SYS_DDR_SDRAM_BASE;
+ *size = (u32) p_size; /* CONFIG_MAX_MEM_MAPPED < 4G */
+ *phys_offset = 0;
+
+#if !defined(CONFIG_PHYS_64BIT) || \
+ !defined(CONFIG_SYS_INIT_RAM_ADDR_PHYS) || \
+ (CONFIG_SYS_INIT_RAM_ADDR_PHYS < 0x100000000ull)
+ if (gd->ram_size > CONFIG_MAX_MEM_MAPPED) {
+ puts("Cannot test more than ");
+ print_size(CONFIG_MAX_MEM_MAPPED,
+ " without proper 36BIT support.\n");
+ }
+#endif
+ printf("Testing 0x%08llx - 0x%08llx\n",
+ (u64)(*vstart) + (*phys_offset),
+ (u64)(*vstart) + (*phys_offset) + (*size) - 1);
+
+ return 0;
+}
+
+/* invalid TLBs for DDR and remap as normal after testing */
+int arch_memory_test_cleanup(u32 *vstart, u32 *size, phys_addr_t *phys_offset)
+{
+ unsigned long epn;
+ u32 tsize, valid, ptr;
+ phys_addr_t rpn = 0;
+ int ddr_esel;
+
+ /* disable the TLBs for this testing */
+ ptr = *vstart;
+
+ while (ptr < (*vstart) + (*size)) {
+ ddr_esel = find_tlb_idx((void *)ptr, 1);
+ if (ddr_esel != -1) {
+ read_tlbcam_entry(ddr_esel, &valid, &tsize, &epn, &rpn);
+ disable_tlb(ddr_esel);
+ }
+ ptr += TSIZE_TO_BYTES(tsize);
+ }
+
+ puts("Remap DDR ");
+ setup_ddr_tlbs(gd->ram_size>>20);
+ puts("\n");
+
+ return 0;
+}
+
+void arch_memory_failure_handle(void)
+{
+ dump_spd_ddr_reg();
+}
+#endif
diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init.c b/arch/powerpc/cpu/mpc85xx/cpu_init.c
new file mode 100644
index 0000000..3c8f59c
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/cpu_init.c
@@ -0,0 +1,744 @@
+/*
+ * Copyright 2007-2011 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2003 Motorola Inc.
+ * Modified by Xianghua Xiao, X.Xiao@motorola.com
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <asm/processor.h>
+#include <ioports.h>
+#include <sata.h>
+#include <fm_eth.h>
+#include <asm/io.h>
+#include <asm/cache.h>
+#include <asm/mmu.h>
+#include <asm/fsl_law.h>
+#include <asm/fsl_serdes.h>
+#include <asm/fsl_srio.h>
+#include <hwconfig.h>
+#include <linux/compiler.h>
+#include "mp.h"
+#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NAND
+#include <nand.h>
+#include <errno.h>
+#endif
+
+#include "../../../../drivers/block/fsl_sata.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_QE
+extern qe_iop_conf_t qe_iop_conf_tab[];
+extern void qe_config_iopin(u8 port, u8 pin, int dir,
+ int open_drain, int assign);
+extern void qe_init(uint qe_base);
+extern void qe_reset(void);
+
+static void config_qe_ioports(void)
+{
+ u8 port, pin;
+ int dir, open_drain, assign;
+ int i;
+
+ for (i = 0; qe_iop_conf_tab[i].assign != QE_IOP_TAB_END; i++) {
+ port = qe_iop_conf_tab[i].port;
+ pin = qe_iop_conf_tab[i].pin;
+ dir = qe_iop_conf_tab[i].dir;
+ open_drain = qe_iop_conf_tab[i].open_drain;
+ assign = qe_iop_conf_tab[i].assign;
+ qe_config_iopin(port, pin, dir, open_drain, assign);
+ }
+}
+#endif
+
+#ifdef CONFIG_CPM2
+void config_8560_ioports (volatile ccsr_cpm_t * cpm)
+{
+ int portnum;
+
+ for (portnum = 0; portnum < 4; portnum++) {
+ uint pmsk = 0,
+ ppar = 0,
+ psor = 0,
+ pdir = 0,
+ podr = 0,
+ pdat = 0;
+ iop_conf_t *iopc = (iop_conf_t *) & iop_conf_tab[portnum][0];
+ iop_conf_t *eiopc = iopc + 32;
+ uint msk = 1;
+
+ /*
+ * NOTE:
+ * index 0 refers to pin 31,
+ * index 31 refers to pin 0
+ */
+ while (iopc < eiopc) {
+ if (iopc->conf) {
+ pmsk |= msk;
+ if (iopc->ppar)
+ ppar |= msk;
+ if (iopc->psor)
+ psor |= msk;
+ if (iopc->pdir)
+ pdir |= msk;
+ if (iopc->podr)
+ podr |= msk;
+ if (iopc->pdat)
+ pdat |= msk;
+ }
+
+ msk <<= 1;
+ iopc++;
+ }
+
+ if (pmsk != 0) {
+ volatile ioport_t *iop = ioport_addr (cpm, portnum);
+ uint tpmsk = ~pmsk;
+
+ /*
+ * the (somewhat confused) paragraph at the
+ * bottom of page 35-5 warns that there might
+ * be "unknown behaviour" when programming
+ * PSORx and PDIRx, if PPARx = 1, so I
+ * decided this meant I had to disable the
+ * dedicated function first, and enable it
+ * last.
+ */
+ iop->ppar &= tpmsk;
+ iop->psor = (iop->psor & tpmsk) | psor;
+ iop->podr = (iop->podr & tpmsk) | podr;
+ iop->pdat = (iop->pdat & tpmsk) | pdat;
+ iop->pdir = (iop->pdir & tpmsk) | pdir;
+ iop->ppar |= ppar;
+ }
+ }
+}
+#endif
+
+#ifdef CONFIG_SYS_FSL_CPC
+static void enable_cpc(void)
+{
+ int i;
+ u32 size = 0;
+
+ cpc_corenet_t *cpc = (cpc_corenet_t *)CONFIG_SYS_FSL_CPC_ADDR;
+
+ for (i = 0; i < CONFIG_SYS_NUM_CPC; i++, cpc++) {
+ u32 cpccfg0 = in_be32(&cpc->cpccfg0);
+ size += CPC_CFG0_SZ_K(cpccfg0);
+#ifdef CONFIG_RAMBOOT_PBL
+ if (in_be32(&cpc->cpcsrcr0) & CPC_SRCR0_SRAMEN) {
+ /* find and disable LAW of SRAM */
+ struct law_entry law = find_law(CONFIG_SYS_INIT_L3_ADDR);
+
+ if (law.index == -1) {
+ printf("\nFatal error happened\n");
+ return;
+ }
+ disable_law(law.index);
+
+ clrbits_be32(&cpc->cpchdbcr0, CPC_HDBCR0_CDQ_SPEC_DIS);
+ out_be32(&cpc->cpccsr0, 0);
+ out_be32(&cpc->cpcsrcr0, 0);
+ }
+#endif
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_CPC_A002
+ setbits_be32(&cpc->cpchdbcr0, CPC_HDBCR0_TAG_ECC_SCRUB_DIS);
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_CPC_A003
+ setbits_be32(&cpc->cpchdbcr0, CPC_HDBCR0_DATA_ECC_SCRUB_DIS);
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_A006593
+ setbits_be32(&cpc->cpchdbcr0, 1 << (31 - 21));
+#endif
+
+ out_be32(&cpc->cpccsr0, CPC_CSR0_CE | CPC_CSR0_PE);
+ /* Read back to sync write */
+ in_be32(&cpc->cpccsr0);
+
+ }
+
+ printf("Corenet Platform Cache: %d KB enabled\n", size);
+}
+
+static void invalidate_cpc(void)
+{
+ int i;
+ cpc_corenet_t *cpc = (cpc_corenet_t *)CONFIG_SYS_FSL_CPC_ADDR;
+
+ for (i = 0; i < CONFIG_SYS_NUM_CPC; i++, cpc++) {
+ /* skip CPC when it used as all SRAM */
+ if (in_be32(&cpc->cpcsrcr0) & CPC_SRCR0_SRAMEN)
+ continue;
+ /* Flash invalidate the CPC and clear all the locks */
+ out_be32(&cpc->cpccsr0, CPC_CSR0_FI | CPC_CSR0_LFC);
+ while (in_be32(&cpc->cpccsr0) & (CPC_CSR0_FI | CPC_CSR0_LFC))
+ ;
+ }
+}
+#else
+#define enable_cpc()
+#define invalidate_cpc()
+#endif /* CONFIG_SYS_FSL_CPC */
+
+/*
+ * Breathe some life into the CPU...
+ *
+ * Set up the memory map
+ * initialize a bunch of registers
+ */
+
+#ifdef CONFIG_FSL_CORENET
+static void corenet_tb_init(void)
+{
+ volatile ccsr_rcpm_t *rcpm =
+ (void *)(CONFIG_SYS_FSL_CORENET_RCPM_ADDR);
+ volatile ccsr_pic_t *pic =
+ (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR);
+ u32 whoami = in_be32(&pic->whoami);
+
+ /* Enable the timebase register for this core */
+ out_be32(&rcpm->ctbenrl, (1 << whoami));
+}
+#endif
+
+void cpu_init_f (void)
+{
+ extern void m8560_cpm_reset (void);
+#ifdef CONFIG_SYS_DCSRBAR_PHYS
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+#endif
+#if defined(CONFIG_SECURE_BOOT)
+ struct law_entry law;
+#endif
+#ifdef CONFIG_MPC8548
+ ccsr_local_ecm_t *ecm = (void *)(CONFIG_SYS_MPC85xx_ECM_ADDR);
+ uint svr = get_svr();
+
+ /*
+ * CPU2 errata workaround: A core hang possible while executing
+ * a msync instruction and a snoopable transaction from an I/O
+ * master tagged to make quick forward progress is present.
+ * Fixed in silicon rev 2.1.
+ */
+ if ((SVR_MAJ(svr) == 1) || ((SVR_MAJ(svr) == 2 && SVR_MIN(svr) == 0x0)))
+ out_be32(&ecm->eebpcr, in_be32(&ecm->eebpcr) | (1 << 16));
+#endif
+
+ disable_tlb(14);
+ disable_tlb(15);
+
+#if defined(CONFIG_SECURE_BOOT)
+ /* Disable the LAW created for NOR flash by the PBI commands */
+ law = find_law(CONFIG_SYS_PBI_FLASH_BASE);
+ if (law.index != -1)
+ disable_law(law.index);
+#endif
+
+#ifdef CONFIG_CPM2
+ config_8560_ioports((ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR);
+#endif
+
+ init_early_memctl_regs();
+
+#if defined(CONFIG_CPM2)
+ m8560_cpm_reset();
+#endif
+#ifdef CONFIG_QE
+ /* Config QE ioports */
+ config_qe_ioports();
+#endif
+#if defined(CONFIG_FSL_DMA)
+ dma_init();
+#endif
+#ifdef CONFIG_FSL_CORENET
+ corenet_tb_init();
+#endif
+ init_used_tlb_cams();
+
+ /* Invalidate the CPC before DDR gets enabled */
+ invalidate_cpc();
+
+ #ifdef CONFIG_SYS_DCSRBAR_PHYS
+ /* set DCSRCR so that DCSR space is 1G */
+ setbits_be32(&gur->dcsrcr, FSL_CORENET_DCSR_SZ_1G);
+ in_be32(&gur->dcsrcr);
+#endif
+
+}
+
+/* Implement a dummy function for those platforms w/o SERDES */
+static void __fsl_serdes__init(void)
+{
+ return ;
+}
+__attribute__((weak, alias("__fsl_serdes__init"))) void fsl_serdes_init(void);
+
+#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2
+int enable_cluster_l2(void)
+{
+ int i = 0;
+ u32 cluster;
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ struct ccsr_cluster_l2 __iomem *l2cache;
+
+ cluster = in_be32(&gur->tp_cluster[i].lower);
+ if (cluster & TP_CLUSTER_EOC)
+ return 0;
+
+ /* The first cache has already been set up, so skip it */
+ i++;
+
+ /* Look through the remaining clusters, and set up their caches */
+ do {
+ int j, cluster_valid = 0;
+
+ l2cache = (void __iomem *)(CONFIG_SYS_FSL_CLUSTER_1_L2 + i * 0x40000);
+
+ cluster = in_be32(&gur->tp_cluster[i].lower);
+
+ /* check that at least one core/accel is enabled in cluster */
+ for (j = 0; j < 4; j++) {
+ u32 idx = (cluster >> (j*8)) & TP_CLUSTER_INIT_MASK;
+ u32 type = in_be32(&gur->tp_ityp[idx]);
+
+ if (type & TP_ITYP_AV)
+ cluster_valid = 1;
+ }
+
+ if (cluster_valid) {
+ /* set stash ID to (cluster) * 2 + 32 + 1 */
+ clrsetbits_be32(&l2cache->l2csr1, 0xff, 32 + i * 2 + 1);
+
+ printf("enable l2 for cluster %d %p\n", i, l2cache);
+
+ out_be32(&l2cache->l2csr0, L2CSR0_L2FI|L2CSR0_L2LFC);
+ while ((in_be32(&l2cache->l2csr0)
+ & (L2CSR0_L2FI|L2CSR0_L2LFC)) != 0)
+ ;
+ out_be32(&l2cache->l2csr0, L2CSR0_L2E|L2CSR0_L2PE|L2CSR0_L2REP_MODE);
+ }
+ i++;
+ } while (!(cluster & TP_CLUSTER_EOC));
+
+ return 0;
+}
+#endif
+
+/*
+ * Initialize L2 as cache.
+ *
+ * The newer 8548, etc, parts have twice as much cache, but
+ * use the same bit-encoding as the older 8555, etc, parts.
+ *
+ */
+int cpu_init_r(void)
+{
+ __maybe_unused u32 svr = get_svr();
+#ifdef CONFIG_SYS_LBC_LCRR
+ fsl_lbc_t *lbc = (void __iomem *)LBC_BASE_ADDR;
+#endif
+#ifdef CONFIG_L2_CACHE
+ ccsr_l2cache_t *l2cache = (void __iomem *)CONFIG_SYS_MPC85xx_L2_ADDR;
+#elif defined(CONFIG_SYS_FSL_QORIQ_CHASSIS2)
+ struct ccsr_cluster_l2 * l2cache = (void __iomem *)CONFIG_SYS_FSL_CLUSTER_1_L2;
+#endif
+#if defined(CONFIG_PPC_SPINTABLE_COMPATIBLE) && defined(CONFIG_MP)
+ extern int spin_table_compat;
+ const char *spin;
+#endif
+
+#if defined(CONFIG_SYS_P4080_ERRATUM_CPU22) || \
+ defined(CONFIG_SYS_FSL_ERRATUM_NMG_CPU_A011)
+ /*
+ * CPU22 and NMG_CPU_A011 share the same workaround.
+ * CPU22 applies to P4080 rev 1.0, 2.0, fixed in 3.0
+ * NMG_CPU_A011 applies to P4080 rev 1.0, 2.0, fixed in 3.0
+ * also applies to P3041 rev 1.0, 1.1, P2041 rev 1.0, 1.1, both
+ * fixed in 2.0. NMG_CPU_A011 is activated by default and can
+ * be disabled by hwconfig with syntax:
+ *
+ * fsl_cpu_a011:disable
+ */
+ extern int enable_cpu_a011_workaround;
+#ifdef CONFIG_SYS_P4080_ERRATUM_CPU22
+ enable_cpu_a011_workaround = (SVR_MAJ(svr) < 3);
+#else
+ char buffer[HWCONFIG_BUFFER_SIZE];
+ char *buf = NULL;
+ int n, res;
+
+ n = getenv_f("hwconfig", buffer, sizeof(buffer));
+ if (n > 0)
+ buf = buffer;
+
+ res = hwconfig_arg_cmp_f("fsl_cpu_a011", "disable", buf);
+ if (res > 0)
+ enable_cpu_a011_workaround = 0;
+ else {
+ if (n >= HWCONFIG_BUFFER_SIZE) {
+ printf("fsl_cpu_a011 was not found. hwconfig variable "
+ "may be too long\n");
+ }
+ enable_cpu_a011_workaround =
+ (SVR_SOC_VER(svr) == SVR_P4080 && SVR_MAJ(svr) < 3) ||
+ (SVR_SOC_VER(svr) != SVR_P4080 && SVR_MAJ(svr) < 2);
+ }
+#endif
+ if (enable_cpu_a011_workaround) {
+ flush_dcache();
+ mtspr(L1CSR2, (mfspr(L1CSR2) | L1CSR2_DCWS));
+ sync();
+ }
+#endif
+
+#if defined(CONFIG_PPC_SPINTABLE_COMPATIBLE) && defined(CONFIG_MP)
+ spin = getenv("spin_table_compat");
+ if (spin && (*spin == 'n'))
+ spin_table_compat = 0;
+ else
+ spin_table_compat = 1;
+#endif
+
+ puts ("L2: ");
+
+#if defined(CONFIG_L2_CACHE)
+ volatile uint cache_ctl;
+ uint ver;
+ u32 l2siz_field;
+
+ ver = SVR_SOC_VER(svr);
+
+ asm("msync;isync");
+ cache_ctl = l2cache->l2ctl;
+
+#if defined(CONFIG_SYS_RAMBOOT) && defined(CONFIG_SYS_INIT_L2_ADDR)
+ if (cache_ctl & MPC85xx_L2CTL_L2E) {
+ /* Clear L2 SRAM memory-mapped base address */
+ out_be32(&l2cache->l2srbar0, 0x0);
+ out_be32(&l2cache->l2srbar1, 0x0);
+
+ /* set MBECCDIS=0, SBECCDIS=0 */
+ clrbits_be32(&l2cache->l2errdis,
+ (MPC85xx_L2ERRDIS_MBECC |
+ MPC85xx_L2ERRDIS_SBECC));
+
+ /* set L2E=0, L2SRAM=0 */
+ clrbits_be32(&l2cache->l2ctl,
+ (MPC85xx_L2CTL_L2E |
+ MPC85xx_L2CTL_L2SRAM_ENTIRE));
+ }
+#endif
+
+ l2siz_field = (cache_ctl >> 28) & 0x3;
+
+ switch (l2siz_field) {
+ case 0x0:
+ printf(" unknown size (0x%08x)\n", cache_ctl);
+ return -1;
+ break;
+ case 0x1:
+ if (ver == SVR_8540 || ver == SVR_8560 ||
+ ver == SVR_8541 || ver == SVR_8555) {
+ puts("128 KB ");
+ /* set L2E=1, L2I=1, & L2BLKSZ=1 (128 Kbyte) */
+ cache_ctl = 0xc4000000;
+ } else {
+ puts("256 KB ");
+ cache_ctl = 0xc0000000; /* set L2E=1, L2I=1, & L2SRAM=0 */
+ }
+ break;
+ case 0x2:
+ if (ver == SVR_8540 || ver == SVR_8560 ||
+ ver == SVR_8541 || ver == SVR_8555) {
+ puts("256 KB ");
+ /* set L2E=1, L2I=1, & L2BLKSZ=2 (256 Kbyte) */
+ cache_ctl = 0xc8000000;
+ } else {
+ puts ("512 KB ");
+ /* set L2E=1, L2I=1, & L2SRAM=0 */
+ cache_ctl = 0xc0000000;
+ }
+ break;
+ case 0x3:
+ puts("1024 KB ");
+ /* set L2E=1, L2I=1, & L2SRAM=0 */
+ cache_ctl = 0xc0000000;
+ break;
+ }
+
+ if (l2cache->l2ctl & MPC85xx_L2CTL_L2E) {
+ puts("already enabled");
+#if defined(CONFIG_SYS_INIT_L2_ADDR) && defined(CONFIG_SYS_FLASH_BASE)
+ u32 l2srbar = l2cache->l2srbar0;
+ if (l2cache->l2ctl & MPC85xx_L2CTL_L2SRAM_ENTIRE
+ && l2srbar >= CONFIG_SYS_FLASH_BASE) {
+ l2srbar = CONFIG_SYS_INIT_L2_ADDR;
+ l2cache->l2srbar0 = l2srbar;
+ printf(", moving to 0x%08x", CONFIG_SYS_INIT_L2_ADDR);
+ }
+#endif /* CONFIG_SYS_INIT_L2_ADDR */
+ puts("\n");
+ } else {
+ asm("msync;isync");
+ l2cache->l2ctl = cache_ctl; /* invalidate & enable */
+ asm("msync;isync");
+ puts("enabled\n");
+ }
+#elif defined(CONFIG_BACKSIDE_L2_CACHE)
+ if (SVR_SOC_VER(svr) == SVR_P2040) {
+ puts("N/A\n");
+ goto skip_l2;
+ }
+
+ u32 l2cfg0 = mfspr(SPRN_L2CFG0);
+
+ /* invalidate the L2 cache */
+ mtspr(SPRN_L2CSR0, (L2CSR0_L2FI|L2CSR0_L2LFC));
+ while (mfspr(SPRN_L2CSR0) & (L2CSR0_L2FI|L2CSR0_L2LFC))
+ ;
+
+#ifdef CONFIG_SYS_CACHE_STASHING
+ /* set stash id to (coreID) * 2 + 32 + L2 (1) */
+ mtspr(SPRN_L2CSR1, (32 + 1));
+#endif
+
+ /* enable the cache */
+ mtspr(SPRN_L2CSR0, CONFIG_SYS_INIT_L2CSR0);
+
+ if (CONFIG_SYS_INIT_L2CSR0 & L2CSR0_L2E) {
+ while (!(mfspr(SPRN_L2CSR0) & L2CSR0_L2E))
+ ;
+ printf("%d KB enabled\n", (l2cfg0 & 0x3fff) * 64);
+ }
+
+skip_l2:
+#elif defined(CONFIG_SYS_FSL_QORIQ_CHASSIS2)
+ if (l2cache->l2csr0 & L2CSR0_L2E)
+ printf("%d KB enabled\n", (l2cache->l2cfg0 & 0x3fff) * 64);
+
+ enable_cluster_l2();
+#else
+ puts("disabled\n");
+#endif
+
+ enable_cpc();
+
+ /* needs to be in ram since code uses global static vars */
+ fsl_serdes_init();
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_A005871
+ if (IS_SVR_REV(svr, 1, 0)) {
+ int i;
+ __be32 *p = (void __iomem *)CONFIG_SYS_DCSRBAR + 0xb004c;
+
+ for (i = 0; i < 12; i++) {
+ p += i + (i > 5 ? 11 : 0);
+ out_be32(p, 0x2);
+ }
+ p = (void __iomem *)CONFIG_SYS_DCSRBAR + 0xb0108;
+ out_be32(p, 0x34);
+ }
+#endif
+
+#ifdef CONFIG_SYS_SRIO
+ srio_init();
+#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER
+ char *s = getenv("bootmaster");
+ if (s) {
+ if (!strcmp(s, "SRIO1")) {
+ srio_boot_master(1);
+ srio_boot_master_release_slave(1);
+ }
+ if (!strcmp(s, "SRIO2")) {
+ srio_boot_master(2);
+ srio_boot_master_release_slave(2);
+ }
+ }
+#endif
+#endif
+
+#if defined(CONFIG_MP)
+ setup_mp();
+#endif
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC13
+ {
+ if (SVR_MAJ(svr) < 3) {
+ void *p;
+ p = (void *)CONFIG_SYS_DCSRBAR + 0x20520;
+ setbits_be32(p, 1 << (31 - 14));
+ }
+ }
+#endif
+
+#ifdef CONFIG_SYS_LBC_LCRR
+ /*
+ * Modify the CLKDIV field of LCRR register to improve the writing
+ * speed for NOR flash.
+ */
+ clrsetbits_be32(&lbc->lcrr, LCRR_CLKDIV, CONFIG_SYS_LBC_LCRR);
+ __raw_readl(&lbc->lcrr);
+ isync();
+#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_LBC103
+ udelay(100);
+#endif
+#endif
+
+#ifdef CONFIG_SYS_FSL_USB1_PHY_ENABLE
+ {
+ ccsr_usb_phy_t *usb_phy1 =
+ (void *)CONFIG_SYS_MPC85xx_USB1_PHY_ADDR;
+ out_be32(&usb_phy1->usb_enable_override,
+ CONFIG_SYS_FSL_USB_ENABLE_OVERRIDE);
+ }
+#endif
+#ifdef CONFIG_SYS_FSL_USB2_PHY_ENABLE
+ {
+ ccsr_usb_phy_t *usb_phy2 =
+ (void *)CONFIG_SYS_MPC85xx_USB2_PHY_ADDR;
+ out_be32(&usb_phy2->usb_enable_override,
+ CONFIG_SYS_FSL_USB_ENABLE_OVERRIDE);
+ }
+#endif
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_USB14
+ /* On P204x/P304x/P50x0 Rev1.0, USB transmit will result internal
+ * multi-bit ECC errors which has impact on performance, so software
+ * should disable all ECC reporting from USB1 and USB2.
+ */
+ if (IS_SVR_REV(get_svr(), 1, 0)) {
+ struct dcsr_dcfg_regs *dcfg = (struct dcsr_dcfg_regs *)
+ (CONFIG_SYS_DCSRBAR + CONFIG_SYS_DCSR_DCFG_OFFSET);
+ setbits_be32(&dcfg->ecccr1,
+ (DCSR_DCFG_ECC_DISABLE_USB1 |
+ DCSR_DCFG_ECC_DISABLE_USB2));
+ }
+#endif
+
+#if defined(CONFIG_SYS_FSL_USB_DUAL_PHY_ENABLE)
+ ccsr_usb_phy_t *usb_phy =
+ (void *)CONFIG_SYS_MPC85xx_USB1_PHY_ADDR;
+ setbits_be32(&usb_phy->pllprg[1],
+ CONFIG_SYS_FSL_USB_PLLPRG2_PHY2_CLK_EN |
+ CONFIG_SYS_FSL_USB_PLLPRG2_PHY1_CLK_EN |
+ CONFIG_SYS_FSL_USB_PLLPRG2_MFI |
+ CONFIG_SYS_FSL_USB_PLLPRG2_PLL_EN);
+ setbits_be32(&usb_phy->port1.ctrl,
+ CONFIG_SYS_FSL_USB_CTRL_PHY_EN);
+ setbits_be32(&usb_phy->port1.drvvbuscfg,
+ CONFIG_SYS_FSL_USB_DRVVBUS_CR_EN);
+ setbits_be32(&usb_phy->port1.pwrfltcfg,
+ CONFIG_SYS_FSL_USB_PWRFLT_CR_EN);
+ setbits_be32(&usb_phy->port2.ctrl,
+ CONFIG_SYS_FSL_USB_CTRL_PHY_EN);
+ setbits_be32(&usb_phy->port2.drvvbuscfg,
+ CONFIG_SYS_FSL_USB_DRVVBUS_CR_EN);
+ setbits_be32(&usb_phy->port2.pwrfltcfg,
+ CONFIG_SYS_FSL_USB_PWRFLT_CR_EN);
+#endif
+
+#ifdef CONFIG_FMAN_ENET
+ fman_enet_init();
+#endif
+
+#if defined(CONFIG_FSL_SATA_V2) && defined(CONFIG_FSL_SATA_ERRATUM_A001)
+ /*
+ * For P1022/1013 Rev1.0 silicon, after power on SATA host
+ * controller is configured in legacy mode instead of the
+ * expected enterprise mode. Software needs to clear bit[28]
+ * of HControl register to change to enterprise mode from
+ * legacy mode. We assume that the controller is offline.
+ */
+ if (IS_SVR_REV(svr, 1, 0) &&
+ ((SVR_SOC_VER(svr) == SVR_P1022) ||
+ (SVR_SOC_VER(svr) == SVR_P1013))) {
+ fsl_sata_reg_t *reg;
+
+ /* first SATA controller */
+ reg = (void *)CONFIG_SYS_MPC85xx_SATA1_ADDR;
+ clrbits_le32(&reg->hcontrol, HCONTROL_ENTERPRISE_EN);
+
+ /* second SATA controller */
+ reg = (void *)CONFIG_SYS_MPC85xx_SATA2_ADDR;
+ clrbits_le32(&reg->hcontrol, HCONTROL_ENTERPRISE_EN);
+ }
+#endif
+
+
+ return 0;
+}
+
+extern void setup_ivors(void);
+
+void arch_preboot_os(void)
+{
+ u32 msr;
+
+ /*
+ * We are changing interrupt offsets and are about to boot the OS so
+ * we need to make sure we disable all async interrupts. EE is already
+ * disabled by the time we get called.
+ */
+ msr = mfmsr();
+ msr &= ~(MSR_ME|MSR_CE);
+ mtmsr(msr);
+
+ setup_ivors();
+}
+
+#if defined(CONFIG_CMD_SATA) && defined(CONFIG_FSL_SATA)
+int sata_initialize(void)
+{
+ if (is_serdes_configured(SATA1) || is_serdes_configured(SATA2))
+ return __sata_initialize();
+
+ return 1;
+}
+#endif
+
+void cpu_secondary_init_r(void)
+{
+#ifdef CONFIG_QE
+ uint qe_base = CONFIG_SYS_IMMR + 0x00080000; /* QE immr base */
+#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NAND
+ int ret;
+ size_t fw_length = CONFIG_SYS_QE_FMAN_FW_LENGTH;
+
+ /* load QE firmware from NAND flash to DDR first */
+ ret = nand_read(&nand_info[0], (loff_t)CONFIG_SYS_QE_FMAN_FW_IN_NAND,
+ &fw_length, (u_char *)CONFIG_SYS_QE_FMAN_FW_ADDR);
+
+ if (ret && ret == -EUCLEAN) {
+ printf ("NAND read for QE firmware at offset %x failed %d\n",
+ CONFIG_SYS_QE_FMAN_FW_IN_NAND, ret);
+ }
+#endif
+ qe_init(qe_base);
+ qe_reset();
+#endif
+}
diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init_early.c b/arch/powerpc/cpu/mpc85xx/cpu_init_early.c
new file mode 100644
index 0000000..3b3c82f
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/cpu_init_early.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2009-2012 Freescale Semiconductor, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <asm/fsl_law.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_A003399_NOR_WORKAROUND
+void setup_ifc(void)
+{
+ struct fsl_ifc *ifc_regs = (void *)CONFIG_SYS_IFC_ADDR;
+ u32 _mas0, _mas1, _mas2, _mas3, _mas7;
+ phys_addr_t flash_phys = CONFIG_SYS_FLASH_BASE_PHYS;
+
+ /*
+ * Adjust the TLB we were running out of to match the phys addr of the
+ * chip select we are adjusting and will return to.
+ */
+ flash_phys += (~CONFIG_SYS_AMASK0) + 1 - 4*1024*1024;
+
+ _mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(15);
+ _mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_TS | MAS1_IPROT |
+ MAS1_TSIZE(BOOKE_PAGESZ_4M);
+ _mas2 = FSL_BOOKE_MAS2(CONFIG_SYS_TEXT_BASE, MAS2_I|MAS2_G);
+ _mas3 = FSL_BOOKE_MAS3(flash_phys, 0, MAS3_SW|MAS3_SR|MAS3_SX);
+ _mas7 = FSL_BOOKE_MAS7(flash_phys);
+
+ mtspr(MAS0, _mas0);
+ mtspr(MAS1, _mas1);
+ mtspr(MAS2, _mas2);
+ mtspr(MAS3, _mas3);
+ mtspr(MAS7, _mas7);
+
+ asm volatile("isync;msync;tlbwe;isync");
+
+#if defined(CONFIG_SYS_PPC_E500_DEBUG_TLB)
+/*
+ * TLB entry for debuggging in AS1
+ * Create temporary TLB entry in AS0 to handle debug exception
+ * As on debug exception MSR is cleared i.e. Address space is changed
+ * to 0. A TLB entry (in AS0) is required to handle debug exception generated
+ * in AS1.
+ *
+ * TLB entry is created for IVPR + IVOR15 to map on valid OP code address
+ * bacause flash's physical address is going to change as
+ * CONFIG_SYS_FLASH_BASE_PHYS.
+ */
+ _mas0 = MAS0_TLBSEL(1) |
+ MAS0_ESEL(CONFIG_SYS_PPC_E500_DEBUG_TLB);
+ _mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_IPROT |
+ MAS1_TSIZE(BOOKE_PAGESZ_4M);
+ _mas2 = FSL_BOOKE_MAS2(CONFIG_SYS_TEXT_BASE, MAS2_I|MAS2_G);
+ _mas3 = FSL_BOOKE_MAS3(flash_phys, 0, MAS3_SW|MAS3_SR|MAS3_SX);
+ _mas7 = FSL_BOOKE_MAS7(flash_phys);
+
+ mtspr(MAS0, _mas0);
+ mtspr(MAS1, _mas1);
+ mtspr(MAS2, _mas2);
+ mtspr(MAS3, _mas3);
+ mtspr(MAS7, _mas7);
+
+ asm volatile("isync;msync;tlbwe;isync");
+#endif
+
+ /* Change flash's physical address */
+ out_be32(&(ifc_regs->cspr_cs[0].cspr), CONFIG_SYS_CSPR0);
+ out_be32(&(ifc_regs->csor_cs[0].csor), CONFIG_SYS_CSOR0);
+ out_be32(&(ifc_regs->amask_cs[0].amask), CONFIG_SYS_AMASK0);
+
+ return ;
+}
+#endif
+
+/* We run cpu_init_early_f in AS = 1 */
+void cpu_init_early_f(void)
+{
+ u32 mas0, mas1, mas2, mas3, mas7;
+ int i;
+#ifdef CONFIG_SYS_FSL_ERRATUM_P1010_A003549
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+#endif
+#ifdef CONFIG_A003399_NOR_WORKAROUND
+ ccsr_l2cache_t *l2cache = (void *)CONFIG_SYS_MPC85xx_L2_ADDR;
+ u32 *dst, *src;
+ void (*setup_ifc_sram)(void);
+#endif
+
+ /* Pointer is writable since we allocated a register for it */
+ gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+ /*
+ * Clear initial global data
+ * we don't use memset so we can share this code with NAND_SPL
+ */
+ for (i = 0; i < sizeof(gd_t); i++)
+ ((char *)gd)[i] = 0;
+
+ mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(13);
+ mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_TS | MAS1_TSIZE(BOOKE_PAGESZ_1M);
+ mas2 = FSL_BOOKE_MAS2(CONFIG_SYS_CCSRBAR, MAS2_I|MAS2_G);
+ mas3 = FSL_BOOKE_MAS3(CONFIG_SYS_CCSRBAR_PHYS, 0, MAS3_SW|MAS3_SR);
+ mas7 = FSL_BOOKE_MAS7(CONFIG_SYS_CCSRBAR_PHYS);
+
+ write_tlb(mas0, mas1, mas2, mas3, mas7);
+
+/*
+ * Work Around for IFC Erratum A-003549. This issue is P1010
+ * specific. LCLK(a free running clk signal) is muxed with IFC_CS3 on P1010 SOC
+ * Hence specifically selecting CS3.
+ */
+#ifdef CONFIG_SYS_FSL_ERRATUM_P1010_A003549
+ setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_LCLK_IFC_CS3);
+#endif
+
+ init_laws();
+
+/*
+ * Work Around for IFC Erratum A003399, issue will hit only when execution
+ * from NOR Flash
+ */
+#ifdef CONFIG_A003399_NOR_WORKAROUND
+#define SRAM_BASE_ADDR (0x00000000)
+ /* TLB for SRAM */
+ mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(9);
+ mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_TS |
+ MAS1_TSIZE(BOOKE_PAGESZ_1M);
+ mas2 = FSL_BOOKE_MAS2(SRAM_BASE_ADDR, MAS2_I);
+ mas3 = FSL_BOOKE_MAS3(SRAM_BASE_ADDR, 0, MAS3_SX|MAS3_SW|MAS3_SR);
+ mas7 = FSL_BOOKE_MAS7(0);
+
+ write_tlb(mas0, mas1, mas2, mas3, mas7);
+
+ out_be32(&l2cache->l2srbar0, SRAM_BASE_ADDR);
+
+ out_be32(&l2cache->l2errdis,
+ (MPC85xx_L2ERRDIS_MBECC | MPC85xx_L2ERRDIS_SBECC));
+
+ out_be32(&l2cache->l2ctl,
+ (MPC85xx_L2CTL_L2E | MPC85xx_L2CTL_L2SRAM_ENTIRE));
+
+ /*
+ * Copy the code in setup_ifc to L2SRAM. Do a word copy
+ * because NOR Flash on P1010 does not support byte
+ * access (Erratum IFC-A002769)
+ */
+ setup_ifc_sram = (void *)SRAM_BASE_ADDR;
+ dst = (u32 *) SRAM_BASE_ADDR;
+ src = (u32 *) setup_ifc;
+ for (i = 0; i < 1024; i++)
+ *dst++ = *src++;
+
+ setup_ifc_sram();
+
+ /* CLEANUP */
+ clrbits_be32(&l2cache->l2ctl,
+ (MPC85xx_L2CTL_L2E |
+ MPC85xx_L2CTL_L2SRAM_ENTIRE));
+ out_be32(&l2cache->l2srbar0, 0x0);
+#endif
+
+ invalidate_tlb(1);
+
+#if defined(CONFIG_SYS_PPC_E500_DEBUG_TLB) && \
+ !(defined(CONFIG_SPL_INIT_MINIMAL) && defined(CONFIG_SPL_BUILD)) && \
+ !defined(CONFIG_NAND_SPL)
+ disable_tlb(CONFIG_SYS_PPC_E500_DEBUG_TLB);
+#endif
+
+ init_tlbs();
+}
diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen1.c b/arch/powerpc/cpu/mpc85xx/ddr-gen1.c
new file mode 100644
index 0000000..8a86819
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/ddr-gen1.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4)
+#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
+#endif
+
+void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
+ unsigned int ctrl_num)
+{
+ unsigned int i;
+ volatile ccsr_ddr_t *ddr = (void *)CONFIG_SYS_MPC8xxx_DDR_ADDR;
+
+ if (ctrl_num != 0) {
+ printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num);
+ return;
+ }
+
+ for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+ if (i == 0) {
+ out_be32(&ddr->cs0_bnds, regs->cs[i].bnds);
+ out_be32(&ddr->cs0_config, regs->cs[i].config);
+
+ } else if (i == 1) {
+ out_be32(&ddr->cs1_bnds, regs->cs[i].bnds);
+ out_be32(&ddr->cs1_config, regs->cs[i].config);
+
+ } else if (i == 2) {
+ out_be32(&ddr->cs2_bnds, regs->cs[i].bnds);
+ out_be32(&ddr->cs2_config, regs->cs[i].config);
+
+ } else if (i == 3) {
+ out_be32(&ddr->cs3_bnds, regs->cs[i].bnds);
+ out_be32(&ddr->cs3_config, regs->cs[i].config);
+ }
+ }
+
+ out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1);
+ out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
+ out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode);
+ out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
+#if defined(CONFIG_MPC8555) || defined(CONFIG_MPC8541)
+ out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl);
+#endif
+
+ /*
+ * 200 painful micro-seconds must elapse between
+ * the DDR clock setup and the DDR config enable.
+ */
+ udelay(200);
+ asm volatile("sync;isync");
+
+ out_be32(&ddr->sdram_cfg, regs->ddr_sdram_cfg);
+
+ asm("sync;isync;msync");
+ udelay(500);
+}
+
+#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)
+/*
+ * Initialize all of memory for ECC, then enable errors.
+ */
+
+void
+ddr_enable_ecc(unsigned int dram_size)
+{
+ volatile ccsr_ddr_t *ddr= (void *)(CONFIG_SYS_MPC8xxx_DDR_ADDR);
+
+ dma_meminit(CONFIG_MEM_INIT_VALUE, dram_size);
+
+ /*
+ * Enable errors for ECC.
+ */
+ debug("DMA DDR: err_disable = 0x%08x\n", ddr->err_disable);
+ ddr->err_disable = 0x00000000;
+ asm("sync;isync;msync");
+ debug("DMA DDR: err_disable = 0x%08x\n", ddr->err_disable);
+}
+
+#endif /* CONFIG_DDR_ECC && ! CONFIG_ECC_INIT_VIA_DDRCONTROLLER */
diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen2.c b/arch/powerpc/cpu/mpc85xx/ddr-gen2.c
new file mode 100644
index 0000000..a705862
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/ddr-gen2.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4)
+#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
+#endif
+
+void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
+ unsigned int ctrl_num)
+{
+ unsigned int i;
+ ccsr_ddr_t *ddr = (void *)CONFIG_SYS_MPC8xxx_DDR_ADDR;
+
+#if defined(CONFIG_SYS_FSL_ERRATUM_NMG_DDR120) && defined(CONFIG_MPC85xx)
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ uint svr;
+#endif
+
+ if (ctrl_num) {
+ printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num);
+ return;
+ }
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_DDR120
+ /*
+ * Set the DDR IO receiver to an acceptable bias point.
+ * Fixed in Rev 2.1.
+ */
+ svr = get_svr();
+ if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0)) {
+ if ((regs->ddr_sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK) ==
+ SDRAM_CFG_SDRAM_TYPE_DDR2)
+ out_be32(&gur->ddrioovcr, 0x90000000);
+ else
+ out_be32(&gur->ddrioovcr, 0xA8000000);
+ }
+#endif
+
+ for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+ if (i == 0) {
+ out_be32(&ddr->cs0_bnds, regs->cs[i].bnds);
+ out_be32(&ddr->cs0_config, regs->cs[i].config);
+
+ } else if (i == 1) {
+ out_be32(&ddr->cs1_bnds, regs->cs[i].bnds);
+ out_be32(&ddr->cs1_config, regs->cs[i].config);
+
+ } else if (i == 2) {
+ out_be32(&ddr->cs2_bnds, regs->cs[i].bnds);
+ out_be32(&ddr->cs2_config, regs->cs[i].config);
+
+ } else if (i == 3) {
+ out_be32(&ddr->cs3_bnds, regs->cs[i].bnds);
+ out_be32(&ddr->cs3_config, regs->cs[i].config);
+ }
+ }
+
+ out_be32(&ddr->timing_cfg_3, regs->timing_cfg_3);
+ out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0);
+ out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1);
+ out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
+ out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
+ out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode);
+ out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2);
+ out_be32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl);
+ out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
+ out_be32(&ddr->sdram_data_init, regs->ddr_data_init);
+ out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl);
+ out_be32(&ddr->init_addr, regs->ddr_init_addr);
+ out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
+
+ /*
+ * 200 painful micro-seconds must elapse between
+ * the DDR clock setup and the DDR config enable.
+ */
+ udelay(200);
+ asm volatile("sync;isync");
+
+ out_be32(&ddr->sdram_cfg, regs->ddr_sdram_cfg);
+
+ /* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done. */
+ while (in_be32(&ddr->sdram_cfg_2) & 0x10) {
+ udelay(10000); /* throttle polling rate */
+ }
+}
diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
new file mode 100644
index 0000000..c5b4720
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/fsl_ddr_sdram.h>
+#include <asm/processor.h>
+
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4)
+#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
+#endif
+
+void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
+ unsigned int ctrl_num)
+{
+ unsigned int i, bus_width;
+ volatile ccsr_ddr_t *ddr;
+ u32 temp_sdram_cfg;
+ u32 total_gb_size_per_controller;
+ int timeout;
+#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134
+ int timeout_save;
+ volatile ccsr_local_ecm_t *ecm = (void *)CONFIG_SYS_MPC85xx_ECM_ADDR;
+ unsigned int csn_bnds_backup = 0, cs_sa, cs_ea, *csn_bnds_t;
+ int csn = -1;
+#endif
+
+ switch (ctrl_num) {
+ case 0:
+ ddr = (void *)CONFIG_SYS_MPC8xxx_DDR_ADDR;
+ break;
+#if defined(CONFIG_SYS_MPC8xxx_DDR2_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 1)
+ case 1:
+ ddr = (void *)CONFIG_SYS_MPC8xxx_DDR2_ADDR;
+ break;
+#endif
+#if defined(CONFIG_SYS_MPC8xxx_DDR3_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 2)
+ case 2:
+ ddr = (void *)CONFIG_SYS_MPC8xxx_DDR3_ADDR;
+ break;
+#endif
+#if defined(CONFIG_SYS_MPC8xxx_DDR4_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 3)
+ case 3:
+ ddr = (void *)CONFIG_SYS_MPC8xxx_DDR4_ADDR;
+ break;
+#endif
+ default:
+ printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num);
+ return;
+ }
+
+ if (regs->ddr_eor)
+ out_be32(&ddr->eor, regs->ddr_eor);
+#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134
+ debug("Workaround for ERRATUM_DDR111_DDR134\n");
+ for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+ cs_sa = (regs->cs[i].bnds >> 16) & 0xfff;
+ cs_ea = regs->cs[i].bnds & 0xfff;
+ if ((cs_sa <= 0xff) && (cs_ea >= 0xff)) {
+ csn = i;
+ csn_bnds_backup = regs->cs[i].bnds;
+ csn_bnds_t = (unsigned int *) &regs->cs[i].bnds;
+ if (cs_ea > 0xeff)
+ *csn_bnds_t = regs->cs[i].bnds + 0x01000000;
+ else
+ *csn_bnds_t = regs->cs[i].bnds + 0x01000100;
+ debug("Found cs%d_bns (0x%08x) covering 0xff000000, "
+ "change it to 0x%x\n",
+ csn, csn_bnds_backup, regs->cs[i].bnds);
+ break;
+ }
+ }
+#endif
+ for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+ if (i == 0) {
+ out_be32(&ddr->cs0_bnds, regs->cs[i].bnds);
+ out_be32(&ddr->cs0_config, regs->cs[i].config);
+ out_be32(&ddr->cs0_config_2, regs->cs[i].config_2);
+
+ } else if (i == 1) {
+ out_be32(&ddr->cs1_bnds, regs->cs[i].bnds);
+ out_be32(&ddr->cs1_config, regs->cs[i].config);
+ out_be32(&ddr->cs1_config_2, regs->cs[i].config_2);
+
+ } else if (i == 2) {
+ out_be32(&ddr->cs2_bnds, regs->cs[i].bnds);
+ out_be32(&ddr->cs2_config, regs->cs[i].config);
+ out_be32(&ddr->cs2_config_2, regs->cs[i].config_2);
+
+ } else if (i == 3) {
+ out_be32(&ddr->cs3_bnds, regs->cs[i].bnds);
+ out_be32(&ddr->cs3_config, regs->cs[i].config);
+ out_be32(&ddr->cs3_config_2, regs->cs[i].config_2);
+ }
+ }
+
+ out_be32(&ddr->timing_cfg_3, regs->timing_cfg_3);
+ out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0);
+ out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1);
+ out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
+ out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
+ out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode);
+ out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2);
+ out_be32(&ddr->sdram_mode_3, regs->ddr_sdram_mode_3);
+ out_be32(&ddr->sdram_mode_4, regs->ddr_sdram_mode_4);
+ out_be32(&ddr->sdram_mode_5, regs->ddr_sdram_mode_5);
+ out_be32(&ddr->sdram_mode_6, regs->ddr_sdram_mode_6);
+ out_be32(&ddr->sdram_mode_7, regs->ddr_sdram_mode_7);
+ out_be32(&ddr->sdram_mode_8, regs->ddr_sdram_mode_8);
+ out_be32(&ddr->sdram_md_cntl, regs->ddr_sdram_md_cntl);
+ out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
+ out_be32(&ddr->sdram_data_init, regs->ddr_data_init);
+ out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl);
+ out_be32(&ddr->init_addr, regs->ddr_init_addr);
+ out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
+
+ out_be32(&ddr->timing_cfg_4, regs->timing_cfg_4);
+ out_be32(&ddr->timing_cfg_5, regs->timing_cfg_5);
+ out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl);
+ out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl);
+ if (regs->ddr_wrlvl_cntl_2)
+ out_be32(&ddr->ddr_wrlvl_cntl_2, regs->ddr_wrlvl_cntl_2);
+ if (regs->ddr_wrlvl_cntl_3)
+ out_be32(&ddr->ddr_wrlvl_cntl_3, regs->ddr_wrlvl_cntl_3);
+
+ out_be32(&ddr->ddr_sr_cntr, regs->ddr_sr_cntr);
+ out_be32(&ddr->ddr_sdram_rcw_1, regs->ddr_sdram_rcw_1);
+ out_be32(&ddr->ddr_sdram_rcw_2, regs->ddr_sdram_rcw_2);
+ out_be32(&ddr->ddr_cdr1, regs->ddr_cdr1);
+ out_be32(&ddr->ddr_cdr2, regs->ddr_cdr2);
+ out_be32(&ddr->err_disable, regs->err_disable);
+ out_be32(&ddr->err_int_en, regs->err_int_en);
+ for (i = 0; i < 32; i++) {
+ if (regs->debug[i]) {
+ debug("Write to debug_%d as %08x\n", i+1, regs->debug[i]);
+ out_be32(&ddr->debug[i], regs->debug[i]);
+ }
+ }
+#ifdef CONFIG_SYS_FSL_ERRATUM_A_004934
+ out_be32(&ddr->debug[28], 0x30003000);
+#endif
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_DDR_A003474
+ out_be32(&ddr->debug[12], 0x00000015);
+ out_be32(&ddr->debug[21], 0x24000000);
+#endif /* CONFIG_SYS_FSL_ERRATUM_DDR_A003474 */
+
+ /* Set, but do not enable the memory */
+ temp_sdram_cfg = regs->ddr_sdram_cfg;
+ temp_sdram_cfg &= ~(SDRAM_CFG_MEM_EN);
+ out_be32(&ddr->sdram_cfg, temp_sdram_cfg);
+#ifdef CONFIG_SYS_FSL_ERRATUM_DDR_A003
+ debug("Workaround for ERRATUM_DDR_A003\n");
+ if (regs->ddr_sdram_rcw_2 & 0x00f00000) {
+ out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2 & 0xf07fffff);
+ out_be32(&ddr->debug[2], 0x00000400);
+ out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl & 0x7fffffff);
+ out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl & 0x7fffffff);
+ out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2 & 0xffffffeb);
+ out_be32(&ddr->mtcr, 0);
+ out_be32(&ddr->debug[12], 0x00000015);
+ out_be32(&ddr->debug[21], 0x24000000);
+ out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval & 0xffff);
+ out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_BI | SDRAM_CFG_MEM_EN);
+
+ asm volatile("sync;isync");
+ while (!(in_be32(&ddr->debug[1]) & 0x2))
+ ;
+
+ switch (regs->ddr_sdram_rcw_2 & 0x00f00000) {
+ case 0x00000000:
+ out_be32(&ddr->sdram_md_cntl,
+ MD_CNTL_MD_EN |
+ MD_CNTL_CS_SEL_CS0_CS1 |
+ 0x04000000 |
+ MD_CNTL_WRCW |
+ MD_CNTL_MD_VALUE(0x02));
+ break;
+ case 0x00100000:
+ out_be32(&ddr->sdram_md_cntl,
+ MD_CNTL_MD_EN |
+ MD_CNTL_CS_SEL_CS0_CS1 |
+ 0x04000000 |
+ MD_CNTL_WRCW |
+ MD_CNTL_MD_VALUE(0x0a));
+ break;
+ case 0x00200000:
+ out_be32(&ddr->sdram_md_cntl,
+ MD_CNTL_MD_EN |
+ MD_CNTL_CS_SEL_CS0_CS1 |
+ 0x04000000 |
+ MD_CNTL_WRCW |
+ MD_CNTL_MD_VALUE(0x12));
+ break;
+ case 0x00300000:
+ out_be32(&ddr->sdram_md_cntl,
+ MD_CNTL_MD_EN |
+ MD_CNTL_CS_SEL_CS0_CS1 |
+ 0x04000000 |
+ MD_CNTL_WRCW |
+ MD_CNTL_MD_VALUE(0x1a));
+ break;
+ default:
+ out_be32(&ddr->sdram_md_cntl,
+ MD_CNTL_MD_EN |
+ MD_CNTL_CS_SEL_CS0_CS1 |
+ 0x04000000 |
+ MD_CNTL_WRCW |
+ MD_CNTL_MD_VALUE(0x02));
+ printf("Unsupported RC10\n");
+ break;
+ }
+
+ while (in_be32(&ddr->sdram_md_cntl) & 0x80000000)
+ ;
+ udelay(6);
+ out_be32(&ddr->sdram_cfg, temp_sdram_cfg);
+ out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
+ out_be32(&ddr->debug[2], 0x0);
+ out_be32(&ddr->ddr_zq_cntl, regs->ddr_zq_cntl);
+ out_be32(&ddr->ddr_wrlvl_cntl, regs->ddr_wrlvl_cntl);
+ out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
+ out_be32(&ddr->debug[12], 0x0);
+ out_be32(&ddr->debug[21], 0x0);
+ out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
+
+ }
+#endif
+ /*
+ * For 8572 DDR1 erratum - DDR controller may enter illegal state
+ * when operatiing in 32-bit bus mode with 4-beat bursts,
+ * This erratum does not affect DDR3 mode, only for DDR2 mode.
+ */
+#ifdef CONFIG_SYS_FSL_ERRATUM_DDR_115
+ debug("Workaround for ERRATUM_DDR_115\n");
+ if ((((in_be32(&ddr->sdram_cfg) >> 24) & 0x7) == SDRAM_TYPE_DDR2)
+ && in_be32(&ddr->sdram_cfg) & 0x80000) {
+ /* set DEBUG_1[31] */
+ setbits_be32(&ddr->debug[0], 1);
+ }
+#endif
+#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134
+ debug("Workaround for ERRATUM_DDR111_DDR134\n");
+ /*
+ * This is the combined workaround for DDR111 and DDR134
+ * following the published errata for MPC8572
+ */
+
+ /* 1. Set EEBACR[3] */
+ setbits_be32(&ecm->eebacr, 0x10000000);
+ debug("Setting EEBACR[3] to 0x%08x\n", in_be32(&ecm->eebacr));
+
+ /* 2. Set DINIT in SDRAM_CFG_2*/
+ setbits_be32(&ddr->sdram_cfg_2, SDRAM_CFG2_D_INIT);
+ debug("Setting sdram_cfg_2[D_INIT] to 0x%08x\n",
+ in_be32(&ddr->sdram_cfg_2));
+
+ /* 3. Set DEBUG_3[21] */
+ setbits_be32(&ddr->debug[2], 0x400);
+ debug("Setting DEBUG_3[21] to 0x%08x\n", in_be32(&ddr->debug[2]));
+
+#endif /* part 1 of the workaound */
+
+ /*
+ * 500 painful micro-seconds must elapse between
+ * the DDR clock setup and the DDR config enable.
+ * DDR2 need 200 us, and DDR3 need 500 us from spec,
+ * we choose the max, that is 500 us for all of case.
+ */
+ udelay(500);
+ asm volatile("sync;isync");
+
+ /* Let the controller go */
+ temp_sdram_cfg = in_be32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI;
+ out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN);
+ asm volatile("sync;isync");
+
+ total_gb_size_per_controller = 0;
+ for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+ if (!(regs->cs[i].config & 0x80000000))
+ continue;
+ total_gb_size_per_controller += 1 << (
+ ((regs->cs[i].config >> 14) & 0x3) + 2 +
+ ((regs->cs[i].config >> 8) & 0x7) + 12 +
+ ((regs->cs[i].config >> 0) & 0x7) + 8 +
+ 3 - ((regs->ddr_sdram_cfg >> 19) & 0x3) -
+ 26); /* minus 26 (count of 64M) */
+ }
+ if (fsl_ddr_get_intl3r() & 0x80000000) /* 3-way interleaving */
+ total_gb_size_per_controller *= 3;
+ else if (regs->cs[0].config & 0x20000000) /* 2-way interleaving */
+ total_gb_size_per_controller <<= 1;
+ /*
+ * total memory / bus width = transactions needed
+ * transactions needed / data rate = seconds
+ * to add plenty of buffer, double the time
+ * For example, 2GB on 666MT/s 64-bit bus takes about 402ms
+ * Let's wait for 800ms
+ */
+ bus_width = 3 - ((ddr->sdram_cfg & SDRAM_CFG_DBW_MASK)
+ >> SDRAM_CFG_DBW_SHIFT);
+ timeout = ((total_gb_size_per_controller << (6 - bus_width)) * 100 /
+ (get_ddr_freq(0) >> 20)) << 1;
+#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134
+ timeout_save = timeout;
+#endif
+ total_gb_size_per_controller >>= 4; /* shift down to gb size */
+ debug("total %d GB\n", total_gb_size_per_controller);
+ debug("Need to wait up to %d * 10ms\n", timeout);
+
+ /* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done. */
+ while ((in_be32(&ddr->sdram_cfg_2) & SDRAM_CFG2_D_INIT) &&
+ (timeout >= 0)) {
+ udelay(10000); /* throttle polling rate */
+ timeout--;
+ }
+
+ if (timeout <= 0)
+ printf("Waiting for D_INIT timeout. Memory may not work.\n");
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134
+ /* continue this workaround */
+
+ /* 4. Clear DEBUG3[21] */
+ clrbits_be32(&ddr->debug[2], 0x400);
+ debug("Clearing D3[21] to 0x%08x\n", in_be32(&ddr->debug[2]));
+
+ /* DDR134 workaround starts */
+ /* A: Clear sdram_cfg_2[odt_cfg] */
+ clrbits_be32(&ddr->sdram_cfg_2, SDRAM_CFG2_ODT_CFG_MASK);
+ debug("Clearing SDRAM_CFG2[ODT_CFG] to 0x%08x\n",
+ in_be32(&ddr->sdram_cfg_2));
+
+ /* B: Set DEBUG1[15] */
+ setbits_be32(&ddr->debug[0], 0x10000);
+ debug("Setting D1[15] to 0x%08x\n", in_be32(&ddr->debug[0]));
+
+ /* C: Set timing_cfg_2[cpo] to 0b11111 */
+ setbits_be32(&ddr->timing_cfg_2, TIMING_CFG_2_CPO_MASK);
+ debug("Setting TMING_CFG_2[CPO] to 0x%08x\n",
+ in_be32(&ddr->timing_cfg_2));
+
+ /* D: Set D6 to 0x9f9f9f9f */
+ out_be32(&ddr->debug[5], 0x9f9f9f9f);
+ debug("Setting D6 to 0x%08x\n", in_be32(&ddr->debug[5]));
+
+ /* E: Set D7 to 0x9f9f9f9f */
+ out_be32(&ddr->debug[6], 0x9f9f9f9f);
+ debug("Setting D7 to 0x%08x\n", in_be32(&ddr->debug[6]));
+
+ /* F: Set D2[20] */
+ setbits_be32(&ddr->debug[1], 0x800);
+ debug("Setting D2[20] to 0x%08x\n", in_be32(&ddr->debug[1]));
+
+ /* G: Poll on D2[20] until cleared */
+ while (in_be32(&ddr->debug[1]) & 0x800)
+ udelay(10000); /* throttle polling rate */
+
+ /* H: Clear D1[15] */
+ clrbits_be32(&ddr->debug[0], 0x10000);
+ debug("Setting D1[15] to 0x%08x\n", in_be32(&ddr->debug[0]));
+
+ /* I: Set sdram_cfg_2[odt_cfg] */
+ setbits_be32(&ddr->sdram_cfg_2,
+ regs->ddr_sdram_cfg_2 & SDRAM_CFG2_ODT_CFG_MASK);
+ debug("Setting sdram_cfg_2 to 0x%08x\n", in_be32(&ddr->sdram_cfg_2));
+
+ /* Continuing with the DDR111 workaround */
+ /* 5. Set D2[21] */
+ setbits_be32(&ddr->debug[1], 0x400);
+ debug("Setting D2[21] to 0x%08x\n", in_be32(&ddr->debug[1]));
+
+ /* 6. Poll D2[21] until its cleared */
+ while (in_be32(&ddr->debug[1]) & 0x400)
+ udelay(10000); /* throttle polling rate */
+
+ /* 7. Wait for state machine 2nd run, roughly 400ms/GB */
+ debug("Wait for %d * 10ms\n", timeout_save);
+ udelay(timeout_save * 10000);
+
+ /* 8. Set sdram_cfg_2[dinit] if options requires */
+ setbits_be32(&ddr->sdram_cfg_2,
+ regs->ddr_sdram_cfg_2 & SDRAM_CFG2_D_INIT);
+ debug("Setting sdram_cfg_2 to 0x%08x\n", in_be32(&ddr->sdram_cfg_2));
+
+ /* 9. Poll until dinit is cleared */
+ timeout = timeout_save;
+ debug("Need to wait up to %d * 10ms\n", timeout);
+ while ((in_be32(&ddr->sdram_cfg_2) & SDRAM_CFG2_D_INIT) &&
+ (timeout >= 0)) {
+ udelay(10000); /* throttle polling rate */
+ timeout--;
+ }
+
+ if (timeout <= 0)
+ printf("Waiting for D_INIT timeout. Memory may not work.\n");
+
+ /* 10. Clear EEBACR[3] */
+ clrbits_be32(&ecm->eebacr, 10000000);
+ debug("Clearing EEBACR[3] to 0x%08x\n", in_be32(&ecm->eebacr));
+
+ if (csn != -1) {
+ csn_bnds_t = (unsigned int *) &regs->cs[csn].bnds;
+ *csn_bnds_t = csn_bnds_backup;
+ debug("Change cs%d_bnds back to 0x%08x\n",
+ csn, regs->cs[csn].bnds);
+ setbits_be32(&ddr->sdram_cfg, 0x2); /* MEM_HALT */
+ switch (csn) {
+ case 0:
+ out_be32(&ddr->cs0_bnds, regs->cs[csn].bnds);
+ break;
+ case 1:
+ out_be32(&ddr->cs1_bnds, regs->cs[csn].bnds);
+ break;
+ case 2:
+ out_be32(&ddr->cs2_bnds, regs->cs[csn].bnds);
+ break;
+ case 3:
+ out_be32(&ddr->cs3_bnds, regs->cs[csn].bnds);
+ break;
+ }
+ clrbits_be32(&ddr->sdram_cfg, 0x2);
+ }
+#endif /* CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134 */
+}
diff --git a/arch/powerpc/cpu/mpc85xx/ether_fcc.c b/arch/powerpc/cpu/mpc85xx/ether_fcc.c
new file mode 100644
index 0000000..7d372aa
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/ether_fcc.c
@@ -0,0 +1,468 @@
+/*
+ * MPC8560 FCC Fast Ethernet
+ * Copyright (c) 2003 Motorola,Inc.
+ * Xianghua Xiao, (X.Xiao@motorola.com)
+ *
+ * Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net)
+ *
+ * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * MPC8560 FCC Fast Ethernet
+ * Basic ET HW initialization and packet RX/TX routines
+ *
+ * This code will not perform the IO port configuration. This should be
+ * done in the iop_conf_t structure specific for the board.
+ *
+ * TODO:
+ * add a PHY driver to do the negotiation
+ * reflect negotiation results in FPSMR
+ * look for ways to configure the board specific stuff elsewhere, eg.
+ * config_xxx.h or the board directory
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/cpm_85xx.h>
+#include <command.h>
+#include <config.h>
+#include <net.h>
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#include <miiphy.h>
+#endif
+
+#if defined(CONFIG_ETHER_ON_FCC) && defined(CONFIG_CMD_NET)
+
+static struct ether_fcc_info_s
+{
+ int ether_index;
+ int proff_enet;
+ ulong cpm_cr_enet_sblock;
+ ulong cpm_cr_enet_page;
+ ulong cmxfcr_mask;
+ ulong cmxfcr_value;
+}
+ ether_fcc_info[] =
+{
+#ifdef CONFIG_ETHER_ON_FCC1
+{
+ 0,
+ PROFF_FCC1,
+ CPM_CR_FCC1_SBLOCK,
+ CPM_CR_FCC1_PAGE,
+ CONFIG_SYS_CMXFCR_MASK1,
+ CONFIG_SYS_CMXFCR_VALUE1
+},
+#endif
+
+#ifdef CONFIG_ETHER_ON_FCC2
+{
+ 1,
+ PROFF_FCC2,
+ CPM_CR_FCC2_SBLOCK,
+ CPM_CR_FCC2_PAGE,
+ CONFIG_SYS_CMXFCR_MASK2,
+ CONFIG_SYS_CMXFCR_VALUE2
+},
+#endif
+
+#ifdef CONFIG_ETHER_ON_FCC3
+{
+ 2,
+ PROFF_FCC3,
+ CPM_CR_FCC3_SBLOCK,
+ CPM_CR_FCC3_PAGE,
+ CONFIG_SYS_CMXFCR_MASK3,
+ CONFIG_SYS_CMXFCR_VALUE3
+},
+#endif
+};
+
+/*---------------------------------------------------------------------*/
+
+/* Maximum input DMA size. Must be a should(?) be a multiple of 4. */
+#define PKT_MAXDMA_SIZE 1520
+
+/* The FCC stores dest/src/type, data, and checksum for receive packets. */
+#define PKT_MAXBUF_SIZE 1518
+#define PKT_MINBUF_SIZE 64
+
+/* Maximum input buffer size. Must be a multiple of 32. */
+#define PKT_MAXBLR_SIZE 1536
+
+#define TOUT_LOOP 1000000
+
+#define TX_BUF_CNT 2
+
+static uint rxIdx; /* index of the current RX buffer */
+static uint txIdx; /* index of the current TX buffer */
+
+/*
+ * FCC Ethernet Tx and Rx buffer descriptors.
+ * Provide for Double Buffering
+ * Note: PKTBUFSRX is defined in net.h
+ */
+
+typedef volatile struct rtxbd {
+ cbd_t rxbd[PKTBUFSRX];
+ cbd_t txbd[TX_BUF_CNT];
+} RTXBD;
+
+/* Good news: the FCC supports external BDs! */
+#ifdef __GNUC__
+static RTXBD rtx __attribute__ ((aligned(8)));
+#else
+#error "rtx must be 64-bit aligned"
+#endif
+
+#undef ET_DEBUG
+
+static int fec_send(struct eth_device *dev, void *packet, int length)
+{
+ int i = 0;
+ int result = 0;
+
+ if (length <= 0) {
+ printf("fec: bad packet size: %d\n", length);
+ goto out;
+ }
+
+ for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
+ if (i >= TOUT_LOOP) {
+ printf("fec: tx buffer not ready\n");
+ goto out;
+ }
+ }
+
+ rtx.txbd[txIdx].cbd_bufaddr = (uint)packet;
+ rtx.txbd[txIdx].cbd_datlen = length;
+ rtx.txbd[txIdx].cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_LAST | \
+ BD_ENET_TX_TC | BD_ENET_TX_PAD);
+
+ for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
+ if (i >= TOUT_LOOP) {
+ printf("fec: tx error\n");
+ goto out;
+ }
+ }
+
+#ifdef ET_DEBUG
+ printf("cycles: 0x%x txIdx=0x%04x status: 0x%04x\n", i, txIdx,rtx.txbd[txIdx].cbd_sc);
+ printf("packets at 0x%08x, length_in_bytes=0x%x\n",(uint)packet,length);
+ for(i=0;i<(length/16 + 1);i++) {
+ printf("%08x %08x %08x %08x\n",*((uint *)rtx.txbd[txIdx].cbd_bufaddr+i*4),\
+ *((uint *)rtx.txbd[txIdx].cbd_bufaddr + i*4 + 1),*((uint *)rtx.txbd[txIdx].cbd_bufaddr + i*4 + 2), \
+ *((uint *)rtx.txbd[txIdx].cbd_bufaddr + i*4 + 3));
+ }
+#endif
+
+ /* return only status bits */
+ result = rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_STATS;
+ txIdx = (txIdx + 1) % TX_BUF_CNT;
+
+out:
+ return result;
+}
+
+static int fec_recv(struct eth_device* dev)
+{
+ int length;
+
+ for (;;)
+ {
+ if (rtx.rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
+ length = -1;
+ break; /* nothing received - leave for() loop */
+ }
+ length = rtx.rxbd[rxIdx].cbd_datlen;
+
+ if (rtx.rxbd[rxIdx].cbd_sc & 0x003f) {
+ printf("fec: rx error %04x\n", rtx.rxbd[rxIdx].cbd_sc);
+ }
+ else {
+ /* Pass the packet up to the protocol layers. */
+ NetReceive(NetRxPackets[rxIdx], length - 4);
+ }
+
+
+ /* Give the buffer back to the FCC. */
+ rtx.rxbd[rxIdx].cbd_datlen = 0;
+
+ /* wrap around buffer index when necessary */
+ if ((rxIdx + 1) >= PKTBUFSRX) {
+ rtx.rxbd[PKTBUFSRX - 1].cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
+ rxIdx = 0;
+ }
+ else {
+ rtx.rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
+ rxIdx++;
+ }
+ }
+ return length;
+}
+
+
+static int fec_init(struct eth_device* dev, bd_t *bis)
+{
+ struct ether_fcc_info_s * info = dev->priv;
+ int i;
+ volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+ volatile ccsr_cpm_cp_t *cp = &(cpm->im_cpm_cp);
+ fcc_enet_t *pram_ptr;
+ unsigned long mem_addr;
+
+#if 0
+ mii_discover_phy();
+#endif
+
+ /* 28.9 - (1-2): ioports have been set up already */
+
+ /* 28.9 - (3): connect FCC's tx and rx clocks */
+ cpm->im_cpm_mux.cmxuar = 0; /* ATM */
+ cpm->im_cpm_mux.cmxfcr = (cpm->im_cpm_mux.cmxfcr & ~info->cmxfcr_mask) |
+ info->cmxfcr_value;
+
+ /* 28.9 - (4): GFMR: disable tx/rx, CCITT CRC, set Mode Ethernet */
+ if(info->ether_index == 0) {
+ cpm->im_cpm_fcc1.gfmr = FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32;
+ } else if (info->ether_index == 1) {
+ cpm->im_cpm_fcc2.gfmr = FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32;
+ } else if (info->ether_index == 2) {
+ cpm->im_cpm_fcc3.gfmr = FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32;
+ }
+
+ /* 28.9 - (5): FPSMR: enable full duplex, select CCITT CRC for Ethernet,MII */
+ if(info->ether_index == 0) {
+ cpm->im_cpm_fcc1.fpsmr = CONFIG_SYS_FCC_PSMR | FCC_PSMR_ENCRC;
+ } else if (info->ether_index == 1){
+ cpm->im_cpm_fcc2.fpsmr = CONFIG_SYS_FCC_PSMR | FCC_PSMR_ENCRC;
+ } else if (info->ether_index == 2){
+ cpm->im_cpm_fcc3.fpsmr = CONFIG_SYS_FCC_PSMR | FCC_PSMR_ENCRC;
+ }
+
+ /* 28.9 - (6): FDSR: Ethernet Syn */
+ if(info->ether_index == 0) {
+ cpm->im_cpm_fcc1.fdsr = 0xD555;
+ } else if (info->ether_index == 1) {
+ cpm->im_cpm_fcc2.fdsr = 0xD555;
+ } else if (info->ether_index == 2) {
+ cpm->im_cpm_fcc3.fdsr = 0xD555;
+ }
+
+ /* reset indeces to current rx/tx bd (see eth_send()/eth_rx()) */
+ rxIdx = 0;
+ txIdx = 0;
+
+ /* Setup Receiver Buffer Descriptors */
+ for (i = 0; i < PKTBUFSRX; i++)
+ {
+ rtx.rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
+ rtx.rxbd[i].cbd_datlen = 0;
+ rtx.rxbd[i].cbd_bufaddr = (uint)NetRxPackets[i];
+ }
+ rtx.rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+ /* Setup Ethernet Transmitter Buffer Descriptors */
+ for (i = 0; i < TX_BUF_CNT; i++)
+ {
+ rtx.txbd[i].cbd_sc = 0;
+ rtx.txbd[i].cbd_datlen = 0;
+ rtx.txbd[i].cbd_bufaddr = 0;
+ }
+ rtx.txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+ /* 28.9 - (7): initialize parameter ram */
+ pram_ptr = (fcc_enet_t *)&(cpm->im_dprambase[info->proff_enet]);
+
+ /* clear whole structure to make sure all reserved fields are zero */
+ memset((void*)pram_ptr, 0, sizeof(fcc_enet_t));
+
+ /*
+ * common Parameter RAM area
+ *
+ * Allocate space in the reserved FCC area of DPRAM for the
+ * internal buffers. No one uses this space (yet), so we
+ * can do this. Later, we will add resource management for
+ * this area.
+ * CPM_FCC_SPECIAL_BASE: 0xB000 for MPC8540, MPC8560
+ * 0x9000 for MPC8541, MPC8555
+ */
+ mem_addr = CPM_FCC_SPECIAL_BASE + ((info->ether_index) * 64);
+ pram_ptr->fen_genfcc.fcc_riptr = mem_addr;
+ pram_ptr->fen_genfcc.fcc_tiptr = mem_addr+32;
+ /*
+ * Set maximum bytes per receive buffer.
+ * It must be a multiple of 32.
+ */
+ pram_ptr->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE; /* 1536 */
+ /* localbus SDRAM should be preferred */
+ pram_ptr->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB |
+ CONFIG_SYS_CPMFCR_RAMTYPE) << 24;
+ pram_ptr->fen_genfcc.fcc_rbase = (unsigned int)(&rtx.rxbd[rxIdx]);
+ pram_ptr->fen_genfcc.fcc_rbdstat = 0;
+ pram_ptr->fen_genfcc.fcc_rbdlen = 0;
+ pram_ptr->fen_genfcc.fcc_rdptr = 0;
+ /* localbus SDRAM should be preferred */
+ pram_ptr->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB |
+ CONFIG_SYS_CPMFCR_RAMTYPE) << 24;
+ pram_ptr->fen_genfcc.fcc_tbase = (unsigned int)(&rtx.txbd[txIdx]);
+ pram_ptr->fen_genfcc.fcc_tbdstat = 0;
+ pram_ptr->fen_genfcc.fcc_tbdlen = 0;
+ pram_ptr->fen_genfcc.fcc_tdptr = 0;
+
+ /* protocol-specific area */
+ pram_ptr->fen_statbuf = 0x0;
+ pram_ptr->fen_cmask = 0xdebb20e3; /* CRC mask */
+ pram_ptr->fen_cpres = 0xffffffff; /* CRC preset */
+ pram_ptr->fen_crcec = 0;
+ pram_ptr->fen_alec = 0;
+ pram_ptr->fen_disfc = 0;
+ pram_ptr->fen_retlim = 15; /* Retry limit threshold */
+ pram_ptr->fen_retcnt = 0;
+ pram_ptr->fen_pper = 0;
+ pram_ptr->fen_boffcnt = 0;
+ pram_ptr->fen_gaddrh = 0;
+ pram_ptr->fen_gaddrl = 0;
+ pram_ptr->fen_mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */
+ /*
+ * Set Ethernet station address.
+ *
+ * This is supplied in the board information structure, so we
+ * copy that into the controller.
+ * So far we have only been given one Ethernet address. We make
+ * it unique by setting a few bits in the upper byte of the
+ * non-static part of the address.
+ */
+#define ea eth_get_dev()->enetaddr
+ pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4];
+ pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2];
+ pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0];
+#undef ea
+ pram_ptr->fen_ibdcount = 0;
+ pram_ptr->fen_ibdstart = 0;
+ pram_ptr->fen_ibdend = 0;
+ pram_ptr->fen_txlen = 0;
+ pram_ptr->fen_iaddrh = 0; /* disable hash */
+ pram_ptr->fen_iaddrl = 0;
+ pram_ptr->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register: 64 */
+ /* pad pointer. use tiptr since we don't need a specific padding char */
+ pram_ptr->fen_padptr = pram_ptr->fen_genfcc.fcc_tiptr;
+ pram_ptr->fen_maxd1 = PKT_MAXDMA_SIZE; /* maximum DMA1 length:1520 */
+ pram_ptr->fen_maxd2 = PKT_MAXDMA_SIZE; /* maximum DMA2 length:1520 */
+
+#if defined(ET_DEBUG)
+ printf("parm_ptr(0xff788500) = %p\n",pram_ptr);
+ printf("pram_ptr->fen_genfcc.fcc_rbase %08x\n",
+ pram_ptr->fen_genfcc.fcc_rbase);
+ printf("pram_ptr->fen_genfcc.fcc_tbase %08x\n",
+ pram_ptr->fen_genfcc.fcc_tbase);
+#endif
+
+ /* 28.9 - (8)(9): clear out events in FCCE */
+ /* 28.9 - (9): FCCM: mask all events */
+ if(info->ether_index == 0) {
+ cpm->im_cpm_fcc1.fcce = ~0x0;
+ cpm->im_cpm_fcc1.fccm = 0;
+ } else if (info->ether_index == 1) {
+ cpm->im_cpm_fcc2.fcce = ~0x0;
+ cpm->im_cpm_fcc2.fccm = 0;
+ } else if (info->ether_index == 2) {
+ cpm->im_cpm_fcc3.fcce = ~0x0;
+ cpm->im_cpm_fcc3.fccm = 0;
+ }
+
+ /* 28.9 - (10-12): we don't use ethernet interrupts */
+
+ /* 28.9 - (13)
+ *
+ * Let's re-initialize the channel now. We have to do it later
+ * than the manual describes because we have just now finished
+ * the BD initialization.
+ */
+ cp->cpcr = mk_cr_cmd(info->cpm_cr_enet_page,
+ info->cpm_cr_enet_sblock,
+ 0x0c,
+ CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ do {
+ __asm__ __volatile__ ("eieio");
+ } while (cp->cpcr & CPM_CR_FLG);
+
+ /* 28.9 - (14): enable tx/rx in gfmr */
+ if(info->ether_index == 0) {
+ cpm->im_cpm_fcc1.gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR;
+ } else if (info->ether_index == 1) {
+ cpm->im_cpm_fcc2.gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR;
+ } else if (info->ether_index == 2) {
+ cpm->im_cpm_fcc3.gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR;
+ }
+
+ return 1;
+}
+
+static void fec_halt(struct eth_device* dev)
+{
+ struct ether_fcc_info_s * info = dev->priv;
+ volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+
+ /* write GFMR: disable tx/rx */
+ if(info->ether_index == 0) {
+ cpm->im_cpm_fcc1.gfmr &= ~(FCC_GFMR_ENT | FCC_GFMR_ENR);
+ } else if(info->ether_index == 1) {
+ cpm->im_cpm_fcc2.gfmr &= ~(FCC_GFMR_ENT | FCC_GFMR_ENR);
+ } else if(info->ether_index == 2) {
+ cpm->im_cpm_fcc3.gfmr &= ~(FCC_GFMR_ENT | FCC_GFMR_ENR);
+ }
+}
+
+int fec_initialize(bd_t *bis)
+{
+ struct eth_device* dev;
+ int i;
+
+ for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++)
+ {
+ dev = (struct eth_device*) malloc(sizeof *dev);
+ memset(dev, 0, sizeof *dev);
+
+ sprintf(dev->name, "FCC%d",
+ ether_fcc_info[i].ether_index + 1);
+ dev->priv = &ether_fcc_info[i];
+ dev->init = fec_init;
+ dev->halt = fec_halt;
+ dev->send = fec_send;
+ dev->recv = fec_recv;
+
+ eth_register(dev);
+
+#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) \
+ && defined(CONFIG_BITBANGMII)
+ miiphy_register(dev->name,
+ bb_miiphy_read, bb_miiphy_write);
+#endif
+ }
+
+ return 1;
+}
+
+#endif
diff --git a/arch/powerpc/cpu/mpc85xx/fdt.c b/arch/powerpc/cpu/mpc85xx/fdt.c
new file mode 100644
index 0000000..bb95f3d
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/fdt.c
@@ -0,0 +1,835 @@
+/*
+ * Copyright 2007-2011 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+#include <asm/processor.h>
+#include <linux/ctype.h>
+#include <asm/io.h>
+#include <asm/fsl_portals.h>
+#ifdef CONFIG_FSL_ESDHC
+#include <fsl_esdhc.h>
+#endif
+#include "../../../../drivers/qe/qe.h" /* For struct qe_firmware */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+extern void ft_qe_setup(void *blob);
+extern void ft_fixup_num_cores(void *blob);
+extern void ft_srio_setup(void *blob);
+
+#ifdef CONFIG_MP
+#include "mp.h"
+
+void ft_fixup_cpu(void *blob, u64 memory_limit)
+{
+ int off;
+ phys_addr_t spin_tbl_addr = get_spin_phys_addr();
+ u32 bootpg = determine_mp_bootpg(NULL);
+ u32 id = get_my_id();
+ const char *enable_method;
+
+ off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
+ while (off != -FDT_ERR_NOTFOUND) {
+ u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0);
+
+ if (reg) {
+ u32 phys_cpu_id = thread_to_core(*reg);
+ u64 val = phys_cpu_id * SIZE_BOOT_ENTRY + spin_tbl_addr;
+ val = cpu_to_fdt64(val);
+ if (*reg == id) {
+ fdt_setprop_string(blob, off, "status",
+ "okay");
+ } else {
+ fdt_setprop_string(blob, off, "status",
+ "disabled");
+ }
+
+ if (hold_cores_in_reset(0)) {
+#ifdef CONFIG_FSL_CORENET
+ /* Cores held in reset, use BRR to release */
+ enable_method = "fsl,brr-holdoff";
+#else
+ /* Cores held in reset, use EEBPCR to release */
+ enable_method = "fsl,eebpcr-holdoff";
+#endif
+ } else {
+ /* Cores out of reset and in a spin-loop */
+ enable_method = "spin-table";
+
+ fdt_setprop(blob, off, "cpu-release-addr",
+ &val, sizeof(val));
+ }
+
+ fdt_setprop_string(blob, off, "enable-method",
+ enable_method);
+ } else {
+ printf ("cpu NULL\n");
+ }
+ off = fdt_node_offset_by_prop_value(blob, off,
+ "device_type", "cpu", 4);
+ }
+
+ /* Reserve the boot page so OSes dont use it */
+ if ((u64)bootpg < memory_limit) {
+ off = fdt_add_mem_rsv(blob, bootpg, (u64)4096);
+ if (off < 0)
+ printf("Failed to reserve memory for bootpg: %s\n",
+ fdt_strerror(off));
+ }
+
+#ifndef CONFIG_MPC8xxx_DISABLE_BPTR
+ /*
+ * Reserve the default boot page so OSes dont use it.
+ * The default boot page is always mapped to bootpg above using
+ * boot page translation.
+ */
+ if (0xfffff000ull < memory_limit) {
+ off = fdt_add_mem_rsv(blob, 0xfffff000ull, (u64)4096);
+ if (off < 0) {
+ printf("Failed to reserve memory for 0xfffff000: %s\n",
+ fdt_strerror(off));
+ }
+ }
+#endif
+
+ /* Reserve spin table page */
+ if (spin_tbl_addr < memory_limit) {
+ off = fdt_add_mem_rsv(blob,
+ (spin_tbl_addr & ~0xffful), 4096);
+ if (off < 0)
+ printf("Failed to reserve memory for spin table: %s\n",
+ fdt_strerror(off));
+ }
+}
+#endif
+
+#ifdef CONFIG_SYS_FSL_CPC
+static inline void ft_fixup_l3cache(void *blob, int off)
+{
+ u32 line_size, num_ways, size, num_sets;
+ cpc_corenet_t *cpc = (void *)CONFIG_SYS_FSL_CPC_ADDR;
+ u32 cfg0 = in_be32(&cpc->cpccfg0);
+
+ size = CPC_CFG0_SZ_K(cfg0) * 1024 * CONFIG_SYS_NUM_CPC;
+ num_ways = CPC_CFG0_NUM_WAYS(cfg0);
+ line_size = CPC_CFG0_LINE_SZ(cfg0);
+ num_sets = size / (line_size * num_ways);
+
+ fdt_setprop(blob, off, "cache-unified", NULL, 0);
+ fdt_setprop_cell(blob, off, "cache-block-size", line_size);
+ fdt_setprop_cell(blob, off, "cache-size", size);
+ fdt_setprop_cell(blob, off, "cache-sets", num_sets);
+ fdt_setprop_cell(blob, off, "cache-level", 3);
+#ifdef CONFIG_SYS_CACHE_STASHING
+ fdt_setprop_cell(blob, off, "cache-stash-id", 1);
+#endif
+}
+#else
+#define ft_fixup_l3cache(x, y)
+#endif
+
+#if defined(CONFIG_L2_CACHE)
+/* return size in kilobytes */
+static inline u32 l2cache_size(void)
+{
+ volatile ccsr_l2cache_t *l2cache = (void *)CONFIG_SYS_MPC85xx_L2_ADDR;
+ volatile u32 l2siz_field = (l2cache->l2ctl >> 28) & 0x3;
+ u32 ver = SVR_SOC_VER(get_svr());
+
+ switch (l2siz_field) {
+ case 0x0:
+ break;
+ case 0x1:
+ if (ver == SVR_8540 || ver == SVR_8560 ||
+ ver == SVR_8541 || ver == SVR_8555)
+ return 128;
+ else
+ return 256;
+ break;
+ case 0x2:
+ if (ver == SVR_8540 || ver == SVR_8560 ||
+ ver == SVR_8541 || ver == SVR_8555)
+ return 256;
+ else
+ return 512;
+ break;
+ case 0x3:
+ return 1024;
+ break;
+ }
+
+ return 0;
+}
+
+static inline void ft_fixup_l2cache(void *blob)
+{
+ int len, off;
+ u32 *ph;
+ struct cpu_type *cpu = identify_cpu(SVR_SOC_VER(get_svr()));
+
+ const u32 line_size = 32;
+ const u32 num_ways = 8;
+ const u32 size = l2cache_size() * 1024;
+ const u32 num_sets = size / (line_size * num_ways);
+
+ off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
+ if (off < 0) {
+ debug("no cpu node fount\n");
+ return;
+ }
+
+ ph = (u32 *)fdt_getprop(blob, off, "next-level-cache", 0);
+
+ if (ph == NULL) {
+ debug("no next-level-cache property\n");
+ return ;
+ }
+
+ off = fdt_node_offset_by_phandle(blob, *ph);
+ if (off < 0) {
+ printf("%s: %s\n", __func__, fdt_strerror(off));
+ return ;
+ }
+
+ if (cpu) {
+ char buf[40];
+
+ if (isdigit(cpu->name[0])) {
+ /* MPCxxxx, where xxxx == 4-digit number */
+ len = sprintf(buf, "fsl,mpc%s-l2-cache-controller",
+ cpu->name) + 1;
+ } else {
+ /* Pxxxx or Txxxx, where xxxx == 4-digit number */
+ len = sprintf(buf, "fsl,%c%s-l2-cache-controller",
+ tolower(cpu->name[0]), cpu->name + 1) + 1;
+ }
+
+ /*
+ * append "cache" after the NULL character that the previous
+ * sprintf wrote. This is how a device tree stores multiple
+ * strings in a property.
+ */
+ len += sprintf(buf + len, "cache") + 1;
+
+ fdt_setprop(blob, off, "compatible", buf, len);
+ }
+ fdt_setprop(blob, off, "cache-unified", NULL, 0);
+ fdt_setprop_cell(blob, off, "cache-block-size", line_size);
+ fdt_setprop_cell(blob, off, "cache-size", size);
+ fdt_setprop_cell(blob, off, "cache-sets", num_sets);
+ fdt_setprop_cell(blob, off, "cache-level", 2);
+
+ /* we dont bother w/L3 since no platform of this type has one */
+}
+#elif defined(CONFIG_BACKSIDE_L2_CACHE) || \
+ defined(CONFIG_SYS_FSL_QORIQ_CHASSIS2)
+static inline void ft_fixup_l2cache(void *blob)
+{
+ int off, l2_off, l3_off = -1;
+ u32 *ph;
+#ifdef CONFIG_BACKSIDE_L2_CACHE
+ u32 l2cfg0 = mfspr(SPRN_L2CFG0);
+#else
+ struct ccsr_cluster_l2 *l2cache =
+ (struct ccsr_cluster_l2 __iomem *)(CONFIG_SYS_FSL_CLUSTER_1_L2);
+ u32 l2cfg0 = in_be32(&l2cache->l2cfg0);
+#endif
+ u32 size, line_size, num_ways, num_sets;
+ int has_l2 = 1;
+
+ /* P2040/P2040E has no L2, so dont set any L2 props */
+ if (SVR_SOC_VER(get_svr()) == SVR_P2040)
+ has_l2 = 0;
+
+ size = (l2cfg0 & 0x3fff) * 64 * 1024;
+ num_ways = ((l2cfg0 >> 14) & 0x1f) + 1;
+ line_size = (((l2cfg0 >> 23) & 0x3) + 1) * 32;
+ num_sets = size / (line_size * num_ways);
+
+ off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
+
+ while (off != -FDT_ERR_NOTFOUND) {
+ ph = (u32 *)fdt_getprop(blob, off, "next-level-cache", 0);
+
+ if (ph == NULL) {
+ debug("no next-level-cache property\n");
+ goto next;
+ }
+
+ l2_off = fdt_node_offset_by_phandle(blob, *ph);
+ if (l2_off < 0) {
+ printf("%s: %s\n", __func__, fdt_strerror(off));
+ goto next;
+ }
+
+ if (has_l2) {
+#ifdef CONFIG_SYS_CACHE_STASHING
+ u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0);
+#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2
+ /* Only initialize every eighth thread */
+ if (reg && !((*reg) % 8))
+#else
+ if (reg)
+#endif
+ fdt_setprop_cell(blob, l2_off, "cache-stash-id",
+ (*reg * 2) + 32 + 1);
+#endif
+
+ fdt_setprop(blob, l2_off, "cache-unified", NULL, 0);
+ fdt_setprop_cell(blob, l2_off, "cache-block-size",
+ line_size);
+ fdt_setprop_cell(blob, l2_off, "cache-size", size);
+ fdt_setprop_cell(blob, l2_off, "cache-sets", num_sets);
+ fdt_setprop_cell(blob, l2_off, "cache-level", 2);
+ fdt_setprop(blob, l2_off, "compatible", "cache", 6);
+ }
+
+ if (l3_off < 0) {
+ ph = (u32 *)fdt_getprop(blob, l2_off, "next-level-cache", 0);
+
+ if (ph == NULL) {
+ debug("no next-level-cache property\n");
+ goto next;
+ }
+ l3_off = *ph;
+ }
+next:
+ off = fdt_node_offset_by_prop_value(blob, off,
+ "device_type", "cpu", 4);
+ }
+ if (l3_off > 0) {
+ l3_off = fdt_node_offset_by_phandle(blob, l3_off);
+ if (l3_off < 0) {
+ printf("%s: %s\n", __func__, fdt_strerror(off));
+ return ;
+ }
+ ft_fixup_l3cache(blob, l3_off);
+ }
+}
+#else
+#define ft_fixup_l2cache(x)
+#endif
+
+static inline void ft_fixup_cache(void *blob)
+{
+ int off;
+
+ off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
+
+ while (off != -FDT_ERR_NOTFOUND) {
+ u32 l1cfg0 = mfspr(SPRN_L1CFG0);
+ u32 l1cfg1 = mfspr(SPRN_L1CFG1);
+ u32 isize, iline_size, inum_sets, inum_ways;
+ u32 dsize, dline_size, dnum_sets, dnum_ways;
+
+ /* d-side config */
+ dsize = (l1cfg0 & 0x7ff) * 1024;
+ dnum_ways = ((l1cfg0 >> 11) & 0xff) + 1;
+ dline_size = (((l1cfg0 >> 23) & 0x3) + 1) * 32;
+ dnum_sets = dsize / (dline_size * dnum_ways);
+
+ fdt_setprop_cell(blob, off, "d-cache-block-size", dline_size);
+ fdt_setprop_cell(blob, off, "d-cache-size", dsize);
+ fdt_setprop_cell(blob, off, "d-cache-sets", dnum_sets);
+
+#ifdef CONFIG_SYS_CACHE_STASHING
+ {
+ u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0);
+ if (reg)
+ fdt_setprop_cell(blob, off, "cache-stash-id",
+ (*reg * 2) + 32 + 0);
+ }
+#endif
+
+ /* i-side config */
+ isize = (l1cfg1 & 0x7ff) * 1024;
+ inum_ways = ((l1cfg1 >> 11) & 0xff) + 1;
+ iline_size = (((l1cfg1 >> 23) & 0x3) + 1) * 32;
+ inum_sets = isize / (iline_size * inum_ways);
+
+ fdt_setprop_cell(blob, off, "i-cache-block-size", iline_size);
+ fdt_setprop_cell(blob, off, "i-cache-size", isize);
+ fdt_setprop_cell(blob, off, "i-cache-sets", inum_sets);
+
+ off = fdt_node_offset_by_prop_value(blob, off,
+ "device_type", "cpu", 4);
+ }
+
+ ft_fixup_l2cache(blob);
+}
+
+
+void fdt_add_enet_stashing(void *fdt)
+{
+ do_fixup_by_compat(fdt, "gianfar", "bd-stash", NULL, 0, 1);
+
+ do_fixup_by_compat_u32(fdt, "gianfar", "rx-stash-len", 96, 1);
+
+ do_fixup_by_compat_u32(fdt, "gianfar", "rx-stash-idx", 0, 1);
+ do_fixup_by_compat(fdt, "fsl,etsec2", "bd-stash", NULL, 0, 1);
+ do_fixup_by_compat_u32(fdt, "fsl,etsec2", "rx-stash-len", 96, 1);
+ do_fixup_by_compat_u32(fdt, "fsl,etsec2", "rx-stash-idx", 0, 1);
+}
+
+#if defined(CONFIG_SYS_DPAA_FMAN) || defined(CONFIG_SYS_DPAA_PME)
+#ifdef CONFIG_SYS_DPAA_FMAN
+static void ft_fixup_clks(void *blob, const char *compat, u32 offset,
+ unsigned long freq)
+{
+ phys_addr_t phys = offset + CONFIG_SYS_CCSRBAR_PHYS;
+ int off = fdt_node_offset_by_compat_reg(blob, compat, phys);
+
+ if (off >= 0) {
+ off = fdt_setprop_cell(blob, off, "clock-frequency", freq);
+ if (off > 0)
+ printf("WARNING enable to set clock-frequency "
+ "for %s: %s\n", compat, fdt_strerror(off));
+ }
+}
+#endif
+
+static void ft_fixup_dpaa_clks(void *blob)
+{
+ sys_info_t sysinfo;
+
+ get_sys_info(&sysinfo);
+#ifdef CONFIG_SYS_DPAA_FMAN
+ ft_fixup_clks(blob, "fsl,fman", CONFIG_SYS_FSL_FM1_OFFSET,
+ sysinfo.freqFMan[0]);
+
+#if (CONFIG_SYS_NUM_FMAN == 2)
+ ft_fixup_clks(blob, "fsl,fman", CONFIG_SYS_FSL_FM2_OFFSET,
+ sysinfo.freqFMan[1]);
+#endif
+#endif
+
+#ifdef CONFIG_SYS_DPAA_QBMAN
+ do_fixup_by_compat_u32(blob, "fsl,qman",
+ "clock-frequency", sysinfo.freqQMAN, 1);
+#endif
+
+#ifdef CONFIG_SYS_DPAA_PME
+ do_fixup_by_compat_u32(blob, "fsl,pme",
+ "clock-frequency", sysinfo.freqPME, 1);
+#endif
+}
+#else
+#define ft_fixup_dpaa_clks(x)
+#endif
+
+#ifdef CONFIG_QE
+static void ft_fixup_qe_snum(void *blob)
+{
+ unsigned int svr;
+
+ svr = mfspr(SPRN_SVR);
+ if (SVR_SOC_VER(svr) == SVR_8569) {
+ if(IS_SVR_REV(svr, 1, 0))
+ do_fixup_by_compat_u32(blob, "fsl,qe",
+ "fsl,qe-num-snums", 46, 1);
+ else
+ do_fixup_by_compat_u32(blob, "fsl,qe",
+ "fsl,qe-num-snums", 76, 1);
+ }
+}
+#endif
+
+/**
+ * fdt_fixup_fman_firmware -- insert the Fman firmware into the device tree
+ *
+ * The binding for an Fman firmware node is documented in
+ * Documentation/powerpc/dts-bindings/fsl/dpaa/fman.txt. This node contains
+ * the actual Fman firmware binary data. The operating system is expected to
+ * be able to parse the binary data to determine any attributes it needs.
+ */
+#ifdef CONFIG_SYS_DPAA_FMAN
+void fdt_fixup_fman_firmware(void *blob)
+{
+ int rc, fmnode, fwnode = -1;
+ uint32_t phandle;
+ struct qe_firmware *fmanfw;
+ const struct qe_header *hdr;
+ unsigned int length;
+ uint32_t crc;
+ const char *p;
+
+ /* The first Fman we find will contain the actual firmware. */
+ fmnode = fdt_node_offset_by_compatible(blob, -1, "fsl,fman");
+ if (fmnode < 0)
+ /* Exit silently if there are no Fman devices */
+ return;
+
+ /* If we already have a firmware node, then also exit silently. */
+ if (fdt_node_offset_by_compatible(blob, -1, "fsl,fman-firmware") > 0)
+ return;
+
+ /* If the environment variable is not set, then exit silently */
+ p = getenv("fman_ucode");
+ if (!p)
+ return;
+
+ fmanfw = (struct qe_firmware *) simple_strtoul(p, NULL, 0);
+ if (!fmanfw)
+ return;
+
+ hdr = &fmanfw->header;
+ length = be32_to_cpu(hdr->length);
+
+ /* Verify the firmware. */
+ if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
+ (hdr->magic[2] != 'F')) {
+ printf("Data at %p is not an Fman firmware\n", fmanfw);
+ return;
+ }
+
+ if (length > CONFIG_SYS_QE_FMAN_FW_LENGTH) {
+ printf("Fman firmware at %p is too large (size=%u)\n",
+ fmanfw, length);
+ return;
+ }
+
+ length -= sizeof(u32); /* Subtract the size of the CRC */
+ crc = be32_to_cpu(*(u32 *)((void *)fmanfw + length));
+ if (crc != crc32_no_comp(0, (void *)fmanfw, length)) {
+ printf("Fman firmware at %p has invalid CRC\n", fmanfw);
+ return;
+ }
+
+ /* Increase the size of the fdt to make room for the node. */
+ rc = fdt_increase_size(blob, fmanfw->header.length);
+ if (rc < 0) {
+ printf("Unable to make room for Fman firmware: %s\n",
+ fdt_strerror(rc));
+ return;
+ }
+
+ /* Create the firmware node. */
+ fwnode = fdt_add_subnode(blob, fmnode, "fman-firmware");
+ if (fwnode < 0) {
+ char s[64];
+ fdt_get_path(blob, fmnode, s, sizeof(s));
+ printf("Could not add firmware node to %s: %s\n", s,
+ fdt_strerror(fwnode));
+ return;
+ }
+ rc = fdt_setprop_string(blob, fwnode, "compatible", "fsl,fman-firmware");
+ if (rc < 0) {
+ char s[64];
+ fdt_get_path(blob, fwnode, s, sizeof(s));
+ printf("Could not add compatible property to node %s: %s\n", s,
+ fdt_strerror(rc));
+ return;
+ }
+ phandle = fdt_create_phandle(blob, fwnode);
+ if (!phandle) {
+ char s[64];
+ fdt_get_path(blob, fwnode, s, sizeof(s));
+ printf("Could not add phandle property to node %s: %s\n", s,
+ fdt_strerror(rc));
+ return;
+ }
+ rc = fdt_setprop(blob, fwnode, "fsl,firmware", fmanfw, fmanfw->header.length);
+ if (rc < 0) {
+ char s[64];
+ fdt_get_path(blob, fwnode, s, sizeof(s));
+ printf("Could not add firmware property to node %s: %s\n", s,
+ fdt_strerror(rc));
+ return;
+ }
+
+ /* Find all other Fman nodes and point them to the firmware node. */
+ while ((fmnode = fdt_node_offset_by_compatible(blob, fmnode, "fsl,fman")) > 0) {
+ rc = fdt_setprop_cell(blob, fmnode, "fsl,firmware-phandle", phandle);
+ if (rc < 0) {
+ char s[64];
+ fdt_get_path(blob, fmnode, s, sizeof(s));
+ printf("Could not add pointer property to node %s: %s\n",
+ s, fdt_strerror(rc));
+ return;
+ }
+ }
+}
+#else
+#define fdt_fixup_fman_firmware(x)
+#endif
+
+#if defined(CONFIG_PPC_P4080)
+static void fdt_fixup_usb(void *fdt)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 rcwsr11 = in_be32(&gur->rcwsr[11]);
+ int off;
+
+ off = fdt_node_offset_by_compatible(fdt, -1, "fsl,mpc85xx-usb2-mph");
+ if ((rcwsr11 & FSL_CORENET_RCWSR11_EC1) !=
+ FSL_CORENET_RCWSR11_EC1_FM1_USB1)
+ fdt_status_disabled(fdt, off);
+
+ off = fdt_node_offset_by_compatible(fdt, -1, "fsl,mpc85xx-usb2-dr");
+ if ((rcwsr11 & FSL_CORENET_RCWSR11_EC2) !=
+ FSL_CORENET_RCWSR11_EC2_USB2)
+ fdt_status_disabled(fdt, off);
+}
+#else
+#define fdt_fixup_usb(x)
+#endif
+
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+ int off;
+ int val;
+ sys_info_t sysinfo;
+
+ /* delete crypto node if not on an E-processor */
+ if (!IS_E_PROCESSOR(get_svr()))
+ fdt_fixup_crypto_node(blob, 0);
+#if CONFIG_SYS_FSL_SEC_COMPAT >= 4
+ else {
+ ccsr_sec_t __iomem *sec;
+
+ sec = (void __iomem *)CONFIG_SYS_FSL_SEC_ADDR;
+ fdt_fixup_crypto_node(blob, in_be32(&sec->secvid_ms));
+ }
+#endif
+
+ fdt_fixup_ethernet(blob);
+
+ fdt_add_enet_stashing(blob);
+
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "timebase-frequency", get_tbclk(), 1);
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "bus-frequency", bd->bi_busfreq, 1);
+ get_sys_info(&sysinfo);
+ off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
+ while (off != -FDT_ERR_NOTFOUND) {
+ u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0);
+ val = cpu_to_fdt32(sysinfo.freqProcessor[*reg]);
+ fdt_setprop(blob, off, "clock-frequency", &val, 4);
+ off = fdt_node_offset_by_prop_value(blob, off, "device_type",
+ "cpu", 4);
+ }
+ do_fixup_by_prop_u32(blob, "device_type", "soc", 4,
+ "bus-frequency", bd->bi_busfreq, 1);
+
+ do_fixup_by_compat_u32(blob, "fsl,pq3-localbus",
+ "bus-frequency", gd->arch.lbc_clk, 1);
+ do_fixup_by_compat_u32(blob, "fsl,elbc",
+ "bus-frequency", gd->arch.lbc_clk, 1);
+#ifdef CONFIG_QE
+ ft_qe_setup(blob);
+ ft_fixup_qe_snum(blob);
+#endif
+
+ fdt_fixup_fman_firmware(blob);
+
+#ifdef CONFIG_SYS_NS16550
+ do_fixup_by_compat_u32(blob, "ns16550",
+ "clock-frequency", CONFIG_SYS_NS16550_CLK, 1);
+#endif
+
+#ifdef CONFIG_CPM2
+ do_fixup_by_compat_u32(blob, "fsl,cpm2-scc-uart",
+ "current-speed", bd->bi_baudrate, 1);
+
+ do_fixup_by_compat_u32(blob, "fsl,cpm2-brg",
+ "clock-frequency", bd->bi_brgfreq, 1);
+#endif
+
+#ifdef CONFIG_FSL_CORENET
+ do_fixup_by_compat_u32(blob, "fsl,qoriq-clockgen-1.0",
+ "clock-frequency", CONFIG_SYS_CLK_FREQ, 1);
+ do_fixup_by_compat_u32(blob, "fsl,qoriq-clockgen-2.0",
+ "clock-frequency", CONFIG_SYS_CLK_FREQ, 1);
+ do_fixup_by_compat_u32(blob, "fsl,mpic",
+ "clock-frequency", get_bus_freq(0)/2, 1);
+#else
+ do_fixup_by_compat_u32(blob, "fsl,mpic",
+ "clock-frequency", get_bus_freq(0), 1);
+#endif
+
+ fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+
+#ifdef CONFIG_MP
+ ft_fixup_cpu(blob, (u64)bd->bi_memstart + (u64)bd->bi_memsize);
+ ft_fixup_num_cores(blob);
+#endif
+
+ ft_fixup_cache(blob);
+
+#if defined(CONFIG_FSL_ESDHC)
+ fdt_fixup_esdhc(blob, bd);
+#endif
+
+ ft_fixup_dpaa_clks(blob);
+
+#if defined(CONFIG_SYS_BMAN_MEM_PHYS)
+ fdt_portal(blob, "fsl,bman-portal", "bman-portals",
+ (u64)CONFIG_SYS_BMAN_MEM_PHYS,
+ CONFIG_SYS_BMAN_MEM_SIZE);
+ fdt_fixup_bportals(blob);
+#endif
+
+#if defined(CONFIG_SYS_QMAN_MEM_PHYS)
+ fdt_portal(blob, "fsl,qman-portal", "qman-portals",
+ (u64)CONFIG_SYS_QMAN_MEM_PHYS,
+ CONFIG_SYS_QMAN_MEM_SIZE);
+
+ fdt_fixup_qportals(blob);
+#endif
+
+#ifdef CONFIG_SYS_SRIO
+ ft_srio_setup(blob);
+#endif
+
+ /*
+ * system-clock = CCB clock/2
+ * Here gd->bus_clk = CCB clock
+ * We are using the system clock as 1588 Timer reference
+ * clock source select
+ */
+ do_fixup_by_compat_u32(blob, "fsl,gianfar-ptp-timer",
+ "timer-frequency", gd->bus_clk/2, 1);
+
+ /*
+ * clock-freq should change to clock-frequency and
+ * flexcan-v1.0 should change to p1010-flexcan respectively
+ * in the future.
+ */
+ do_fixup_by_compat_u32(blob, "fsl,flexcan-v1.0",
+ "clock_freq", gd->bus_clk/2, 1);
+
+ do_fixup_by_compat_u32(blob, "fsl,flexcan-v1.0",
+ "clock-frequency", gd->bus_clk/2, 1);
+
+ do_fixup_by_compat_u32(blob, "fsl,p1010-flexcan",
+ "clock-frequency", gd->bus_clk/2, 1);
+
+ fdt_fixup_usb(blob);
+}
+
+/*
+ * For some CCSR devices, we only have the virtual address, not the physical
+ * address. This is because we map CCSR as a whole, so we typically don't need
+ * a macro for the physical address of any device within CCSR. In this case,
+ * we calculate the physical address of that device using it's the difference
+ * between the virtual address of the device and the virtual address of the
+ * beginning of CCSR.
+ */
+#define CCSR_VIRT_TO_PHYS(x) \
+ (CONFIG_SYS_CCSRBAR_PHYS + ((x) - CONFIG_SYS_CCSRBAR))
+
+static void msg(const char *name, uint64_t uaddr, uint64_t daddr)
+{
+ printf("Warning: U-Boot configured %s at address %llx,\n"
+ "but the device tree has it at %llx\n", name, uaddr, daddr);
+}
+
+/*
+ * Verify the device tree
+ *
+ * This function compares several CONFIG_xxx macros that contain physical
+ * addresses with the corresponding nodes in the device tree, to see if
+ * the physical addresses are all correct. For example, if
+ * CONFIG_SYS_NS16550_COM1 is defined, then it contains the virtual address
+ * of the first UART. We convert this to a physical address and compare
+ * that with the physical address of the first ns16550-compatible node
+ * in the device tree. If they don't match, then we display a warning.
+ *
+ * Returns 1 on success, 0 on failure
+ */
+int ft_verify_fdt(void *fdt)
+{
+ uint64_t addr = 0;
+ int aliases;
+ int off;
+
+ /* First check the CCSR base address */
+ off = fdt_node_offset_by_prop_value(fdt, -1, "device_type", "soc", 4);
+ if (off > 0)
+ addr = fdt_get_base_address(fdt, off);
+
+ if (!addr) {
+ printf("Warning: could not determine base CCSR address in "
+ "device tree\n");
+ /* No point in checking anything else */
+ return 0;
+ }
+
+ if (addr != CONFIG_SYS_CCSRBAR_PHYS) {
+ msg("CCSR", CONFIG_SYS_CCSRBAR_PHYS, addr);
+ /* No point in checking anything else */
+ return 0;
+ }
+
+ /*
+ * Check some nodes via aliases. We assume that U-Boot and the device
+ * tree enumerate the devices equally. E.g. the first serial port in
+ * U-Boot is the same as "serial0" in the device tree.
+ */
+ aliases = fdt_path_offset(fdt, "/aliases");
+ if (aliases > 0) {
+#ifdef CONFIG_SYS_NS16550_COM1
+ if (!fdt_verify_alias_address(fdt, aliases, "serial0",
+ CCSR_VIRT_TO_PHYS(CONFIG_SYS_NS16550_COM1)))
+ return 0;
+#endif
+
+#ifdef CONFIG_SYS_NS16550_COM2
+ if (!fdt_verify_alias_address(fdt, aliases, "serial1",
+ CCSR_VIRT_TO_PHYS(CONFIG_SYS_NS16550_COM2)))
+ return 0;
+#endif
+ }
+
+ /*
+ * The localbus node is typically a root node, even though the lbc
+ * controller is part of CCSR. If we were to put the lbc node under
+ * the SOC node, then the 'ranges' property in the lbc node would
+ * translate through the 'ranges' property of the parent SOC node, and
+ * we don't want that. Since it's a separate node, it's possible for
+ * the 'reg' property to be wrong, so check it here. For now, we
+ * only check for "fsl,elbc" nodes.
+ */
+#ifdef CONFIG_SYS_LBC_ADDR
+ off = fdt_node_offset_by_compatible(fdt, -1, "fsl,elbc");
+ if (off > 0) {
+ const fdt32_t *reg = fdt_getprop(fdt, off, "reg", NULL);
+ if (reg) {
+ uint64_t uaddr = CCSR_VIRT_TO_PHYS(CONFIG_SYS_LBC_ADDR);
+
+ addr = fdt_translate_address(fdt, off, reg);
+ if (uaddr != addr) {
+ msg("the localbus", uaddr, addr);
+ return 0;
+ }
+ }
+ }
+#endif
+
+ return 1;
+}
diff --git a/arch/powerpc/cpu/mpc85xx/fixed_ivor.S b/arch/powerpc/cpu/mpc85xx/fixed_ivor.S
new file mode 100644
index 0000000..320cae3
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/fixed_ivor.S
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * Kumar Gala <kumar.gala@freescale.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* This file is intended to be included by other asm code since
+ * we will want to execute this on both the primary core when
+ * it does a bootm and the secondary core's that get released
+ * out of the spin table */
+
+#define SET_IVOR(vector_number, vector_offset) \
+ li r3,vector_offset@l; \
+ mtspr SPRN_IVOR##vector_number,r3;
+
+#define SET_GIVOR(vector_number, vector_offset) \
+ li r3,vector_offset@l; \
+ mtspr SPRN_GIVOR##vector_number,r3;
+
+ SET_IVOR(0, 0x020) /* Critical Input */
+ SET_IVOR(1, 0x000) /* Machine Check */
+ SET_IVOR(2, 0x060) /* Data Storage */
+ SET_IVOR(3, 0x080) /* Instruction Storage */
+ SET_IVOR(4, 0x0a0) /* External Input */
+ SET_IVOR(5, 0x0c0) /* Alignment */
+ SET_IVOR(6, 0x0e0) /* Program */
+ SET_IVOR(7, 0x100) /* FP Unavailable */
+ SET_IVOR(8, 0x120) /* System Call */
+ SET_IVOR(9, 0x140) /* Auxiliary Processor Unavailable */
+ SET_IVOR(10, 0x160) /* Decrementer */
+ SET_IVOR(11, 0x180) /* Fixed Interval Timer */
+ SET_IVOR(12, 0x1a0) /* Watchdog Timer */
+ SET_IVOR(13, 0x1c0) /* Data TLB Error */
+ SET_IVOR(14, 0x1e0) /* Instruction TLB Error */
+ SET_IVOR(15, 0x040) /* Debug */
+
+/* e500v1 & e500v2 only */
+#ifndef CONFIG_E500MC
+ SET_IVOR(32, 0x200) /* SPE Unavailable */
+ SET_IVOR(33, 0x220) /* Embedded FP Data */
+ SET_IVOR(34, 0x240) /* Embedded FP Round */
+#endif
+
+ SET_IVOR(35, 0x260) /* Performance monitor */
+
+/* e500mc only */
+#ifdef CONFIG_E500MC
+ SET_IVOR(36, 0x280) /* Processor doorbell */
+ SET_IVOR(37, 0x2a0) /* Processor doorbell critical */
+ SET_IVOR(38, 0x2c0) /* Guest Processor doorbell */
+ SET_IVOR(39, 0x2e0) /* Guest Processor critical & machine check */
+ SET_IVOR(40, 0x300) /* Hypervisor system call */
+ SET_IVOR(41, 0x320) /* Hypervisor Priviledge */
+
+ SET_GIVOR(2, 0x060) /* Guest Data Storage */
+ SET_GIVOR(3, 0x080) /* Guest Instruction Storage */
+ SET_GIVOR(4, 0x0a0) /* Guest External Input */
+ SET_GIVOR(8, 0x120) /* Guest System Call */
+ SET_GIVOR(13, 0x1c0) /* Guest Data TLB Error */
+ SET_GIVOR(14, 0x1e0) /* Guest Instruction TLB Error */
+#endif
diff --git a/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c b/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c
new file mode 100644
index 0000000..93eca76
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_serdes.h>
+#include <asm/immap_85xx.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/fsl_law.h>
+#include <asm/errno.h>
+#include "fsl_corenet2_serdes.h"
+
+static u64 serdes1_prtcl_map;
+static u64 serdes2_prtcl_map;
+#ifdef CONFIG_SYS_FSL_SRDS_3
+static u64 serdes3_prtcl_map;
+#endif
+#ifdef CONFIG_SYS_FSL_SRDS_4
+static u64 serdes4_prtcl_map;
+#endif
+
+#ifdef DEBUG
+static const char *serdes_prtcl_str[] = {
+ [NONE] = "NA",
+ [PCIE1] = "PCIE1",
+ [PCIE2] = "PCIE2",
+ [PCIE3] = "PCIE3",
+ [PCIE4] = "PCIE4",
+ [SATA1] = "SATA1",
+ [SATA2] = "SATA2",
+ [SRIO1] = "SRIO1",
+ [SRIO2] = "SRIO2",
+ [SGMII_FM1_DTSEC1] = "SGMII_FM1_DTSEC1",
+ [SGMII_FM1_DTSEC2] = "SGMII_FM1_DTSEC2",
+ [SGMII_FM1_DTSEC3] = "SGMII_FM1_DTSEC3",
+ [SGMII_FM1_DTSEC4] = "SGMII_FM1_DTSEC4",
+ [SGMII_FM1_DTSEC5] = "SGMII_FM1_DTSEC5",
+ [SGMII_FM1_DTSEC6] = "SGMII_FM1_DTSEC6",
+ [SGMII_FM2_DTSEC1] = "SGMII_FM2_DTSEC1",
+ [SGMII_FM2_DTSEC2] = "SGMII_FM2_DTSEC2",
+ [SGMII_FM2_DTSEC3] = "SGMII_FM2_DTSEC3",
+ [SGMII_FM2_DTSEC4] = "SGMII_FM2_DTSEC4",
+ [XAUI_FM1] = "XAUI_FM1",
+ [XAUI_FM2] = "XAUI_FM2",
+ [AURORA] = "DEBUG",
+ [CPRI1] = "CPRI1",
+ [CPRI2] = "CPRI2",
+ [CPRI3] = "CPRI3",
+ [CPRI4] = "CPRI4",
+ [CPRI5] = "CPRI5",
+ [CPRI6] = "CPRI6",
+ [CPRI7] = "CPRI7",
+ [CPRI8] = "CPRI8",
+ [XAUI_FM1_MAC9] = "XAUI_FM1_MAC9",
+ [XAUI_FM1_MAC10] = "XAUI_FM1_MAC10",
+ [XAUI_FM2_MAC9] = "XAUI_FM2_MAC9",
+ [XAUI_FM2_MAC10] = "XAUI_FM2_MAC10",
+ [HIGIG_FM1_MAC9] = "HiGig_FM1_MAC9",
+ [HIGIG_FM1_MAC10] = "HiGig_FM1_MAC10",
+ [HIGIG_FM2_MAC9] = "HiGig_FM2_MAC9",
+ [HIGIG_FM2_MAC10] = "HiGig_FM2_MAC10",
+ [QSGMII_FM1_A] = "QSGMII_FM1_A",
+ [QSGMII_FM1_B] = "QSGMII_FM1_B",
+ [QSGMII_FM2_A] = "QSGMII_FM2_A",
+ [QSGMII_FM2_B] = "QSGMII_FM2_B",
+ [XFI_FM1_MAC9] = "XFI_FM1_MAC9",
+ [XFI_FM1_MAC10] = "XFI_FM1_MAC10",
+ [XFI_FM2_MAC9] = "XFI_FM2_MAC9",
+ [XFI_FM2_MAC10] = "XFI_FM2_MAC10",
+ [INTERLAKEN] = "INTERLAKEN",
+};
+#endif
+
+int is_serdes_configured(enum srds_prtcl device)
+{
+ u64 ret = 0;
+
+ ret |= (1ULL << device) & serdes1_prtcl_map;
+ ret |= (1ULL << device) & serdes2_prtcl_map;
+#ifdef CONFIG_SYS_FSL_SRDS_3
+ ret |= (1ULL << device) & serdes3_prtcl_map;
+#endif
+#ifdef CONFIG_SYS_FSL_SRDS_4
+ ret |= (1ULL << device) & serdes4_prtcl_map;
+#endif
+
+ return !!ret;
+}
+
+int serdes_get_first_lane(u32 sd, enum srds_prtcl device)
+{
+ const ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 cfg = in_be32(&gur->rcwsr[4]);
+ int i;
+
+ switch (sd) {
+ case FSL_SRDS_1:
+ cfg &= FSL_CORENET2_RCWSR4_SRDS1_PRTCL;
+ cfg >>= FSL_CORENET2_RCWSR4_SRDS1_PRTCL_SHIFT;
+ break;
+ case FSL_SRDS_2:
+ cfg &= FSL_CORENET2_RCWSR4_SRDS2_PRTCL;
+ cfg >>= FSL_CORENET2_RCWSR4_SRDS2_PRTCL_SHIFT;
+ break;
+#ifdef CONFIG_SYS_FSL_SRDS_3
+ case FSL_SRDS_3:
+ cfg &= FSL_CORENET2_RCWSR4_SRDS3_PRTCL;
+ cfg >>= FSL_CORENET2_RCWSR4_SRDS3_PRTCL_SHIFT;
+ break;
+#endif
+#ifdef CONFIG_SYS_FSL_SRDS_4
+ case FSL_SRDS_4:
+ cfg &= FSL_CORENET2_RCWSR4_SRDS4_PRTCL;
+ cfg >>= FSL_CORENET2_RCWSR4_SRDS4_PRTCL_SHIFT;
+ break;
+#endif
+ default:
+ printf("invalid SerDes%d\n", sd);
+ break;
+ }
+ /* Is serdes enabled at all? */
+ if (unlikely(cfg == 0))
+ return -ENODEV;
+
+ for (i = 0; i < SRDS_MAX_LANES; i++) {
+ if (serdes_get_prtcl(sd, cfg, i) == device)
+ return i;
+ }
+
+ return -ENODEV;
+}
+
+u64 serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift)
+{
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u64 serdes_prtcl_map = 0;
+ u32 cfg;
+ int lane;
+
+ cfg = in_be32(&gur->rcwsr[4]) & sd_prctl_mask;
+ /* Is serdes enabled at all? */
+ if (!cfg) {
+ printf("SERDES%d is not enabled\n", sd + 1);
+ return 0;
+ }
+
+ cfg >>= sd_prctl_shift;
+ printf("Using SERDES%d Protocol: %d (0x%x)\n", sd + 1, cfg, cfg);
+ if (!is_serdes_prtcl_valid(sd, cfg))
+ printf("SERDES%d[PRTCL] = 0x%x is not valid\n", sd + 1, cfg);
+
+ for (lane = 0; lane < SRDS_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes_get_prtcl(sd, cfg, lane);
+ serdes_prtcl_map |= (1ULL << lane_prtcl);
+ }
+
+ return serdes_prtcl_map;
+}
+
+void fsl_serdes_init(void)
+{
+
+ serdes1_prtcl_map = serdes_init(FSL_SRDS_1,
+ CONFIG_SYS_FSL_CORENET_SERDES_ADDR,
+ FSL_CORENET2_RCWSR4_SRDS1_PRTCL,
+ FSL_CORENET2_RCWSR4_SRDS1_PRTCL_SHIFT);
+ serdes2_prtcl_map = serdes_init(FSL_SRDS_2,
+ CONFIG_SYS_FSL_CORENET_SERDES_ADDR + FSL_SRDS_2 * 0x1000,
+ FSL_CORENET2_RCWSR4_SRDS2_PRTCL,
+ FSL_CORENET2_RCWSR4_SRDS2_PRTCL_SHIFT);
+#ifdef CONFIG_SYS_FSL_SRDS_3
+ serdes3_prtcl_map = serdes_init(FSL_SRDS_3,
+ CONFIG_SYS_FSL_CORENET_SERDES_ADDR + FSL_SRDS_3 * 0x1000,
+ FSL_CORENET2_RCWSR4_SRDS3_PRTCL,
+ FSL_CORENET2_RCWSR4_SRDS3_PRTCL_SHIFT);
+#endif
+#ifdef CONFIG_SYS_FSL_SRDS_4
+ serdes4_prtcl_map = serdes_init(FSL_SRDS_4,
+ CONFIG_SYS_FSL_CORENET_SERDES_ADDR + FSL_SRDS_4 * 0x1000,
+ FSL_CORENET2_RCWSR4_SRDS4_PRTCL,
+ FSL_CORENET2_RCWSR4_SRDS4_PRTCL_SHIFT);
+#endif
+
+}
diff --git a/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.h b/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.h
new file mode 100644
index 0000000..2258f41
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __FSL_CORENET2_SERDES_H
+#define __FSL_CORENET2_SERDES_H
+
+int is_serdes_prtcl_valid(int serdes, u32 prtcl);
+int serdes_lane_enabled(int lane);
+enum srds_prtcl serdes_get_prtcl(int serdes, int cfg, int lane);
+#endif /* __FSL_CORENET2_SERDES_H */
diff --git a/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c b/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c
new file mode 100644
index 0000000..b621adf
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c
@@ -0,0 +1,876 @@
+/*
+ * Copyright 2009-2011 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
+#include <hwconfig.h>
+#endif
+#include <asm/fsl_serdes.h>
+#include <asm/immap_85xx.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/fsl_law.h>
+#include <asm/errno.h>
+#include "fsl_corenet_serdes.h"
+
+/*
+ * The work-arounds for erratum SERDES8 and SERDES-A001 are linked together.
+ * The code is already very complicated as it is, and separating the two
+ * completely would just make things worse. We try to keep them as separate
+ * as possible, but for now we require SERDES8 if SERDES_A001 is defined.
+ */
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES_A001
+#ifndef CONFIG_SYS_P4080_ERRATUM_SERDES8
+#error "CONFIG_SYS_P4080_ERRATUM_SERDES_A001 requires CONFIG_SYS_P4080_ERRATUM_SERDES8"
+#endif
+#endif
+
+static u32 serdes_prtcl_map;
+
+#ifdef DEBUG
+static const char *serdes_prtcl_str[] = {
+ [NONE] = "NA",
+ [PCIE1] = "PCIE1",
+ [PCIE2] = "PCIE2",
+ [PCIE3] = "PCIE3",
+ [PCIE4] = "PCIE4",
+ [SATA1] = "SATA1",
+ [SATA2] = "SATA2",
+ [SRIO1] = "SRIO1",
+ [SRIO2] = "SRIO2",
+ [SGMII_FM1_DTSEC1] = "SGMII_FM1_DTSEC1",
+ [SGMII_FM1_DTSEC2] = "SGMII_FM1_DTSEC2",
+ [SGMII_FM1_DTSEC3] = "SGMII_FM1_DTSEC3",
+ [SGMII_FM1_DTSEC4] = "SGMII_FM1_DTSEC4",
+ [SGMII_FM1_DTSEC5] = "SGMII_FM1_DTSEC5",
+ [SGMII_FM2_DTSEC1] = "SGMII_FM2_DTSEC1",
+ [SGMII_FM2_DTSEC2] = "SGMII_FM2_DTSEC2",
+ [SGMII_FM2_DTSEC3] = "SGMII_FM2_DTSEC3",
+ [SGMII_FM2_DTSEC4] = "SGMII_FM2_DTSEC4",
+ [SGMII_FM2_DTSEC5] = "SGMII_FM2_DTSEC5",
+ [XAUI_FM1] = "XAUI_FM1",
+ [XAUI_FM2] = "XAUI_FM2",
+ [AURORA] = "DEBUG",
+};
+#endif
+
+static const struct {
+ int idx;
+ unsigned int lpd; /* RCW lane powerdown bit */
+ int bank;
+} lanes[SRDS_MAX_LANES] = {
+ { 0, 152, FSL_SRDS_BANK_1 },
+ { 1, 153, FSL_SRDS_BANK_1 },
+ { 2, 154, FSL_SRDS_BANK_1 },
+ { 3, 155, FSL_SRDS_BANK_1 },
+ { 4, 156, FSL_SRDS_BANK_1 },
+ { 5, 157, FSL_SRDS_BANK_1 },
+ { 6, 158, FSL_SRDS_BANK_1 },
+ { 7, 159, FSL_SRDS_BANK_1 },
+ { 8, 160, FSL_SRDS_BANK_1 },
+ { 9, 161, FSL_SRDS_BANK_1 },
+ { 16, 162, FSL_SRDS_BANK_2 },
+ { 17, 163, FSL_SRDS_BANK_2 },
+ { 18, 164, FSL_SRDS_BANK_2 },
+ { 19, 165, FSL_SRDS_BANK_2 },
+#ifdef CONFIG_PPC_P4080
+ { 20, 170, FSL_SRDS_BANK_3 },
+ { 21, 171, FSL_SRDS_BANK_3 },
+ { 22, 172, FSL_SRDS_BANK_3 },
+ { 23, 173, FSL_SRDS_BANK_3 },
+#else
+ { 20, 166, FSL_SRDS_BANK_3 },
+ { 21, 167, FSL_SRDS_BANK_3 },
+ { 22, 168, FSL_SRDS_BANK_3 },
+ { 23, 169, FSL_SRDS_BANK_3 },
+#endif
+#if SRDS_MAX_BANK > 3
+ { 24, 175, FSL_SRDS_BANK_4 },
+ { 25, 176, FSL_SRDS_BANK_4 },
+#endif
+};
+
+int serdes_get_lane_idx(int lane)
+{
+ return lanes[lane].idx;
+}
+
+int serdes_get_bank_by_lane(int lane)
+{
+ return lanes[lane].bank;
+}
+
+int serdes_lane_enabled(int lane)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ serdes_corenet_t *regs = (void *)CONFIG_SYS_FSL_CORENET_SERDES_ADDR;
+
+ int bank = lanes[lane].bank;
+ int word = lanes[lane].lpd / 32;
+ int bit = lanes[lane].lpd % 32;
+
+ if (in_be32(&regs->bank[bank].rstctl) & SRDS_RSTCTL_SDPD)
+ return 0;
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
+ /*
+ * For banks two and three, use the srds_lpd_b[] array instead of the
+ * RCW, because this array contains the real values of SRDS_LPD_B2 and
+ * SRDS_LPD_B3.
+ */
+ if (bank > 0)
+ return !(srds_lpd_b[bank] & (8 >> (lane - (6 + 4 * bank))));
+#endif
+
+ return !(in_be32(&gur->rcwsr[word]) & (0x80000000 >> bit));
+}
+
+int is_serdes_configured(enum srds_prtcl device)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ /* Is serdes enabled at all? */
+ if (!(in_be32(&gur->rcwsr[5]) & FSL_CORENET_RCWSR5_SRDS_EN))
+ return 0;
+
+ return (1 << device) & serdes_prtcl_map;
+}
+
+static int __serdes_get_first_lane(uint32_t prtcl, enum srds_prtcl device)
+{
+ int i;
+
+ for (i = 0; i < SRDS_MAX_LANES; i++) {
+ if (serdes_get_prtcl(prtcl, i) == device)
+ return i;
+ }
+
+ return -ENODEV;
+}
+
+/*
+ * Returns the SERDES lane (0..SRDS_MAX_LANES-1) that routes to the given
+ * device. This depends on the current SERDES protocol, as defined in the RCW.
+ *
+ * Returns a negative error code if SERDES is disabled or the given device is
+ * not supported in the current SERDES protocol.
+ */
+int serdes_get_first_lane(enum srds_prtcl device)
+{
+ u32 prtcl;
+ const ccsr_gur_t *gur;
+
+ gur = (typeof(gur))CONFIG_SYS_MPC85xx_GUTS_ADDR;
+
+ /* Is serdes enabled at all? */
+ if (unlikely((in_be32(&gur->rcwsr[5]) & 0x2000) == 0))
+ return -ENODEV;
+
+ prtcl = (in_be32(&gur->rcwsr[4]) & FSL_CORENET_RCWSR4_SRDS_PRTCL) >> 26;
+
+ return __serdes_get_first_lane(prtcl, device);
+}
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES9
+/*
+ * Returns the SERDES bank (1, 2, or 3) that a given device is on for a given
+ * SERDES protocol.
+ *
+ * Returns a negative error code if the given device is not supported for the
+ * given SERDES protocol.
+ */
+static int serdes_get_bank_by_device(uint32_t prtcl, enum srds_prtcl device)
+{
+ int lane;
+
+ lane = __serdes_get_first_lane(prtcl, device);
+ if (unlikely(lane < 0))
+ return lane;
+
+ return serdes_get_bank_by_lane(lane);
+}
+
+static uint32_t __serdes_get_lane_count(uint32_t prtcl, enum srds_prtcl device,
+ int first)
+{
+ int lane;
+
+ for (lane = first; lane < SRDS_MAX_LANES; lane++) {
+ if (serdes_get_prtcl(prtcl, lane) != device)
+ break;
+ }
+
+ return lane - first;
+}
+
+static void __serdes_reset_rx(serdes_corenet_t *regs,
+ uint32_t prtcl,
+ enum srds_prtcl device)
+{
+ int lane, idx, first, last;
+
+ lane = __serdes_get_first_lane(prtcl, device);
+ if (unlikely(lane < 0))
+ return;
+ first = serdes_get_lane_idx(lane);
+ last = first + __serdes_get_lane_count(prtcl, device, lane);
+
+ /*
+ * Set BnGCRy0[RRST] = 0 for each lane in the each bank that is
+ * selected as XAUI to place the lane into reset.
+ */
+ for (idx = first; idx < last; idx++)
+ clrbits_be32(&regs->lane[idx].gcr0, SRDS_GCR0_RRST);
+
+ /* Wait at least 250 ns */
+ udelay(1);
+
+ /*
+ * Set BnGCRy0[RRST] = 1 for each lane in the each bank that is
+ * selected as XAUI to bring the lane out of reset.
+ */
+ for (idx = first; idx < last; idx++)
+ setbits_be32(&regs->lane[idx].gcr0, SRDS_GCR0_RRST);
+}
+
+void serdes_reset_rx(enum srds_prtcl device)
+{
+ u32 prtcl;
+ const ccsr_gur_t *gur;
+ serdes_corenet_t *regs;
+
+ if (unlikely(device == NONE))
+ return;
+
+ gur = (typeof(gur))CONFIG_SYS_MPC85xx_GUTS_ADDR;
+
+ /* Is serdes enabled at all? */
+ if (unlikely((in_be32(&gur->rcwsr[5]) & 0x2000) == 0))
+ return;
+
+ regs = (typeof(regs))CONFIG_SYS_FSL_CORENET_SERDES_ADDR;
+ prtcl = (in_be32(&gur->rcwsr[4]) & FSL_CORENET_RCWSR4_SRDS_PRTCL) >> 26;
+
+ __serdes_reset_rx(regs, prtcl, device);
+}
+#endif
+
+#ifndef CONFIG_SYS_DCSRBAR_PHYS
+#define CONFIG_SYS_DCSRBAR_PHYS 0x80000000 /* Must be 1GB-aligned for rev1.0 */
+#define CONFIG_SYS_DCSRBAR 0x80000000
+#define __DCSR_NOT_DEFINED_BY_CONFIG
+#endif
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
+/*
+ * Enable a SERDES bank that was disabled via the RCW
+ *
+ * We only call this function for SERDES8 and SERDES-A001 in cases we really
+ * want to enable the bank, whether we actually want to use the lanes or not,
+ * so make sure at least one lane is enabled. We're only enabling this one
+ * lane to satisfy errata requirements that the bank be enabled.
+ *
+ * We use a local variable instead of srds_lpd_b[] because we want drivers to
+ * think that the lanes actually are disabled.
+ */
+static void enable_bank(ccsr_gur_t *gur, int bank)
+{
+ u32 rcw5;
+ u32 temp_lpd_b = srds_lpd_b[bank];
+
+ /*
+ * If we're asked to disable all lanes, just pretend we're doing
+ * that.
+ */
+ if (temp_lpd_b == 0xF)
+ temp_lpd_b = 0xE;
+
+ /*
+ * Enable the lanes SRDS_LPD_Bn. The RCW bits are read-only in
+ * CCSR, and read/write in DSCR.
+ */
+ rcw5 = in_be32(gur->rcwsr + 5);
+ if (bank == FSL_SRDS_BANK_2) {
+ rcw5 &= ~FSL_CORENET_RCWSRn_SRDS_LPD_B2;
+ rcw5 |= temp_lpd_b << 26;
+ } else if (bank == FSL_SRDS_BANK_3) {
+ rcw5 &= ~FSL_CORENET_RCWSRn_SRDS_LPD_B3;
+ rcw5 |= temp_lpd_b << 18;
+ } else {
+ printf("SERDES: enable_bank: bad bank %d\n", bank + 1);
+ return;
+ }
+
+ /* See similar code in cpu/mpc85xx/cpu_init.c for an explanation
+ * of the DCSR mapping.
+ */
+ {
+#ifdef __DCSR_NOT_DEFINED_BY_CONFIG
+ struct law_entry law = find_law(CONFIG_SYS_DCSRBAR_PHYS);
+ int law_index;
+ if (law.index == -1)
+ law_index = set_next_law(CONFIG_SYS_DCSRBAR_PHYS,
+ LAW_SIZE_1M, LAW_TRGT_IF_DCSR);
+ else
+ set_law(law.index, CONFIG_SYS_DCSRBAR_PHYS, LAW_SIZE_1M,
+ LAW_TRGT_IF_DCSR);
+#endif
+ u32 *p = (void *)CONFIG_SYS_DCSRBAR + 0x20114;
+ out_be32(p, rcw5);
+#ifdef __DCSR_NOT_DEFINED_BY_CONFIG
+ if (law.index == -1)
+ disable_law(law_index);
+ else
+ set_law(law.index, law.addr, law.size, law.trgt_id);
+#endif
+ }
+}
+
+/*
+ * To avoid problems with clock jitter, rev 2 p4080 uses the pll from
+ * bank 3 to clock banks 2 and 3, as well as a limited selection of
+ * protocol configurations. This requires that banks 2 and 3's lanes be
+ * disabled in the RCW, and enabled with some fixup here to re-enable
+ * them, and to configure bank 2's clock parameters in bank 3's pll in
+ * cases where they differ.
+ */
+static void p4080_erratum_serdes8(serdes_corenet_t *regs, ccsr_gur_t *gur,
+ u32 devdisr, u32 devdisr2, int cfg)
+{
+ int srds_ratio_b2;
+ int rfck_sel;
+
+ /*
+ * The disabled lanes of bank 2 will cause the associated
+ * logic blocks to be disabled in DEVDISR. We reverse that here.
+ *
+ * Note that normally it is not permitted to clear DEVDISR bits
+ * once the device has been disabled, but the hardware people
+ * say that this special case is OK.
+ */
+ clrbits_be32(&gur->devdisr, devdisr);
+ clrbits_be32(&gur->devdisr2, devdisr2);
+
+ /*
+ * Some protocols require special handling. There are a few
+ * additional protocol configurations that can be used, which are
+ * not listed here. See app note 4065 for supported protocol
+ * configurations.
+ */
+ switch (cfg) {
+ case 0x19:
+ /*
+ * Bank 2 has PCIe which wants BWSEL -- tell bank 3's PLL.
+ * SGMII on bank 3 should still be usable.
+ */
+ setbits_be32(&regs->bank[FSL_SRDS_BANK_3].pllcr1,
+ SRDS_PLLCR1_PLL_BWSEL);
+ break;
+
+ case 0x0f:
+ case 0x10:
+ /*
+ * Banks 2 (XAUI) and 3 (SGMII) have different clocking
+ * requirements in these configurations. Bank 3 cannot
+ * be used and should have its lanes (but not the bank
+ * itself) disabled in the RCW. We set up bank 3's pll
+ * for bank 2's needs here.
+ */
+ srds_ratio_b2 = (in_be32(&gur->rcwsr[4]) >> 13) & 7;
+
+ /* Determine refclock from XAUI ratio */
+ switch (srds_ratio_b2) {
+ case 1: /* 20:1 */
+ rfck_sel = SRDS_PLLCR0_RFCK_SEL_156_25;
+ break;
+ case 2: /* 25:1 */
+ rfck_sel = SRDS_PLLCR0_RFCK_SEL_125;
+ break;
+ default:
+ printf("SERDES: bad SRDS_RATIO_B2 %d\n",
+ srds_ratio_b2);
+ return;
+ }
+
+ clrsetbits_be32(&regs->bank[FSL_SRDS_BANK_3].pllcr0,
+ SRDS_PLLCR0_RFCK_SEL_MASK, rfck_sel);
+
+ clrsetbits_be32(&regs->bank[FSL_SRDS_BANK_3].pllcr0,
+ SRDS_PLLCR0_FRATE_SEL_MASK,
+ SRDS_PLLCR0_FRATE_SEL_6_25);
+ break;
+ }
+
+ enable_bank(gur, FSL_SRDS_BANK_3);
+}
+#endif
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES_A005
+/*
+ * If PCIe is not selected as a protocol for any lanes driven by a given PLL,
+ * that PLL should have SRDSBnPLLCR1[PLLBW_SEL] = 0.
+ */
+static void p4080_erratum_serdes_a005(serdes_corenet_t *regs, unsigned int cfg)
+{
+ enum srds_prtcl device;
+
+ switch (cfg) {
+ case 0x13:
+ case 0x16:
+ /*
+ * If SRDS_PRTCL = 0x13 or 0x16, set SRDSB1PLLCR1[PLLBW_SEL]
+ * to 0.
+ */
+ clrbits_be32(&regs->bank[FSL_SRDS_BANK_1].pllcr1,
+ SRDS_PLLCR1_PLL_BWSEL);
+ break;
+ case 0x19:
+ /*
+ * If SRDS_PRTCL = 0x19, set SRDSB1PLLCR1[PLLBW_SEL] to 0 and
+ * SRDSB3PLLCR1[PLLBW_SEL] to 1.
+ */
+ clrbits_be32(&regs->bank[FSL_SRDS_BANK_1].pllcr1,
+ SRDS_PLLCR1_PLL_BWSEL);
+ setbits_be32(&regs->bank[FSL_SRDS_BANK_3].pllcr1,
+ SRDS_PLLCR1_PLL_BWSEL);
+ break;
+ }
+
+ /*
+ * Set SRDSBnPLLCR1[PLLBW_SEL] to 0 for each bank that selects XAUI
+ * before XAUI is initialized.
+ */
+ for (device = XAUI_FM1; device <= XAUI_FM2; device++) {
+ if (is_serdes_configured(device)) {
+ int bank = serdes_get_bank_by_device(cfg, device);
+
+ clrbits_be32(&regs->bank[bank].pllcr1,
+ SRDS_PLLCR1_PLL_BWSEL);
+ }
+ }
+}
+#endif
+
+/*
+ * Wait for the RSTDONE bit to get set, or a one-second timeout.
+ */
+static void wait_for_rstdone(unsigned int bank)
+{
+ serdes_corenet_t *srds_regs =
+ (void *)CONFIG_SYS_FSL_CORENET_SERDES_ADDR;
+ unsigned long long end_tick;
+ u32 rstctl;
+
+ /* wait for reset complete or 1-second timeout */
+ end_tick = usec2ticks(1000000) + get_ticks();
+ do {
+ rstctl = in_be32(&srds_regs->bank[bank].rstctl);
+ if (rstctl & SRDS_RSTCTL_RSTDONE)
+ break;
+ } while (end_tick > get_ticks());
+
+ if (!(rstctl & SRDS_RSTCTL_RSTDONE))
+ printf("SERDES: timeout resetting bank %u\n", bank + 1);
+}
+
+
+static void __soc_serdes_init(void)
+{
+ /* Allow for SoC-specific initialization in <SOC>_serdes.c */
+};
+void soc_serdes_init(void) __attribute__((weak, alias("__soc_serdes_init")));
+
+void fsl_serdes_init(void)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ int cfg;
+ serdes_corenet_t *srds_regs;
+#ifdef CONFIG_PPC_P5040
+ serdes_corenet_t *srds2_regs;
+#endif
+ int lane, bank, idx;
+ int have_bank[SRDS_MAX_BANK] = {};
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
+ u32 serdes8_devdisr = 0;
+ u32 serdes8_devdisr2 = 0;
+ char srds_lpd_opt[16];
+ const char *srds_lpd_arg;
+ size_t arglen;
+#endif
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES_A001
+ int need_serdes_a001; /* true == need work-around for SERDES A001 */
+#endif
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
+ char buffer[HWCONFIG_BUFFER_SIZE];
+ char *buf = NULL;
+
+ /*
+ * Extract hwconfig from environment since we have not properly setup
+ * the environment but need it for ddr config params
+ */
+ if (getenv_f("hwconfig", buffer, sizeof(buffer)) > 0)
+ buf = buffer;
+#endif
+
+ /* Is serdes enabled at all? */
+ if (!(in_be32(&gur->rcwsr[5]) & FSL_CORENET_RCWSR5_SRDS_EN))
+ return;
+
+ srds_regs = (void *)(CONFIG_SYS_FSL_CORENET_SERDES_ADDR);
+ cfg = (in_be32(&gur->rcwsr[4]) & FSL_CORENET_RCWSR4_SRDS_PRTCL) >> 26;
+ debug("Using SERDES configuration 0x%x, lane settings:\n", cfg);
+
+ if (!is_serdes_prtcl_valid(cfg)) {
+ printf("SERDES[PRTCL] = 0x%x is not valid\n", cfg);
+ return;
+ }
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
+ /*
+ * Display a warning if banks two and three are not disabled in the RCW,
+ * since our work-around for SERDES8 depends on these banks being
+ * disabled at power-on.
+ */
+#define B2_B3 (FSL_CORENET_RCWSRn_SRDS_LPD_B2 | FSL_CORENET_RCWSRn_SRDS_LPD_B3)
+ if ((in_be32(&gur->rcwsr[5]) & B2_B3) != B2_B3) {
+ printf("Warning: SERDES8 requires banks two and "
+ "three to be disabled in the RCW\n");
+ }
+
+ /*
+ * Store the values of the fsl_srds_lpd_b2 and fsl_srds_lpd_b3
+ * hwconfig options into the srds_lpd_b[] array. See README.p4080ds
+ * for a description of these options.
+ */
+ for (bank = 1; bank < ARRAY_SIZE(srds_lpd_b); bank++) {
+ sprintf(srds_lpd_opt, "fsl_srds_lpd_b%u", bank + 1);
+ srds_lpd_arg =
+ hwconfig_subarg_f("serdes", srds_lpd_opt, &arglen, buf);
+ if (srds_lpd_arg)
+ srds_lpd_b[bank] =
+ simple_strtoul(srds_lpd_arg, NULL, 0) & 0xf;
+ }
+
+ if ((cfg == 0xf) || (cfg == 0x10)) {
+ /*
+ * For SERDES protocols 0xF and 0x10, force bank 3 to be
+ * disabled, because it is not supported.
+ */
+ srds_lpd_b[FSL_SRDS_BANK_3] = 0xF;
+ }
+#endif
+
+ /* Look for banks with all lanes disabled, and power down the bank. */
+ for (lane = 0; lane < SRDS_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes_get_prtcl(cfg, lane);
+ if (serdes_lane_enabled(lane)) {
+ have_bank[serdes_get_bank_by_lane(lane)] = 1;
+ serdes_prtcl_map |= (1 << lane_prtcl);
+ }
+ }
+
+#ifdef CONFIG_PPC_P5040
+ /*
+ * Lanes on bank 4 on P5040 are commented-out, but for some SERDES
+ * protocols, these lanes are routed to SATA. We use serdes_prtcl_map
+ * to decide whether a protocol is supported on a given lane, so SATA
+ * will be identified as not supported, and therefore not initialized.
+ * So for protocols which use SATA on bank4, we add SATA support in
+ * serdes_prtcl_map.
+ */
+ switch (cfg) {
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ serdes_prtcl_map |= 1 << SATA1 | 1 << SATA2;
+ break;
+ default:
+ srds2_regs = (void *)CONFIG_SYS_FSL_CORENET_SERDES2_ADDR;
+
+ /* We don't need bank 4, so power it down */
+ setbits_be32(&srds2_regs->bank[0].rstctl, SRDS_RSTCTL_SDPD);
+ }
+#endif
+
+ soc_serdes_init();
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
+ /*
+ * Bank two uses the clock from bank three, so if bank two is enabled,
+ * then bank three must also be enabled.
+ */
+ if (have_bank[FSL_SRDS_BANK_2])
+ have_bank[FSL_SRDS_BANK_3] = 1;
+#endif
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES_A001
+ /*
+ * The work-aroud for erratum SERDES-A001 is needed only if bank two
+ * is disabled and bank three is enabled. The converse is also true,
+ * but SERDES8 ensures that bank 3 is always enabled if bank 2 is
+ * enabled, so there's no point in complicating the code to handle
+ * that situation.
+ */
+ need_serdes_a001 =
+ !have_bank[FSL_SRDS_BANK_2] && have_bank[FSL_SRDS_BANK_3];
+#endif
+
+ /* Power down the banks we're not interested in */
+ for (bank = 0; bank < SRDS_MAX_BANK; bank++) {
+ if (!have_bank[bank]) {
+ printf("SERDES: bank %d disabled\n", bank + 1);
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES_A001
+ /*
+ * Erratum SERDES-A001 says bank two needs to be powered
+ * down after bank three is powered up, so don't power
+ * down bank two here.
+ */
+ if (!need_serdes_a001 || (bank != FSL_SRDS_BANK_2))
+ setbits_be32(&srds_regs->bank[bank].rstctl,
+ SRDS_RSTCTL_SDPD);
+#else
+ setbits_be32(&srds_regs->bank[bank].rstctl,
+ SRDS_RSTCTL_SDPD);
+#endif
+ }
+ }
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_A004699
+ /*
+ * To avoid the situation that resulted in the P4080 erratum
+ * SERDES-8, a given SerDes bank will use the PLLs from the previous
+ * bank if one of the PLL frequencies is a multiple of the other. For
+ * instance, if bank 3 is running at 2.5GHz and bank 2 is at 1.25GHz,
+ * then bank 3 will use bank 2's PLL. P5040 Erratum A-004699 says
+ * that, in this situation, lane synchronization is not initiated. So
+ * when we detect a bank with a "borrowed" PLL, we have to manually
+ * initiate lane synchronization.
+ */
+ for (bank = FSL_SRDS_BANK_2; bank <= FSL_SRDS_BANK_3; bank++) {
+ /* Determine the first lane for this bank */
+ unsigned int lane;
+
+ for (lane = 0; lane < SRDS_MAX_LANES; lane++)
+ if (lanes[lane].bank == bank)
+ break;
+ idx = lanes[lane].idx;
+
+ /*
+ * Check if the PLL for the bank is borrowed. The UOTHL
+ * bit of the first lane will tell us that.
+ */
+ if (in_be32(&srds_regs->lane[idx].gcr0) & SRDS_GCR0_UOTHL) {
+ /* Manually start lane synchronization */
+ setbits_be32(&srds_regs->bank[bank].pllcr0,
+ SRDS_PLLCR0_PVCOCNT_EN);
+ }
+ }
+#endif
+
+#if defined(CONFIG_SYS_P4080_ERRATUM_SERDES8) || defined (CONFIG_SYS_P4080_ERRATUM_SERDES9)
+ for (lane = 0; lane < SRDS_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl;
+
+ idx = serdes_get_lane_idx(lane);
+ lane_prtcl = serdes_get_prtcl(cfg, lane);
+
+#ifdef DEBUG
+ switch (lane) {
+ case 0:
+ puts("Bank1: ");
+ break;
+ case 10:
+ puts("\nBank2: ");
+ break;
+ case 14:
+ puts("\nBank3: ");
+ break;
+ default:
+ break;
+ }
+
+ printf("%s ", serdes_prtcl_str[lane_prtcl]);
+#endif
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES9
+ /*
+ * Set BnTTLCRy0[FLT_SEL] = 011011 and set BnTTLCRy0[31] = 1
+ * for each of the SerDes lanes selected as SGMII, XAUI, SRIO,
+ * or AURORA before the device is initialized.
+ *
+ * Note that this part of the SERDES-9 work-around is
+ * redundant if the work-around for A-4580 has already been
+ * applied via PBI.
+ */
+ switch (lane_prtcl) {
+ case SGMII_FM1_DTSEC1:
+ case SGMII_FM1_DTSEC2:
+ case SGMII_FM1_DTSEC3:
+ case SGMII_FM1_DTSEC4:
+ case SGMII_FM2_DTSEC1:
+ case SGMII_FM2_DTSEC2:
+ case SGMII_FM2_DTSEC3:
+ case SGMII_FM2_DTSEC4:
+ case SGMII_FM2_DTSEC5:
+ case XAUI_FM1:
+ case XAUI_FM2:
+ case SRIO1:
+ case SRIO2:
+ case AURORA:
+ out_be32(&srds_regs->lane[idx].ttlcr0,
+ SRDS_TTLCR0_FLT_SEL_KFR_26 |
+ SRDS_TTLCR0_FLT_SEL_KPH_28 |
+ SRDS_TTLCR0_FLT_SEL_750PPM |
+ SRDS_TTLCR0_FREQOVD_EN);
+ break;
+ default:
+ break;
+ }
+#endif
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
+ switch (lane_prtcl) {
+ case PCIE1:
+ case PCIE2:
+ case PCIE3:
+ serdes8_devdisr |= FSL_CORENET_DEVDISR_PCIE1 >>
+ (lane_prtcl - PCIE1);
+ break;
+ case SRIO1:
+ case SRIO2:
+ serdes8_devdisr |= FSL_CORENET_DEVDISR_SRIO1 >>
+ (lane_prtcl - SRIO1);
+ break;
+ case SGMII_FM1_DTSEC1:
+ serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM1 |
+ FSL_CORENET_DEVDISR2_DTSEC1_1;
+ break;
+ case SGMII_FM1_DTSEC2:
+ serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM1 |
+ FSL_CORENET_DEVDISR2_DTSEC1_2;
+ break;
+ case SGMII_FM1_DTSEC3:
+ serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM1 |
+ FSL_CORENET_DEVDISR2_DTSEC1_3;
+ break;
+ case SGMII_FM1_DTSEC4:
+ serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM1 |
+ FSL_CORENET_DEVDISR2_DTSEC1_4;
+ break;
+ case SGMII_FM2_DTSEC1:
+ serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM2 |
+ FSL_CORENET_DEVDISR2_DTSEC2_1;
+ break;
+ case SGMII_FM2_DTSEC2:
+ serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM2 |
+ FSL_CORENET_DEVDISR2_DTSEC2_2;
+ break;
+ case SGMII_FM2_DTSEC3:
+ serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM2 |
+ FSL_CORENET_DEVDISR2_DTSEC2_3;
+ break;
+ case SGMII_FM2_DTSEC4:
+ serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM2 |
+ FSL_CORENET_DEVDISR2_DTSEC2_4;
+ break;
+ case SGMII_FM2_DTSEC5:
+ serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM2 |
+ FSL_CORENET_DEVDISR2_DTSEC2_5;
+ break;
+ case XAUI_FM1:
+ serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM1 |
+ FSL_CORENET_DEVDISR2_10GEC1;
+ break;
+ case XAUI_FM2:
+ serdes8_devdisr2 |= FSL_CORENET_DEVDISR2_FM2 |
+ FSL_CORENET_DEVDISR2_10GEC2;
+ break;
+ case AURORA:
+ break;
+ default:
+ break;
+ }
+
+#endif
+ }
+#endif
+
+#ifdef DEBUG
+ puts("\n");
+#endif
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES_A005
+ p4080_erratum_serdes_a005(srds_regs, cfg);
+#endif
+
+ for (idx = 0; idx < SRDS_MAX_BANK; idx++) {
+ bank = idx;
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
+ /*
+ * Change bank init order to 0, 2, 1, so that the third bank's
+ * PLL is established before we start the second bank. The
+ * second bank uses the third bank's PLL.
+ */
+
+ if (idx == 1)
+ bank = FSL_SRDS_BANK_3;
+ else if (idx == 2)
+ bank = FSL_SRDS_BANK_2;
+#endif
+
+ /* Skip disabled banks */
+ if (!have_bank[bank])
+ continue;
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
+ if (idx == 1) {
+ /*
+ * Re-enable devices on banks two and three that were
+ * disabled by the RCW, and then enable bank three. The
+ * devices need to be enabled before either bank is
+ * powered up.
+ */
+ p4080_erratum_serdes8(srds_regs, gur, serdes8_devdisr,
+ serdes8_devdisr2, cfg);
+ } else if (idx == 2) {
+ /* Enable bank two now that bank three is enabled. */
+ enable_bank(gur, FSL_SRDS_BANK_2);
+ }
+#endif
+
+ wait_for_rstdone(bank);
+ }
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES_A001
+ if (need_serdes_a001) {
+ /* Bank 3 has been enabled, so now we can disable bank 2 */
+ setbits_be32(&srds_regs->bank[FSL_SRDS_BANK_2].rstctl,
+ SRDS_RSTCTL_SDPD);
+ }
+#endif
+}
diff --git a/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.h b/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.h
new file mode 100644
index 0000000..3c551e9
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *
+ * Author: Roy Zang <tie-fei.zang@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __FSL_CORENET_SERDES_H
+#define __FSL_CORENET_SERDES_H
+
+enum srds_bank {
+ FSL_SRDS_BANK_1 = 0,
+ FSL_SRDS_BANK_2 = 1,
+ FSL_SRDS_BANK_3 = 2,
+};
+
+int is_serdes_prtcl_valid(u32 prtcl);
+int serdes_get_lane_idx(int lane);
+int serdes_get_bank_by_lane(int lane);
+int serdes_lane_enabled(int lane);
+enum srds_prtcl serdes_get_prtcl(int cfg, int lane);
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
+extern uint16_t srds_lpd_b[SRDS_MAX_BANK];
+#endif
+
+#endif /* __FSL_CORENET_SERDES_H */
diff --git a/arch/powerpc/cpu/mpc85xx/interrupts.c b/arch/powerpc/cpu/mpc85xx/interrupts.c
new file mode 100644
index 0000000..7ab7113
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/interrupts.c
@@ -0,0 +1,126 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002 (440 port)
+ * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com
+ *
+ * (C) Copyright 2003 Motorola Inc. (MPC85xx port)
+ * Xianghua Xiao (X.Xiao@motorola.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#ifdef CONFIG_POST
+#include <post.h>
+#endif
+
+int interrupt_init_cpu(unsigned int *decrementer_count)
+{
+ ccsr_pic_t __iomem *pic = (void *)CONFIG_SYS_MPC8xxx_PIC_ADDR;
+
+#ifdef CONFIG_POST
+ /*
+ * The POST word is stored in the PIC's TFRR register which gets
+ * cleared when the PIC is reset. Save it off so we can restore it
+ * later.
+ */
+ ulong post_word = post_word_load();
+#endif
+
+ out_be32(&pic->gcr, MPC85xx_PICGCR_RST);
+ while (in_be32(&pic->gcr) & MPC85xx_PICGCR_RST)
+ ;
+ out_be32(&pic->gcr, MPC85xx_PICGCR_M);
+ in_be32(&pic->gcr);
+
+ *decrementer_count = get_tbclk() / CONFIG_SYS_HZ;
+
+ /* PIE is same as DIE, dec interrupt enable */
+ mtspr(SPRN_TCR, TCR_PIE);
+
+#ifdef CONFIG_INTERRUPTS
+ pic->iivpr1 = 0x810001; /* 50220 enable ecm interrupts */
+ debug("iivpr1@%x = %x\n", (uint)&pic->iivpr1, pic->iivpr1);
+
+ pic->iivpr2 = 0x810002; /* 50240 enable ddr interrupts */
+ debug("iivpr2@%x = %x\n", (uint)&pic->iivpr2, pic->iivpr2);
+
+ pic->iivpr3 = 0x810003; /* 50260 enable lbc interrupts */
+ debug("iivpr3@%x = %x\n", (uint)&pic->iivpr3, pic->iivpr3);
+
+#ifdef CONFIG_PCI1
+ pic->iivpr8 = 0x810008; /* enable pci1 interrupts */
+ debug("iivpr8@%x = %x\n", (uint)&pic->iivpr8, pic->iivpr8);
+#endif
+#if defined(CONFIG_PCI2) || defined(CONFIG_PCIE2)
+ pic->iivpr9 = 0x810009; /* enable pci1 interrupts */
+ debug("iivpr9@%x = %x\n", (uint)&pic->iivpr9, pic->iivpr9);
+#endif
+#ifdef CONFIG_PCIE1
+ pic->iivpr10 = 0x81000a; /* enable pcie1 interrupts */
+ debug("iivpr10@%x = %x\n", (uint)&pic->iivpr10, pic->iivpr10);
+#endif
+#ifdef CONFIG_PCIE3
+ pic->iivpr11 = 0x81000b; /* enable pcie3 interrupts */
+ debug("iivpr11@%x = %x\n", (uint)&pic->iivpr11, pic->iivpr11);
+#endif
+
+ pic->ctpr=0; /* 40080 clear current task priority register */
+#endif
+
+#ifdef CONFIG_POST
+ post_word_store(post_word);
+#endif
+
+ return (0);
+}
+
+/* Install and free a interrupt handler. Not implemented yet. */
+
+void
+irq_install_handler(int vec, interrupt_handler_t *handler, void *arg)
+{
+ return;
+}
+
+void
+irq_free_handler(int vec)
+{
+ return;
+}
+
+void timer_interrupt_cpu(struct pt_regs *regs)
+{
+ /* PIS is same as DIS, dec interrupt status */
+ mtspr(SPRN_TSR, TSR_PIS);
+}
+
+#if defined(CONFIG_CMD_IRQ)
+/* irqinfo - print information about PCI devices,not implemented. */
+int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ return 0;
+}
+#endif
diff --git a/arch/powerpc/cpu/mpc85xx/liodn.c b/arch/powerpc/cpu/mpc85xx/liodn.c
new file mode 100644
index 0000000..2e53367
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/liodn.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+
+#include <asm/immap_85xx.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/fsl_portals.h>
+#include <asm/fsl_liodn.h>
+
+int get_dpaa_liodn(enum fsl_dpaa_dev dpaa_dev, u32 *liodns, int liodn_offset)
+{
+ liodns[0] = liodn_bases[dpaa_dev].id[0] + liodn_offset;
+
+ if (liodn_bases[dpaa_dev].num_ids == 2)
+ liodns[1] = liodn_bases[dpaa_dev].id[1] + liodn_offset;
+
+ return liodn_bases[dpaa_dev].num_ids;
+}
+
+#ifdef CONFIG_SYS_SRIO
+static void set_srio_liodn(struct srio_liodn_id_table *tbl, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ unsigned long reg_off = tbl[i].reg_offset[0];
+ out_be32((u32 *)reg_off, tbl[i].id[0]);
+
+ if (tbl[i].num_ids == 2) {
+ reg_off = tbl[i].reg_offset[1];
+ out_be32((u32 *)reg_off, tbl[i].id[1]);
+ }
+ }
+}
+#endif
+
+static void set_liodn(struct liodn_id_table *tbl, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ u32 liodn;
+ if (tbl[i].num_ids == 2) {
+ liodn = (tbl[i].id[0] << 16) | tbl[i].id[1];
+ } else {
+ liodn = tbl[i].id[0];
+ }
+
+ out_be32((volatile u32 *)(tbl[i].reg_offset), liodn);
+ }
+}
+
+static void setup_sec_liodn_base(void)
+{
+ ccsr_sec_t *sec = (void *)CONFIG_SYS_FSL_SEC_ADDR;
+ u32 base;
+
+ if (!IS_E_PROCESSOR(get_svr()))
+ return;
+
+ /* QILCR[QSLOM] */
+ out_be32(&sec->qilcr_ms, 0x3ff<<16);
+
+ base = (liodn_bases[FSL_HW_PORTAL_SEC].id[0] << 16) |
+ liodn_bases[FSL_HW_PORTAL_SEC].id[1];
+
+ out_be32(&sec->qilcr_ls, base);
+}
+
+#ifdef CONFIG_SYS_DPAA_FMAN
+static void setup_fman_liodn_base(enum fsl_dpaa_dev dev,
+ struct liodn_id_table *tbl, int size)
+{
+ int i;
+ ccsr_fman_t *fm;
+ u32 base;
+
+ switch(dev) {
+ case FSL_HW_PORTAL_FMAN1:
+ fm = (void *)CONFIG_SYS_FSL_FM1_ADDR;
+ break;
+
+#if (CONFIG_SYS_NUM_FMAN == 2)
+ case FSL_HW_PORTAL_FMAN2:
+ fm = (void *)CONFIG_SYS_FSL_FM2_ADDR;
+ break;
+#endif
+ default:
+ printf("Error: Invalid device type to %s\n", __FUNCTION__);
+ return ;
+ }
+
+ base = (liodn_bases[dev].id[0] << 16) | liodn_bases[dev].id[0];
+
+ /* setup all bases the same */
+ for (i = 0; i < 32; i++) {
+ out_be32(&fm->fm_dma.fmdmplr[i], base);
+ }
+
+ /* update tbl to ... */
+ for (i = 0; i < size; i++)
+ tbl[i].id[0] += liodn_bases[dev].id[0];
+}
+#endif
+
+static void setup_pme_liodn_base(void)
+{
+#ifdef CONFIG_SYS_DPAA_PME
+ ccsr_pme_t *pme = (void *)CONFIG_SYS_FSL_CORENET_PME_ADDR;
+ u32 base = (liodn_bases[FSL_HW_PORTAL_PME].id[0] << 16) |
+ liodn_bases[FSL_HW_PORTAL_PME].id[1];
+
+ out_be32(&pme->liodnbr, base);
+#endif
+}
+
+#ifdef CONFIG_SYS_FSL_RAID_ENGINE
+static void setup_raide_liodn_base(void)
+{
+ struct ccsr_raide *raide = (void *)CONFIG_SYS_FSL_RAID_ENGINE_ADDR;
+
+ /* setup raid engine liodn base for data/desc ; both set to 47 */
+ u32 base = (liodn_bases[FSL_HW_PORTAL_RAID_ENGINE].id[0] << 16) |
+ liodn_bases[FSL_HW_PORTAL_RAID_ENGINE].id[0];
+
+ out_be32(&raide->liodnbr, base);
+}
+#endif
+
+#ifdef CONFIG_SYS_DPAA_RMAN
+static void set_rman_liodn(struct liodn_id_table *tbl, int size)
+{
+ int i;
+ struct ccsr_rman *rman = (void *)CONFIG_SYS_FSL_CORENET_RMAN_ADDR;
+
+ for (i = 0; i < size; i++) {
+ /* write the RMan block number */
+ out_be32(&rman->mmitar, i);
+ /* write the liodn offset corresponding to the block */
+ out_be32((u32 *)(tbl[i].reg_offset), tbl[i].id[0]);
+ }
+}
+
+static void setup_rman_liodn_base(struct liodn_id_table *tbl, int size)
+{
+ int i;
+ struct ccsr_rman *rman = (void *)CONFIG_SYS_FSL_CORENET_RMAN_ADDR;
+ u32 base = liodn_bases[FSL_HW_PORTAL_RMAN].id[0];
+
+ out_be32(&rman->mmliodnbr, base);
+
+ /* update liodn offset */
+ for (i = 0; i < size; i++)
+ tbl[i].id[0] += base;
+}
+#endif
+
+void set_liodns(void)
+{
+ /* setup general liodn offsets */
+ set_liodn(liodn_tbl, liodn_tbl_sz);
+
+#ifdef CONFIG_SYS_SRIO
+ /* setup SRIO port liodns */
+ set_srio_liodn(srio_liodn_tbl, srio_liodn_tbl_sz);
+#endif
+
+ /* setup SEC block liodn bases & offsets if we have one */
+ if (IS_E_PROCESSOR(get_svr())) {
+ set_liodn(sec_liodn_tbl, sec_liodn_tbl_sz);
+ setup_sec_liodn_base();
+ }
+
+ /* setup FMAN block(s) liodn bases & offsets if we have one */
+#ifdef CONFIG_SYS_DPAA_FMAN
+ set_liodn(fman1_liodn_tbl, fman1_liodn_tbl_sz);
+ setup_fman_liodn_base(FSL_HW_PORTAL_FMAN1, fman1_liodn_tbl,
+ fman1_liodn_tbl_sz);
+
+#if (CONFIG_SYS_NUM_FMAN == 2)
+ set_liodn(fman2_liodn_tbl, fman2_liodn_tbl_sz);
+ setup_fman_liodn_base(FSL_HW_PORTAL_FMAN2, fman2_liodn_tbl,
+ fman2_liodn_tbl_sz);
+#endif
+#endif
+ /* setup PME liodn base */
+ setup_pme_liodn_base();
+
+#ifdef CONFIG_SYS_FSL_RAID_ENGINE
+ /* raid engine ccr addr code for liodn */
+ set_liodn(raide_liodn_tbl, raide_liodn_tbl_sz);
+ setup_raide_liodn_base();
+#endif
+
+#ifdef CONFIG_SYS_DPAA_RMAN
+ /* setup RMan liodn offsets */
+ set_rman_liodn(rman_liodn_tbl, rman_liodn_tbl_sz);
+ /* setup RMan liodn base */
+ setup_rman_liodn_base(rman_liodn_tbl, rman_liodn_tbl_sz);
+#endif
+}
+
+#ifdef CONFIG_SYS_SRIO
+static void fdt_fixup_srio_liodn(void *blob, struct srio_liodn_id_table *tbl)
+{
+ int i, srio_off;
+
+ /* search for srio node, if doesn't exist just return - nothing todo */
+ srio_off = fdt_node_offset_by_compatible(blob, -1, "fsl,srio");
+ if (srio_off < 0)
+ return ;
+
+ for (i = 0; i < srio_liodn_tbl_sz; i++) {
+ int off, portid = tbl[i].portid;
+
+ off = fdt_node_offset_by_prop_value(blob, srio_off,
+ "cell-index", &portid, 4);
+ if (off >= 0) {
+ off = fdt_setprop(blob, off, "fsl,liodn",
+ &tbl[i].id[0],
+ sizeof(u32) * tbl[i].num_ids);
+ if (off > 0)
+ printf("WARNING unable to set fsl,liodn for "
+ "fsl,srio port %d: %s\n",
+ portid, fdt_strerror(off));
+ } else {
+ debug("WARNING: couldn't set fsl,liodn for srio: %s.\n",
+ fdt_strerror(off));
+ }
+ }
+}
+#endif
+
+#define CONFIG_SYS_MAX_PCI_EPS 8
+#define CONFIG_SYS_PCI_EP_LIODN_START 256
+
+static void fdt_fixup_pci_liodn_offsets(void *fdt, const char *compat)
+{
+ int off, pci_idx = 0, pci_cnt = 0, i, rc;
+ const uint32_t *base_liodn;
+ uint32_t liodn_offs[CONFIG_SYS_MAX_PCI_EPS + 1] = { 0 };
+
+ /*
+ * Count the number of pci nodes.
+ * It's needed later when the interleaved liodn offsets are generated.
+ */
+ off = fdt_node_offset_by_compatible(fdt, -1, compat);
+ while (off != -FDT_ERR_NOTFOUND) {
+ pci_cnt++;
+ off = fdt_node_offset_by_compatible(fdt, off, compat);
+ }
+
+ for (off = fdt_node_offset_by_compatible(fdt, -1, compat);
+ off != -FDT_ERR_NOTFOUND;
+ off = fdt_node_offset_by_compatible(fdt, off, compat)) {
+ base_liodn = fdt_getprop(fdt, off, "fsl,liodn", &rc);
+ if (!base_liodn) {
+ char path[64];
+
+ if (fdt_get_path(fdt, off, path, sizeof(path)) < 0)
+ strcpy(path, "(unknown)");
+ printf("WARNING Could not get liodn of node %s: %s\n",
+ path, fdt_strerror(rc));
+ continue;
+ }
+ for (i = 0; i < CONFIG_SYS_MAX_PCI_EPS; i++)
+ liodn_offs[i + 1] = CONFIG_SYS_PCI_EP_LIODN_START +
+ i * pci_cnt + pci_idx - *base_liodn;
+ rc = fdt_setprop(fdt, off, "fsl,liodn-offset-list",
+ liodn_offs, sizeof(liodn_offs));
+ if (rc) {
+ char path[64];
+
+ if (fdt_get_path(fdt, off, path, sizeof(path)) < 0)
+ strcpy(path, "(unknown)");
+ printf("WARNING Unable to set fsl,liodn-offset-list for "
+ "node %s: %s\n", path, fdt_strerror(rc));
+ continue;
+ }
+ pci_idx++;
+ }
+}
+
+static void fdt_fixup_liodn_tbl(void *blob, struct liodn_id_table *tbl, int sz)
+{
+ int i;
+
+ for (i = 0; i < sz; i++) {
+ int off;
+
+ if (tbl[i].compat == NULL)
+ continue;
+
+ off = fdt_node_offset_by_compat_reg(blob,
+ tbl[i].compat, tbl[i].compat_offset);
+ if (off >= 0) {
+ off = fdt_setprop(blob, off, "fsl,liodn",
+ &tbl[i].id[0],
+ sizeof(u32) * tbl[i].num_ids);
+ if (off > 0)
+ printf("WARNING unable to set fsl,liodn for "
+ "%s: %s\n",
+ tbl[i].compat, fdt_strerror(off));
+ } else {
+ debug("WARNING: could not set fsl,liodn for %s: %s.\n",
+ tbl[i].compat, fdt_strerror(off));
+ }
+ }
+}
+
+void fdt_fixup_liodn(void *blob)
+{
+#ifdef CONFIG_SYS_SRIO
+ fdt_fixup_srio_liodn(blob, srio_liodn_tbl);
+#endif
+
+ fdt_fixup_liodn_tbl(blob, liodn_tbl, liodn_tbl_sz);
+#ifdef CONFIG_SYS_DPAA_FMAN
+ fdt_fixup_liodn_tbl(blob, fman1_liodn_tbl, fman1_liodn_tbl_sz);
+#if (CONFIG_SYS_NUM_FMAN == 2)
+ fdt_fixup_liodn_tbl(blob, fman2_liodn_tbl, fman2_liodn_tbl_sz);
+#endif
+#endif
+ fdt_fixup_liodn_tbl(blob, sec_liodn_tbl, sec_liodn_tbl_sz);
+
+#ifdef CONFIG_SYS_FSL_RAID_ENGINE
+ fdt_fixup_liodn_tbl(blob, raide_liodn_tbl, raide_liodn_tbl_sz);
+#endif
+
+#ifdef CONFIG_SYS_DPAA_RMAN
+ fdt_fixup_liodn_tbl(blob, rman_liodn_tbl, rman_liodn_tbl_sz);
+#endif
+
+ fdt_fixup_pci_liodn_offsets(blob, "fsl,qoriq-pcie-v2.4");
+}
diff --git a/arch/powerpc/cpu/mpc85xx/mp.c b/arch/powerpc/cpu/mpc85xx/mp.c
new file mode 100644
index 0000000..861c8e0
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/mp.c
@@ -0,0 +1,488 @@
+/*
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <ioports.h>
+#include <lmb.h>
+#include <asm/io.h>
+#include <asm/mmu.h>
+#include <asm/fsl_law.h>
+#include <asm/fsl_ddr_sdram.h>
+#include "mp.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+u32 fsl_ddr_get_intl3r(void);
+
+extern u32 __spin_table[];
+
+u32 get_my_id()
+{
+ return mfspr(SPRN_PIR);
+}
+
+/*
+ * Determine if U-Boot should keep secondary cores in reset, or let them out
+ * of reset and hold them in a spinloop
+ */
+int hold_cores_in_reset(int verbose)
+{
+ /* Default to no, overriden by 'y', 'yes', 'Y', 'Yes', or '1' */
+ if (getenv_yesno("mp_holdoff") == 1) {
+ if (verbose) {
+ puts("Secondary cores are being held in reset.\n");
+ puts("See 'mp_holdoff' environment variable\n");
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int cpu_reset(int nr)
+{
+ volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR);
+ out_be32(&pic->pir, 1 << nr);
+ /* the dummy read works around an errata on early 85xx MP PICs */
+ (void)in_be32(&pic->pir);
+ out_be32(&pic->pir, 0x0);
+
+ return 0;
+}
+
+int cpu_status(int nr)
+{
+ u32 *table, id = get_my_id();
+
+ if (hold_cores_in_reset(1))
+ return 0;
+
+ if (nr == id) {
+ table = (u32 *)&__spin_table;
+ printf("table base @ 0x%p\n", table);
+ } else if (is_core_disabled(nr)) {
+ puts("Disabled\n");
+ } else {
+ table = (u32 *)&__spin_table + nr * NUM_BOOT_ENTRY;
+ printf("Running on cpu %d\n", id);
+ printf("\n");
+ printf("table @ 0x%p\n", table);
+ printf(" addr - 0x%08x\n", table[BOOT_ENTRY_ADDR_LOWER]);
+ printf(" r3 - 0x%08x\n", table[BOOT_ENTRY_R3_LOWER]);
+ printf(" pir - 0x%08x\n", table[BOOT_ENTRY_PIR]);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_FSL_CORENET
+int cpu_disable(int nr)
+{
+ volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ setbits_be32(&gur->coredisrl, 1 << nr);
+
+ return 0;
+}
+
+int is_core_disabled(int nr) {
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 coredisrl = in_be32(&gur->coredisrl);
+
+ return (coredisrl & (1 << nr));
+}
+#else
+int cpu_disable(int nr)
+{
+ volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ switch (nr) {
+ case 0:
+ setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU0);
+ break;
+ case 1:
+ setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU1);
+ break;
+ default:
+ printf("Invalid cpu number for disable %d\n", nr);
+ return 1;
+ }
+
+ return 0;
+}
+
+int is_core_disabled(int nr) {
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 devdisr = in_be32(&gur->devdisr);
+
+ switch (nr) {
+ case 0:
+ return (devdisr & MPC85xx_DEVDISR_CPU0);
+ case 1:
+ return (devdisr & MPC85xx_DEVDISR_CPU1);
+ default:
+ printf("Invalid cpu number for disable %d\n", nr);
+ }
+
+ return 0;
+}
+#endif
+
+static u8 boot_entry_map[4] = {
+ 0,
+ BOOT_ENTRY_PIR,
+ BOOT_ENTRY_R3_LOWER,
+};
+
+int cpu_release(int nr, int argc, char * const argv[])
+{
+ u32 i, val, *table = (u32 *)&__spin_table + nr * NUM_BOOT_ENTRY;
+ u64 boot_addr;
+
+ if (hold_cores_in_reset(1))
+ return 0;
+
+ if (nr == get_my_id()) {
+ printf("Invalid to release the boot core.\n\n");
+ return 1;
+ }
+
+ if (argc != 4) {
+ printf("Invalid number of arguments to release.\n\n");
+ return 1;
+ }
+
+ boot_addr = simple_strtoull(argv[0], NULL, 16);
+
+ /* handle pir, r3 */
+ for (i = 1; i < 3; i++) {
+ if (argv[i][0] != '-') {
+ u8 entry = boot_entry_map[i];
+ val = simple_strtoul(argv[i], NULL, 16);
+ table[entry] = val;
+ }
+ }
+
+ table[BOOT_ENTRY_ADDR_UPPER] = (u32)(boot_addr >> 32);
+
+ /* ensure all table updates complete before final address write */
+ eieio();
+
+ table[BOOT_ENTRY_ADDR_LOWER] = (u32)(boot_addr & 0xffffffff);
+
+ return 0;
+}
+
+u32 determine_mp_bootpg(unsigned int *pagesize)
+{
+ u32 bootpg;
+#ifdef CONFIG_SYS_FSL_ERRATUM_A004468
+ u32 svr = get_svr();
+ u32 granule_size, check;
+ struct law_entry e;
+#endif
+
+
+ /* use last 4K of mapped memory */
+ bootpg = ((gd->ram_size > CONFIG_MAX_MEM_MAPPED) ?
+ CONFIG_MAX_MEM_MAPPED : gd->ram_size) +
+ CONFIG_SYS_SDRAM_BASE - 4096;
+ if (pagesize)
+ *pagesize = 4096;
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_A004468
+/*
+ * Erratum A004468 has two parts. The 3-way interleaving applies to T4240,
+ * to be fixed in rev 2.0. The 2-way interleaving applies to many SoCs. But
+ * the way boot page chosen in u-boot avoids hitting this erratum. So only
+ * thw workaround for 3-way interleaving is needed.
+ *
+ * To make sure boot page translation works with 3-Way DDR interleaving
+ * enforce a check for the following constrains
+ * 8K granule size requires BRSIZE=8K and
+ * bootpg >> log2(BRSIZE) %3 == 1
+ * 4K and 1K granule size requires BRSIZE=4K and
+ * bootpg >> log2(BRSIZE) %3 == 0
+ */
+ if (SVR_SOC_VER(svr) == SVR_T4240 && SVR_MAJ(svr) < 2) {
+ e = find_law(bootpg);
+ switch (e.trgt_id) {
+ case LAW_TRGT_IF_DDR_INTLV_123:
+ granule_size = fsl_ddr_get_intl3r() & 0x1f;
+ if (granule_size == FSL_DDR_3WAY_8KB_INTERLEAVING) {
+ if (pagesize)
+ *pagesize = 8192;
+ bootpg &= 0xffffe000; /* align to 8KB */
+ check = bootpg >> 13;
+ while ((check % 3) != 1)
+ check--;
+ bootpg = check << 13;
+ debug("Boot page (8K) at 0x%08x\n", bootpg);
+ break;
+ } else {
+ bootpg &= 0xfffff000; /* align to 4KB */
+ check = bootpg >> 12;
+ while ((check % 3) != 0)
+ check--;
+ bootpg = check << 12;
+ debug("Boot page (4K) at 0x%08x\n", bootpg);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+#endif /* CONFIG_SYS_FSL_ERRATUM_A004468 */
+
+ return bootpg;
+}
+
+phys_addr_t get_spin_phys_addr(void)
+{
+ return virt_to_phys(&__spin_table);
+}
+
+#ifdef CONFIG_FSL_CORENET
+static void plat_mp_up(unsigned long bootpg, unsigned int pagesize)
+{
+ u32 cpu_up_mask, whoami, brsize = LAW_SIZE_4K;
+ u32 *table = (u32 *)&__spin_table;
+ volatile ccsr_gur_t *gur;
+ volatile ccsr_local_t *ccm;
+ volatile ccsr_rcpm_t *rcpm;
+ volatile ccsr_pic_t *pic;
+ int timeout = 10;
+ u32 mask = cpu_mask();
+ struct law_entry e;
+
+ gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ ccm = (void *)(CONFIG_SYS_FSL_CORENET_CCM_ADDR);
+ rcpm = (void *)(CONFIG_SYS_FSL_CORENET_RCPM_ADDR);
+ pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR);
+
+ whoami = in_be32(&pic->whoami);
+ cpu_up_mask = 1 << whoami;
+ out_be32(&ccm->bstrl, bootpg);
+
+ e = find_law(bootpg);
+ /* pagesize is only 4K or 8K */
+ if (pagesize == 8192)
+ brsize = LAW_SIZE_8K;
+ out_be32(&ccm->bstrar, LAW_EN | e.trgt_id << 20 | brsize);
+ debug("BRSIZE is 0x%x\n", brsize);
+
+ /* readback to sync write */
+ in_be32(&ccm->bstrar);
+
+ /* disable time base at the platform */
+ out_be32(&rcpm->ctbenrl, cpu_up_mask);
+
+ out_be32(&gur->brrl, mask);
+
+ /* wait for everyone */
+ while (timeout) {
+ unsigned int i, cpu, nr_cpus = cpu_numcores();
+
+ for_each_cpu(i, cpu, nr_cpus, mask) {
+ if (table[cpu * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER])
+ cpu_up_mask |= (1 << cpu);
+ }
+
+ if ((cpu_up_mask & mask) == mask)
+ break;
+
+ udelay(100);
+ timeout--;
+ }
+
+ if (timeout == 0)
+ printf("CPU up timeout. CPU up mask is %x should be %x\n",
+ cpu_up_mask, mask);
+
+ /* enable time base at the platform */
+ out_be32(&rcpm->ctbenrl, 0);
+
+ /* readback to sync write */
+ in_be32(&rcpm->ctbenrl);
+
+ mtspr(SPRN_TBWU, 0);
+ mtspr(SPRN_TBWL, 0);
+
+ out_be32(&rcpm->ctbenrl, mask);
+
+#ifdef CONFIG_MPC8xxx_DISABLE_BPTR
+ /*
+ * Disabling Boot Page Translation allows the memory region 0xfffff000
+ * to 0xffffffff to be used normally. Leaving Boot Page Translation
+ * enabled remaps 0xfffff000 to SDRAM which makes that memory region
+ * unusable for normal operation but it does allow OSes to easily
+ * reset a processor core to put it back into U-Boot's spinloop.
+ */
+ clrbits_be32(&ccm->bstrar, LAW_EN);
+#endif
+}
+#else
+static void plat_mp_up(unsigned long bootpg, unsigned int pagesize)
+{
+ u32 up, cpu_up_mask, whoami;
+ u32 *table = (u32 *)&__spin_table;
+ volatile u32 bpcr;
+ volatile ccsr_local_ecm_t *ecm = (void *)(CONFIG_SYS_MPC85xx_ECM_ADDR);
+ volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR);
+ u32 devdisr;
+ int timeout = 10;
+
+ whoami = in_be32(&pic->whoami);
+ out_be32(&ecm->bptr, 0x80000000 | (bootpg >> 12));
+
+ /* disable time base at the platform */
+ devdisr = in_be32(&gur->devdisr);
+ if (whoami)
+ devdisr |= MPC85xx_DEVDISR_TB0;
+ else
+ devdisr |= MPC85xx_DEVDISR_TB1;
+ out_be32(&gur->devdisr, devdisr);
+
+ /* release the hounds */
+ up = ((1 << cpu_numcores()) - 1);
+ bpcr = in_be32(&ecm->eebpcr);
+ bpcr |= (up << 24);
+ out_be32(&ecm->eebpcr, bpcr);
+ asm("sync; isync; msync");
+
+ cpu_up_mask = 1 << whoami;
+ /* wait for everyone */
+ while (timeout) {
+ int i;
+ for (i = 0; i < cpu_numcores(); i++) {
+ if (table[i * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER])
+ cpu_up_mask |= (1 << i);
+ };
+
+ if ((cpu_up_mask & up) == up)
+ break;
+
+ udelay(100);
+ timeout--;
+ }
+
+ if (timeout == 0)
+ printf("CPU up timeout. CPU up mask is %x should be %x\n",
+ cpu_up_mask, up);
+
+ /* enable time base at the platform */
+ if (whoami)
+ devdisr |= MPC85xx_DEVDISR_TB1;
+ else
+ devdisr |= MPC85xx_DEVDISR_TB0;
+ out_be32(&gur->devdisr, devdisr);
+
+ /* readback to sync write */
+ in_be32(&gur->devdisr);
+
+ mtspr(SPRN_TBWU, 0);
+ mtspr(SPRN_TBWL, 0);
+
+ devdisr &= ~(MPC85xx_DEVDISR_TB0 | MPC85xx_DEVDISR_TB1);
+ out_be32(&gur->devdisr, devdisr);
+
+#ifdef CONFIG_MPC8xxx_DISABLE_BPTR
+ /*
+ * Disabling Boot Page Translation allows the memory region 0xfffff000
+ * to 0xffffffff to be used normally. Leaving Boot Page Translation
+ * enabled remaps 0xfffff000 to SDRAM which makes that memory region
+ * unusable for normal operation but it does allow OSes to easily
+ * reset a processor core to put it back into U-Boot's spinloop.
+ */
+ clrbits_be32(&ecm->bptr, 0x80000000);
+#endif
+}
+#endif
+
+void cpu_mp_lmb_reserve(struct lmb *lmb)
+{
+ u32 bootpg = determine_mp_bootpg(NULL);
+
+ lmb_reserve(lmb, bootpg, 4096);
+}
+
+void setup_mp(void)
+{
+ extern u32 __secondary_start_page;
+ extern u32 __bootpg_addr, __spin_table_addr, __second_half_boot_page;
+
+ int i;
+ ulong fixup = (u32)&__secondary_start_page;
+ u32 bootpg, bootpg_map, pagesize;
+
+ bootpg = determine_mp_bootpg(&pagesize);
+
+ /*
+ * pagesize is only 4K or 8K
+ * we only use the last 4K of boot page
+ * bootpg_map saves the address for the boot page
+ * 8K is used for the workaround of 3-way DDR interleaving
+ */
+
+ bootpg_map = bootpg;
+
+ if (pagesize == 8192)
+ bootpg += 4096; /* use 2nd half */
+
+ /* Some OSes expect secondary cores to be held in reset */
+ if (hold_cores_in_reset(0))
+ return;
+
+ /*
+ * Store the bootpg's cache-able half address for use by secondary
+ * CPU cores to continue to boot
+ */
+ __bootpg_addr = (u32)virt_to_phys(&__second_half_boot_page);
+
+ /* Store spin table's physical address for use by secondary cores */
+ __spin_table_addr = (u32)get_spin_phys_addr();
+
+ /* flush bootpg it before copying invalidate any staled cacheline */
+ flush_cache(bootpg, 4096);
+
+ /* look for the tlb covering the reset page, there better be one */
+ i = find_tlb_idx((void *)CONFIG_BPTR_VIRT_ADDR, 1);
+
+ /* we found a match */
+ if (i != -1) {
+ /* map reset page to bootpg so we can copy code there */
+ disable_tlb(i);
+
+ set_tlb(1, CONFIG_BPTR_VIRT_ADDR, bootpg, /* tlb, epn, rpn */
+ MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, /* perms, wimge */
+ 0, i, BOOKE_PAGESZ_4K, 1); /* ts, esel, tsize, iprot */
+
+ memcpy((void *)CONFIG_BPTR_VIRT_ADDR, (void *)fixup, 4096);
+
+ plat_mp_up(bootpg_map, pagesize);
+ } else {
+ puts("WARNING: No reset page TLB. "
+ "Skipping secondary core setup\n");
+ }
+}
diff --git a/arch/powerpc/cpu/mpc85xx/mp.h b/arch/powerpc/cpu/mpc85xx/mp.h
new file mode 100644
index 0000000..ad9950b
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/mp.h
@@ -0,0 +1,21 @@
+#ifndef __MPC85XX_MP_H_
+#define __MPC85XX_MP_H_
+
+#include <asm/mp.h>
+
+phys_addr_t get_spin_phys_addr(void);
+u32 get_my_id(void);
+int hold_cores_in_reset(int verbose);
+
+#define BOOT_ENTRY_ADDR_UPPER 0
+#define BOOT_ENTRY_ADDR_LOWER 1
+#define BOOT_ENTRY_R3_UPPER 2
+#define BOOT_ENTRY_R3_LOWER 3
+#define BOOT_ENTRY_RESV 4
+#define BOOT_ENTRY_PIR 5
+#define BOOT_ENTRY_R6_UPPER 6
+#define BOOT_ENTRY_R6_LOWER 7
+#define NUM_BOOT_ENTRY 16 /* pad to 64 bytes */
+#define SIZE_BOOT_ENTRY (NUM_BOOT_ENTRY * sizeof(u32))
+
+#endif
diff --git a/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c
new file mode 100644
index 0000000..ec96e81
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2008,2010 Freescale Semiconductor, Inc.
+ * Dave Liu <daveliu@freescale.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+/* PORDEVSR register */
+#define GUTS_PORDEVSR_OFFS 0xc
+#define GUTS_PORDEVSR_SERDES2_IO_SEL 0x38000000
+#define GUTS_PORDEVSR_SERDES2_IO_SEL_SHIFT 27
+
+/* SerDes CR0 register */
+#define FSL_SRDSCR0_OFFS 0x0
+#define FSL_SRDSCR0_TXEQA_MASK 0x00007000
+#define FSL_SRDSCR0_TXEQA_SGMII 0x00004000
+#define FSL_SRDSCR0_TXEQA_SATA 0x00001000
+#define FSL_SRDSCR0_TXEQE_MASK 0x00000700
+#define FSL_SRDSCR0_TXEQE_SGMII 0x00000400
+#define FSL_SRDSCR0_TXEQE_SATA 0x00000100
+
+/* SerDes CR1 register */
+#define FSL_SRDSCR1_OFFS 0x4
+#define FSL_SRDSCR1_LANEA_MASK 0x80200000
+#define FSL_SRDSCR1_LANEA_OFF 0x80200000
+#define FSL_SRDSCR1_LANEE_MASK 0x08020000
+#define FSL_SRDSCR1_LANEE_OFF 0x08020000
+
+/* SerDes CR2 register */
+#define FSL_SRDSCR2_OFFS 0x8
+#define FSL_SRDSCR2_EICA_MASK 0x00001f00
+#define FSL_SRDSCR2_EICA_SGMII 0x00000400
+#define FSL_SRDSCR2_EICA_SATA 0x00001400
+#define FSL_SRDSCR2_EICE_MASK 0x0000001f
+#define FSL_SRDSCR2_EICE_SGMII 0x00000004
+#define FSL_SRDSCR2_EICE_SATA 0x00000014
+
+/* SerDes CR3 register */
+#define FSL_SRDSCR3_OFFS 0xc
+#define FSL_SRDSCR3_LANEA_MASK 0x3f000700
+#define FSL_SRDSCR3_LANEA_SGMII 0x00000000
+#define FSL_SRDSCR3_LANEA_SATA 0x15000500
+#define FSL_SRDSCR3_LANEE_MASK 0x003f0007
+#define FSL_SRDSCR3_LANEE_SGMII 0x00000000
+#define FSL_SRDSCR3_LANEE_SATA 0x00150005
+
+#define SRDS1_MAX_LANES 8
+#define SRDS2_MAX_LANES 2
+
+static u32 serdes1_prtcl_map, serdes2_prtcl_map;
+
+static u8 serdes1_cfg_tbl[][SRDS1_MAX_LANES] = {
+ [0x2] = {PCIE1, PCIE1, PCIE1, PCIE1, NONE, NONE, NONE, NONE},
+ [0x3] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1},
+ [0x5] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2},
+ [0x7] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE3, PCIE3},
+};
+
+static u8 serdes2_cfg_tbl[][SRDS2_MAX_LANES] = {
+ [0x1] = {SATA1, SATA2},
+ [0x3] = {SATA1, NONE},
+ [0x4] = {SGMII_TSEC1, SGMII_TSEC3},
+ [0x6] = {SGMII_TSEC1, NONE},
+};
+
+int is_serdes_configured(enum srds_prtcl device)
+{
+ int ret = (1 << device) & serdes1_prtcl_map;
+
+ if (ret)
+ return ret;
+
+ return (1 << device) & serdes2_prtcl_map;
+}
+
+void fsl_serdes_init(void)
+{
+ void *guts = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ void *sd = (void *)CONFIG_SYS_MPC85xx_SERDES2_ADDR;
+ u32 pordevsr = in_be32(guts + GUTS_PORDEVSR_OFFS);
+ u32 srds1_io_sel, srds2_io_sel;
+ u32 tmp;
+ int lane;
+
+ srds1_io_sel = (pordevsr & MPC85xx_PORDEVSR_IO_SEL) >>
+ MPC85xx_PORDEVSR_IO_SEL_SHIFT;
+
+ /* parse the SRDS2_IO_SEL of PORDEVSR */
+ srds2_io_sel = (pordevsr & GUTS_PORDEVSR_SERDES2_IO_SEL)
+ >> GUTS_PORDEVSR_SERDES2_IO_SEL_SHIFT;
+
+ debug("PORDEVSR[SRDS1_IO_SEL] = %x\n", srds1_io_sel);
+ debug("PORDEVSR[SRDS2_IO_SEL] = %x\n", srds2_io_sel);
+
+ switch (srds2_io_sel) {
+ case 1: /* Lane A - SATA1, Lane E - SATA2 */
+ /* CR 0 */
+ tmp = in_be32(sd + FSL_SRDSCR0_OFFS);
+ tmp &= ~FSL_SRDSCR0_TXEQA_MASK;
+ tmp |= FSL_SRDSCR0_TXEQA_SATA;
+ tmp &= ~FSL_SRDSCR0_TXEQE_MASK;
+ tmp |= FSL_SRDSCR0_TXEQE_SATA;
+ out_be32(sd + FSL_SRDSCR0_OFFS, tmp);
+ /* CR 1 */
+ tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
+ tmp &= ~FSL_SRDSCR1_LANEA_MASK;
+ tmp &= ~FSL_SRDSCR1_LANEE_MASK;
+ out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
+ /* CR 2 */
+ tmp = in_be32(sd + FSL_SRDSCR2_OFFS);
+ tmp &= ~FSL_SRDSCR2_EICA_MASK;
+ tmp |= FSL_SRDSCR2_EICA_SATA;
+ tmp &= ~FSL_SRDSCR2_EICE_MASK;
+ tmp |= FSL_SRDSCR2_EICE_SATA;
+ out_be32(sd + FSL_SRDSCR2_OFFS, tmp);
+ /* CR 3 */
+ tmp = in_be32(sd + FSL_SRDSCR3_OFFS);
+ tmp &= ~FSL_SRDSCR3_LANEA_MASK;
+ tmp |= FSL_SRDSCR3_LANEA_SATA;
+ tmp &= ~FSL_SRDSCR3_LANEE_MASK;
+ tmp |= FSL_SRDSCR3_LANEE_SATA;
+ out_be32(sd + FSL_SRDSCR3_OFFS, tmp);
+ break;
+ case 3: /* Lane A - SATA1, Lane E - disabled */
+ /* CR 0 */
+ tmp = in_be32(sd + FSL_SRDSCR0_OFFS);
+ tmp &= ~FSL_SRDSCR0_TXEQA_MASK;
+ tmp |= FSL_SRDSCR0_TXEQA_SATA;
+ out_be32(sd + FSL_SRDSCR0_OFFS, tmp);
+ /* CR 1 */
+ tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
+ tmp &= ~FSL_SRDSCR1_LANEE_MASK;
+ tmp |= FSL_SRDSCR1_LANEE_OFF;
+ out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
+ /* CR 2 */
+ tmp = in_be32(sd + FSL_SRDSCR2_OFFS);
+ tmp &= ~FSL_SRDSCR2_EICA_MASK;
+ tmp |= FSL_SRDSCR2_EICA_SATA;
+ out_be32(sd + FSL_SRDSCR2_OFFS, tmp);
+ /* CR 3 */
+ tmp = in_be32(sd + FSL_SRDSCR3_OFFS);
+ tmp &= ~FSL_SRDSCR3_LANEA_MASK;
+ tmp |= FSL_SRDSCR3_LANEA_SATA;
+ out_be32(sd + FSL_SRDSCR3_OFFS, tmp);
+ break;
+ case 4: /* Lane A - eTSEC1 SGMII, Lane E - eTSEC3 SGMII */
+ /* CR 0 */
+ tmp = in_be32(sd + FSL_SRDSCR0_OFFS);
+ tmp &= ~FSL_SRDSCR0_TXEQA_MASK;
+ tmp |= FSL_SRDSCR0_TXEQA_SGMII;
+ tmp &= ~FSL_SRDSCR0_TXEQE_MASK;
+ tmp |= FSL_SRDSCR0_TXEQE_SGMII;
+ out_be32(sd + FSL_SRDSCR0_OFFS, tmp);
+ /* CR 1 */
+ tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
+ tmp &= ~FSL_SRDSCR1_LANEA_MASK;
+ tmp &= ~FSL_SRDSCR1_LANEE_MASK;
+ out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
+ /* CR 2 */
+ tmp = in_be32(sd + FSL_SRDSCR2_OFFS);
+ tmp &= ~FSL_SRDSCR2_EICA_MASK;
+ tmp |= FSL_SRDSCR2_EICA_SGMII;
+ tmp &= ~FSL_SRDSCR2_EICE_MASK;
+ tmp |= FSL_SRDSCR2_EICE_SGMII;
+ out_be32(sd + FSL_SRDSCR2_OFFS, tmp);
+ /* CR 3 */
+ tmp = in_be32(sd + FSL_SRDSCR3_OFFS);
+ tmp &= ~FSL_SRDSCR3_LANEA_MASK;
+ tmp |= FSL_SRDSCR3_LANEA_SGMII;
+ tmp &= ~FSL_SRDSCR3_LANEE_MASK;
+ tmp |= FSL_SRDSCR3_LANEE_SGMII;
+ out_be32(sd + FSL_SRDSCR3_OFFS, tmp);
+ break;
+ case 6: /* Lane A - eTSEC1 SGMII, Lane E - disabled */
+ /* CR 0 */
+ tmp = in_be32(sd + FSL_SRDSCR0_OFFS);
+ tmp &= ~FSL_SRDSCR0_TXEQA_MASK;
+ tmp |= FSL_SRDSCR0_TXEQA_SGMII;
+ out_be32(sd + FSL_SRDSCR0_OFFS, tmp);
+ /* CR 1 */
+ tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
+ tmp &= ~FSL_SRDSCR1_LANEE_MASK;
+ tmp |= FSL_SRDSCR1_LANEE_OFF;
+ out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
+ /* CR 2 */
+ tmp = in_be32(sd + FSL_SRDSCR2_OFFS);
+ tmp &= ~FSL_SRDSCR2_EICA_MASK;
+ tmp |= FSL_SRDSCR2_EICA_SGMII;
+ out_be32(sd + FSL_SRDSCR2_OFFS, tmp);
+ /* CR 3 */
+ tmp = in_be32(sd + FSL_SRDSCR3_OFFS);
+ tmp &= ~FSL_SRDSCR3_LANEA_MASK;
+ tmp |= FSL_SRDSCR3_LANEA_SGMII;
+ out_be32(sd + FSL_SRDSCR3_OFFS, tmp);
+ break;
+ case 7: /* Lane A - disabled, Lane E - disabled */
+ /* CR 1 */
+ tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
+ tmp &= ~FSL_SRDSCR1_LANEA_MASK;
+ tmp |= FSL_SRDSCR1_LANEA_OFF;
+ tmp &= ~FSL_SRDSCR1_LANEE_MASK;
+ tmp |= FSL_SRDSCR1_LANEE_OFF;
+ out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
+ break;
+ default:
+ break;
+ }
+
+ if (srds1_io_sel >= ARRAY_SIZE(serdes1_cfg_tbl)) {
+ printf("Invalid PORDEVSR[SRDS1_IO_SEL] = %d\n", srds1_io_sel);
+ return;
+ }
+ for (lane = 0; lane < SRDS1_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes1_cfg_tbl[srds1_io_sel][lane];
+ serdes1_prtcl_map |= (1 << lane_prtcl);
+ }
+
+ if (srds2_io_sel >= ARRAY_SIZE(serdes2_cfg_tbl)) {
+ printf("Invalid PORDEVSR[SRDS2_IO_SEL] = %d\n", srds2_io_sel);
+ return;
+ }
+
+ for (lane = 0; lane < SRDS2_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes2_cfg_tbl[srds2_io_sel][lane];
+ serdes2_prtcl_map |= (1 << lane_prtcl);
+ }
+}
diff --git a/arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c
new file mode 100644
index 0000000..3483366
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+#define SRDS1_MAX_LANES 8
+#define SRDS2_MAX_LANES 4
+
+static u32 serdes1_prtcl_map, serdes2_prtcl_map;
+
+static u8 serdes1_cfg_tbl[][SRDS1_MAX_LANES] = {
+ [0x2] = {PCIE1, PCIE1, PCIE1, PCIE1, NONE, NONE, NONE, NONE},
+ [0x3] = {PCIE1, PCIE1, PCIE1, PCIE1, NONE, NONE, NONE, NONE},
+ [0x4] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2},
+ [0x5] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2},
+ [0x6] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2},
+ [0x7] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2},
+};
+
+static u8 serdes2_cfg_tbl[][SRDS2_MAX_LANES] = {
+ [0x1] = {NONE, NONE, SGMII_TSEC1, SGMII_TSEC3},
+ [0x3] = {NONE, NONE, SGMII_TSEC1, SGMII_TSEC3},
+ [0x5] = {NONE, NONE, SGMII_TSEC1, SGMII_TSEC3},
+ [0x6] = {PCIE3, NONE, NONE, NONE},
+ [0x7] = {PCIE3, NONE, SGMII_TSEC1, SGMII_TSEC3},
+};
+
+int is_serdes_configured(enum srds_prtcl device)
+{
+ int ret = (1 << device) & serdes1_prtcl_map;
+
+ if (ret)
+ return ret;
+
+ return (1 << device) & serdes2_prtcl_map;
+}
+
+void fsl_serdes_init(void)
+{
+ ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
+ u32 pordevsr = in_be32(&gur->pordevsr);
+ u32 srds_cfg = (pordevsr & MPC85xx_PORDEVSR_IO_SEL) >>
+ MPC85xx_PORDEVSR_IO_SEL_SHIFT;
+ int lane;
+
+ debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg);
+
+ if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);
+ return;
+ }
+ for (lane = 0; lane < SRDS1_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes1_cfg_tbl[srds_cfg][lane];
+ serdes1_prtcl_map |= (1 << lane_prtcl);
+ }
+
+ if (srds_cfg >= ARRAY_SIZE(serdes2_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);
+ return;
+ }
+
+ for (lane = 0; lane < SRDS2_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes2_cfg_tbl[srds_cfg][lane];
+ serdes2_prtcl_map |= (1 << lane_prtcl);
+ }
+
+ if (pordevsr & MPC85xx_PORDEVSR_SGMII1_DIS)
+ serdes2_prtcl_map &= ~(1 << SGMII_TSEC1);
+
+ if (pordevsr & MPC85xx_PORDEVSR_SGMII3_DIS)
+ serdes2_prtcl_map &= ~(1 << SGMII_TSEC3);
+}
diff --git a/arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c
new file mode 100644
index 0000000..c9eea15
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+#define SRDS1_MAX_LANES 8
+
+static u32 serdes1_prtcl_map;
+
+static u8 serdes1_cfg_tbl[][SRDS1_MAX_LANES] = {
+ [0x3] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO1, SRIO1, SRIO1, SRIO1},
+ [0x4] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO1, SRIO1, SRIO1, SRIO1},
+ [0x5] = {NONE, NONE, NONE, NONE, SRIO1, SRIO1, SRIO1, SRIO1},
+ [0x6] = {NONE, NONE, NONE, NONE, SRIO1, SRIO1, SRIO1, SRIO1},
+ [0x7] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1},
+};
+
+int is_serdes_configured(enum srds_prtcl prtcl)
+{
+ return (1 << prtcl) & serdes1_prtcl_map;
+}
+
+void fsl_serdes_init(void)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 pordevsr = in_be32(&gur->pordevsr);
+ u32 srds1_cfg = (pordevsr & MPC85xx_PORDEVSR_IO_SEL) >>
+ MPC85xx_PORDEVSR_IO_SEL_SHIFT;
+ int lane;
+
+ debug("PORDEVSR[IO_SEL] = %x\n", srds1_cfg);
+
+ if (srds1_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL] = %d\n", srds1_cfg);
+ return ;
+ }
+
+ for (lane = 0; lane < SRDS1_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes1_cfg_tbl[srds1_cfg][lane];
+ serdes1_prtcl_map |= (1 << lane_prtcl);
+ }
+}
diff --git a/arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c
new file mode 100644
index 0000000..49a0290
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+#define SRDS1_MAX_LANES 8
+
+static u32 serdes1_prtcl_map;
+
+static u8 serdes1_cfg_tbl[][SRDS1_MAX_LANES] = {
+ [0x3] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO1, SRIO1, SRIO1, SRIO1},
+ [0x4] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO1, SRIO1, SRIO1, SRIO1},
+ [0x5] = {NONE, NONE, NONE, NONE, SRIO1, SRIO1, SRIO1, SRIO1},
+ [0x6] = {NONE, NONE, NONE, NONE, SRIO1, SRIO1, SRIO1, SRIO1},
+ [0x7] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1},
+};
+
+int is_serdes_configured(enum srds_prtcl prtcl)
+{
+ return (1 << prtcl) & serdes1_prtcl_map;
+}
+
+void fsl_serdes_init(void)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 pordevsr = in_be32(&gur->pordevsr);
+ u32 srds_cfg = (pordevsr & MPC85xx_PORDEVSR_IO_SEL) >>
+ MPC85xx_PORDEVSR_IO_SEL_SHIFT;
+ int lane;
+
+ debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg);
+
+ if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);
+ return;
+ }
+
+ for (lane = 0; lane < SRDS1_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes1_cfg_tbl[srds_cfg][lane];
+ serdes1_prtcl_map |= (1 << lane_prtcl);
+ }
+}
diff --git a/arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c
new file mode 100644
index 0000000..7af6aff
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+#define SRDS1_MAX_LANES 4
+
+static u32 serdes1_prtcl_map;
+
+static u8 serdes1_cfg_tbl[][SRDS1_MAX_LANES] = {
+ [0x0] = {PCIE1, NONE, NONE, NONE},
+ [0x1] = {SRIO1, SRIO2, SGMII_TSEC1, SGMII_TSEC2},
+ [0x2] = {SRIO1, SRIO2, SGMII_TSEC1, SGMII_TSEC2},
+ [0x3] = {SRIO1, SRIO2, NONE, NONE},
+ [0x4] = {PCIE1, NONE, SGMII_TSEC1, SGMII_TSEC2},
+ [0x5] = {PCIE1, PCIE1, SGMII_TSEC1, SGMII_TSEC2},
+ [0x6] = {PCIE1, NONE, SRIO1, SRIO2},
+ [0x7] = {PCIE1, PCIE1, SRIO1, SRIO2},
+ [0x8] = {PCIE1, PCIE1, SRIO1, SRIO2},
+ [0x9] = {SRIO1, SRIO1, SRIO1, SRIO1},
+ [0xa] = {SRIO1, SRIO1, SRIO1, SRIO1},
+ [0xb] = {SRIO1, SRIO1, SRIO1, SRIO1},
+ [0xc] = {PCIE1, SRIO1, SGMII_TSEC1, SGMII_TSEC2},
+ [0xf] = {PCIE1, PCIE1, PCIE1, PCIE1},
+};
+
+int is_serdes_configured(enum srds_prtcl prtcl)
+{
+ return (1 << prtcl) & serdes1_prtcl_map;
+}
+
+void fsl_serdes_init(void)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 pordevsr = in_be32(&gur->pordevsr);
+ u32 srds_cfg = (pordevsr & MPC85xx_PORDEVSR_IO_SEL) >>
+ MPC85xx_PORDEVSR_IO_SEL_SHIFT;
+ int lane;
+
+ debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg);
+
+ if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);
+ return;
+ }
+
+ for (lane = 0; lane < SRDS1_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes1_cfg_tbl[srds_cfg][lane];
+ serdes1_prtcl_map |= (1 << lane_prtcl);
+ }
+}
diff --git a/arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c
new file mode 100644
index 0000000..fcccb52
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+#define SRDS1_MAX_LANES 8
+
+static u32 serdes1_prtcl_map;
+
+static u8 serdes1_cfg_tbl[][SRDS1_MAX_LANES] = {
+ [0x2] = {PCIE1, PCIE1, PCIE1, PCIE1, NONE, NONE, NONE, NONE},
+ [0x3] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2},
+ [0x6] = {NONE, NONE, NONE, NONE, SRIO1, SRIO1, SRIO1, SRIO1},
+ [0x7] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE3, PCIE3},
+ [0xb] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO1, SRIO1, SRIO1, SRIO1},
+ [0xc] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO1, SRIO1, SRIO1, SRIO1},
+ [0xd] = {NONE, NONE, NONE, NONE, SRIO1, SRIO1, SRIO1, SRIO1},
+ [0xe] = {NONE, NONE, NONE, NONE, SRIO1, SRIO1, SRIO1, SRIO1},
+ [0xf] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1},
+};
+
+int is_serdes_configured(enum srds_prtcl prtcl)
+{
+ return (1 << prtcl) & serdes1_prtcl_map;
+}
+
+void fsl_serdes_init(void)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 pordevsr = in_be32(&gur->pordevsr);
+ u32 srds_cfg = (pordevsr & MPC85xx_PORDEVSR_IO_SEL) >>
+ MPC85xx_PORDEVSR_IO_SEL_SHIFT;
+ int lane;
+
+ debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg);
+
+ if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);
+ return;
+ }
+
+ for (lane = 0; lane < SRDS1_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes1_cfg_tbl[srds_cfg][lane];
+ serdes1_prtcl_map |= (1 << lane_prtcl);
+ }
+
+ if (!(pordevsr & MPC85xx_PORDEVSR_SGMII1_DIS))
+ serdes1_prtcl_map |= (1 << SGMII_TSEC1);
+
+ if (!(pordevsr & MPC85xx_PORDEVSR_SGMII2_DIS))
+ serdes1_prtcl_map |= (1 << SGMII_TSEC2);
+
+ if (!(pordevsr & MPC85xx_PORDEVSR_SGMII3_DIS))
+ serdes1_prtcl_map |= (1 << SGMII_TSEC3);
+
+ if (!(pordevsr & MPC85xx_PORDEVSR_SGMII4_DIS))
+ serdes1_prtcl_map |= (1 << SGMII_TSEC4);
+}
diff --git a/arch/powerpc/cpu/mpc85xx/p1010_serdes.c b/arch/powerpc/cpu/mpc85xx/p1010_serdes.c
new file mode 100644
index 0000000..1f7dba0
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/p1010_serdes.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Author: Prabhakar Kushwaha <prabhakar@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+#define SRDS1_MAX_LANES 4
+#define SRDS2_MAX_LANES 2
+
+static u32 serdes1_prtcl_map, serdes2_prtcl_map;
+
+static const u8 serdes1_cfg_tbl[][SRDS1_MAX_LANES] = {
+ [0x00] = {NONE, NONE, NONE, NONE},
+ [0x01] = {PCIE1, PCIE2, SGMII_TSEC2, SGMII_TSEC3},
+ [0x02] = {PCIE1, SGMII_TSEC1, SGMII_TSEC2, SGMII_TSEC3},
+ [0x03] = {NONE, SGMII_TSEC1, SGMII_TSEC2, SGMII_TSEC3},
+};
+
+static const u8 serdes2_cfg_tbl[][SRDS2_MAX_LANES] = {
+ [0x00] = {NONE, NONE},
+ [0x01] = {SATA1, SATA2},
+ [0x02] = {SATA1, SATA2},
+ [0x03] = {PCIE1, PCIE2},
+};
+
+
+int is_serdes_configured(enum srds_prtcl device)
+{
+ int ret = (1 << device) & serdes1_prtcl_map;
+
+ if (ret)
+ return ret;
+
+ return (1 << device) & serdes2_prtcl_map;
+}
+
+void fsl_serdes_init(void)
+{
+ ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
+ u32 pordevsr = in_be32(&gur->pordevsr);
+ u32 srds_cfg = (pordevsr & MPC85xx_PORDEVSR_IO_SEL) >>
+ MPC85xx_PORDEVSR_IO_SEL_SHIFT;
+ int lane;
+
+ debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg);
+
+ if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);
+ return;
+ }
+ for (lane = 0; lane < SRDS1_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes1_cfg_tbl[srds_cfg][lane];
+ serdes1_prtcl_map |= (1 << lane_prtcl);
+ }
+
+ if (srds_cfg >= ARRAY_SIZE(serdes2_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);
+ return;
+ }
+
+ for (lane = 0; lane < SRDS2_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes2_cfg_tbl[srds_cfg][lane];
+ serdes2_prtcl_map |= (1 << lane_prtcl);
+ }
+}
diff --git a/arch/powerpc/cpu/mpc85xx/p1021_serdes.c b/arch/powerpc/cpu/mpc85xx/p1021_serdes.c
new file mode 100644
index 0000000..d6d2696
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/p1021_serdes.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+typedef struct serdes_85xx {
+ u32 srdscr0; /* 0x00 - SRDS Control Register 0 */
+ u32 srdscr1; /* 0x04 - SRDS Control Register 1 */
+ u32 srdscr2; /* 0x08 - SRDS Control Register 2 */
+ u32 srdscr3; /* 0x0C - SRDS Control Register 3 */
+ u32 srdscr4; /* 0x10 - SRDS Control Register 4 */
+} serdes_85xx_t;
+#define FSL_SRDSCR3_EIC0(x) (((x) & 0x1f) << 8)
+#define FSL_SRDSCR3_EIC0_MASK FSL_SRDSCR3_EIC0(0x1f)
+#define FSL_SRDSCR3_EIC1(x) (((x) & 0x1f) << 0)
+#define FSL_SRDSCR3_EIC1_MASK FSL_SRDSCR3_EIC1(0x1f)
+#define FSL_SRDSCR4_EIC2(x) (((x) & 0x1f) << 8)
+#define FSL_SRDSCR4_EIC2_MASK FSL_SRDSCR4_EIC2(0x1f)
+#define FSL_SRDSCR4_EIC3(x) (((x) & 0x1f) << 0)
+#define FSL_SRDSCR4_EIC3_MASK FSL_SRDSCR4_EIC3(0x1f)
+#define EIC_PCIE 0x13
+#define EIC_SGMII 0x04
+
+#define SRDS1_MAX_LANES 4
+
+static u32 serdes1_prtcl_map;
+
+static u8 serdes1_cfg_tbl[][SRDS1_MAX_LANES] = {
+ [0x0] = {PCIE1, NONE, NONE, NONE},
+ [0x6] = {PCIE1, PCIE1, PCIE1, PCIE1},
+ [0xe] = {PCIE1, PCIE2, SGMII_TSEC2, SGMII_TSEC3},
+ [0xf] = {PCIE1, PCIE1, SGMII_TSEC2, SGMII_TSEC3},
+};
+
+int is_serdes_configured(enum srds_prtcl prtcl)
+{
+ return (1 << prtcl) & serdes1_prtcl_map;
+}
+
+void fsl_serdes_init(void)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ serdes_85xx_t *serdes = (void *)CONFIG_SYS_MPC85xx_SERDES1_ADDR;
+
+ u32 pordevsr = in_be32(&gur->pordevsr);
+ u32 srds_cfg = (pordevsr & MPC85xx_PORDEVSR_IO_SEL) >>
+ MPC85xx_PORDEVSR_IO_SEL_SHIFT;
+ int lane;
+ u32 mask, val;
+
+ debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg);
+
+ if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);
+ return;
+ }
+
+ for (lane = 0; lane < SRDS1_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes1_cfg_tbl[srds_cfg][lane];
+ serdes1_prtcl_map |= (1 << lane_prtcl);
+ }
+
+ /* Init SERDES Receiver electrical idle detection control for PCIe */
+
+ /* Lane 0 is always PCIe 1 */
+ mask = FSL_SRDSCR3_EIC0_MASK;
+ val = FSL_SRDSCR3_EIC0(EIC_PCIE);
+
+ /* Lane 1 */
+ if ((serdes1_cfg_tbl[srds_cfg][1] == PCIE1) ||
+ (serdes1_cfg_tbl[srds_cfg][1] == PCIE2)) {
+ mask |= FSL_SRDSCR3_EIC1_MASK;
+ val |= FSL_SRDSCR3_EIC1(EIC_PCIE);
+ }
+
+ /* Handle lanes 0 & 1 */
+ clrsetbits_be32(&serdes->srdscr3, mask, val);
+
+ /* Handle lanes 2 & 3 */
+ if (srds_cfg == 0x6) {
+ mask = FSL_SRDSCR4_EIC2_MASK | FSL_SRDSCR4_EIC3_MASK;
+ val = FSL_SRDSCR4_EIC2(EIC_PCIE) | FSL_SRDSCR4_EIC3(EIC_PCIE);
+ clrsetbits_be32(&serdes->srdscr4, mask, val);
+ }
+
+ /* 100 ms delay */
+ udelay(100000);
+}
diff --git a/arch/powerpc/cpu/mpc85xx/p1022_serdes.c b/arch/powerpc/cpu/mpc85xx/p1022_serdes.c
new file mode 100644
index 0000000..ed49920
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/p1022_serdes.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+#define SRDS1_MAX_LANES 4
+#define SRDS2_MAX_LANES 2
+
+static u32 serdes1_prtcl_map, serdes2_prtcl_map;
+
+static const u8 serdes1_cfg_tbl[][SRDS1_MAX_LANES] = {
+ [0x00] = {NONE, NONE, NONE, NONE},
+ [0x01] = {NONE, NONE, NONE, NONE},
+ [0x02] = {NONE, NONE, NONE, NONE},
+ [0x03] = {NONE, NONE, NONE, NONE},
+ [0x04] = {NONE, NONE, NONE, NONE},
+ [0x06] = {PCIE1, PCIE3, SGMII_TSEC1, PCIE2},
+ [0x07] = {PCIE1, PCIE3, SGMII_TSEC1, PCIE2},
+ [0x09] = {PCIE1, NONE, NONE, NONE},
+ [0x0a] = {PCIE1, PCIE3, SGMII_TSEC1, SGMII_TSEC2},
+ [0x0b] = {PCIE1, PCIE3, SGMII_TSEC1, SGMII_TSEC2},
+ [0x0d] = {PCIE1, PCIE1, SGMII_TSEC1, SGMII_TSEC2},
+ [0x0e] = {PCIE1, PCIE1, SGMII_TSEC1, SGMII_TSEC2},
+ [0x0f] = {PCIE1, PCIE1, SGMII_TSEC1, SGMII_TSEC2},
+ [0x15] = {PCIE1, PCIE3, PCIE2, PCIE2},
+ [0x16] = {PCIE1, PCIE3, PCIE2, PCIE2},
+ [0x17] = {PCIE1, PCIE3, PCIE2, PCIE2},
+ [0x18] = {PCIE1, PCIE1, PCIE2, PCIE2},
+ [0x19] = {PCIE1, PCIE1, PCIE2, PCIE2},
+ [0x1a] = {PCIE1, PCIE1, PCIE2, PCIE2},
+ [0x1b] = {PCIE1, PCIE1, PCIE2, PCIE2},
+ [0x1c] = {PCIE1, PCIE1, PCIE1, PCIE1},
+ [0x1d] = {PCIE1, PCIE1, PCIE2, PCIE2},
+ [0x1e] = {PCIE1, PCIE1, PCIE2, PCIE2},
+ [0x1f] = {PCIE1, PCIE1, PCIE2, PCIE2},
+};
+
+static const u8 serdes2_cfg_tbl[][SRDS2_MAX_LANES] = {
+ [0x00] = {PCIE3, PCIE3},
+ [0x01] = {PCIE2, PCIE3},
+ [0x02] = {SATA1, SATA2},
+ [0x03] = {SGMII_TSEC1, SGMII_TSEC2},
+ [0x04] = {NONE, NONE},
+ [0x06] = {SATA1, SATA2},
+ [0x07] = {NONE, NONE},
+ [0x09] = {PCIE3, PCIE2},
+ [0x0a] = {SATA1, SATA2},
+ [0x0b] = {NONE, NONE},
+ [0x0d] = {PCIE3, PCIE2},
+ [0x0e] = {SATA1, SATA2},
+ [0x0f] = {NONE, NONE},
+ [0x15] = {SGMII_TSEC1, SGMII_TSEC2},
+ [0x16] = {SATA1, SATA2},
+ [0x17] = {NONE, NONE},
+ [0x18] = {PCIE3, PCIE3},
+ [0x19] = {SGMII_TSEC1, SGMII_TSEC2},
+ [0x1a] = {SATA1, SATA2},
+ [0x1b] = {NONE, NONE},
+ [0x1c] = {PCIE3, PCIE3},
+ [0x1d] = {SGMII_TSEC1, SGMII_TSEC2},
+ [0x1e] = {SATA1, SATA2},
+ [0x1f] = {NONE, NONE},
+};
+
+int is_serdes_configured(enum srds_prtcl device)
+{
+ int ret = (1 << device) & serdes1_prtcl_map;
+
+ if (ret)
+ return ret;
+
+ return (1 << device) & serdes2_prtcl_map;
+}
+
+void fsl_serdes_init(void)
+{
+ ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
+ u32 pordevsr = in_be32(&gur->pordevsr);
+ u32 srds_cfg = (pordevsr & MPC85xx_PORDEVSR_IO_SEL) >>
+ MPC85xx_PORDEVSR_IO_SEL_SHIFT;
+ int lane;
+
+ debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg);
+
+ if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);
+ return;
+ }
+ for (lane = 0; lane < SRDS1_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes1_cfg_tbl[srds_cfg][lane];
+ serdes1_prtcl_map |= (1 << lane_prtcl);
+ }
+
+ if (srds_cfg >= ARRAY_SIZE(serdes2_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);
+ return;
+ }
+
+ for (lane = 0; lane < SRDS2_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes2_cfg_tbl[srds_cfg][lane];
+ serdes2_prtcl_map |= (1 << lane_prtcl);
+ }
+}
diff --git a/arch/powerpc/cpu/mpc85xx/p1023_serdes.c b/arch/powerpc/cpu/mpc85xx/p1023_serdes.c
new file mode 100644
index 0000000..0b4ae90
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/p1023_serdes.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ * Author: Roy Zang <tie-fei.zang@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+#define SRDS1_MAX_LANES 4
+
+static u32 serdes1_prtcl_map;
+
+static const u8 serdes1_cfg_tbl[][SRDS1_MAX_LANES] = {
+ [0x00] = {PCIE1, PCIE2, NONE, NONE},
+ [0x01] = {PCIE1, PCIE2, PCIE3, NONE},
+ [0x02] = {PCIE1, PCIE2, PCIE3, SGMII_FM1_DTSEC2},
+ [0x03] = {PCIE1, PCIE2, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2},
+};
+
+int is_serdes_configured(enum srds_prtcl device)
+{
+ int ret = (1 << device) & serdes1_prtcl_map;
+ return ret;
+}
+
+void fsl_serdes_init(void)
+{
+ ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
+ u32 pordevsr = in_be32(&gur->pordevsr);
+ u32 srds_cfg = (pordevsr & MPC85xx_PORDEVSR_IO_SEL) >>
+ MPC85xx_PORDEVSR_IO_SEL_SHIFT;
+ int lane;
+
+ debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg);
+
+ if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);
+ return;
+ }
+ for (lane = 0; lane < SRDS1_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes1_cfg_tbl[srds_cfg][lane];
+ serdes1_prtcl_map |= (1 << lane_prtcl);
+ }
+
+}
diff --git a/arch/powerpc/cpu/mpc85xx/p2020_serdes.c b/arch/powerpc/cpu/mpc85xx/p2020_serdes.c
new file mode 100644
index 0000000..01af333
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/p2020_serdes.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+#define SRDS1_MAX_LANES 4
+
+static u32 serdes1_prtcl_map;
+
+static u8 serdes1_cfg_tbl[][SRDS1_MAX_LANES] = {
+ [0x0] = {PCIE1, NONE, NONE, NONE},
+ [0x2] = {PCIE1, PCIE2, PCIE3, PCIE3},
+ [0x4] = {PCIE1, PCIE1, PCIE3, PCIE3},
+ [0x6] = {PCIE1, PCIE1, PCIE1, PCIE1},
+ [0x7] = {SRIO2, SRIO1, NONE, NONE},
+ [0x8] = {SRIO2, SRIO2, SRIO2, SRIO2},
+ [0x9] = {SRIO2, SRIO2, SRIO2, SRIO2},
+ [0xa] = {SRIO2, SRIO2, SRIO2, SRIO2},
+ [0xb] = {SRIO2, SRIO1, SGMII_TSEC2, SGMII_TSEC3},
+ [0xc] = {SRIO2, SRIO1, SGMII_TSEC2, SGMII_TSEC3},
+ [0xd] = {PCIE1, SRIO1, SGMII_TSEC2, SGMII_TSEC3},
+ [0xe] = {PCIE1, PCIE2, SGMII_TSEC2, SGMII_TSEC3},
+ [0xf] = {PCIE1, PCIE1, SGMII_TSEC2, SGMII_TSEC3},
+};
+
+int is_serdes_configured(enum srds_prtcl prtcl)
+{
+ return (1 << prtcl) & serdes1_prtcl_map;
+}
+
+void fsl_serdes_init(void)
+{
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 pordevsr = in_be32(&gur->pordevsr);
+ u32 srds_cfg = (pordevsr & MPC85xx_PORDEVSR_IO_SEL) >>
+ MPC85xx_PORDEVSR_IO_SEL_SHIFT;
+ int lane;
+
+ debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg);
+
+ if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);
+ return;
+ }
+
+ for (lane = 0; lane < SRDS1_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes1_cfg_tbl[srds_cfg][lane];
+ serdes1_prtcl_map |= (1 << lane_prtcl);
+ }
+}
diff --git a/arch/powerpc/cpu/mpc85xx/p2041_ids.c b/arch/powerpc/cpu/mpc85xx/p2041_ids.c
new file mode 100644
index 0000000..ef685fe
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/p2041_ids.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_portals.h>
+#include <asm/fsl_liodn.h>
+
+#ifdef CONFIG_SYS_DPAA_QBMAN
+struct qportal_info qp_info[CONFIG_SYS_QMAN_NUM_PORTALS] = {
+ /* dqrr liodn, frame data liodn, liodn off, sdest */
+ SET_QP_INFO(1, 2, 1, 0),
+ SET_QP_INFO(3, 4, 2, 1),
+ SET_QP_INFO(5, 6, 3, 2),
+ SET_QP_INFO(7, 8, 4, 3),
+ SET_QP_INFO(9, 10, 5, 0),
+ SET_QP_INFO(11, 12, 6, 1),
+ SET_QP_INFO(13, 14, 7, 2),
+ SET_QP_INFO(15, 16, 8, 3),
+ SET_QP_INFO(17, 18, 9, 0), /* for now sdest to 0 */
+ SET_QP_INFO(19, 20, 10, 0), /* for now sdest to 0 */
+};
+#endif
+
+struct srio_liodn_id_table srio_liodn_tbl[] = {
+ SET_SRIO_LIODN_2(1, 199, 200),
+ SET_SRIO_LIODN_2(2, 201, 202),
+};
+int srio_liodn_tbl_sz = ARRAY_SIZE(srio_liodn_tbl);
+
+struct liodn_id_table liodn_tbl[] = {
+#ifdef CONFIG_SYS_DPAA_QBMAN
+ SET_QMAN_LIODN(31),
+ SET_BMAN_LIODN(32),
+#endif
+
+ SET_SDHC_LIODN(1, 64),
+
+ SET_PME_LIODN(117),
+
+ SET_USB_LIODN(1, "fsl-usb2-mph", 125),
+ SET_USB_LIODN(2, "fsl-usb2-dr", 126),
+
+ SET_SATA_LIODN(1, 127),
+ SET_SATA_LIODN(2, 128),
+
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 1, 193),
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 2, 194),
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 3, 195),
+
+ SET_DMA_LIODN(1, 197),
+ SET_DMA_LIODN(2, 198),
+
+ SET_GUTS_LIODN("fsl,rapidio-delta", 199, rio1liodnr, 0),
+ SET_GUTS_LIODN(NULL, 200, rio2liodnr, 0),
+ SET_GUTS_LIODN(NULL, 201, rio1maintliodnr, 0),
+ SET_GUTS_LIODN(NULL, 202, rio2maintliodnr, 0),
+};
+int liodn_tbl_sz = ARRAY_SIZE(liodn_tbl);
+
+#ifdef CONFIG_SYS_DPAA_FMAN
+struct liodn_id_table fman1_liodn_tbl[] = {
+ SET_FMAN_RX_1G_LIODN(1, 0, 10),
+ SET_FMAN_RX_1G_LIODN(1, 1, 11),
+ SET_FMAN_RX_1G_LIODN(1, 2, 12),
+ SET_FMAN_RX_1G_LIODN(1, 3, 13),
+ SET_FMAN_RX_1G_LIODN(1, 4, 14),
+#if (CONFIG_SYS_NUM_FM1_10GEC == 1)
+ SET_FMAN_RX_10G_LIODN(1, 0, 15),
+#endif
+};
+int fman1_liodn_tbl_sz = ARRAY_SIZE(fman1_liodn_tbl);
+#endif
+
+struct liodn_id_table sec_liodn_tbl[] = {
+ SET_SEC_JR_LIODN_ENTRY(0, 129, 130),
+ SET_SEC_JR_LIODN_ENTRY(1, 131, 132),
+ SET_SEC_JR_LIODN_ENTRY(2, 133, 134),
+ SET_SEC_JR_LIODN_ENTRY(3, 135, 136),
+ SET_SEC_RTIC_LIODN_ENTRY(a, 154),
+ SET_SEC_RTIC_LIODN_ENTRY(b, 155),
+ SET_SEC_RTIC_LIODN_ENTRY(c, 156),
+ SET_SEC_RTIC_LIODN_ENTRY(d, 157),
+ SET_SEC_DECO_LIODN_ENTRY(0, 97, 98),
+ SET_SEC_DECO_LIODN_ENTRY(1, 99, 100),
+};
+int sec_liodn_tbl_sz = ARRAY_SIZE(sec_liodn_tbl);
+
+#ifdef CONFIG_SYS_DPAA_RMAN
+struct liodn_id_table rman_liodn_tbl[] = {
+ /* Set RMan block 0-3 liodn offset */
+ SET_RMAN_LIODN(0, 6),
+ SET_RMAN_LIODN(1, 7),
+ SET_RMAN_LIODN(2, 8),
+ SET_RMAN_LIODN(3, 9),
+};
+int rman_liodn_tbl_sz = ARRAY_SIZE(rman_liodn_tbl);
+#endif
+
+struct liodn_id_table liodn_bases[] = {
+ [FSL_HW_PORTAL_SEC] = SET_LIODN_BASE_2(64, 100),
+#ifdef CONFIG_SYS_DPAA_FMAN
+ [FSL_HW_PORTAL_FMAN1] = SET_LIODN_BASE_1(32),
+#endif
+#ifdef CONFIG_SYS_DPAA_PME
+ [FSL_HW_PORTAL_PME] = SET_LIODN_BASE_2(136, 172),
+#endif
+#ifdef CONFIG_SYS_DPAA_RMAN
+ [FSL_HW_PORTAL_RMAN] = SET_LIODN_BASE_1(80),
+#endif
+};
diff --git a/arch/powerpc/cpu/mpc85xx/p2041_serdes.c b/arch/powerpc/cpu/mpc85xx/p2041_serdes.c
new file mode 100644
index 0000000..87335c9
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/p2041_serdes.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_serdes.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include "fsl_corenet_serdes.h"
+
+static u8 serdes_cfg_tbl[][SRDS_MAX_LANES] = {
+ [0x2] = {NONE, NONE, PCIE1, PCIE1, SRIO1, SRIO1, SRIO1, SRIO1,
+ NONE, NONE, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, NONE, NONE, NONE, NONE, },
+ [0x5] = {NONE, NONE, PCIE1, PCIE3, PCIE2, PCIE2, PCIE2, PCIE2,
+ NONE, NONE, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, NONE, NONE, NONE, NONE, },
+ [0x8] = {NONE, NONE, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, PCIE2,
+ PCIE2, PCIE2, PCIE2, NONE, NONE, NONE, NONE, SATA1,
+ SATA2, NONE, NONE, NONE, NONE, },
+ [0x9] = {NONE, NONE, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, PCIE2,
+ PCIE2, PCIE2, PCIE2, NONE, NONE, XAUI_FM1, XAUI_FM1,
+ XAUI_FM1, XAUI_FM1, NONE, NONE, NONE, NONE, },
+ [0xa] = {NONE, NONE, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, PCIE2,
+ PCIE2, PCIE2, PCIE2, NONE, NONE, PCIE3, PCIE3, PCIE3,
+ PCIE3, NONE, NONE, NONE, NONE, },
+ [0xf] = {NONE, NONE, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, SRIO2,
+ SRIO2, SRIO1, SRIO1, NONE, NONE, PCIE3, SGMII_FM1_DTSEC5,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, NONE, NONE, NONE, NONE, },
+ [0x14] = {NONE, NONE, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, PCIE2,
+ PCIE2, SRIO1, SRIO1, NONE, NONE, AURORA,
+ SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, NONE,
+ NONE, NONE, NONE, },
+ [0x16] = {NONE, NONE, PCIE1, PCIE3, PCIE2, PCIE2, SGMII_FM1_DTSEC3,
+ SGMII_FM1_DTSEC4, NONE, NONE, NONE, NONE, SATA1, SATA2, NONE,
+ NONE, NONE, NONE, },
+ [0x17] = {NONE, NONE, PCIE1, PCIE3, PCIE2, PCIE2, SGMII_FM1_DTSEC3,
+ SGMII_FM1_DTSEC4, NONE, NONE, XAUI_FM1, XAUI_FM1, XAUI_FM1,
+ XAUI_FM1, NONE, NONE, NONE, NONE, },
+ [0x19] = {NONE, NONE, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, PCIE2,
+ PCIE2, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, NONE, NONE,
+ NONE, NONE, SATA1, SATA2, NONE, NONE, NONE, NONE, },
+ [0x1a] = {NONE, NONE, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, SRIO2,
+ SRIO2, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, NONE, NONE,
+ NONE, NONE, SATA1, SATA2, NONE, NONE, NONE, NONE, },
+ [0x1c] = {NONE, NONE, PCIE1, SGMII_FM1_DTSEC2, PCIE2, PCIE2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, NONE, NONE, AURORA,
+ SGMII_FM1_DTSEC5, NONE, NONE, NONE, NONE, NONE, NONE, },
+};
+
+enum srds_prtcl serdes_get_prtcl(int cfg, int lane)
+{
+ enum srds_prtcl prtcl;
+ u32 svr = get_svr();
+ u32 ver = SVR_SOC_VER(svr);
+
+ if (!serdes_lane_enabled(lane))
+ return NONE;
+
+ prtcl = serdes_cfg_tbl[cfg][lane];
+
+ /* P2040[e] does not support XAUI */
+ if (ver == SVR_P2040 && prtcl == XAUI_FM1)
+ prtcl = NONE;
+
+ return prtcl;
+}
+
+int is_serdes_prtcl_valid(u32 prtcl)
+{
+ int i;
+ u32 svr = get_svr();
+ u32 ver = SVR_SOC_VER(svr);
+
+ if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl))
+ return 0;
+
+ /* P2040[e] does not support XAUI */
+ if (ver == SVR_P2040 && prtcl == XAUI_FM1)
+ return 0;
+
+ for (i = 0; i < SRDS_MAX_LANES; i++) {
+ if (serdes_cfg_tbl[prtcl][i] != NONE)
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc85xx/p3041_ids.c b/arch/powerpc/cpu/mpc85xx/p3041_ids.c
new file mode 100644
index 0000000..cab03f8
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/p3041_ids.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_portals.h>
+#include <asm/fsl_liodn.h>
+
+#ifdef CONFIG_SYS_DPAA_QBMAN
+struct qportal_info qp_info[CONFIG_SYS_QMAN_NUM_PORTALS] = {
+ /* dqrr liodn, frame data liodn, liodn off, sdest */
+ SET_QP_INFO(1, 2, 1, 0),
+ SET_QP_INFO(3, 4, 2, 1),
+ SET_QP_INFO(5, 6, 3, 2),
+ SET_QP_INFO(7, 8, 4, 3),
+ SET_QP_INFO(9, 10, 5, 0),
+ SET_QP_INFO(1, 12, 6, 1),
+ SET_QP_INFO(13, 14, 7, 2),
+ SET_QP_INFO(15, 16, 8, 3),
+ SET_QP_INFO(17, 18, 9, 0), /* for now sdest to 0 */
+ SET_QP_INFO(19, 20, 10, 0), /* for now sdest to 0 */
+};
+#endif
+
+struct srio_liodn_id_table srio_liodn_tbl[] = {
+ SET_SRIO_LIODN_2(1, 199, 200),
+ SET_SRIO_LIODN_2(2, 201, 202),
+};
+int srio_liodn_tbl_sz = ARRAY_SIZE(srio_liodn_tbl);
+
+struct liodn_id_table liodn_tbl[] = {
+#ifdef CONFIG_SYS_DPAA_QBMAN
+ SET_QMAN_LIODN(31),
+ SET_BMAN_LIODN(32),
+#endif
+
+ SET_SDHC_LIODN(1, 64),
+
+ SET_PME_LIODN(117),
+
+ SET_USB_LIODN(1, "fsl-usb2-mph", 125),
+ SET_USB_LIODN(2, "fsl-usb2-dr", 126),
+
+ SET_SATA_LIODN(1, 127),
+ SET_SATA_LIODN(2, 128),
+
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 1, 193),
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 2, 194),
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 3, 195),
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 4, 196),
+
+ SET_DMA_LIODN(1, 197),
+ SET_DMA_LIODN(2, 198),
+
+ SET_GUTS_LIODN("fsl,rapidio-delta", 199, rio1liodnr, 0),
+ SET_GUTS_LIODN(NULL, 200, rio2liodnr, 0),
+ SET_GUTS_LIODN(NULL, 201, rio1maintliodnr, 0),
+ SET_GUTS_LIODN(NULL, 202, rio2maintliodnr, 0),
+};
+int liodn_tbl_sz = ARRAY_SIZE(liodn_tbl);
+
+#ifdef CONFIG_SYS_DPAA_FMAN
+struct liodn_id_table fman1_liodn_tbl[] = {
+ SET_FMAN_RX_1G_LIODN(1, 0, 10),
+ SET_FMAN_RX_1G_LIODN(1, 1, 11),
+ SET_FMAN_RX_1G_LIODN(1, 2, 12),
+ SET_FMAN_RX_1G_LIODN(1, 3, 13),
+ SET_FMAN_RX_1G_LIODN(1, 4, 14),
+ SET_FMAN_RX_10G_LIODN(1, 0, 15),
+};
+int fman1_liodn_tbl_sz = ARRAY_SIZE(fman1_liodn_tbl);
+#endif
+
+struct liodn_id_table sec_liodn_tbl[] = {
+ SET_SEC_JR_LIODN_ENTRY(0, 129, 130),
+ SET_SEC_JR_LIODN_ENTRY(1, 131, 132),
+ SET_SEC_JR_LIODN_ENTRY(2, 133, 134),
+ SET_SEC_JR_LIODN_ENTRY(3, 135, 136),
+ SET_SEC_RTIC_LIODN_ENTRY(a, 154),
+ SET_SEC_RTIC_LIODN_ENTRY(b, 155),
+ SET_SEC_RTIC_LIODN_ENTRY(c, 156),
+ SET_SEC_RTIC_LIODN_ENTRY(d, 157),
+ SET_SEC_DECO_LIODN_ENTRY(0, 97, 98),
+ SET_SEC_DECO_LIODN_ENTRY(1, 99, 100),
+};
+int sec_liodn_tbl_sz = ARRAY_SIZE(sec_liodn_tbl);
+
+#ifdef CONFIG_SYS_DPAA_RMAN
+struct liodn_id_table rman_liodn_tbl[] = {
+ /* Set RMan block 0-3 liodn offset */
+ SET_RMAN_LIODN(0, 6),
+ SET_RMAN_LIODN(1, 7),
+ SET_RMAN_LIODN(2, 8),
+ SET_RMAN_LIODN(3, 9),
+};
+int rman_liodn_tbl_sz = ARRAY_SIZE(rman_liodn_tbl);
+#endif
+
+struct liodn_id_table liodn_bases[] = {
+ [FSL_HW_PORTAL_SEC] = SET_LIODN_BASE_2(64, 100),
+#ifdef CONFIG_SYS_DPAA_FMAN
+ [FSL_HW_PORTAL_FMAN1] = SET_LIODN_BASE_1(32),
+#endif
+#ifdef CONFIG_SYS_DPAA_PME
+ [FSL_HW_PORTAL_PME] = SET_LIODN_BASE_2(136, 172),
+#endif
+#ifdef CONFIG_SYS_DPAA_RMAN
+ [FSL_HW_PORTAL_RMAN] = SET_LIODN_BASE_1(80),
+#endif
+};
diff --git a/arch/powerpc/cpu/mpc85xx/p3041_serdes.c b/arch/powerpc/cpu/mpc85xx/p3041_serdes.c
new file mode 100644
index 0000000..a36dcd5
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/p3041_serdes.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2009-2011 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_serdes.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include "fsl_corenet_serdes.h"
+
+static u8 serdes_cfg_tbl[][SRDS_MAX_LANES] = {
+ [0x2] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2,
+ PCIE4, AURORA, PCIE3, SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3,
+ SGMII_FM1_DTSEC4, NONE, NONE, SATA1, SATA2, },
+ [0x4] = {SRIO2, SRIO2, SRIO2, SRIO2, SRIO1, SRIO1, SRIO1, SRIO1,
+ PCIE2, AURORA, PCIE3, SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3,
+ SGMII_FM1_DTSEC4, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1, },
+ [0xb] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO2, SRIO2, SRIO1, SRIO1,
+ PCIE2, AURORA, PCIE3, SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3,
+ SGMII_FM1_DTSEC4, NONE, NONE, SATA1, SATA2, },
+ [0x10] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1,
+ AURORA, AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1,
+ NONE, NONE, SATA1, SATA2, },
+ [0x11] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, NONE, NONE, SATA1, SATA2, },
+ [0x13] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, XAUI_FM1, XAUI_FM1,
+ XAUI_FM1, XAUI_FM1, },
+ [0x14] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, PCIE3, PCIE3, PCIE3, PCIE3,
+ SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3,
+ SGMII_FM1_DTSEC4, },
+ [0x15] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1,
+ NONE, NONE, SATA1, SATA2, },
+ [0x16] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, SRIO1, SRIO1, SRIO1,
+ SRIO1, },
+ [0x17] = {SRIO2, SRIO2, SRIO2, SRIO2, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, NONE, NONE, SATA1, SATA2, },
+ [0x18] = {SRIO2, SRIO2, SRIO2, SRIO2, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, SGMII_FM1_DTSEC5, NONE,
+ NONE, NONE, },
+ [0x1b] = {SRIO2, SRIO2, SRIO2, SRIO2, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1,
+ NONE, NONE, SATA1, SATA2, },
+ [0x1d] = {SRIO2, SRIO2, SRIO2, SRIO2, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, PCIE3, PCIE3, PCIE3, PCIE3, NONE, NONE,
+ SATA1, SATA2, },
+ [0x20] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, XAUI_FM1, XAUI_FM1,
+ XAUI_FM1, XAUI_FM1, },
+ [0x21] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, PCIE3, PCIE3, PCIE3, PCIE3,
+ SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3,
+ SGMII_FM1_DTSEC4, },
+ [0x22] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1,
+ NONE, NONE, SATA1, SATA2, },
+ [0x23] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO2, SRIO2, SRIO1, SRIO1,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, NONE, NONE, SATA1, SATA2, },
+ [0x24] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO2, SRIO2, SRIO1, SRIO1,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, SGMII_FM1_DTSEC5, NONE,
+ NONE, NONE, },
+ [0x28] = {PCIE1, PCIE1, PCIE3, PCIE3, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, NONE, NONE, SATA1, SATA2, },
+ [0x29] = {PCIE1, PCIE1, PCIE3, PCIE3, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, SGMII_FM1_DTSEC5, NONE,
+ NONE, NONE, },
+ [0x2a] = {PCIE1, PCIE1, PCIE3, PCIE3, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, XAUI_FM1, XAUI_FM1,
+ XAUI_FM1, XAUI_FM1, },
+ [0x2b] = {PCIE1, PCIE1, PCIE3, PCIE3, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1,
+ NONE, NONE, SATA1, SATA2, },
+ [0x2f] = {PCIE1, PCIE1, PCIE3, PCIE3, SRIO2, SRIO2, SRIO1, SRIO1,
+ AURORA, AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1,
+ NONE, NONE, SATA1, SATA2, },
+ [0x31] = {PCIE1, PCIE1, PCIE3, PCIE3, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, SGMII_FM1_DTSEC5, NONE,
+ NONE, NONE, },
+ [0x33] = {PCIE1, PCIE1, PCIE3, PCIE3, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1,
+ NONE, NONE, SATA1, SATA2, },
+ [0x34] = {PCIE1, PCIE1, PCIE1, PCIE1, SGMII_FM1_DTSEC1,
+ SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, AURORA,
+ AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1, NONE,
+ NONE, SATA1, SATA2, },
+ [0x35] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, AURORA, AURORA, XAUI_FM1,
+ XAUI_FM1, XAUI_FM1, XAUI_FM1, NONE, NONE, SATA1, SATA2, },
+ [0x36] = {PCIE1, PCIE1, PCIE3, PCIE3, SGMII_FM1_DTSEC1,
+ SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, AURORA,
+ AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1, NONE,
+ NONE, SATA1, SATA2, },
+ [0x37] = {PCIE1, PCIE1, PCIE3, PCIE3, PCIE2, PCIE2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, AURORA, AURORA, XAUI_FM1,
+ XAUI_FM1, XAUI_FM1, XAUI_FM1, NONE, NONE, SATA1, SATA2, },
+};
+
+enum srds_prtcl serdes_get_prtcl(int cfg, int lane)
+{
+ if (!serdes_lane_enabled(lane))
+ return NONE;
+
+ return serdes_cfg_tbl[cfg][lane];
+}
+
+int is_serdes_prtcl_valid(u32 prtcl) {
+ int i;
+
+ if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl))
+ return 0;
+
+ for (i = 0; i < SRDS_MAX_LANES; i++) {
+ if (serdes_cfg_tbl[prtcl][i] != NONE)
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc85xx/p4080_ids.c b/arch/powerpc/cpu/mpc85xx/p4080_ids.c
new file mode 100644
index 0000000..5c287fb
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/p4080_ids.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_portals.h>
+#include <asm/fsl_liodn.h>
+
+#ifdef CONFIG_SYS_DPAA_QBMAN
+struct qportal_info qp_info[CONFIG_SYS_QMAN_NUM_PORTALS] = {
+ /* dqrr liodn, frame data liodn, liodn off, sdest */
+ SET_QP_INFO( 1, 2, 1, 0),
+ SET_QP_INFO( 3, 4, 2, 1),
+ SET_QP_INFO( 5, 6, 3, 2),
+ SET_QP_INFO( 7, 8, 4, 3),
+ SET_QP_INFO( 9, 10, 5, 4),
+ SET_QP_INFO(11, 12, 6, 5),
+ SET_QP_INFO(13, 14, 7, 6),
+ SET_QP_INFO(15, 16, 8, 7),
+ SET_QP_INFO(17, 18, 9, 0), /* for now sdest to 0 */
+ SET_QP_INFO(19, 20, 10, 0), /* for now sdest to 0 */
+};
+#endif
+
+struct srio_liodn_id_table srio_liodn_tbl[] = {
+ SET_SRIO_LIODN_1(1, 198),
+ SET_SRIO_LIODN_1(2, 199),
+};
+int srio_liodn_tbl_sz = ARRAY_SIZE(srio_liodn_tbl);
+
+struct liodn_id_table liodn_tbl[] = {
+ SET_USB_LIODN(1, "fsl-usb2-mph", 127),
+ SET_USB_LIODN(2, "fsl-usb2-dr", 157),
+
+ SET_SDHC_LIODN(1, 156),
+
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 1, 193),
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 2, 194),
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 3, 195),
+
+ SET_DMA_LIODN(1, 196),
+ SET_DMA_LIODN(2, 197),
+
+ SET_GUTS_LIODN("fsl,srio-rmu", 200, rmuliodnr, 0xd3000),
+
+#ifdef CONFIG_SYS_DPAA_QBMAN
+ SET_QMAN_LIODN(31),
+ SET_BMAN_LIODN(32),
+#endif
+ SET_PME_LIODN(128),
+};
+int liodn_tbl_sz = ARRAY_SIZE(liodn_tbl);
+
+#ifdef CONFIG_SYS_DPAA_FMAN
+struct liodn_id_table fman1_liodn_tbl[] = {
+ SET_FMAN_RX_1G_LIODN(1, 0, 11),
+ SET_FMAN_RX_1G_LIODN(1, 1, 12),
+ SET_FMAN_RX_1G_LIODN(1, 2, 13),
+ SET_FMAN_RX_1G_LIODN(1, 3, 14),
+ SET_FMAN_RX_10G_LIODN(1, 0, 15),
+};
+int fman1_liodn_tbl_sz = ARRAY_SIZE(fman1_liodn_tbl);
+
+#if (CONFIG_SYS_NUM_FMAN == 2)
+struct liodn_id_table fman2_liodn_tbl[] = {
+ SET_FMAN_RX_1G_LIODN(2, 0, 16),
+ SET_FMAN_RX_1G_LIODN(2, 1, 17),
+ SET_FMAN_RX_1G_LIODN(2, 2, 18),
+ SET_FMAN_RX_1G_LIODN(2, 3, 19),
+ SET_FMAN_RX_10G_LIODN(2, 0, 20),
+};
+int fman2_liodn_tbl_sz = ARRAY_SIZE(fman2_liodn_tbl);
+#endif
+#endif
+
+struct liodn_id_table sec_liodn_tbl[] = {
+ /*
+ * We assume currently that all JR are in the same partition
+ * and as such they need to represent the same LIODN due to
+ * a 4080 rev.2 h/w requirement that DECOs sharing from themselves
+ * or from another DECO have the two Non-SEQ LIODN values equal
+ */
+ SET_SEC_JR_LIODN_ENTRY(0, 146, 154), /* (0, 146, 154), */
+ SET_SEC_JR_LIODN_ENTRY(1, 146, 154), /* (1, 147, 155), */
+ SET_SEC_JR_LIODN_ENTRY(2, 146, 154), /* (2, 178, 186), */
+ SET_SEC_JR_LIODN_ENTRY(3, 146, 154), /* (3, 179, 187), */
+ SET_SEC_RTIC_LIODN_ENTRY(a, 144),
+ SET_SEC_RTIC_LIODN_ENTRY(b, 145),
+ SET_SEC_RTIC_LIODN_ENTRY(c, 176),
+ SET_SEC_RTIC_LIODN_ENTRY(d, 177),
+ SET_SEC_DECO_LIODN_ENTRY(0, 129, 161),
+ SET_SEC_DECO_LIODN_ENTRY(1, 130, 162),
+ SET_SEC_DECO_LIODN_ENTRY(2, 131, 163),
+ SET_SEC_DECO_LIODN_ENTRY(3, 132, 164),
+ SET_SEC_DECO_LIODN_ENTRY(4, 133, 165),
+};
+int sec_liodn_tbl_sz = ARRAY_SIZE(sec_liodn_tbl);
+
+struct liodn_id_table liodn_bases[] = {
+ [FSL_HW_PORTAL_SEC] = SET_LIODN_BASE_2(96, 106),
+#ifdef CONFIG_SYS_DPAA_FMAN
+ [FSL_HW_PORTAL_FMAN1] = SET_LIODN_BASE_1(32),
+#if (CONFIG_SYS_NUM_FMAN == 2)
+ [FSL_HW_PORTAL_FMAN2] = SET_LIODN_BASE_1(64),
+#endif
+#endif
+#ifdef CONFIG_SYS_DPAA_PME
+ [FSL_HW_PORTAL_PME] = SET_LIODN_BASE_2(116, 133),
+#endif
+};
diff --git a/arch/powerpc/cpu/mpc85xx/p4080_serdes.c b/arch/powerpc/cpu/mpc85xx/p4080_serdes.c
new file mode 100644
index 0000000..94ec445
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/p4080_serdes.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/fsl_serdes.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include "fsl_corenet_serdes.h"
+
+static u8 serdes_cfg_tbl[][SRDS_MAX_LANES] = {
+ [0x2] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1,
+ AURORA, AURORA, XAUI_FM2, XAUI_FM2, XAUI_FM2, XAUI_FM2,
+ XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1},
+ [0x5] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, XAUI_FM2, XAUI_FM2, XAUI_FM2, XAUI_FM2,
+ XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1},
+ [0x8] = {PCIE1, PCIE1, PCIE3, PCIE3, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, XAUI_FM2, XAUI_FM2, XAUI_FM2, XAUI_FM2,
+ XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1},
+ [0xd] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, SGMII_FM2_DTSEC3,
+ SGMII_FM2_DTSEC4, AURORA, AURORA, XAUI_FM2, XAUI_FM2, XAUI_FM2,
+ XAUI_FM2, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1},
+ [0xe] = {PCIE1, PCIE1, PCIE3, PCIE3, PCIE2, PCIE2, SGMII_FM2_DTSEC3,
+ SGMII_FM2_DTSEC4, AURORA, AURORA, XAUI_FM2, XAUI_FM2, XAUI_FM2,
+ XAUI_FM2, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1},
+ [0xf] = {PCIE1, PCIE1, PCIE1, PCIE1, SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4, AURORA, AURORA, XAUI_FM2,
+ XAUI_FM2, XAUI_FM2, XAUI_FM2, NONE, NONE, NONE, NONE},
+ [0x10] = {PCIE1, PCIE1, PCIE3, PCIE3, SGMII_FM2_DTSEC1,
+ SGMII_FM2_DTSEC2, SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4,
+ AURORA, AURORA, XAUI_FM2, XAUI_FM2, XAUI_FM2, XAUI_FM2,
+ NONE, NONE, NONE, NONE},
+ [0x13] = {SRIO2, SRIO2, SRIO2, SRIO2, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, XAUI_FM2, XAUI_FM2, XAUI_FM2, XAUI_FM2,
+ XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1},
+ [0x16] = {SRIO2, SRIO2, SRIO2, SRIO2, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4, SGMII_FM1_DTSEC1,
+ SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4},
+ [0x19] = {SRIO2, SRIO2, SRIO2, SRIO2, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, PCIE3, PCIE3, PCIE3, PCIE3, SGMII_FM1_DTSEC1,
+ SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4},
+ [0x1d] = {PCIE1, PCIE1, PCIE3, PCIE3, NONE, SRIO2, NONE, SRIO1,
+ AURORA, AURORA, XAUI_FM2, XAUI_FM2, XAUI_FM2, XAUI_FM2,
+ XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1},
+ [0x22] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, XAUI_FM2, XAUI_FM2, XAUI_FM2, XAUI_FM2,
+ XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1},
+ [0x25] = {PCIE1, PCIE1, PCIE3, PCIE3, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, XAUI_FM2, XAUI_FM2, XAUI_FM2, XAUI_FM2,
+ XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1},
+};
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8
+uint16_t srds_lpd_b[SRDS_MAX_BANK];
+#endif
+
+enum srds_prtcl serdes_get_prtcl(int cfg, int lane)
+{
+ if (!serdes_lane_enabled(lane))
+ return NONE;
+
+ return serdes_cfg_tbl[cfg][lane];
+}
+
+int is_serdes_prtcl_valid(u32 prtcl) {
+ int i;
+
+ if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl))
+ return 0;
+
+ for (i = 0; i < SRDS_MAX_LANES; i++) {
+ if (serdes_cfg_tbl[prtcl][i] != NONE)
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc85xx/p5020_ids.c b/arch/powerpc/cpu/mpc85xx/p5020_ids.c
new file mode 100644
index 0000000..ca05b9c
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/p5020_ids.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_portals.h>
+#include <asm/fsl_liodn.h>
+
+#ifdef CONFIG_SYS_DPAA_QBMAN
+struct qportal_info qp_info[CONFIG_SYS_QMAN_NUM_PORTALS] = {
+ /* dqrr liodn, frame data liodn, liodn off, sdest */
+ SET_QP_INFO(1, 2, 1, 0),
+ SET_QP_INFO(3, 4, 2, 1),
+ SET_QP_INFO(5, 6, 3, 0),
+ SET_QP_INFO(7, 8, 4, 1),
+ SET_QP_INFO(9, 10, 5, 0),
+ SET_QP_INFO(11, 12, 6, 1),
+ SET_QP_INFO(13, 14, 7, 0),
+ SET_QP_INFO(15, 16, 8, 1),
+ SET_QP_INFO(17, 18, 9, 0),
+ SET_QP_INFO(19, 20, 10, 1),
+};
+#endif
+
+struct srio_liodn_id_table srio_liodn_tbl[] = {
+ SET_SRIO_LIODN_2(1, 199, 200),
+ SET_SRIO_LIODN_2(2, 201, 202),
+};
+int srio_liodn_tbl_sz = ARRAY_SIZE(srio_liodn_tbl);
+
+struct liodn_id_table liodn_tbl[] = {
+#ifdef CONFIG_SYS_DPAA_QBMAN
+ SET_QMAN_LIODN(31),
+ SET_BMAN_LIODN(32),
+#endif
+
+ SET_SDHC_LIODN(1, 64),
+
+ SET_PME_LIODN(117),
+
+ SET_USB_LIODN(1, "fsl-usb2-mph", 125),
+ SET_USB_LIODN(2, "fsl-usb2-dr", 126),
+
+ SET_SATA_LIODN(1, 127),
+ SET_SATA_LIODN(2, 128),
+
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 1, 193),
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 2, 194),
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 3, 195),
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 4, 196),
+
+ SET_DMA_LIODN(1, 197),
+ SET_DMA_LIODN(2, 198),
+
+ SET_GUTS_LIODN("fsl,rapidio-delta", 199, rio1liodnr, 0),
+ SET_GUTS_LIODN(NULL, 200, rio2liodnr, 0),
+ SET_GUTS_LIODN(NULL, 201, rio1maintliodnr, 0),
+ SET_GUTS_LIODN(NULL, 202, rio2maintliodnr, 0),
+};
+int liodn_tbl_sz = ARRAY_SIZE(liodn_tbl);
+
+#ifdef CONFIG_SYS_DPAA_FMAN
+struct liodn_id_table fman1_liodn_tbl[] = {
+ SET_FMAN_RX_1G_LIODN(1, 0, 10),
+ SET_FMAN_RX_1G_LIODN(1, 1, 11),
+ SET_FMAN_RX_1G_LIODN(1, 2, 12),
+ SET_FMAN_RX_1G_LIODN(1, 3, 13),
+ SET_FMAN_RX_1G_LIODN(1, 4, 14),
+ SET_FMAN_RX_10G_LIODN(1, 0, 15),
+};
+int fman1_liodn_tbl_sz = ARRAY_SIZE(fman1_liodn_tbl);
+#endif
+
+struct liodn_id_table sec_liodn_tbl[] = {
+ SET_SEC_JR_LIODN_ENTRY(0, 129, 130),
+ SET_SEC_JR_LIODN_ENTRY(1, 131, 132),
+ SET_SEC_JR_LIODN_ENTRY(2, 133, 134),
+ SET_SEC_JR_LIODN_ENTRY(3, 135, 136),
+ SET_SEC_RTIC_LIODN_ENTRY(a, 154),
+ SET_SEC_RTIC_LIODN_ENTRY(b, 155),
+ SET_SEC_RTIC_LIODN_ENTRY(c, 156),
+ SET_SEC_RTIC_LIODN_ENTRY(d, 157),
+ SET_SEC_DECO_LIODN_ENTRY(0, 97, 98),
+ SET_SEC_DECO_LIODN_ENTRY(1, 99, 100),
+};
+int sec_liodn_tbl_sz = ARRAY_SIZE(sec_liodn_tbl);
+
+#ifdef CONFIG_SYS_FSL_RAID_ENGINE
+struct liodn_id_table raide_liodn_tbl[] = {
+ SET_RAID_ENGINE_JQ_LIODN_ENTRY(0, 0, 60),
+ SET_RAID_ENGINE_JQ_LIODN_ENTRY(0, 1, 61),
+ SET_RAID_ENGINE_JQ_LIODN_ENTRY(1, 0, 62),
+ SET_RAID_ENGINE_JQ_LIODN_ENTRY(1, 1, 63),
+};
+int raide_liodn_tbl_sz = ARRAY_SIZE(raide_liodn_tbl);
+#endif
+
+#ifdef CONFIG_SYS_DPAA_RMAN
+struct liodn_id_table rman_liodn_tbl[] = {
+ /* Set RMan block 0-3 liodn offset */
+ SET_RMAN_LIODN(0, 6),
+ SET_RMAN_LIODN(1, 7),
+ SET_RMAN_LIODN(2, 8),
+ SET_RMAN_LIODN(3, 9),
+};
+int rman_liodn_tbl_sz = ARRAY_SIZE(rman_liodn_tbl);
+#endif
+
+struct liodn_id_table liodn_bases[] = {
+ [FSL_HW_PORTAL_SEC] = SET_LIODN_BASE_2(64, 100),
+#ifdef CONFIG_SYS_DPAA_FMAN
+ [FSL_HW_PORTAL_FMAN1] = SET_LIODN_BASE_1(32),
+#endif
+#ifdef CONFIG_SYS_DPAA_PME
+ [FSL_HW_PORTAL_PME] = SET_LIODN_BASE_2(136, 172),
+#endif
+#ifdef CONFIG_SYS_FSL_RAID_ENGINE
+ [FSL_HW_PORTAL_RAID_ENGINE] = SET_LIODN_BASE_1(47),
+#endif
+#ifdef CONFIG_SYS_DPAA_RMAN
+ [FSL_HW_PORTAL_RMAN] = SET_LIODN_BASE_1(80),
+#endif
+};
diff --git a/arch/powerpc/cpu/mpc85xx/p5020_serdes.c b/arch/powerpc/cpu/mpc85xx/p5020_serdes.c
new file mode 100644
index 0000000..a36dcd5
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/p5020_serdes.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2009-2011 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_serdes.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include "fsl_corenet_serdes.h"
+
+static u8 serdes_cfg_tbl[][SRDS_MAX_LANES] = {
+ [0x2] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2,
+ PCIE4, AURORA, PCIE3, SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3,
+ SGMII_FM1_DTSEC4, NONE, NONE, SATA1, SATA2, },
+ [0x4] = {SRIO2, SRIO2, SRIO2, SRIO2, SRIO1, SRIO1, SRIO1, SRIO1,
+ PCIE2, AURORA, PCIE3, SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3,
+ SGMII_FM1_DTSEC4, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1, },
+ [0xb] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO2, SRIO2, SRIO1, SRIO1,
+ PCIE2, AURORA, PCIE3, SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3,
+ SGMII_FM1_DTSEC4, NONE, NONE, SATA1, SATA2, },
+ [0x10] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1,
+ AURORA, AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1,
+ NONE, NONE, SATA1, SATA2, },
+ [0x11] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, NONE, NONE, SATA1, SATA2, },
+ [0x13] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, XAUI_FM1, XAUI_FM1,
+ XAUI_FM1, XAUI_FM1, },
+ [0x14] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, PCIE3, PCIE3, PCIE3, PCIE3,
+ SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3,
+ SGMII_FM1_DTSEC4, },
+ [0x15] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1,
+ NONE, NONE, SATA1, SATA2, },
+ [0x16] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, SRIO1, SRIO1, SRIO1,
+ SRIO1, },
+ [0x17] = {SRIO2, SRIO2, SRIO2, SRIO2, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, NONE, NONE, SATA1, SATA2, },
+ [0x18] = {SRIO2, SRIO2, SRIO2, SRIO2, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, SGMII_FM1_DTSEC5, NONE,
+ NONE, NONE, },
+ [0x1b] = {SRIO2, SRIO2, SRIO2, SRIO2, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1,
+ NONE, NONE, SATA1, SATA2, },
+ [0x1d] = {SRIO2, SRIO2, SRIO2, SRIO2, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, PCIE3, PCIE3, PCIE3, PCIE3, NONE, NONE,
+ SATA1, SATA2, },
+ [0x20] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, XAUI_FM1, XAUI_FM1,
+ XAUI_FM1, XAUI_FM1, },
+ [0x21] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, PCIE3, PCIE3, PCIE3, PCIE3,
+ SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3,
+ SGMII_FM1_DTSEC4, },
+ [0x22] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1,
+ NONE, NONE, SATA1, SATA2, },
+ [0x23] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO2, SRIO2, SRIO1, SRIO1,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, NONE, NONE, SATA1, SATA2, },
+ [0x24] = {PCIE1, PCIE1, PCIE1, PCIE1, SRIO2, SRIO2, SRIO1, SRIO1,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, SGMII_FM1_DTSEC5, NONE,
+ NONE, NONE, },
+ [0x28] = {PCIE1, PCIE1, PCIE3, PCIE3, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, NONE, NONE, SATA1, SATA2, },
+ [0x29] = {PCIE1, PCIE1, PCIE3, PCIE3, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, SGMII_FM1_DTSEC5, NONE,
+ NONE, NONE, },
+ [0x2a] = {PCIE1, PCIE1, PCIE3, PCIE3, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, XAUI_FM1, XAUI_FM1,
+ XAUI_FM1, XAUI_FM1, },
+ [0x2b] = {PCIE1, PCIE1, PCIE3, PCIE3, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1,
+ NONE, NONE, SATA1, SATA2, },
+ [0x2f] = {PCIE1, PCIE1, PCIE3, PCIE3, SRIO2, SRIO2, SRIO1, SRIO1,
+ AURORA, AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1,
+ NONE, NONE, SATA1, SATA2, },
+ [0x31] = {PCIE1, PCIE1, PCIE3, PCIE3, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, SGMII_FM1_DTSEC5, NONE,
+ NONE, NONE, },
+ [0x33] = {PCIE1, PCIE1, PCIE3, PCIE3, SRIO1, SRIO1, SRIO1, SRIO1,
+ AURORA, AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1,
+ NONE, NONE, SATA1, SATA2, },
+ [0x34] = {PCIE1, PCIE1, PCIE1, PCIE1, SGMII_FM1_DTSEC1,
+ SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, AURORA,
+ AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1, NONE,
+ NONE, SATA1, SATA2, },
+ [0x35] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, AURORA, AURORA, XAUI_FM1,
+ XAUI_FM1, XAUI_FM1, XAUI_FM1, NONE, NONE, SATA1, SATA2, },
+ [0x36] = {PCIE1, PCIE1, PCIE3, PCIE3, SGMII_FM1_DTSEC1,
+ SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, AURORA,
+ AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1, NONE,
+ NONE, SATA1, SATA2, },
+ [0x37] = {PCIE1, PCIE1, PCIE3, PCIE3, PCIE2, PCIE2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, AURORA, AURORA, XAUI_FM1,
+ XAUI_FM1, XAUI_FM1, XAUI_FM1, NONE, NONE, SATA1, SATA2, },
+};
+
+enum srds_prtcl serdes_get_prtcl(int cfg, int lane)
+{
+ if (!serdes_lane_enabled(lane))
+ return NONE;
+
+ return serdes_cfg_tbl[cfg][lane];
+}
+
+int is_serdes_prtcl_valid(u32 prtcl) {
+ int i;
+
+ if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl))
+ return 0;
+
+ for (i = 0; i < SRDS_MAX_LANES; i++) {
+ if (serdes_cfg_tbl[prtcl][i] != NONE)
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc85xx/p5040_ids.c b/arch/powerpc/cpu/mpc85xx/p5040_ids.c
new file mode 100644
index 0000000..878ee3e
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/p5040_ids.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_portals.h>
+#include <asm/fsl_liodn.h>
+
+#ifdef CONFIG_SYS_DPAA_QBMAN
+struct qportal_info qp_info[CONFIG_SYS_QMAN_NUM_PORTALS] = {
+ /* dqrr liodn, frame data liodn, liodn off, sdest */
+ SET_QP_INFO(1, 2, 1, 0),
+ SET_QP_INFO(3, 4, 2, 1),
+ SET_QP_INFO(5, 6, 3, 2),
+ SET_QP_INFO(7, 8, 4, 3),
+ SET_QP_INFO(9, 10, 5, 0),
+ SET_QP_INFO(11, 12, 6, 1),
+ SET_QP_INFO(13, 14, 7, 2),
+ SET_QP_INFO(15, 16, 8, 3),
+ SET_QP_INFO(17, 18, 9, 0), /* for now, set sdest to 0 */
+ SET_QP_INFO(19, 20, 10, 0), /* for now, set sdest to 0 */
+};
+#endif
+
+struct liodn_id_table liodn_tbl[] = {
+#ifdef CONFIG_SYS_DPAA_QBMAN
+ SET_QMAN_LIODN(31),
+ SET_BMAN_LIODN(32),
+#endif
+
+ SET_SDHC_LIODN(1, 64),
+
+ SET_USB_LIODN(1, "fsl-usb2-mph", 93),
+ SET_USB_LIODN(2, "fsl-usb2-dr", 94),
+
+ SET_SATA_LIODN(1, 95),
+ SET_SATA_LIODN(2, 96),
+
+ SET_PCI_LIODN_BASE(CONFIG_SYS_FSL_PCIE_COMPAT, 1, 195),
+ SET_PCI_LIODN_BASE(CONFIG_SYS_FSL_PCIE_COMPAT, 2, 196),
+ SET_PCI_LIODN_BASE(CONFIG_SYS_FSL_PCIE_COMPAT, 3, 197),
+
+ SET_DMA_LIODN(1, 193),
+ SET_DMA_LIODN(2, 194),
+};
+int liodn_tbl_sz = ARRAY_SIZE(liodn_tbl);
+
+#ifdef CONFIG_SYS_DPAA_FMAN
+struct liodn_id_table fman1_liodn_tbl[] = {
+ SET_FMAN_RX_1G_LIODN(1, 0, 6),
+ SET_FMAN_RX_1G_LIODN(1, 1, 7),
+ SET_FMAN_RX_1G_LIODN(1, 2, 8),
+ SET_FMAN_RX_1G_LIODN(1, 3, 9),
+ SET_FMAN_RX_1G_LIODN(1, 4, 10),
+ SET_FMAN_RX_10G_LIODN(1, 0, 11),
+};
+int fman1_liodn_tbl_sz = ARRAY_SIZE(fman1_liodn_tbl);
+
+#if (CONFIG_SYS_NUM_FMAN == 2)
+struct liodn_id_table fman2_liodn_tbl[] = {
+ SET_FMAN_RX_1G_LIODN(2, 0, 12),
+ SET_FMAN_RX_1G_LIODN(2, 1, 13),
+ SET_FMAN_RX_1G_LIODN(2, 2, 14),
+ SET_FMAN_RX_1G_LIODN(2, 3, 15),
+ SET_FMAN_RX_1G_LIODN(2, 4, 16),
+ SET_FMAN_RX_10G_LIODN(2, 0, 17),
+};
+int fman2_liodn_tbl_sz = ARRAY_SIZE(fman2_liodn_tbl);
+#endif
+#endif
+
+struct liodn_id_table sec_liodn_tbl[] = {
+ SET_SEC_JR_LIODN_ENTRY(0, 129, 130),
+ SET_SEC_JR_LIODN_ENTRY(1, 131, 132),
+ SET_SEC_JR_LIODN_ENTRY(2, 133, 134),
+ SET_SEC_JR_LIODN_ENTRY(3, 135, 136),
+ SET_SEC_RTIC_LIODN_ENTRY(a, 89),
+ SET_SEC_RTIC_LIODN_ENTRY(b, 90),
+ SET_SEC_RTIC_LIODN_ENTRY(c, 91),
+ SET_SEC_RTIC_LIODN_ENTRY(d, 92),
+ SET_SEC_DECO_LIODN_ENTRY(0, 139, 140),
+ SET_SEC_DECO_LIODN_ENTRY(1, 141, 142),
+ SET_SEC_DECO_LIODN_ENTRY(2, 143, 144),
+ SET_SEC_DECO_LIODN_ENTRY(3, 145, 146),
+};
+int sec_liodn_tbl_sz = ARRAY_SIZE(sec_liodn_tbl);
+
+#ifdef CONFIG_SYS_FSL_RAID_ENGINE
+struct liodn_id_table raide_liodn_tbl[] = {
+ SET_RAID_ENGINE_JQ_LIODN_ENTRY(0, 0, 60),
+ SET_RAID_ENGINE_JQ_LIODN_ENTRY(0, 1, 61),
+ SET_RAID_ENGINE_JQ_LIODN_ENTRY(1, 0, 62),
+ SET_RAID_ENGINE_JQ_LIODN_ENTRY(1, 1, 63),
+};
+int raide_liodn_tbl_sz = ARRAY_SIZE(raide_liodn_tbl);
+#endif
+
+struct liodn_id_table liodn_bases[] = {
+ [FSL_HW_PORTAL_SEC] = SET_LIODN_BASE_2(64, 101),
+#ifdef CONFIG_SYS_DPAA_FMAN
+ [FSL_HW_PORTAL_FMAN1] = SET_LIODN_BASE_1(32),
+#endif
+#if (CONFIG_SYS_NUM_FMAN == 2)
+ [FSL_HW_PORTAL_FMAN2] = SET_LIODN_BASE_1(160),
+#endif
+#ifdef CONFIG_SYS_FSL_RAID_ENGINE
+ [FSL_HW_PORTAL_RAID_ENGINE] = SET_LIODN_BASE_1(49),
+#endif
+};
diff --git a/arch/powerpc/cpu/mpc85xx/p5040_serdes.c b/arch/powerpc/cpu/mpc85xx/p5040_serdes.c
new file mode 100644
index 0000000..d646e85
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/p5040_serdes.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2009-2011 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_serdes.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include "fsl_corenet_serdes.h"
+
+/*
+ * Note: For P5040, the fourth SerDes bank (with two lanes) is on SerDes2, but
+ * U-boot only supports one SerDes controller. Therefore, we ignore bank 4 in
+ * this table. This works because most of the SerDes code is for errata
+ * work-arounds, and there are no P5040 errata that effect bank 4.
+ */
+
+static u8 serdes_cfg_tbl[][SRDS_MAX_LANES] = {
+ [0x00] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4, SGMII_FM1_DTSEC1,
+ SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4,
+ XAUI_FM2, XAUI_FM2, XAUI_FM2, XAUI_FM2, /* SATA1, SATA2, */ },
+ [0x01] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2,
+ SGMII_FM1_DTSEC3, SGMII_FM2_DTSEC4, XAUI_FM1, XAUI_FM1,
+ XAUI_FM1, XAUI_FM1, XAUI_FM2, XAUI_FM2, XAUI_FM2,
+ XAUI_FM2, /* SATA1, SATA2 */ },
+ [0x02] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, SGMII_FM1_DTSEC3,
+ SGMII_FM1_DTSEC4, SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4,
+ XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM2, XAUI_FM2,
+ XAUI_FM2, XAUI_FM2, /* SATA1, SATA2 */ },
+ [0x03] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, SGMII_FM2_DTSEC1,
+ SGMII_FM2_DTSEC2, SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4,
+ SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3,
+ SGMII_FM1_DTSEC4, XAUI_FM2, XAUI_FM2, XAUI_FM2, XAUI_FM2,
+ /* SATA1, SATA2 */ },
+ [0x04] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE3, SGMII_FM2_DTSEC1,
+ SGMII_FM2_DTSEC2, SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4,
+ SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3,
+ SGMII_FM1_DTSEC4, XAUI_FM2, XAUI_FM2, XAUI_FM2, XAUI_FM2,
+ /* SATA1, SATA2 */ },
+ [0x05] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE3, SGMII_FM1_DTSEC3,
+ SGMII_FM1_DTSEC4, SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4,
+ XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM2, XAUI_FM2,
+ XAUI_FM2, XAUI_FM2, /* SATA1, SATA2 */ },
+ [0x06] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4, SGMII_FM1_DTSEC1,
+ SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4,
+ XAUI_FM2, XAUI_FM2, XAUI_FM2, XAUI_FM2, /* SATA1, SATA2 */ },
+ [0x07] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1,
+ SGMII_FM1_DTSEC3, SGMII_FM2_DTSEC4, XAUI_FM1, XAUI_FM1,
+ XAUI_FM1, XAUI_FM1, XAUI_FM2, XAUI_FM2, XAUI_FM2,
+ XAUI_FM2, /* SATA1, SATA2 */ },
+ [0x11] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, NONE, NONE, SATA1, SATA2,
+ /* NONE, NONE */ },
+ [0x15] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1,
+ NONE, NONE, SATA1, SATA2, /* NONE, NONE */ },
+ [0x2a] = {PCIE1, PCIE1, PCIE3, PCIE3, PCIE2, PCIE2, PCIE2, PCIE2,
+ AURORA, AURORA, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, XAUI_FM2, XAUI_FM2,
+ XAUI_FM2, XAUI_FM2, /* NONE, NONE */ },
+ [0x34] = {PCIE1, PCIE1, PCIE1, PCIE1, SGMII_FM1_DTSEC1,
+ SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, AURORA,
+ AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1, NONE,
+ NONE, SATA1, SATA2, /* NONE, NONE */ },
+ [0x35] = {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, AURORA, AURORA, XAUI_FM1,
+ XAUI_FM1, XAUI_FM1, XAUI_FM1, NONE, NONE, SATA1, SATA2,
+ /* NONE, NONE */ },
+ [0x36] = {PCIE1, PCIE1, PCIE3, PCIE3, SGMII_FM1_DTSEC1,
+ SGMII_FM1_DTSEC2, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, AURORA,
+ AURORA, XAUI_FM1, XAUI_FM1, XAUI_FM1, XAUI_FM1, NONE,
+ NONE, SATA1, SATA2, /* NONE, NONE */ },
+};
+
+enum srds_prtcl serdes_get_prtcl(int cfg, int lane)
+{
+ if (!serdes_lane_enabled(lane))
+ return NONE;
+
+ return serdes_cfg_tbl[cfg][lane];
+}
+
+int is_serdes_prtcl_valid(u32 prtcl)
+{
+ int i;
+
+ if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl))
+ return 0;
+
+ for (i = 0; i < SRDS_MAX_LANES; i++) {
+ if (serdes_cfg_tbl[prtcl][i] != NONE)
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc85xx/pci.c b/arch/powerpc/cpu/mpc85xx/pci.c
new file mode 100644
index 0000000..75d2716
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/pci.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2004 Freescale Semiconductor.
+ * Copyright (C) 2003 Motorola Inc.
+ * Xianghua Xiao (x.xiao@motorola.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * PCI Configuration space access support for MPC85xx PCI Bridge
+ */
+#include <common.h>
+#include <asm/cpm_85xx.h>
+#include <pci.h>
+
+#if !defined(CONFIG_FSL_PCI_INIT)
+
+#ifndef CONFIG_SYS_PCI1_MEM_BUS
+#define CONFIG_SYS_PCI1_MEM_BUS CONFIG_SYS_PCI1_MEM_BASE
+#endif
+
+#ifndef CONFIG_SYS_PCI1_IO_BUS
+#define CONFIG_SYS_PCI1_IO_BUS CONFIG_SYS_PCI1_IO_BASE
+#endif
+
+#ifndef CONFIG_SYS_PCI2_MEM_BUS
+#define CONFIG_SYS_PCI2_MEM_BUS CONFIG_SYS_PCI2_MEM_BASE
+#endif
+
+#ifndef CONFIG_SYS_PCI2_IO_BUS
+#define CONFIG_SYS_PCI2_IO_BUS CONFIG_SYS_PCI2_IO_BASE
+#endif
+
+static struct pci_controller *pci_hose;
+
+void
+pci_mpc85xx_init(struct pci_controller *board_hose)
+{
+ u16 reg16;
+ u32 dev;
+
+ volatile ccsr_pcix_t *pcix = (void *)(CONFIG_SYS_MPC85xx_PCIX_ADDR);
+#ifdef CONFIG_MPC85XX_PCI2
+ volatile ccsr_pcix_t *pcix2 = (void *)(CONFIG_SYS_MPC85xx_PCIX2_ADDR);
+#endif
+ volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ struct pci_controller * hose;
+
+ pci_hose = board_hose;
+
+ hose = &pci_hose[0];
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ pci_setup_indirect(hose,
+ (CONFIG_SYS_IMMR+0x8000),
+ (CONFIG_SYS_IMMR+0x8004));
+
+ /*
+ * Hose scan.
+ */
+ dev = PCI_BDF(hose->first_busno, 0, 0);
+ pci_hose_read_config_word (hose, dev, PCI_COMMAND, &reg16);
+ reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+ pci_hose_write_config_word(hose, dev, PCI_COMMAND, reg16);
+
+ /*
+ * Clear non-reserved bits in status register.
+ */
+ pci_hose_write_config_word(hose, dev, PCI_STATUS, 0xffff);
+
+ if (!(gur->pordevsr & MPC85xx_PORDEVSR_PCI1)) {
+ /* PCI-X init */
+ if (CONFIG_SYS_CLK_FREQ < 66000000)
+ printf("PCI-X will only work at 66 MHz\n");
+
+ reg16 = PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ
+ | PCI_X_CMD_ERO | PCI_X_CMD_DPERR_E;
+ pci_hose_write_config_word(hose, dev, PCIX_COMMAND, reg16);
+ }
+
+ pcix->potar1 = (CONFIG_SYS_PCI1_MEM_BUS >> 12) & 0x000fffff;
+ pcix->potear1 = 0x00000000;
+ pcix->powbar1 = (CONFIG_SYS_PCI1_MEM_PHYS >> 12) & 0x000fffff;
+ pcix->powbear1 = 0x00000000;
+ pcix->powar1 = (POWAR_EN | POWAR_MEM_READ |
+ POWAR_MEM_WRITE | (__ilog2(CONFIG_SYS_PCI1_MEM_SIZE) - 1));
+
+ pcix->potar2 = (CONFIG_SYS_PCI1_IO_BUS >> 12) & 0x000fffff;
+ pcix->potear2 = 0x00000000;
+ pcix->powbar2 = (CONFIG_SYS_PCI1_IO_PHYS >> 12) & 0x000fffff;
+ pcix->powbear2 = 0x00000000;
+ pcix->powar2 = (POWAR_EN | POWAR_IO_READ |
+ POWAR_IO_WRITE | (__ilog2(CONFIG_SYS_PCI1_IO_SIZE) - 1));
+
+ pcix->pitar1 = 0x00000000;
+ pcix->piwbar1 = 0x00000000;
+ pcix->piwar1 = (PIWAR_EN | PIWAR_PF | PIWAR_LOCAL |
+ PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP | PIWAR_MEM_2G);
+
+ pcix->powar3 = 0;
+ pcix->powar4 = 0;
+ pcix->piwar2 = 0;
+ pcix->piwar3 = 0;
+
+ pci_set_region(hose->regions + 0,
+ CONFIG_SYS_PCI1_MEM_BUS,
+ CONFIG_SYS_PCI1_MEM_PHYS,
+ CONFIG_SYS_PCI1_MEM_SIZE,
+ PCI_REGION_MEM);
+
+ pci_set_region(hose->regions + 1,
+ CONFIG_SYS_PCI1_IO_BUS,
+ CONFIG_SYS_PCI1_IO_PHYS,
+ CONFIG_SYS_PCI1_IO_SIZE,
+ PCI_REGION_IO);
+
+ hose->region_count = 2;
+
+ pci_register_hose(hose);
+
+#if defined(CONFIG_MPC8555CDS) || defined(CONFIG_MPC8541CDS)
+ /*
+ * This is a SW workaround for an apparent HW problem
+ * in the PCI controller on the MPC85555/41 CDS boards.
+ * The first config cycle must be to a valid, known
+ * device on the PCI bus in order to trick the PCI
+ * controller state machine into a known valid state.
+ * Without this, the first config cycle has the chance
+ * of hanging the controller permanently, just leaving
+ * it in a semi-working state, or leaving it working.
+ *
+ * Pick on the Tundra, Device 17, to get it right.
+ */
+ {
+ u8 header_type;
+
+ pci_hose_read_config_byte(hose,
+ PCI_BDF(0,BRIDGE_ID,0),
+ PCI_HEADER_TYPE,
+ &header_type);
+ }
+#endif
+
+ hose->last_busno = pci_hose_scan(hose);
+
+#ifdef CONFIG_MPC85XX_PCI2
+ hose = &pci_hose[1];
+
+ hose->first_busno = pci_hose[0].last_busno + 1;
+ hose->last_busno = 0xff;
+
+ pci_setup_indirect(hose,
+ (CONFIG_SYS_IMMR+0x9000),
+ (CONFIG_SYS_IMMR+0x9004));
+
+ dev = PCI_BDF(hose->first_busno, 0, 0);
+ pci_hose_read_config_word (hose, dev, PCI_COMMAND, &reg16);
+ reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+ pci_hose_write_config_word(hose, dev, PCI_COMMAND, reg16);
+
+ /*
+ * Clear non-reserved bits in status register.
+ */
+ pci_hose_write_config_word(hose, dev, PCI_STATUS, 0xffff);
+
+ pcix2->potar1 = (CONFIG_SYS_PCI2_MEM_BUS >> 12) & 0x000fffff;
+ pcix2->potear1 = 0x00000000;
+ pcix2->powbar1 = (CONFIG_SYS_PCI2_MEM_PHYS >> 12) & 0x000fffff;
+ pcix2->powbear1 = 0x00000000;
+ pcix2->powar1 = (POWAR_EN | POWAR_MEM_READ |
+ POWAR_MEM_WRITE | (__ilog2(CONFIG_SYS_PCI2_MEM_SIZE) - 1));
+
+ pcix2->potar2 = (CONFIG_SYS_PCI2_IO_BUS >> 12) & 0x000fffff;
+ pcix2->potear2 = 0x00000000;
+ pcix2->powbar2 = (CONFIG_SYS_PCI2_IO_PHYS >> 12) & 0x000fffff;
+ pcix2->powbear2 = 0x00000000;
+ pcix2->powar2 = (POWAR_EN | POWAR_IO_READ |
+ POWAR_IO_WRITE | (__ilog2(CONFIG_SYS_PCI2_IO_SIZE) - 1));
+
+ pcix2->pitar1 = 0x00000000;
+ pcix2->piwbar1 = 0x00000000;
+ pcix2->piwar1 = (PIWAR_EN | PIWAR_PF | PIWAR_LOCAL |
+ PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP | PIWAR_MEM_2G);
+
+ pcix2->powar3 = 0;
+ pcix2->powar4 = 0;
+ pcix2->piwar2 = 0;
+ pcix2->piwar3 = 0;
+
+ pci_set_region(hose->regions + 0,
+ CONFIG_SYS_PCI2_MEM_BUS,
+ CONFIG_SYS_PCI2_MEM_PHYS,
+ CONFIG_SYS_PCI2_MEM_SIZE,
+ PCI_REGION_MEM);
+
+ pci_set_region(hose->regions + 1,
+ CONFIG_SYS_PCI2_IO_BUS,
+ CONFIG_SYS_PCI2_IO_PHYS,
+ CONFIG_SYS_PCI2_IO_SIZE,
+ PCI_REGION_IO);
+
+ hose->region_count = 2;
+
+ /*
+ * Hose scan.
+ */
+ pci_register_hose(hose);
+
+ hose->last_busno = pci_hose_scan(hose);
+#endif
+}
+#endif /* !CONFIG_FSL_PCI_INIT */
diff --git a/arch/powerpc/cpu/mpc85xx/portals.c b/arch/powerpc/cpu/mpc85xx/portals.c
new file mode 100644
index 0000000..672edde
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/portals.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+
+#include <asm/processor.h>
+#include <asm/io.h>
+
+#include <asm/fsl_portals.h>
+#include <asm/fsl_liodn.h>
+
+void setup_portals(void)
+{
+ ccsr_qman_t *qman = (void *)CONFIG_SYS_FSL_QMAN_ADDR;
+#ifdef CONFIG_FSL_CORENET
+ int i;
+
+ for (i = 0; i < CONFIG_SYS_QMAN_NUM_PORTALS; i++) {
+ u8 sdest = qp_info[i].sdest;
+ u16 fliodn = qp_info[i].fliodn;
+ u16 dliodn = qp_info[i].dliodn;
+ u16 liodn_off = qp_info[i].liodn_offset;
+
+ out_be32(&qman->qcsp[i].qcsp_lio_cfg, (liodn_off << 16) |
+ dliodn);
+ /* set frame liodn */
+ out_be32(&qman->qcsp[i].qcsp_io_cfg, (sdest << 16) | fliodn);
+ }
+#endif
+
+ /* Set the Qman initiator BAR to match the LAW (for DQRR stashing) */
+#ifdef CONFIG_PHYS_64BIT
+ out_be32(&qman->qcsp_bare, (u32)(CONFIG_SYS_QMAN_MEM_PHYS >> 32));
+#endif
+ out_be32(&qman->qcsp_bar, (u32)CONFIG_SYS_QMAN_MEM_PHYS);
+}
+
+/* Update portal containter to match LAW setup of portal in phy map */
+void fdt_portal(void *blob, const char *compat, const char *container,
+ u64 addr, u32 size)
+{
+ int off;
+
+ off = fdt_node_offset_by_compatible(blob, -1, compat);
+ if (off < 0)
+ return ;
+
+ off = fdt_parent_offset(blob, off);
+ /* if non-zero assume we have a container */
+ if (off > 0) {
+ char buf[60];
+ const char *p, *name;
+ u32 *range;
+ int len;
+
+ /* fixup ranges */
+ range = fdt_getprop_w(blob, off, "ranges", &len);
+ if (range == NULL) {
+ printf("ERROR: container for %s has no ranges", compat);
+ return ;
+ }
+
+ range[0] = 0;
+ if (len == 16) {
+ range[1] = addr >> 32;
+ range[2] = addr & 0xffffffff;
+ range[3] = size;
+ } else {
+ range[1] = addr & 0xffffffff;
+ range[2] = size;
+ }
+ fdt_setprop_inplace(blob, off, "ranges", range, len);
+
+ /* fixup the name */
+ name = fdt_get_name(blob, off, &len);
+ p = memchr(name, '@', len);
+
+ if (p)
+ len = p - name;
+
+ /* if we are given a container name check it
+ * against what we found, if it doesnt match exit out */
+ if (container && (memcmp(container, name, len))) {
+ printf("WARNING: container names didn't match %s %s\n",
+ container, name);
+ return ;
+ }
+
+ memcpy(&buf, name, len);
+ len += sprintf(&buf[len], "@%llx", addr);
+ fdt_set_name(blob, off, buf);
+ return ;
+ }
+
+ printf("ERROR: %s isn't in a container. Not supported\n", compat);
+}
+
+static int fdt_qportal(void *blob, int off, int id, char *name,
+ enum fsl_dpaa_dev dev, int create)
+{
+ int childoff, dev_off, ret = 0;
+ uint32_t dev_handle;
+#ifdef CONFIG_FSL_CORENET
+ int num;
+ u32 liodns[2];
+#endif
+
+ childoff = fdt_subnode_offset(blob, off, name);
+ if (create) {
+ char handle[64], *p;
+
+ strncpy(handle, name, sizeof(handle));
+ p = strchr(handle, '@');
+ if (!strncmp(name, "fman", 4)) {
+ *p = *(p + 1);
+ p++;
+ }
+ *p = '\0';
+
+ dev_off = fdt_path_offset(blob, handle);
+ /* skip this node if alias is not found */
+ if (dev_off == -FDT_ERR_BADPATH)
+ return 0;
+ if (dev_off < 0)
+ return dev_off;
+
+ if (childoff <= 0)
+ childoff = fdt_add_subnode(blob, off, name);
+
+ /* need to update the dev_off after adding a subnode */
+ dev_off = fdt_path_offset(blob, handle);
+ if (dev_off < 0)
+ return dev_off;
+
+ if (childoff > 0) {
+ dev_handle = fdt_get_phandle(blob, dev_off);
+ if (dev_handle <= 0) {
+ dev_handle = fdt_alloc_phandle(blob);
+ ret = fdt_set_phandle(blob, dev_off,
+ dev_handle);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = fdt_setprop(blob, childoff, "dev-handle",
+ &dev_handle, sizeof(dev_handle));
+ if (ret < 0)
+ return ret;
+
+#ifdef CONFIG_FSL_CORENET
+ num = get_dpaa_liodn(dev, &liodns[0], id);
+ ret = fdt_setprop(blob, childoff, "fsl,liodn",
+ &liodns[0], sizeof(u32) * num);
+ if (!strncmp(name, "pme", 3)) {
+ u32 pme_rev1, pme_rev2;
+ ccsr_pme_t *pme_regs =
+ (void *)CONFIG_SYS_FSL_CORENET_PME_ADDR;
+
+ pme_rev1 = in_be32(&pme_regs->pm_ip_rev_1);
+ pme_rev2 = in_be32(&pme_regs->pm_ip_rev_2);
+ ret = fdt_setprop(blob, childoff,
+ "fsl,pme-rev1", &pme_rev1, sizeof(u32));
+ if (ret < 0)
+ return ret;
+ ret = fdt_setprop(blob, childoff,
+ "fsl,pme-rev2", &pme_rev2, sizeof(u32));
+ }
+#endif
+ } else {
+ return childoff;
+ }
+ } else {
+ if (childoff > 0)
+ ret = fdt_del_node(blob, childoff);
+ }
+
+ return ret;
+}
+
+void fdt_fixup_qportals(void *blob)
+{
+ int off, err;
+ unsigned int maj, min;
+ unsigned int ip_cfg;
+ ccsr_qman_t *qman = (void *)CONFIG_SYS_FSL_QMAN_ADDR;
+ u32 rev_1 = in_be32(&qman->ip_rev_1);
+ u32 rev_2 = in_be32(&qman->ip_rev_2);
+ char compat[64];
+ int compat_len;
+
+ maj = (rev_1 >> 8) & 0xff;
+ min = rev_1 & 0xff;
+ ip_cfg = rev_2 & 0xff;
+
+ compat_len = sprintf(compat, "fsl,qman-portal-%u.%u.%u",
+ maj, min, ip_cfg) + 1;
+ compat_len += sprintf(compat + compat_len, "fsl,qman-portal") + 1;
+
+ off = fdt_node_offset_by_compatible(blob, -1, "fsl,qman-portal");
+ while (off != -FDT_ERR_NOTFOUND) {
+#ifdef CONFIG_FSL_CORENET
+ u32 liodns[2];
+#endif
+ const int *ci = fdt_getprop(blob, off, "cell-index", NULL);
+ int i = *ci;
+#ifdef CONFIG_SYS_DPAA_FMAN
+ int j;
+#endif
+
+ err = fdt_setprop(blob, off, "compatible", compat, compat_len);
+ if (err < 0)
+ goto err;
+
+#ifdef CONFIG_FSL_CORENET
+ liodns[0] = qp_info[i].dliodn;
+ liodns[1] = qp_info[i].fliodn;
+
+ err = fdt_setprop(blob, off, "fsl,liodn",
+ &liodns, sizeof(u32) * 2);
+ if (err < 0)
+ goto err;
+#endif
+
+ i++;
+
+ err = fdt_qportal(blob, off, i, "crypto@0", FSL_HW_PORTAL_SEC,
+ IS_E_PROCESSOR(get_svr()));
+ if (err < 0)
+ goto err;
+
+#ifdef CONFIG_FSL_CORENET
+#ifdef CONFIG_SYS_DPAA_PME
+ err = fdt_qportal(blob, off, i, "pme@0", FSL_HW_PORTAL_PME, 1);
+ if (err < 0)
+ goto err;
+#else
+ fdt_qportal(blob, off, i, "pme@0", FSL_HW_PORTAL_PME, 0);
+#endif
+#endif
+
+#ifdef CONFIG_SYS_DPAA_FMAN
+ for (j = 0; j < CONFIG_SYS_NUM_FMAN; j++) {
+ char name[] = "fman@0";
+
+ name[sizeof(name) - 2] = '0' + j;
+ err = fdt_qportal(blob, off, i, name,
+ FSL_HW_PORTAL_FMAN1 + j, 1);
+ if (err < 0)
+ goto err;
+ }
+#endif
+#ifdef CONFIG_SYS_DPAA_RMAN
+ err = fdt_qportal(blob, off, i, "rman@0",
+ FSL_HW_PORTAL_RMAN, 1);
+ if (err < 0)
+ goto err;
+#endif
+
+err:
+ if (err < 0) {
+ printf("ERROR: unable to create props for %s: %s\n",
+ fdt_get_name(blob, off, NULL), fdt_strerror(err));
+ return;
+ }
+
+ off = fdt_node_offset_by_compatible(blob, off, "fsl,qman-portal");
+ }
+}
+
+void fdt_fixup_bportals(void *blob)
+{
+ int off, err;
+ unsigned int maj, min;
+ unsigned int ip_cfg;
+ ccsr_bman_t *bman = (void *)CONFIG_SYS_FSL_BMAN_ADDR;
+ u32 rev_1 = in_be32(&bman->ip_rev_1);
+ u32 rev_2 = in_be32(&bman->ip_rev_2);
+ char compat[64];
+ int compat_len;
+
+ maj = (rev_1 >> 8) & 0xff;
+ min = rev_1 & 0xff;
+
+ ip_cfg = rev_2 & 0xff;
+
+ compat_len = sprintf(compat, "fsl,bman-portal-%u.%u.%u",
+ maj, min, ip_cfg) + 1;
+ compat_len += sprintf(compat + compat_len, "fsl,bman-portal") + 1;
+
+ off = fdt_node_offset_by_compatible(blob, -1, "fsl,bman-portal");
+ while (off != -FDT_ERR_NOTFOUND) {
+ err = fdt_setprop(blob, off, "compatible", compat, compat_len);
+ if (err < 0) {
+ printf("ERROR: unable to create props for %s: %s\n",
+ fdt_get_name(blob, off, NULL),
+ fdt_strerror(err));
+ return;
+ }
+
+ off = fdt_node_offset_by_compatible(blob, off, "fsl,bman-portal");
+ }
+
+}
diff --git a/arch/powerpc/cpu/mpc85xx/qe_io.c b/arch/powerpc/cpu/mpc85xx/qe_io.c
new file mode 100644
index 0000000..72a29b7
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/qe_io.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2006 Freescale Semiconductor, Inc.
+ *
+ * Dave Liu <daveliu@freescale.com>
+ * based on source code of Shlomi Gridish
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "common.h"
+#include "asm/errno.h"
+#include "asm/io.h"
+#include "asm/immap_85xx.h"
+
+#if defined(CONFIG_QE)
+#define NUM_OF_PINS 32
+void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign)
+{
+ u32 pin_2bit_mask;
+ u32 pin_2bit_dir;
+ u32 pin_2bit_assign;
+ u32 pin_1bit_mask;
+ u32 tmp_val;
+ volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ volatile par_io_t *par_io = (volatile par_io_t *)
+ &(gur->qe_par_io);
+
+ /* Caculate pin location and 2bit mask and dir */
+ pin_2bit_mask = (u32)(0x3 << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2));
+ pin_2bit_dir = (u32)(dir << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2));
+
+ /* Setup the direction */
+ tmp_val = (pin > (NUM_OF_PINS/2) - 1) ? \
+ in_be32(&par_io[port].cpdir2) :
+ in_be32(&par_io[port].cpdir1);
+
+ if (pin > (NUM_OF_PINS/2) -1) {
+ out_be32(&par_io[port].cpdir2, ~pin_2bit_mask & tmp_val);
+ out_be32(&par_io[port].cpdir2, pin_2bit_dir | tmp_val);
+ } else {
+ out_be32(&par_io[port].cpdir1, ~pin_2bit_mask & tmp_val);
+ out_be32(&par_io[port].cpdir1, pin_2bit_dir | tmp_val);
+ }
+
+ /* Calculate pin location for 1bit mask */
+ pin_1bit_mask = (u32)(1 << (NUM_OF_PINS - (pin+1)));
+
+ /* Setup the open drain */
+ tmp_val = in_be32(&par_io[port].cpodr);
+ if (open_drain)
+ out_be32(&par_io[port].cpodr, pin_1bit_mask | tmp_val);
+ else
+ out_be32(&par_io[port].cpodr, ~pin_1bit_mask & tmp_val);
+
+ /* Setup the assignment */
+ tmp_val = (pin > (NUM_OF_PINS/2) - 1) ?
+ in_be32(&par_io[port].cppar2):
+ in_be32(&par_io[port].cppar1);
+ pin_2bit_assign = (u32)(assign
+ << (NUM_OF_PINS - (pin%(NUM_OF_PINS/2)+1)*2));
+
+ /* Clear and set 2 bits mask */
+ if (pin > (NUM_OF_PINS/2) - 1) {
+ out_be32(&par_io[port].cppar2, ~pin_2bit_mask & tmp_val);
+ out_be32(&par_io[port].cppar2, pin_2bit_assign | tmp_val);
+ } else {
+ out_be32(&par_io[port].cppar1, ~pin_2bit_mask & tmp_val);
+ out_be32(&par_io[port].cppar1, pin_2bit_assign | tmp_val);
+ }
+}
+
+#endif /* CONFIG_QE */
diff --git a/arch/powerpc/cpu/mpc85xx/release.S b/arch/powerpc/cpu/mpc85xx/release.S
new file mode 100644
index 0000000..a4a21b0
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/release.S
@@ -0,0 +1,493 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor, Inc.
+ * Kumar Gala <kumar.gala@freescale.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <mpc85xx.h>
+#include <version.h>
+
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+/* To boot secondary cpus, we need a place for them to start up.
+ * Normally, they start at 0xfffffffc, but that's usually the
+ * firmware, and we don't want to have to run the firmware again.
+ * Instead, the primary cpu will set the BPTR to point here to
+ * this page. We then set up the core, and head to
+ * start_secondary. Note that this means that the code below
+ * must never exceed 1023 instructions (the branch at the end
+ * would then be the 1024th).
+ */
+ .globl __secondary_start_page
+ .align 12
+__secondary_start_page:
+/* First do some preliminary setup */
+ lis r3, HID0_EMCP@h /* enable machine check */
+#ifndef CONFIG_E500MC
+ ori r3,r3,HID0_TBEN@l /* enable Timebase */
+#endif
+#ifdef CONFIG_PHYS_64BIT
+ ori r3,r3,HID0_ENMAS7@l /* enable MAS7 updates */
+#endif
+ mtspr SPRN_HID0,r3
+
+#ifndef CONFIG_E500MC
+ li r3,(HID1_ASTME|HID1_ABE)@l /* Addr streaming & broadcast */
+ mfspr r0,PVR
+ andi. r0,r0,0xff
+ cmpwi r0,0x50@l /* if we are rev 5.0 or greater set MBDD */
+ blt 1f
+ /* Set MBDD bit also */
+ ori r3, r3, HID1_MBDD@l
+1:
+ mtspr SPRN_HID1,r3
+#endif
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_CPU_A003999
+ mfspr r3,SPRN_HDBCR1
+ oris r3,r3,0x0100
+ mtspr SPRN_HDBCR1,r3
+#endif
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_A004510
+ mfspr r3,SPRN_SVR
+ rlwinm r3,r3,0,0xff
+ li r4,CONFIG_SYS_FSL_ERRATUM_A004510_SVR_REV
+ cmpw r3,r4
+ beq 1f
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_A004510_SVR_REV2
+ li r4,CONFIG_SYS_FSL_ERRATUM_A004510_SVR_REV2
+ cmpw r3,r4
+ beq 1f
+#endif
+
+ /* Not a supported revision affected by erratum */
+ b 2f
+
+1: /* Erratum says set bits 55:60 to 001001 */
+ msync
+ isync
+ mfspr r3,SPRN_HDBCR0
+ li r4,0x48
+ rlwimi r3,r4,0,0x1f8
+ mtspr SPRN_HDBCR0,r3
+ isync
+2:
+#endif
+
+ /* Enable branch prediction */
+ lis r3,BUCSR_ENABLE@h
+ ori r3,r3,BUCSR_ENABLE@l
+ mtspr SPRN_BUCSR,r3
+
+ /* Ensure TB is 0 */
+ li r3,0
+ mttbl r3
+ mttbu r3
+
+ /* Enable/invalidate the I-Cache */
+ lis r2,(L1CSR1_ICFI|L1CSR1_ICLFR)@h
+ ori r2,r2,(L1CSR1_ICFI|L1CSR1_ICLFR)@l
+ mtspr SPRN_L1CSR1,r2
+1:
+ mfspr r3,SPRN_L1CSR1
+ and. r1,r3,r2
+ bne 1b
+
+ lis r3,(L1CSR1_CPE|L1CSR1_ICE)@h
+ ori r3,r3,(L1CSR1_CPE|L1CSR1_ICE)@l
+ mtspr SPRN_L1CSR1,r3
+ isync
+2:
+ mfspr r3,SPRN_L1CSR1
+ andi. r1,r3,L1CSR1_ICE@l
+ beq 2b
+
+ /* Enable/invalidate the D-Cache */
+ lis r2,(L1CSR0_DCFI|L1CSR0_DCLFR)@h
+ ori r2,r2,(L1CSR0_DCFI|L1CSR0_DCLFR)@l
+ mtspr SPRN_L1CSR0,r2
+1:
+ mfspr r3,SPRN_L1CSR0
+ and. r1,r3,r2
+ bne 1b
+
+ lis r3,(L1CSR0_CPE|L1CSR0_DCE)@h
+ ori r3,r3,(L1CSR0_CPE|L1CSR0_DCE)@l
+ mtspr SPRN_L1CSR0,r3
+ isync
+2:
+ mfspr r3,SPRN_L1CSR0
+ andi. r1,r3,L1CSR0_DCE@l
+ beq 2b
+
+#define toreset(x) (x - __secondary_start_page + 0xfffff000)
+
+ /* get our PIR to figure out our table entry */
+ lis r3,toreset(__spin_table_addr)@h
+ ori r3,r3,toreset(__spin_table_addr)@l
+ lwz r3,0(r3)
+
+ mfspr r0,SPRN_PIR
+#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2
+/*
+ * PIR definition for Chassis 2
+ * 0-17 Reserved (logic 0s)
+ * 18-19 CHIP_ID, 2'b00 - SoC 1
+ * all others - reserved
+ * 20-24 CLUSTER_ID 5'b00000 - CCM 1
+ * all others - reserved
+ * 25-26 CORE_CLUSTER_ID 2'b00 - cluster 1
+ * 2'b01 - cluster 2
+ * 2'b10 - cluster 3
+ * 2'b11 - cluster 4
+ * 27-28 CORE_ID 2'b00 - core 0
+ * 2'b01 - core 1
+ * 2'b10 - core 2
+ * 2'b11 - core 3
+ * 29-31 THREAD_ID 3'b000 - thread 0
+ * 3'b001 - thread 1
+ *
+ * Power-on PIR increments threads by 0x01, cores within a cluster by 0x08
+ * and clusters by 0x20.
+ *
+ * We renumber PIR so that all threads in the system are consecutive.
+ */
+
+ rlwinm r8,r0,29,0x03 /* r8 = core within cluster */
+ srwi r10,r0,5 /* r10 = cluster */
+
+ mulli r5,r10,CONFIG_SYS_FSL_CORES_PER_CLUSTER
+ add r5,r5,r8 /* for spin table index */
+ mulli r4,r5,CONFIG_SYS_FSL_THREADS_PER_CORE /* for PIR */
+#elif defined(CONFIG_E500MC)
+ rlwinm r4,r0,27,27,31
+ mr r5,r4
+#else
+ mr r4,r0
+ mr r5,r4
+#endif
+
+ /*
+ * r10 has the base address for the entry.
+ * we cannot access it yet before setting up a new TLB
+ */
+ slwi r8,r5,6 /* spin table is padded to 64 byte */
+ add r10,r3,r8
+
+ mtspr SPRN_PIR,r4 /* write to PIR register */
+
+#ifdef CONFIG_SYS_CACHE_STASHING
+ /* set stash id to (coreID) * 2 + 32 + L1 CT (0) */
+ slwi r8,r4,1
+ addi r8,r8,32
+ mtspr L1CSR2,r8
+#endif
+
+#if defined(CONFIG_SYS_P4080_ERRATUM_CPU22) || \
+ defined(CONFIG_SYS_FSL_ERRATUM_NMG_CPU_A011)
+ /*
+ * CPU22 applies to P4080 rev 1.0, 2.0, fixed in 3.0
+ * NMG_CPU_A011 applies to P4080 rev 1.0, 2.0, fixed in 3.0
+ * also appleis to P3041 rev 1.0, 1.1, P2041 rev 1.0, 1.1
+ */
+ mfspr r3,SPRN_SVR
+ rlwinm r6,r3,24,~0x800 /* clear E bit */
+
+ lis r5,SVR_P4080@h
+ ori r5,r5,SVR_P4080@l
+ cmpw r6,r5
+ bne 1f
+
+ rlwinm r3,r3,0,0xf0
+ li r5,0x30
+ cmpw r3,r5
+ bge 2f
+1:
+#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_CPU_A011
+ lis r3,toreset(enable_cpu_a011_workaround)@ha
+ lwz r3,toreset(enable_cpu_a011_workaround)@l(r3)
+ cmpwi r3,0
+ beq 2f
+#endif
+ mfspr r3,L1CSR2
+ oris r3,r3,(L1CSR2_DCWS)@h
+ mtspr L1CSR2,r3
+2:
+#endif
+
+#ifdef CONFIG_BACKSIDE_L2_CACHE
+ /* skip L2 setup on P2040/P2040E as they have no L2 */
+ mfspr r3,SPRN_SVR
+ rlwinm r6,r3,24,~0x800 /* clear E bit of SVR */
+
+ lis r3,SVR_P2040@h
+ ori r3,r3,SVR_P2040@l
+ cmpw r6,r3
+ beq 3f
+
+ /* Enable/invalidate the L2 cache */
+ msync
+ lis r2,(L2CSR0_L2FI|L2CSR0_L2LFC)@h
+ ori r2,r2,(L2CSR0_L2FI|L2CSR0_L2LFC)@l
+ mtspr SPRN_L2CSR0,r2
+1:
+ mfspr r3,SPRN_L2CSR0
+ and. r1,r3,r2
+ bne 1b
+
+#ifdef CONFIG_SYS_CACHE_STASHING
+ /* set stash id to (coreID) * 2 + 32 + L2 (1) */
+ addi r3,r8,1
+ mtspr SPRN_L2CSR1,r3
+#endif
+
+ lis r3,CONFIG_SYS_INIT_L2CSR0@h
+ ori r3,r3,CONFIG_SYS_INIT_L2CSR0@l
+ mtspr SPRN_L2CSR0,r3
+ isync
+2:
+ mfspr r3,SPRN_L2CSR0
+ andis. r1,r3,L2CSR0_L2E@h
+ beq 2b
+#endif
+3:
+ /* setup mapping for the spin table, WIMGE=0b00100 */
+ lis r13,toreset(__spin_table_addr)@h
+ ori r13,r13,toreset(__spin_table_addr)@l
+ lwz r13,0(r13)
+ /* mask by 4K */
+ rlwinm r13,r13,0,0,19
+
+ lis r11,(MAS0_TLBSEL(1)|MAS0_ESEL(1))@h
+ mtspr SPRN_MAS0,r11
+ lis r11,(MAS1_VALID|MAS1_IPROT)@h
+ ori r11,r11,(MAS1_TS|MAS1_TSIZE(BOOKE_PAGESZ_4K))@l
+ mtspr SPRN_MAS1,r11
+ oris r11,r13,(MAS2_M|MAS2_G)@h
+ ori r11,r13,(MAS2_M|MAS2_G)@l
+ mtspr SPRN_MAS2,r11
+ oris r11,r13,(MAS3_SX|MAS3_SW|MAS3_SR)@h
+ ori r11,r13,(MAS3_SX|MAS3_SW|MAS3_SR)@l
+ mtspr SPRN_MAS3,r11
+ li r11,0
+ mtspr SPRN_MAS7,r11
+ tlbwe
+
+ /*
+ * __bootpg_addr has the address of __second_half_boot_page
+ * jump there in AS=1 space with cache enabled
+ */
+ lis r13,toreset(__bootpg_addr)@h
+ ori r13,r13,toreset(__bootpg_addr)@l
+ lwz r11,0(r13)
+ mtspr SPRN_SRR0,r11
+ mfmsr r13
+ ori r12,r13,MSR_IS|MSR_DS@l
+ mtspr SPRN_SRR1,r12
+ rfi
+
+ /*
+ * Allocate some space for the SDRAM address of the bootpg.
+ * This variable has to be in the boot page so that it can
+ * be accessed by secondary cores when they come out of reset.
+ */
+ .align L1_CACHE_SHIFT
+ .globl __bootpg_addr
+__bootpg_addr:
+ .long 0
+
+ .global __spin_table_addr
+__spin_table_addr:
+ .long 0
+
+ /*
+ * This variable is set by cpu_init_r() after parsing hwconfig
+ * to enable workaround for erratum NMG_CPU_A011.
+ */
+ .align L1_CACHE_SHIFT
+ .global enable_cpu_a011_workaround
+enable_cpu_a011_workaround:
+ .long 1
+
+ /* Fill in the empty space. The actual reset vector is
+ * the last word of the page */
+__secondary_start_code_end:
+ .space 4092 - (__secondary_start_code_end - __secondary_start_page)
+__secondary_reset_vector:
+ b __secondary_start_page
+
+
+/* this is a separated page for the spin table and cacheable boot code */
+ .align L1_CACHE_SHIFT
+ .global __second_half_boot_page
+__second_half_boot_page:
+#ifdef CONFIG_PPC_SPINTABLE_COMPATIBLE
+ lis r3,(spin_table_compat - __second_half_boot_page)@h
+ ori r3,r3,(spin_table_compat - __second_half_boot_page)@l
+ add r3,r3,r11 /* r11 has the address of __second_half_boot_page */
+ lwz r14,0(r3)
+#endif
+
+#define ENTRY_ADDR_UPPER 0
+#define ENTRY_ADDR_LOWER 4
+#define ENTRY_R3_UPPER 8
+#define ENTRY_R3_LOWER 12
+#define ENTRY_RESV 16
+#define ENTRY_PIR 20
+#define ENTRY_SIZE 64
+ /*
+ * setup the entry
+ * r10 has the base address of the spin table.
+ * spin table is defined as
+ * struct {
+ * uint64_t entry_addr;
+ * uint64_t r3;
+ * uint32_t rsvd1;
+ * uint32_t pir;
+ * };
+ * we pad this struct to 64 bytes so each entry is in its own cacheline
+ */
+ li r3,0
+ li r8,1
+ mfspr r4,SPRN_PIR
+ stw r3,ENTRY_ADDR_UPPER(r10)
+ stw r3,ENTRY_R3_UPPER(r10)
+ stw r4,ENTRY_R3_LOWER(r10)
+ stw r3,ENTRY_RESV(r10)
+ stw r4,ENTRY_PIR(r10)
+ msync
+ stw r8,ENTRY_ADDR_LOWER(r10)
+
+ /* spin waiting for addr */
+3:
+/*
+ * To comply with ePAPR 1.1, the spin table has been moved to cache-enabled
+ * memory. Old OS may not work with this change. A patch is waiting to be
+ * accepted for Linux kernel. Other OS needs similar fix to spin table.
+ * For OSes with old spin table code, we can enable this temporary fix by
+ * setting environmental variable "spin_table_compat". For new OSes, set
+ * "spin_table_compat=no". After Linux is fixed, we can remove this macro
+ * and related code. For now, it is enabled by default.
+ */
+#ifdef CONFIG_PPC_SPINTABLE_COMPATIBLE
+ cmpwi r14,0
+ beq 4f
+ dcbf 0, r10
+ sync
+4:
+#endif
+ lwz r4,ENTRY_ADDR_LOWER(r10)
+ andi. r11,r4,1
+ bne 3b
+ isync
+
+ /* setup IVORs to match fixed offsets */
+#include "fixed_ivor.S"
+
+ /* get the upper bits of the addr */
+ lwz r11,ENTRY_ADDR_UPPER(r10)
+
+ /* setup branch addr */
+ mtspr SPRN_SRR0,r4
+
+ /* mark the entry as released */
+ li r8,3
+ stw r8,ENTRY_ADDR_LOWER(r10)
+
+ /* mask by ~64M to setup our tlb we will jump to */
+ rlwinm r12,r4,0,0,5
+
+ /*
+ * setup r3, r4, r5, r6, r7, r8, r9
+ * r3 contains the value to put in the r3 register at secondary cpu
+ * entry. The high 32-bits are ignored on 32-bit chip implementations.
+ * 64-bit chip implementations however shall load all 64-bits
+ */
+#ifdef CONFIG_SYS_PPC64
+ ld r3,ENTRY_R3_UPPER(r10)
+#else
+ lwz r3,ENTRY_R3_LOWER(r10)
+#endif
+ li r4,0
+ li r5,0
+ li r6,0
+ lis r7,(64*1024*1024)@h
+ li r8,0
+ li r9,0
+
+ /* load up the pir */
+ lwz r0,ENTRY_PIR(r10)
+ mtspr SPRN_PIR,r0
+ mfspr r0,SPRN_PIR
+ stw r0,ENTRY_PIR(r10)
+
+ mtspr IVPR,r12
+/*
+ * Coming here, we know the cpu has one TLB mapping in TLB1[0]
+ * which maps 0xfffff000-0xffffffff one-to-one. We set up a
+ * second mapping that maps addr 1:1 for 64M, and then we jump to
+ * addr
+ */
+ lis r10,(MAS0_TLBSEL(1)|MAS0_ESEL(0))@h
+ mtspr SPRN_MAS0,r10
+ lis r10,(MAS1_VALID|MAS1_IPROT)@h
+ ori r10,r10,(MAS1_TSIZE(BOOKE_PAGESZ_64M))@l
+ mtspr SPRN_MAS1,r10
+ /* WIMGE = 0b00000 for now */
+ mtspr SPRN_MAS2,r12
+ ori r12,r12,(MAS3_SX|MAS3_SW|MAS3_SR)
+ mtspr SPRN_MAS3,r12
+#ifdef CONFIG_ENABLE_36BIT_PHYS
+ mtspr SPRN_MAS7,r11
+#endif
+ tlbwe
+
+/* Now we have another mapping for this page, so we jump to that
+ * mapping
+ */
+ mtspr SPRN_SRR1,r13
+ rfi
+
+
+ .align 6
+ .globl __spin_table
+__spin_table:
+ .space CONFIG_MAX_CPUS*ENTRY_SIZE
+
+#ifdef CONFIG_PPC_SPINTABLE_COMPATIBLE
+ .align L1_CACHE_SHIFT
+ .global spin_table_compat
+spin_table_compat:
+ .long 1
+
+#endif
+
+__spin_table_end:
+ .space 4096 - (__spin_table_end - __spin_table)
diff --git a/arch/powerpc/cpu/mpc85xx/resetvec.S b/arch/powerpc/cpu/mpc85xx/resetvec.S
new file mode 100644
index 0000000..29555d4
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/resetvec.S
@@ -0,0 +1,2 @@
+ .section .resetvec,"ax"
+ b _start_e500
diff --git a/arch/powerpc/cpu/mpc85xx/serial_scc.c b/arch/powerpc/cpu/mpc85xx/serial_scc.c
new file mode 100644
index 0000000..6345362
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/serial_scc.c
@@ -0,0 +1,278 @@
+/*
+ * (C) Copyright 2003 Motorola Inc.
+ * Xianghua Xiao (X.Xiao@motorola.com)
+ * Modified based on 8260 for 8560.
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00.
+ */
+
+/*
+ * Minimal serial functions needed to use one of the SCC ports
+ * as serial console interface.
+ */
+
+#include <common.h>
+#include <asm/cpm_85xx.h>
+#include <serial.h>
+#include <linux/compiler.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_CONS_ON_SCC)
+
+#if CONFIG_CONS_INDEX == 1 /* Console on SCC1 */
+
+#define SCC_INDEX 0
+#define PROFF_SCC PROFF_SCC1
+#define CMXSCR_MASK (CMXSCR_GR1|CMXSCR_SC1|\
+ CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK)
+#define CMXSCR_VALUE (CMXSCR_RS1CS_BRG1|CMXSCR_TS1CS_BRG1)
+#define CPM_CR_SCC_PAGE CPM_CR_SCC1_PAGE
+#define CPM_CR_SCC_SBLOCK CPM_CR_SCC1_SBLOCK
+
+#elif CONFIG_CONS_INDEX == 2 /* Console on SCC2 */
+
+#define SCC_INDEX 1
+#define PROFF_SCC PROFF_SCC2
+#define CMXSCR_MASK (CMXSCR_GR2|CMXSCR_SC2|\
+ CMXSCR_RS2CS_MSK|CMXSCR_TS2CS_MSK)
+#define CMXSCR_VALUE (CMXSCR_RS2CS_BRG2|CMXSCR_TS2CS_BRG2)
+#define CPM_CR_SCC_PAGE CPM_CR_SCC2_PAGE
+#define CPM_CR_SCC_SBLOCK CPM_CR_SCC2_SBLOCK
+
+#elif CONFIG_CONS_INDEX == 3 /* Console on SCC3 */
+
+#define SCC_INDEX 2
+#define PROFF_SCC PROFF_SCC3
+#define CMXSCR_MASK (CMXSCR_GR3|CMXSCR_SC3|\
+ CMXSCR_RS3CS_MSK|CMXSCR_TS3CS_MSK)
+#define CMXSCR_VALUE (CMXSCR_RS3CS_BRG3|CMXSCR_TS3CS_BRG3)
+#define CPM_CR_SCC_PAGE CPM_CR_SCC3_PAGE
+#define CPM_CR_SCC_SBLOCK CPM_CR_SCC3_SBLOCK
+
+#elif CONFIG_CONS_INDEX == 4 /* Console on SCC4 */
+
+#define SCC_INDEX 3
+#define PROFF_SCC PROFF_SCC4
+#define CMXSCR_MASK (CMXSCR_GR4|CMXSCR_SC4|\
+ CMXSCR_RS4CS_MSK|CMXSCR_TS4CS_MSK)
+#define CMXSCR_VALUE (CMXSCR_RS4CS_BRG4|CMXSCR_TS4CS_BRG4)
+#define CPM_CR_SCC_PAGE CPM_CR_SCC4_PAGE
+#define CPM_CR_SCC_SBLOCK CPM_CR_SCC4_SBLOCK
+
+#else
+
+#error "console not correctly defined"
+
+#endif
+
+static int mpc85xx_serial_init(void)
+{
+ volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+ volatile ccsr_cpm_scc_t *sp;
+ volatile scc_uart_t *up;
+ volatile cbd_t *tbdf, *rbdf;
+ volatile ccsr_cpm_cp_t *cp = &(cpm->im_cpm_cp);
+ uint dpaddr;
+
+ /* initialize pointers to SCC */
+
+ sp = (ccsr_cpm_scc_t *) &(cpm->im_cpm_scc[SCC_INDEX]);
+ up = (scc_uart_t *)&(cpm->im_dprambase[PROFF_SCC]);
+
+ /* Disable transmitter/receiver.
+ */
+ sp->gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+ /* put the SCC channel into NMSI (non multiplexd serial interface)
+ * mode and wire the selected SCC Tx and Rx clocks to BRGx (15-15).
+ */
+ cpm->im_cpm_mux.cmxscr = \
+ (cpm->im_cpm_mux.cmxscr&~CMXSCR_MASK)|CMXSCR_VALUE;
+
+ /* Set up the baud rate generator.
+ */
+ serial_setbrg ();
+
+ /* Allocate space for two buffer descriptors in the DP ram.
+ * damm: allocating space after the two buffers for rx/tx data
+ */
+
+ dpaddr = m8560_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16);
+
+ /* Set the physical address of the host memory buffers in
+ * the buffer descriptors.
+ */
+ rbdf = (cbd_t *)&(cpm->im_dprambase[dpaddr]);
+ rbdf->cbd_bufaddr = (uint) (rbdf+2);
+ rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+ tbdf = rbdf + 1;
+ tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+ tbdf->cbd_sc = BD_SC_WRAP;
+
+ /* Set up the uart parameters in the parameter ram.
+ */
+ up->scc_genscc.scc_rbase = dpaddr;
+ up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t);
+ up->scc_genscc.scc_rfcr = CPMFCR_EB;
+ up->scc_genscc.scc_tfcr = CPMFCR_EB;
+ up->scc_genscc.scc_mrblr = 1;
+ up->scc_maxidl = 0;
+ up->scc_brkcr = 1;
+ up->scc_parec = 0;
+ up->scc_frmec = 0;
+ up->scc_nosec = 0;
+ up->scc_brkec = 0;
+ up->scc_uaddr1 = 0;
+ up->scc_uaddr2 = 0;
+ up->scc_toseq = 0;
+ up->scc_char1 = up->scc_char2 = up->scc_char3 = up->scc_char4 = 0x8000;
+ up->scc_char5 = up->scc_char6 = up->scc_char7 = up->scc_char8 = 0x8000;
+ up->scc_rccm = 0xc0ff;
+
+ /* Mask all interrupts and remove anything pending.
+ */
+ sp->sccm = 0;
+ sp->scce = 0xffff;
+
+ /* Set 8 bit FIFO, 16 bit oversampling and UART mode.
+ */
+ sp->gsmrh = SCC_GSMRH_RFW; /* 8 bit FIFO */
+ sp->gsmrl = \
+ SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16 | SCC_GSMRL_MODE_UART;
+
+ /* Set CTS no flow control, 1 stop bit, 8 bit character length,
+ * normal async UART mode, no parity
+ */
+ sp->psmr = SCU_PSMR_CL;
+
+ /* execute the "Init Rx and Tx params" CP command.
+ */
+
+ while (cp->cpcr & CPM_CR_FLG) /* wait if cp is busy */
+ ;
+
+ cp->cpcr = mk_cr_cmd(CPM_CR_SCC_PAGE, CPM_CR_SCC_SBLOCK,
+ 0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+ while (cp->cpcr & CPM_CR_FLG) /* wait if cp is busy */
+ ;
+
+ /* Enable transmitter/receiver.
+ */
+ sp->gsmrl |= SCC_GSMRL_ENR | SCC_GSMRL_ENT;
+
+ return (0);
+}
+
+static void mpc85xx_serial_setbrg(void)
+{
+#if defined(CONFIG_CONS_USE_EXTC)
+ m8560_cpm_extcbrg(SCC_INDEX, gd->baudrate,
+ CONFIG_CONS_EXTC_RATE, CONFIG_CONS_EXTC_PINSEL);
+#else
+ m8560_cpm_setbrg(SCC_INDEX, gd->baudrate);
+#endif
+}
+
+static void mpc85xx_serial_putc(const char c)
+{
+ volatile scc_uart_t *up;
+ volatile cbd_t *tbdf;
+ volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+
+ if (c == '\n')
+ serial_putc ('\r');
+
+ up = (scc_uart_t *)&(cpm->im_dprambase[PROFF_SCC]);
+ tbdf = (cbd_t *)&(cpm->im_dprambase[up->scc_genscc.scc_tbase]);
+
+ /* Wait for last character to go.
+ */
+ while (tbdf->cbd_sc & BD_SC_READY)
+ ;
+
+ /* Load the character into the transmit buffer.
+ */
+ *(volatile char *)tbdf->cbd_bufaddr = c;
+ tbdf->cbd_datlen = 1;
+ tbdf->cbd_sc |= BD_SC_READY;
+}
+
+static int mpc85xx_serial_getc(void)
+{
+ volatile cbd_t *rbdf;
+ volatile scc_uart_t *up;
+ volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+ unsigned char c;
+
+ up = (scc_uart_t *)&(cpm->im_dprambase[PROFF_SCC]);
+ rbdf = (cbd_t *)&(cpm->im_dprambase[up->scc_genscc.scc_rbase]);
+
+ /* Wait for character to show up.
+ */
+ while (rbdf->cbd_sc & BD_SC_EMPTY)
+ ;
+
+ /* Grab the char and clear the buffer again.
+ */
+ c = *(volatile unsigned char *)rbdf->cbd_bufaddr;
+ rbdf->cbd_sc |= BD_SC_EMPTY;
+
+ return (c);
+}
+
+static int mpc85xx_serial_tstc(void)
+{
+ volatile cbd_t *rbdf;
+ volatile scc_uart_t *up;
+ volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+
+ up = (scc_uart_t *)&(cpm->im_dprambase[PROFF_SCC]);
+ rbdf = (cbd_t *)&(cpm->im_dprambase[up->scc_genscc.scc_rbase]);
+
+ return ((rbdf->cbd_sc & BD_SC_EMPTY) == 0);
+}
+
+static struct serial_device mpc85xx_serial_drv = {
+ .name = "mpc85xx_serial",
+ .start = mpc85xx_serial_init,
+ .stop = NULL,
+ .setbrg = mpc85xx_serial_setbrg,
+ .putc = mpc85xx_serial_putc,
+ .puts = default_serial_puts,
+ .getc = mpc85xx_serial_getc,
+ .tstc = mpc85xx_serial_tstc,
+};
+
+void mpc85xx_serial_initialize(void)
+{
+ serial_register(&mpc85xx_serial_drv);
+}
+
+__weak struct serial_device *default_serial_console(void)
+{
+ return &mpc85xx_serial_drv;
+}
+#endif /* CONFIG_CONS_ON_SCC */
diff --git a/arch/powerpc/cpu/mpc85xx/speed.c b/arch/powerpc/cpu/mpc85xx/speed.c
new file mode 100644
index 0000000..a4d6e9c
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/speed.c
@@ -0,0 +1,475 @@
+/*
+ * Copyright 2004, 2007-2011 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2003 Motorola Inc.
+ * Xianghua Xiao, (X.Xiao@motorola.com)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc_asm.tmpl>
+#include <linux/compiler.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* --------------------------------------------------------------- */
+
+void get_sys_info (sys_info_t * sysInfo)
+{
+ volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+#ifdef CONFIG_FSL_IFC
+ struct fsl_ifc *ifc_regs = (void *)CONFIG_SYS_IFC_ADDR;
+ u32 ccr;
+#endif
+#ifdef CONFIG_FSL_CORENET
+ volatile ccsr_clk_t *clk = (void *)(CONFIG_SYS_FSL_CORENET_CLK_ADDR);
+ unsigned int cpu;
+
+ const u8 core_cplx_PLL[16] = {
+ [ 0] = 0, /* CC1 PPL / 1 */
+ [ 1] = 0, /* CC1 PPL / 2 */
+ [ 2] = 0, /* CC1 PPL / 4 */
+ [ 4] = 1, /* CC2 PPL / 1 */
+ [ 5] = 1, /* CC2 PPL / 2 */
+ [ 6] = 1, /* CC2 PPL / 4 */
+ [ 8] = 2, /* CC3 PPL / 1 */
+ [ 9] = 2, /* CC3 PPL / 2 */
+ [10] = 2, /* CC3 PPL / 4 */
+ [12] = 3, /* CC4 PPL / 1 */
+ [13] = 3, /* CC4 PPL / 2 */
+ [14] = 3, /* CC4 PPL / 4 */
+ };
+
+ const u8 core_cplx_PLL_div[16] = {
+ [ 0] = 1, /* CC1 PPL / 1 */
+ [ 1] = 2, /* CC1 PPL / 2 */
+ [ 2] = 4, /* CC1 PPL / 4 */
+ [ 4] = 1, /* CC2 PPL / 1 */
+ [ 5] = 2, /* CC2 PPL / 2 */
+ [ 6] = 4, /* CC2 PPL / 4 */
+ [ 8] = 1, /* CC3 PPL / 1 */
+ [ 9] = 2, /* CC3 PPL / 2 */
+ [10] = 4, /* CC3 PPL / 4 */
+ [12] = 1, /* CC4 PPL / 1 */
+ [13] = 2, /* CC4 PPL / 2 */
+ [14] = 4, /* CC4 PPL / 4 */
+ };
+ uint i, freqCC_PLL[6], rcw_tmp;
+ uint ratio[6];
+ unsigned long sysclk = CONFIG_SYS_CLK_FREQ;
+ uint mem_pll_rat;
+
+ sysInfo->freqSystemBus = sysclk;
+#ifdef CONFIG_DDR_CLK_FREQ
+ sysInfo->freqDDRBus = CONFIG_DDR_CLK_FREQ;
+#else
+ sysInfo->freqDDRBus = sysclk;
+#endif
+
+ sysInfo->freqSystemBus *= (in_be32(&gur->rcwsr[0]) >> 25) & 0x1f;
+ mem_pll_rat = (in_be32(&gur->rcwsr[0]) >>
+ FSL_CORENET_RCWSR0_MEM_PLL_RAT_SHIFT)
+ & FSL_CORENET_RCWSR0_MEM_PLL_RAT_MASK;
+ if (mem_pll_rat > 2)
+ sysInfo->freqDDRBus *= mem_pll_rat;
+ else
+ sysInfo->freqDDRBus = sysInfo->freqSystemBus * mem_pll_rat;
+
+ ratio[0] = (in_be32(&clk->pllc1gsr) >> 1) & 0x3f;
+ ratio[1] = (in_be32(&clk->pllc2gsr) >> 1) & 0x3f;
+ ratio[2] = (in_be32(&clk->pllc3gsr) >> 1) & 0x3f;
+ ratio[3] = (in_be32(&clk->pllc4gsr) >> 1) & 0x3f;
+ ratio[4] = (in_be32(&clk->pllc5gsr) >> 1) & 0x3f;
+ ratio[5] = (in_be32(&clk->pllc6gsr) >> 1) & 0x3f;
+ for (i = 0; i < 6; i++) {
+ if (ratio[i] > 4)
+ freqCC_PLL[i] = sysclk * ratio[i];
+ else
+ freqCC_PLL[i] = sysInfo->freqSystemBus * ratio[i];
+ }
+#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2
+ /*
+ * Each cluster has up to 4 cores, sharing the same PLL selection.
+ * The cluster assignment is fixed per SoC. PLL1, PLL2, PLL3 are
+ * cluster group A, feeding cores on cluster 1 and cluster 2.
+ * PLL4, PLL5, PLL6 are cluster group B, feeding cores on cluster 3
+ * and cluster 4 if existing.
+ */
+ for_each_cpu(i, cpu, cpu_numcores(), cpu_mask()) {
+ int cluster = fsl_qoriq_core_to_cluster(cpu);
+ u32 c_pll_sel = (in_be32(&clk->clkcsr[cluster].clkcncsr) >> 27)
+ & 0xf;
+ u32 cplx_pll = core_cplx_PLL[c_pll_sel];
+ if (cplx_pll > 3)
+ printf("Unsupported architecture configuration"
+ " in function %s\n", __func__);
+ cplx_pll += (cluster / 2) * 3;
+ sysInfo->freqProcessor[cpu] =
+ freqCC_PLL[cplx_pll] / core_cplx_PLL_div[c_pll_sel];
+ }
+#ifdef CONFIG_PPC_B4860
+#define FM1_CLK_SEL 0xe0000000
+#define FM1_CLK_SHIFT 29
+#else
+#define PME_CLK_SEL 0xe0000000
+#define PME_CLK_SHIFT 29
+#define FM1_CLK_SEL 0x1c000000
+#define FM1_CLK_SHIFT 26
+#endif
+ rcw_tmp = in_be32(&gur->rcwsr[7]);
+
+#ifdef CONFIG_SYS_DPAA_PME
+ switch ((rcw_tmp & PME_CLK_SEL) >> PME_CLK_SHIFT) {
+ case 1:
+ sysInfo->freqPME = freqCC_PLL[0];
+ break;
+ case 2:
+ sysInfo->freqPME = freqCC_PLL[0] / 2;
+ break;
+ case 3:
+ sysInfo->freqPME = freqCC_PLL[0] / 3;
+ break;
+ case 4:
+ sysInfo->freqPME = freqCC_PLL[0] / 4;
+ break;
+ case 6:
+ sysInfo->freqPME = freqCC_PLL[1] / 2;
+ break;
+ case 7:
+ sysInfo->freqPME = freqCC_PLL[1] / 3;
+ break;
+ default:
+ printf("Error: Unknown PME clock select!\n");
+ case 0:
+ sysInfo->freqPME = sysInfo->freqSystemBus / 2;
+ break;
+
+ }
+#endif
+
+#ifdef CONFIG_SYS_DPAA_QBMAN
+ sysInfo->freqQMAN = sysInfo->freqSystemBus / 2;
+#endif
+
+#ifdef CONFIG_SYS_DPAA_FMAN
+ switch ((rcw_tmp & FM1_CLK_SEL) >> FM1_CLK_SHIFT) {
+ case 1:
+ sysInfo->freqFMan[0] = freqCC_PLL[3];
+ break;
+ case 2:
+ sysInfo->freqFMan[0] = freqCC_PLL[3] / 2;
+ break;
+ case 3:
+ sysInfo->freqFMan[0] = freqCC_PLL[3] / 3;
+ break;
+ case 4:
+ sysInfo->freqFMan[0] = freqCC_PLL[3] / 4;
+ break;
+ case 5:
+ sysInfo->freqFMan[0] = sysInfo->freqSystemBus;
+ break;
+ case 6:
+ sysInfo->freqFMan[0] = freqCC_PLL[4] / 2;
+ break;
+ case 7:
+ sysInfo->freqFMan[0] = freqCC_PLL[4] / 3;
+ break;
+ default:
+ printf("Error: Unknown FMan1 clock select!\n");
+ case 0:
+ sysInfo->freqFMan[0] = sysInfo->freqSystemBus / 2;
+ break;
+ }
+#if (CONFIG_SYS_NUM_FMAN) == 2
+#define FM2_CLK_SEL 0x00000038
+#define FM2_CLK_SHIFT 3
+ rcw_tmp = in_be32(&gur->rcwsr[15]);
+ switch ((rcw_tmp & FM2_CLK_SEL) >> FM2_CLK_SHIFT) {
+ case 1:
+ sysInfo->freqFMan[1] = freqCC_PLL[4];
+ break;
+ case 2:
+ sysInfo->freqFMan[1] = freqCC_PLL[4] / 2;
+ break;
+ case 3:
+ sysInfo->freqFMan[1] = freqCC_PLL[4] / 3;
+ break;
+ case 4:
+ sysInfo->freqFMan[1] = freqCC_PLL[4] / 4;
+ break;
+ case 6:
+ sysInfo->freqFMan[1] = freqCC_PLL[3] / 2;
+ break;
+ case 7:
+ sysInfo->freqFMan[1] = freqCC_PLL[3] / 3;
+ break;
+ default:
+ printf("Error: Unknown FMan2 clock select!\n");
+ case 0:
+ sysInfo->freqFMan[1] = sysInfo->freqSystemBus / 2;
+ break;
+ }
+#endif /* CONFIG_SYS_NUM_FMAN == 2 */
+#endif /* CONFIG_SYS_DPAA_FMAN */
+
+#else /* CONFIG_SYS_FSL_QORIQ_CHASSIS2 */
+
+ for_each_cpu(i, cpu, cpu_numcores(), cpu_mask()) {
+ u32 c_pll_sel = (in_be32(&clk->clkcsr[cpu].clkcncsr) >> 27)
+ & 0xf;
+ u32 cplx_pll = core_cplx_PLL[c_pll_sel];
+
+ sysInfo->freqProcessor[cpu] =
+ freqCC_PLL[cplx_pll] / core_cplx_PLL_div[c_pll_sel];
+ }
+#define PME_CLK_SEL 0x80000000
+#define FM1_CLK_SEL 0x40000000
+#define FM2_CLK_SEL 0x20000000
+#define HWA_ASYNC_DIV 0x04000000
+#if (CONFIG_SYS_FSL_NUM_CC_PLLS == 2)
+#define HWA_CC_PLL 1
+#elif (CONFIG_SYS_FSL_NUM_CC_PLLS == 3)
+#define HWA_CC_PLL 2
+#elif (CONFIG_SYS_FSL_NUM_CC_PLLS == 4)
+#define HWA_CC_PLL 2
+#else
+#error CONFIG_SYS_FSL_NUM_CC_PLLS not set or unknown case
+#endif
+ rcw_tmp = in_be32(&gur->rcwsr[7]);
+
+#ifdef CONFIG_SYS_DPAA_PME
+ if (rcw_tmp & PME_CLK_SEL) {
+ if (rcw_tmp & HWA_ASYNC_DIV)
+ sysInfo->freqPME = freqCC_PLL[HWA_CC_PLL] / 4;
+ else
+ sysInfo->freqPME = freqCC_PLL[HWA_CC_PLL] / 2;
+ } else {
+ sysInfo->freqPME = sysInfo->freqSystemBus / 2;
+ }
+#endif
+
+#ifdef CONFIG_SYS_DPAA_FMAN
+ if (rcw_tmp & FM1_CLK_SEL) {
+ if (rcw_tmp & HWA_ASYNC_DIV)
+ sysInfo->freqFMan[0] = freqCC_PLL[HWA_CC_PLL] / 4;
+ else
+ sysInfo->freqFMan[0] = freqCC_PLL[HWA_CC_PLL] / 2;
+ } else {
+ sysInfo->freqFMan[0] = sysInfo->freqSystemBus / 2;
+ }
+#if (CONFIG_SYS_NUM_FMAN) == 2
+ if (rcw_tmp & FM2_CLK_SEL) {
+ if (rcw_tmp & HWA_ASYNC_DIV)
+ sysInfo->freqFMan[1] = freqCC_PLL[HWA_CC_PLL] / 4;
+ else
+ sysInfo->freqFMan[1] = freqCC_PLL[HWA_CC_PLL] / 2;
+ } else {
+ sysInfo->freqFMan[1] = sysInfo->freqSystemBus / 2;
+ }
+#endif
+#endif
+
+#ifdef CONFIG_SYS_DPAA_QBMAN
+ sysInfo->freqQMAN = sysInfo->freqSystemBus / 2;
+#endif
+
+#endif /* CONFIG_SYS_FSL_QORIQ_CHASSIS2 */
+
+#else /* CONFIG_FSL_CORENET */
+ uint plat_ratio, e500_ratio, half_freqSystemBus;
+ int i;
+#ifdef CONFIG_QE
+ __maybe_unused u32 qe_ratio;
+#endif
+
+ plat_ratio = (gur->porpllsr) & 0x0000003e;
+ plat_ratio >>= 1;
+ sysInfo->freqSystemBus = plat_ratio * CONFIG_SYS_CLK_FREQ;
+
+ /* Divide before multiply to avoid integer
+ * overflow for processor speeds above 2GHz */
+ half_freqSystemBus = sysInfo->freqSystemBus/2;
+ for (i = 0; i < cpu_numcores(); i++) {
+ e500_ratio = ((gur->porpllsr) >> (i * 8 + 16)) & 0x3f;
+ sysInfo->freqProcessor[i] = e500_ratio * half_freqSystemBus;
+ }
+
+ /* Note: freqDDRBus is the MCLK frequency, not the data rate. */
+ sysInfo->freqDDRBus = sysInfo->freqSystemBus;
+
+#ifdef CONFIG_DDR_CLK_FREQ
+ {
+ u32 ddr_ratio = ((gur->porpllsr) & MPC85xx_PORPLLSR_DDR_RATIO)
+ >> MPC85xx_PORPLLSR_DDR_RATIO_SHIFT;
+ if (ddr_ratio != 0x7)
+ sysInfo->freqDDRBus = ddr_ratio * CONFIG_DDR_CLK_FREQ;
+ }
+#endif
+
+#ifdef CONFIG_QE
+#if defined(CONFIG_P1012) || defined(CONFIG_P1021) || defined(CONFIG_P1025)
+ sysInfo->freqQE = sysInfo->freqSystemBus;
+#else
+ qe_ratio = ((gur->porpllsr) & MPC85xx_PORPLLSR_QE_RATIO)
+ >> MPC85xx_PORPLLSR_QE_RATIO_SHIFT;
+ sysInfo->freqQE = qe_ratio * CONFIG_SYS_CLK_FREQ;
+#endif
+#endif
+
+#ifdef CONFIG_SYS_DPAA_FMAN
+ sysInfo->freqFMan[0] = sysInfo->freqSystemBus;
+#endif
+
+#endif /* CONFIG_FSL_CORENET */
+
+#if defined(CONFIG_FSL_LBC)
+ uint lcrr_div;
+#if defined(CONFIG_SYS_LBC_LCRR)
+ /* We will program LCRR to this value later */
+ lcrr_div = CONFIG_SYS_LBC_LCRR & LCRR_CLKDIV;
+#else
+ lcrr_div = in_be32(&(LBC_BASE_ADDR)->lcrr) & LCRR_CLKDIV;
+#endif
+ if (lcrr_div == 2 || lcrr_div == 4 || lcrr_div == 8) {
+#if defined(CONFIG_FSL_CORENET)
+ /* If this is corenet based SoC, bit-representation
+ * for four times the clock divider values.
+ */
+ lcrr_div *= 4;
+#elif !defined(CONFIG_MPC8540) && !defined(CONFIG_MPC8541) && \
+ !defined(CONFIG_MPC8555) && !defined(CONFIG_MPC8560)
+ /*
+ * Yes, the entire PQ38 family use the same
+ * bit-representation for twice the clock divider values.
+ */
+ lcrr_div *= 2;
+#endif
+ sysInfo->freqLocalBus = sysInfo->freqSystemBus / lcrr_div;
+ } else {
+ /* In case anyone cares what the unknown value is */
+ sysInfo->freqLocalBus = lcrr_div;
+ }
+#endif
+
+#if defined(CONFIG_FSL_IFC)
+ ccr = in_be32(&ifc_regs->ifc_ccr);
+ ccr = ((ccr & IFC_CCR_CLK_DIV_MASK) >> IFC_CCR_CLK_DIV_SHIFT) + 1;
+
+ sysInfo->freqLocalBus = sysInfo->freqSystemBus / ccr;
+#endif
+}
+
+
+int get_clocks (void)
+{
+ sys_info_t sys_info;
+#ifdef CONFIG_MPC8544
+ volatile ccsr_gur_t *gur = (void *) CONFIG_SYS_MPC85xx_GUTS_ADDR;
+#endif
+#if defined(CONFIG_CPM2)
+ volatile ccsr_cpm_t *cpm = (ccsr_cpm_t *)CONFIG_SYS_MPC85xx_CPM_ADDR;
+ uint sccr, dfbrg;
+
+ /* set VCO = 4 * BRG */
+ cpm->im_cpm_intctl.sccr &= 0xfffffffc;
+ sccr = cpm->im_cpm_intctl.sccr;
+ dfbrg = (sccr & SCCR_DFBRG_MSK) >> SCCR_DFBRG_SHIFT;
+#endif
+ get_sys_info (&sys_info);
+ gd->cpu_clk = sys_info.freqProcessor[0];
+ gd->bus_clk = sys_info.freqSystemBus;
+ gd->mem_clk = sys_info.freqDDRBus;
+ gd->arch.lbc_clk = sys_info.freqLocalBus;
+
+#ifdef CONFIG_QE
+ gd->arch.qe_clk = sys_info.freqQE;
+ gd->arch.brg_clk = gd->arch.qe_clk / 2;
+#endif
+ /*
+ * The base clock for I2C depends on the actual SOC. Unfortunately,
+ * there is no pattern that can be used to determine the frequency, so
+ * the only choice is to look up the actual SOC number and use the value
+ * for that SOC. This information is taken from application note
+ * AN2919.
+ */
+#if defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
+ defined(CONFIG_MPC8560) || defined(CONFIG_MPC8555)
+ gd->arch.i2c1_clk = sys_info.freqSystemBus;
+#elif defined(CONFIG_MPC8544)
+ /*
+ * On the 8544, the I2C clock is the same as the SEC clock. This can be
+ * either CCB/2 or CCB/3, depending on the value of cfg_sec_freq. See
+ * 4.4.3.3 of the 8544 RM. Note that this might actually work for all
+ * 85xx, but only the 8544 has cfg_sec_freq, so it's unknown if the
+ * PORDEVSR2_SEC_CFG bit is 0 on all 85xx boards that are not an 8544.
+ */
+ if (gur->pordevsr2 & MPC85xx_PORDEVSR2_SEC_CFG)
+ gd->arch.i2c1_clk = sys_info.freqSystemBus / 3;
+ else
+ gd->arch.i2c1_clk = sys_info.freqSystemBus / 2;
+#else
+ /* Most 85xx SOCs use CCB/2, so this is the default behavior. */
+ gd->arch.i2c1_clk = sys_info.freqSystemBus / 2;
+#endif
+ gd->arch.i2c2_clk = gd->arch.i2c1_clk;
+
+#if defined(CONFIG_FSL_ESDHC)
+#if defined(CONFIG_MPC8569) || defined(CONFIG_P1010) ||\
+ defined(CONFIG_P1014)
+ gd->arch.sdhc_clk = gd->bus_clk;
+#else
+ gd->arch.sdhc_clk = gd->bus_clk / 2;
+#endif
+#endif /* defined(CONFIG_FSL_ESDHC) */
+
+#if defined(CONFIG_CPM2)
+ gd->arch.vco_out = 2*sys_info.freqSystemBus;
+ gd->arch.cpm_clk = gd->arch.vco_out / 2;
+ gd->arch.scc_clk = gd->arch.vco_out / 4;
+ gd->arch.brg_clk = gd->arch.vco_out / (1 << (2 * (dfbrg + 1)));
+#endif
+
+ if(gd->cpu_clk != 0) return (0);
+ else return (1);
+}
+
+
+/********************************************
+ * get_bus_freq
+ * return system bus freq in Hz
+ *********************************************/
+ulong get_bus_freq (ulong dummy)
+{
+ return gd->bus_clk;
+}
+
+/********************************************
+ * get_ddr_freq
+ * return ddr bus freq in Hz
+ *********************************************/
+ulong get_ddr_freq (ulong dummy)
+{
+ return gd->mem_clk;
+}
diff --git a/arch/powerpc/cpu/mpc85xx/spl_minimal.c b/arch/powerpc/cpu/mpc85xx/spl_minimal.c
new file mode 100644
index 0000000..c6b9cd0
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/spl_minimal.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/global_data.h>
+#include <asm/fsl_ifc.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void cpu_init_f(void)
+{
+#ifdef CONFIG_SYS_INIT_L2_ADDR
+ ccsr_l2cache_t *l2cache = (void *)CONFIG_SYS_MPC85xx_L2_ADDR;
+
+ out_be32(&l2cache->l2srbar0, CONFIG_SYS_INIT_L2_ADDR);
+
+ /* set MBECCDIS=1, SBECCDIS=1 */
+ out_be32(&l2cache->l2errdis,
+ (MPC85xx_L2ERRDIS_MBECC | MPC85xx_L2ERRDIS_SBECC));
+
+ /* set L2E=1 & L2SRAM=001 */
+ out_be32(&l2cache->l2ctl,
+ (MPC85xx_L2CTL_L2E | MPC85xx_L2CTL_L2SRAM_ENTIRE));
+#endif
+}
+
+#ifndef CONFIG_SYS_FSL_TBCLK_DIV
+#define CONFIG_SYS_FSL_TBCLK_DIV 8
+#endif
+
+void udelay(unsigned long usec)
+{
+ u32 ticks_per_usec = gd->bus_clk / (CONFIG_SYS_FSL_TBCLK_DIV * 1000000);
+ u32 ticks = ticks_per_usec * usec;
+ u32 s = mfspr(SPRN_TBRL);
+
+ while ((mfspr(SPRN_TBRL) - s) < ticks);
+}
diff --git a/arch/powerpc/cpu/mpc85xx/start.S b/arch/powerpc/cpu/mpc85xx/start.S
new file mode 100644
index 0000000..2657982
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/start.S
@@ -0,0 +1,1979 @@
+/*
+ * Copyright 2004, 2007-2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2003 Motorola,Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* U-Boot Startup Code for Motorola 85xx PowerPC based Embedded Boards
+ *
+ * The processor starts at 0xfffffffc and the code is first executed in the
+ * last 4K page(0xfffff000-0xffffffff) in flash/rom.
+ *
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <mpc85xx.h>
+#include <version.h>
+
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#undef MSR_KERNEL
+#define MSR_KERNEL ( MSR_ME ) /* Machine Check */
+
+#if defined(CONFIG_NAND_SPL) || \
+ (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_INIT_MINIMAL))
+#define MINIMAL_SPL
+#endif
+
+#if !defined(CONFIG_SPL) && !defined(CONFIG_SYS_RAMBOOT) && !defined(CONFIG_SECURE_BOOT)
+#define NOR_BOOT
+#endif
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+ START_GOT
+ GOT_ENTRY(_GOT2_TABLE_)
+ GOT_ENTRY(_FIXUP_TABLE_)
+
+#ifndef MINIMAL_SPL
+ GOT_ENTRY(_start)
+ GOT_ENTRY(_start_of_vectors)
+ GOT_ENTRY(_end_of_vectors)
+ GOT_ENTRY(transfer_to_handler)
+#endif
+
+ GOT_ENTRY(__init_end)
+ GOT_ENTRY(__bss_end)
+ GOT_ENTRY(__bss_start)
+ END_GOT
+
+/*
+ * e500 Startup -- after reset only the last 4KB of the effective
+ * address space is mapped in the MMU L2 TLB1 Entry0. The .bootpg
+ * section is located at THIS LAST page and basically does three
+ * things: clear some registers, set up exception tables and
+ * add more TLB entries for 'larger spaces'(e.g. the boot rom) to
+ * continue the boot procedure.
+
+ * Once the boot rom is mapped by TLB entries we can proceed
+ * with normal startup.
+ *
+ */
+
+ .section .bootpg,"ax"
+ .globl _start_e500
+
+_start_e500:
+/* Enable debug exception */
+ li r1,MSR_DE
+ mtmsr r1
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_A004510
+ mfspr r3,SPRN_SVR
+ rlwinm r3,r3,0,0xff
+ li r4,CONFIG_SYS_FSL_ERRATUM_A004510_SVR_REV
+ cmpw r3,r4
+ beq 1f
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_A004510_SVR_REV2
+ li r4,CONFIG_SYS_FSL_ERRATUM_A004510_SVR_REV2
+ cmpw r3,r4
+ beq 1f
+#endif
+
+ /* Not a supported revision affected by erratum */
+ li r27,0
+ b 2f
+
+1: li r27,1 /* Remember for later that we have the erratum */
+ /* Erratum says set bits 55:60 to 001001 */
+ msync
+ isync
+ mfspr r3,SPRN_HDBCR0
+ li r4,0x48
+ rlwimi r3,r4,0,0x1f8
+ mtspr SPRN_HDBCR0,r3
+ isync
+2:
+#endif
+
+#if defined(CONFIG_SECURE_BOOT) && defined(CONFIG_E500MC)
+ /* ISBC uses L2 as stack.
+ * Disable L2 cache here so that u-boot can enable it later
+ * as part of it's normal flow
+ */
+
+ /* Check if L2 is enabled */
+ mfspr r3, SPRN_L2CSR0
+ lis r2, L2CSR0_L2E@h
+ ori r2, r2, L2CSR0_L2E@l
+ and. r4, r3, r2
+ beq l2_disabled
+
+ mfspr r3, SPRN_L2CSR0
+ /* Flush L2 cache */
+ lis r2,(L2CSR0_L2FL)@h
+ ori r2, r2, (L2CSR0_L2FL)@l
+ or r3, r2, r3
+ sync
+ isync
+ mtspr SPRN_L2CSR0,r3
+ isync
+1:
+ mfspr r3, SPRN_L2CSR0
+ and. r1, r3, r2
+ bne 1b
+
+ mfspr r3, SPRN_L2CSR0
+ lis r2, L2CSR0_L2E@h
+ ori r2, r2, L2CSR0_L2E@l
+ andc r4, r3, r2
+ sync
+ isync
+ mtspr SPRN_L2CSR0,r4
+ isync
+
+l2_disabled:
+#endif
+
+/* clear registers/arrays not reset by hardware */
+
+ /* L1 */
+ li r0,2
+ mtspr L1CSR0,r0 /* invalidate d-cache */
+ mtspr L1CSR1,r0 /* invalidate i-cache */
+
+ mfspr r1,DBSR
+ mtspr DBSR,r1 /* Clear all valid bits */
+
+
+ .macro create_tlb1_entry esel ts tsize epn wimg rpn perm phy_high scratch
+ lis \scratch, FSL_BOOKE_MAS0(1, \esel, 0)@h
+ ori \scratch, \scratch, FSL_BOOKE_MAS0(1, \esel, 0)@l
+ mtspr MAS0, \scratch
+ lis \scratch, FSL_BOOKE_MAS1(1, 1, 0, \ts, \tsize)@h
+ ori \scratch, \scratch, FSL_BOOKE_MAS1(1, 1, 0, \ts, \tsize)@l
+ mtspr MAS1, \scratch
+ lis \scratch, FSL_BOOKE_MAS2(\epn, \wimg)@h
+ ori \scratch, \scratch, FSL_BOOKE_MAS2(\epn, \wimg)@l
+ mtspr MAS2, \scratch
+ lis \scratch, FSL_BOOKE_MAS3(\rpn, 0, \perm)@h
+ ori \scratch, \scratch, FSL_BOOKE_MAS3(\rpn, 0, \perm)@l
+ mtspr MAS3, \scratch
+ lis \scratch, \phy_high@h
+ ori \scratch, \scratch, \phy_high@l
+ mtspr MAS7, \scratch
+ isync
+ msync
+ tlbwe
+ isync
+ .endm
+
+ .macro create_tlb0_entry esel ts tsize epn wimg rpn perm phy_high scratch
+ lis \scratch, FSL_BOOKE_MAS0(0, \esel, 0)@h
+ ori \scratch, \scratch, FSL_BOOKE_MAS0(0, \esel, 0)@l
+ mtspr MAS0, \scratch
+ lis \scratch, FSL_BOOKE_MAS1(1, 0, 0, \ts, \tsize)@h
+ ori \scratch, \scratch, FSL_BOOKE_MAS1(1, 0, 0, \ts, \tsize)@l
+ mtspr MAS1, \scratch
+ lis \scratch, FSL_BOOKE_MAS2(\epn, \wimg)@h
+ ori \scratch, \scratch, FSL_BOOKE_MAS2(\epn, \wimg)@l
+ mtspr MAS2, \scratch
+ lis \scratch, FSL_BOOKE_MAS3(\rpn, 0, \perm)@h
+ ori \scratch, \scratch, FSL_BOOKE_MAS3(\rpn, 0, \perm)@l
+ mtspr MAS3, \scratch
+ lis \scratch, \phy_high@h
+ ori \scratch, \scratch, \phy_high@l
+ mtspr MAS7, \scratch
+ isync
+ msync
+ tlbwe
+ isync
+ .endm
+
+ .macro delete_tlb1_entry esel scratch
+ lis \scratch, FSL_BOOKE_MAS0(1, \esel, 0)@h
+ ori \scratch, \scratch, FSL_BOOKE_MAS0(1, \esel, 0)@l
+ mtspr MAS0, \scratch
+ li \scratch, 0
+ mtspr MAS1, \scratch
+ isync
+ msync
+ tlbwe
+ isync
+ .endm
+
+ .macro delete_tlb0_entry esel epn wimg scratch
+ lis \scratch, FSL_BOOKE_MAS0(0, \esel, 0)@h
+ ori \scratch, \scratch, FSL_BOOKE_MAS0(0, \esel, 0)@l
+ mtspr MAS0, \scratch
+ li \scratch, 0
+ mtspr MAS1, \scratch
+ lis \scratch, FSL_BOOKE_MAS2(\epn, \wimg)@h
+ ori \scratch, \scratch, FSL_BOOKE_MAS2(\epn, \wimg)@l
+ mtspr MAS2, \scratch
+ isync
+ msync
+ tlbwe
+ isync
+ .endm
+
+/* Interrupt vectors do not fit in minimal SPL. */
+#if !defined(MINIMAL_SPL)
+ /* Setup interrupt vectors */
+ lis r1,CONFIG_SYS_MONITOR_BASE@h
+ mtspr IVPR,r1
+
+ lis r3,(CONFIG_SYS_MONITOR_BASE & 0xffff)@h
+ ori r3,r3,(CONFIG_SYS_MONITOR_BASE & 0xffff)@l
+
+ addi r4,r3,CriticalInput - _start + _START_OFFSET
+ mtspr IVOR0,r4 /* 0: Critical input */
+ addi r4,r3,MachineCheck - _start + _START_OFFSET
+ mtspr IVOR1,r4 /* 1: Machine check */
+ addi r4,r3,DataStorage - _start + _START_OFFSET
+ mtspr IVOR2,r4 /* 2: Data storage */
+ addi r4,r3,InstStorage - _start + _START_OFFSET
+ mtspr IVOR3,r4 /* 3: Instruction storage */
+ addi r4,r3,ExtInterrupt - _start + _START_OFFSET
+ mtspr IVOR4,r4 /* 4: External interrupt */
+ addi r4,r3,Alignment - _start + _START_OFFSET
+ mtspr IVOR5,r4 /* 5: Alignment */
+ addi r4,r3,ProgramCheck - _start + _START_OFFSET
+ mtspr IVOR6,r4 /* 6: Program check */
+ addi r4,r3,FPUnavailable - _start + _START_OFFSET
+ mtspr IVOR7,r4 /* 7: floating point unavailable */
+ addi r4,r3,SystemCall - _start + _START_OFFSET
+ mtspr IVOR8,r4 /* 8: System call */
+ /* 9: Auxiliary processor unavailable(unsupported) */
+ addi r4,r3,Decrementer - _start + _START_OFFSET
+ mtspr IVOR10,r4 /* 10: Decrementer */
+ addi r4,r3,IntervalTimer - _start + _START_OFFSET
+ mtspr IVOR11,r4 /* 11: Interval timer */
+ addi r4,r3,WatchdogTimer - _start + _START_OFFSET
+ mtspr IVOR12,r4 /* 12: Watchdog timer */
+ addi r4,r3,DataTLBError - _start + _START_OFFSET
+ mtspr IVOR13,r4 /* 13: Data TLB error */
+ addi r4,r3,InstructionTLBError - _start + _START_OFFSET
+ mtspr IVOR14,r4 /* 14: Instruction TLB error */
+ addi r4,r3,DebugBreakpoint - _start + _START_OFFSET
+ mtspr IVOR15,r4 /* 15: Debug */
+#endif
+
+ /* Clear and set up some registers. */
+ li r0,0x0000
+ lis r1,0xffff
+ mtspr DEC,r0 /* prevent dec exceptions */
+ mttbl r0 /* prevent fit & wdt exceptions */
+ mttbu r0
+ mtspr TSR,r1 /* clear all timer exception status */
+ mtspr TCR,r0 /* disable all */
+ mtspr ESR,r0 /* clear exception syndrome register */
+ mtspr MCSR,r0 /* machine check syndrome register */
+ mtxer r0 /* clear integer exception register */
+
+#ifdef CONFIG_SYS_BOOK3E_HV
+ mtspr MAS8,r0 /* make sure MAS8 is clear */
+#endif
+
+ /* Enable Time Base and Select Time Base Clock */
+ lis r0,HID0_EMCP@h /* Enable machine check */
+#if defined(CONFIG_ENABLE_36BIT_PHYS)
+ ori r0,r0,HID0_ENMAS7@l /* Enable MAS7 */
+#endif
+#ifndef CONFIG_E500MC
+ ori r0,r0,HID0_TBEN@l /* Enable Timebase */
+#endif
+ mtspr HID0,r0
+
+#ifndef CONFIG_E500MC
+ li r0,(HID1_ASTME|HID1_ABE)@l /* Addr streaming & broadcast */
+ mfspr r3,PVR
+ andi. r3,r3, 0xff
+ cmpwi r3,0x50@l /* if we are rev 5.0 or greater set MBDD */
+ blt 1f
+ /* Set MBDD bit also */
+ ori r0, r0, HID1_MBDD@l
+1:
+ mtspr HID1,r0
+#endif
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_CPU_A003999
+ mfspr r3,SPRN_HDBCR1
+ oris r3,r3,0x0100
+ mtspr SPRN_HDBCR1,r3
+#endif
+
+ /* Enable Branch Prediction */
+#if defined(CONFIG_BTB)
+ lis r0,BUCSR_ENABLE@h
+ ori r0,r0,BUCSR_ENABLE@l
+ mtspr SPRN_BUCSR,r0
+#endif
+
+#if defined(CONFIG_SYS_INIT_DBCR)
+ lis r1,0xffff
+ ori r1,r1,0xffff
+ mtspr DBSR,r1 /* Clear all status bits */
+ lis r0,CONFIG_SYS_INIT_DBCR@h /* DBCR0[IDM] must be set */
+ ori r0,r0,CONFIG_SYS_INIT_DBCR@l
+ mtspr DBCR0,r0
+#endif
+
+#ifdef CONFIG_MPC8569
+#define CONFIG_SYS_LBC_ADDR (CONFIG_SYS_CCSRBAR_DEFAULT + 0x5000)
+#define CONFIG_SYS_LBCR_ADDR (CONFIG_SYS_LBC_ADDR + 0xd0)
+
+ /* MPC8569 Rev.0 silcon needs to set bit 13 of LBCR to allow elBC to
+ * use address space which is more than 12bits, and it must be done in
+ * the 4K boot page. So we set this bit here.
+ */
+
+ /* create a temp mapping TLB0[0] for LBCR */
+ create_tlb0_entry 0, \
+ 0, BOOKE_PAGESZ_4K, \
+ CONFIG_SYS_LBC_ADDR, MAS2_I|MAS2_G, \
+ CONFIG_SYS_LBC_ADDR, MAS3_SW|MAS3_SR, \
+ 0, r6
+
+ /* Set LBCR register */
+ lis r4,CONFIG_SYS_LBCR_ADDR@h
+ ori r4,r4,CONFIG_SYS_LBCR_ADDR@l
+
+ lis r5,CONFIG_SYS_LBC_LBCR@h
+ ori r5,r5,CONFIG_SYS_LBC_LBCR@l
+ stw r5,0(r4)
+ isync
+
+ /* invalidate this temp TLB */
+ lis r4,CONFIG_SYS_LBC_ADDR@h
+ ori r4,r4,CONFIG_SYS_LBC_ADDR@l
+ tlbivax 0,r4
+ isync
+
+#endif /* CONFIG_MPC8569 */
+
+/*
+ * Search for the TLB that covers the code we're executing, and shrink it
+ * so that it covers only this 4K page. That will ensure that any other
+ * TLB we create won't interfere with it. We assume that the TLB exists,
+ * which is why we don't check the Valid bit of MAS1. We also assume
+ * it is in TLB1.
+ *
+ * This is necessary, for example, when booting from the on-chip ROM,
+ * which (oddly) creates a single 4GB TLB that covers CCSR and DDR.
+ */
+ bl nexti /* Find our address */
+nexti: mflr r1 /* R1 = our PC */
+ li r2, 0
+ mtspr MAS6, r2 /* Assume the current PID and AS are 0 */
+ isync
+ msync
+ tlbsx 0, r1 /* This must succeed */
+
+ mfspr r14, MAS0 /* Save ESEL for later */
+ rlwinm r14, r14, 16, 0xfff
+
+ /* Set the size of the TLB to 4KB */
+ mfspr r3, MAS1
+ li r2, 0xF80
+ andc r3, r3, r2 /* Clear the TSIZE bits */
+ ori r3, r3, MAS1_TSIZE(BOOKE_PAGESZ_4K)@l
+ oris r3, r3, MAS1_IPROT@h
+ mtspr MAS1, r3
+
+ /*
+ * Set the base address of the TLB to our PC. We assume that
+ * virtual == physical. We also assume that MAS2_EPN == MAS3_RPN.
+ */
+ lis r3, MAS2_EPN@h
+ ori r3, r3, MAS2_EPN@l /* R3 = MAS2_EPN */
+
+ and r1, r1, r3 /* Our PC, rounded down to the nearest page */
+
+ mfspr r2, MAS2
+ andc r2, r2, r3
+ or r2, r2, r1
+#ifdef CONFIG_SYS_FSL_ERRATUM_A004510
+ cmpwi r27,0
+ beq 1f
+ andi. r15, r2, MAS2_I|MAS2_G /* save the old I/G for later */
+ rlwinm r2, r2, 0, ~MAS2_I
+ ori r2, r2, MAS2_G
+1:
+#endif
+ mtspr MAS2, r2 /* Set the EPN to our PC base address */
+
+ mfspr r2, MAS3
+ andc r2, r2, r3
+ or r2, r2, r1
+ mtspr MAS3, r2 /* Set the RPN to our PC base address */
+
+ isync
+ msync
+ tlbwe
+
+/*
+ * Clear out any other TLB entries that may exist, to avoid conflicts.
+ * Our TLB entry is in r14.
+ */
+ li r0, TLBIVAX_ALL | TLBIVAX_TLB0
+ tlbivax 0, r0
+ tlbsync
+
+ mfspr r4, SPRN_TLB1CFG
+ rlwinm r4, r4, 0, TLBnCFG_NENTRY_MASK
+
+ li r3, 0
+ mtspr MAS1, r3
+1: cmpw r3, r14
+ rlwinm r5, r3, 16, MAS0_ESEL_MSK
+ addi r3, r3, 1
+ beq 2f /* skip the entry we're executing from */
+
+ oris r5, r5, MAS0_TLBSEL(1)@h
+ mtspr MAS0, r5
+
+ isync
+ tlbwe
+ isync
+ msync
+
+2: cmpw r3, r4
+ blt 1b
+
+#if defined(CONFIG_SYS_PPC_E500_DEBUG_TLB) && !defined(MINIMAL_SPL)
+/*
+ * TLB entry for debuggging in AS1
+ * Create temporary TLB entry in AS0 to handle debug exception
+ * As on debug exception MSR is cleared i.e. Address space is changed
+ * to 0. A TLB entry (in AS0) is required to handle debug exception generated
+ * in AS1.
+ */
+
+#ifdef NOR_BOOT
+/*
+ * TLB entry is created for IVPR + IVOR15 to map on valid OP code address
+ * bacause flash's virtual address maps to 0xff800000 - 0xffffffff.
+ * and this window is outside of 4K boot window.
+ */
+ create_tlb1_entry CONFIG_SYS_PPC_E500_DEBUG_TLB, \
+ 0, BOOKE_PAGESZ_4M, \
+ CONFIG_SYS_MONITOR_BASE & 0xffc00000, MAS2_I|MAS2_G, \
+ 0xffc00000, MAS3_SX|MAS3_SW|MAS3_SR, \
+ 0, r6
+
+#elif !defined(CONFIG_SYS_RAMBOOT) && defined(CONFIG_SECURE_BOOT)
+ create_tlb1_entry CONFIG_SYS_PPC_E500_DEBUG_TLB, \
+ 0, BOOKE_PAGESZ_1M, \
+ CONFIG_SYS_MONITOR_BASE, MAS2_I|MAS2_G, \
+ CONFIG_SYS_PBI_FLASH_WINDOW, MAS3_SX|MAS3_SW|MAS3_SR, \
+ 0, r6
+#else
+/*
+ * TLB entry is created for IVPR + IVOR15 to map on valid OP code address
+ * because "nexti" will resize TLB to 4K
+ */
+ create_tlb1_entry CONFIG_SYS_PPC_E500_DEBUG_TLB, \
+ 0, BOOKE_PAGESZ_256K, \
+ CONFIG_SYS_MONITOR_BASE & 0xfffc0000, MAS2_I, \
+ CONFIG_SYS_MONITOR_BASE & 0xfffc0000, MAS3_SX|MAS3_SW|MAS3_SR, \
+ 0, r6
+#endif
+#endif
+
+/*
+ * Relocate CCSR, if necessary. We relocate CCSR if (obviously) the default
+ * location is not where we want it. This typically happens on a 36-bit
+ * system, where we want to move CCSR to near the top of 36-bit address space.
+ *
+ * To move CCSR, we create two temporary TLBs, one for the old location, and
+ * another for the new location. On CoreNet systems, we also need to create
+ * a special, temporary LAW.
+ *
+ * As a general rule, TLB0 is used for short-term TLBs, and TLB1 is used for
+ * long-term TLBs, so we use TLB0 here.
+ */
+#if (CONFIG_SYS_CCSRBAR_DEFAULT != CONFIG_SYS_CCSRBAR_PHYS)
+
+#if !defined(CONFIG_SYS_CCSRBAR_PHYS_HIGH) || !defined(CONFIG_SYS_CCSRBAR_PHYS_LOW)
+#error "CONFIG_SYS_CCSRBAR_PHYS_HIGH and CONFIG_SYS_CCSRBAR_PHYS_LOW) must be defined."
+#endif
+
+create_ccsr_new_tlb:
+ /*
+ * Create a TLB for the new location of CCSR. Register R8 is reserved
+ * for the virtual address of this TLB (CONFIG_SYS_CCSRBAR).
+ */
+ lis r8, CONFIG_SYS_CCSRBAR@h
+ ori r8, r8, CONFIG_SYS_CCSRBAR@l
+ lis r9, (CONFIG_SYS_CCSRBAR + 0x1000)@h
+ ori r9, r9, (CONFIG_SYS_CCSRBAR + 0x1000)@l
+ create_tlb0_entry 0, \
+ 0, BOOKE_PAGESZ_4K, \
+ CONFIG_SYS_CCSRBAR, MAS2_I|MAS2_G, \
+ CONFIG_SYS_CCSRBAR_PHYS_LOW, MAS3_SW|MAS3_SR, \
+ CONFIG_SYS_CCSRBAR_PHYS_HIGH, r3
+ /*
+ * Create a TLB for the current location of CCSR. Register R9 is reserved
+ * for the virtual address of this TLB (CONFIG_SYS_CCSRBAR + 0x1000).
+ */
+create_ccsr_old_tlb:
+ create_tlb0_entry 1, \
+ 0, BOOKE_PAGESZ_4K, \
+ CONFIG_SYS_CCSRBAR + 0x1000, MAS2_I|MAS2_G, \
+ CONFIG_SYS_CCSRBAR_DEFAULT, MAS3_SW|MAS3_SR, \
+ 0, r3 /* The default CCSR address is always a 32-bit number */
+
+
+ /*
+ * We have a TLB for what we think is the current (old) CCSR. Let's
+ * verify that, otherwise we won't be able to move it.
+ * CONFIG_SYS_CCSRBAR_DEFAULT is always a 32-bit number, so we only
+ * need to compare the lower 32 bits of CCSRBAR on CoreNet systems.
+ */
+verify_old_ccsr:
+ lis r0, CONFIG_SYS_CCSRBAR_DEFAULT@h
+ ori r0, r0, CONFIG_SYS_CCSRBAR_DEFAULT@l
+#ifdef CONFIG_FSL_CORENET
+ lwz r1, 4(r9) /* CCSRBARL */
+#else
+ lwz r1, 0(r9) /* CCSRBAR, shifted right by 12 */
+ slwi r1, r1, 12
+#endif
+
+ cmpl 0, r0, r1
+
+ /*
+ * If the value we read from CCSRBARL is not what we expect, then
+ * enter an infinite loop. This will at least allow a debugger to
+ * halt execution and examine TLBs, etc. There's no point in going
+ * on.
+ */
+infinite_debug_loop:
+ bne infinite_debug_loop
+
+#ifdef CONFIG_FSL_CORENET
+
+#define CCSR_LAWBARH0 (CONFIG_SYS_CCSRBAR + 0x1000)
+#define LAW_EN 0x80000000
+#define LAW_SIZE_4K 0xb
+#define CCSRBAR_LAWAR (LAW_EN | (0x1e << 20) | LAW_SIZE_4K)
+#define CCSRAR_C 0x80000000 /* Commit */
+
+create_temp_law:
+ /*
+ * On CoreNet systems, we create the temporary LAW using a special LAW
+ * target ID of 0x1e. LAWBARH is at offset 0xc00 in CCSR.
+ */
+ lis r0, CONFIG_SYS_CCSRBAR_PHYS_HIGH@h
+ ori r0, r0, CONFIG_SYS_CCSRBAR_PHYS_HIGH@l
+ lis r1, CONFIG_SYS_CCSRBAR_PHYS_LOW@h
+ ori r1, r1, CONFIG_SYS_CCSRBAR_PHYS_LOW@l
+ lis r2, CCSRBAR_LAWAR@h
+ ori r2, r2, CCSRBAR_LAWAR@l
+
+ stw r0, 0xc00(r9) /* LAWBARH0 */
+ stw r1, 0xc04(r9) /* LAWBARL0 */
+ sync
+ stw r2, 0xc08(r9) /* LAWAR0 */
+
+ /*
+ * Read back from LAWAR to ensure the update is complete. e500mc
+ * cores also require an isync.
+ */
+ lwz r0, 0xc08(r9) /* LAWAR0 */
+ isync
+
+ /*
+ * Read the current CCSRBARH and CCSRBARL using load word instructions.
+ * Follow this with an isync instruction. This forces any outstanding
+ * accesses to configuration space to completion.
+ */
+read_old_ccsrbar:
+ lwz r0, 0(r9) /* CCSRBARH */
+ lwz r0, 4(r9) /* CCSRBARL */
+ isync
+
+ /*
+ * Write the new values for CCSRBARH and CCSRBARL to their old
+ * locations. The CCSRBARH has a shadow register. When the CCSRBARH
+ * has a new value written it loads a CCSRBARH shadow register. When
+ * the CCSRBARL is written, the CCSRBARH shadow register contents
+ * along with the CCSRBARL value are loaded into the CCSRBARH and
+ * CCSRBARL registers, respectively. Follow this with a sync
+ * instruction.
+ */
+write_new_ccsrbar:
+ lis r0, CONFIG_SYS_CCSRBAR_PHYS_HIGH@h
+ ori r0, r0, CONFIG_SYS_CCSRBAR_PHYS_HIGH@l
+ lis r1, CONFIG_SYS_CCSRBAR_PHYS_LOW@h
+ ori r1, r1, CONFIG_SYS_CCSRBAR_PHYS_LOW@l
+ lis r2, CCSRAR_C@h
+ ori r2, r2, CCSRAR_C@l
+
+ stw r0, 0(r9) /* Write to CCSRBARH */
+ sync /* Make sure we write to CCSRBARH first */
+ stw r1, 4(r9) /* Write to CCSRBARL */
+ sync
+
+ /*
+ * Write a 1 to the commit bit (C) of CCSRAR at the old location.
+ * Follow this with a sync instruction.
+ */
+ stw r2, 8(r9)
+ sync
+
+ /* Delete the temporary LAW */
+delete_temp_law:
+ li r1, 0
+ stw r1, 0xc08(r8)
+ sync
+ stw r1, 0xc00(r8)
+ stw r1, 0xc04(r8)
+ sync
+
+#else /* #ifdef CONFIG_FSL_CORENET */
+
+write_new_ccsrbar:
+ /*
+ * Read the current value of CCSRBAR using a load word instruction
+ * followed by an isync. This forces all accesses to configuration
+ * space to complete.
+ */
+ sync
+ lwz r0, 0(r9)
+ isync
+
+/* CONFIG_SYS_CCSRBAR_PHYS right shifted by 12 */
+#define CCSRBAR_PHYS_RS12 ((CONFIG_SYS_CCSRBAR_PHYS_HIGH << 20) | \
+ (CONFIG_SYS_CCSRBAR_PHYS_LOW >> 12))
+
+ /* Write the new value to CCSRBAR. */
+ lis r0, CCSRBAR_PHYS_RS12@h
+ ori r0, r0, CCSRBAR_PHYS_RS12@l
+ stw r0, 0(r9)
+ sync
+
+ /*
+ * The manual says to perform a load of an address that does not
+ * access configuration space or the on-chip SRAM using an existing TLB,
+ * but that doesn't appear to be necessary. We will do the isync,
+ * though.
+ */
+ isync
+
+ /*
+ * Read the contents of CCSRBAR from its new location, followed by
+ * another isync.
+ */
+ lwz r0, 0(r8)
+ isync
+
+#endif /* #ifdef CONFIG_FSL_CORENET */
+
+ /* Delete the temporary TLBs */
+delete_temp_tlbs:
+ delete_tlb0_entry 0, CONFIG_SYS_CCSRBAR, MAS2_I|MAS2_G, r3
+ delete_tlb0_entry 1, CONFIG_SYS_CCSRBAR + 0x1000, MAS2_I|MAS2_G, r3
+
+#endif /* #if (CONFIG_SYS_CCSRBAR_DEFAULT != CONFIG_SYS_CCSRBAR_PHYS) */
+
+#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2
+create_ccsr_l2_tlb:
+ /*
+ * Create a TLB for the MMR location of CCSR
+ * to access L2CSR0 register
+ */
+ create_tlb0_entry 0, \
+ 0, BOOKE_PAGESZ_4K, \
+ CONFIG_SYS_CCSRBAR + 0xC20000, MAS2_I|MAS2_G, \
+ CONFIG_SYS_CCSRBAR_PHYS_LOW + 0xC20000, MAS3_SW|MAS3_SR, \
+ CONFIG_SYS_CCSRBAR_PHYS_HIGH, r3
+
+enable_l2_cluster_l2:
+ /* enable L2 cache */
+ lis r3, (CONFIG_SYS_CCSRBAR + 0xC20000)@h
+ ori r3, r3, (CONFIG_SYS_CCSRBAR + 0xC20000)@l
+ li r4, 33 /* stash id */
+ stw r4, 4(r3)
+ lis r4, (L2CSR0_L2FI|L2CSR0_L2LFC)@h
+ ori r4, r4, (L2CSR0_L2FI|L2CSR0_L2LFC)@l
+ sync
+ stw r4, 0(r3) /* invalidate L2 */
+1: sync
+ lwz r0, 0(r3)
+ twi 0, r0, 0
+ isync
+ and. r1, r0, r4
+ bne 1b
+ lis r4, (L2CSR0_L2E|L2CSR0_L2PE)@h
+ ori r4, r4, (L2CSR0_L2REP_MODE)@l
+ sync
+ stw r4, 0(r3) /* enable L2 */
+delete_ccsr_l2_tlb:
+ delete_tlb0_entry 0, CONFIG_SYS_CCSRBAR + 0xC20000, MAS2_I|MAS2_G, r3
+#endif
+
+ /*
+ * Enable the L1. On e6500, this has to be done
+ * after the L2 is up.
+ */
+
+#ifdef CONFIG_SYS_CACHE_STASHING
+ /* set stash id to (coreID) * 2 + 32 + L1 CT (0) */
+ li r2,(32 + 0)
+ mtspr L1CSR2,r2
+#endif
+
+ /* Enable/invalidate the I-Cache */
+ lis r2,(L1CSR1_ICFI|L1CSR1_ICLFR)@h
+ ori r2,r2,(L1CSR1_ICFI|L1CSR1_ICLFR)@l
+ mtspr SPRN_L1CSR1,r2
+1:
+ mfspr r3,SPRN_L1CSR1
+ and. r1,r3,r2
+ bne 1b
+
+ lis r3,(L1CSR1_CPE|L1CSR1_ICE)@h
+ ori r3,r3,(L1CSR1_CPE|L1CSR1_ICE)@l
+ mtspr SPRN_L1CSR1,r3
+ isync
+2:
+ mfspr r3,SPRN_L1CSR1
+ andi. r1,r3,L1CSR1_ICE@l
+ beq 2b
+
+ /* Enable/invalidate the D-Cache */
+ lis r2,(L1CSR0_DCFI|L1CSR0_DCLFR)@h
+ ori r2,r2,(L1CSR0_DCFI|L1CSR0_DCLFR)@l
+ mtspr SPRN_L1CSR0,r2
+1:
+ mfspr r3,SPRN_L1CSR0
+ and. r1,r3,r2
+ bne 1b
+
+ lis r3,(L1CSR0_CPE|L1CSR0_DCE)@h
+ ori r3,r3,(L1CSR0_CPE|L1CSR0_DCE)@l
+ mtspr SPRN_L1CSR0,r3
+ isync
+2:
+ mfspr r3,SPRN_L1CSR0
+ andi. r1,r3,L1CSR0_DCE@l
+ beq 2b
+#ifdef CONFIG_SYS_FSL_ERRATUM_A004510
+#define DCSR_LAWBARH0 (CONFIG_SYS_CCSRBAR + 0x1000)
+#define LAW_SIZE_1M 0x13
+#define DCSRBAR_LAWAR (LAW_EN | (0x1d << 20) | LAW_SIZE_1M)
+
+ cmpwi r27,0
+ beq 9f
+
+ /*
+ * Create a TLB entry for CCSR
+ *
+ * We're executing out of TLB1 entry in r14, and that's the only
+ * TLB entry that exists. To allocate some TLB entries for our
+ * own use, flip a bit high enough that we won't flip it again
+ * via incrementing.
+ */
+
+ xori r8, r14, 32
+ lis r0, MAS0_TLBSEL(1)@h
+ rlwimi r0, r8, 16, MAS0_ESEL_MSK
+ lis r1, FSL_BOOKE_MAS1(1, 1, 0, 0, BOOKE_PAGESZ_16M)@h
+ ori r1, r1, FSL_BOOKE_MAS1(1, 1, 0, 0, BOOKE_PAGESZ_16M)@l
+ lis r7, CONFIG_SYS_CCSRBAR@h
+ ori r7, r7, CONFIG_SYS_CCSRBAR@l
+ ori r2, r7, MAS2_I|MAS2_G
+ lis r3, FSL_BOOKE_MAS3(CONFIG_SYS_CCSRBAR_PHYS_LOW, 0, (MAS3_SW|MAS3_SR))@h
+ ori r3, r3, FSL_BOOKE_MAS3(CONFIG_SYS_CCSRBAR_PHYS_LOW, 0, (MAS3_SW|MAS3_SR))@l
+ lis r4, CONFIG_SYS_CCSRBAR_PHYS_HIGH@h
+ ori r4, r4, CONFIG_SYS_CCSRBAR_PHYS_HIGH@l
+ mtspr MAS0, r0
+ mtspr MAS1, r1
+ mtspr MAS2, r2
+ mtspr MAS3, r3
+ mtspr MAS7, r4
+ isync
+ tlbwe
+ isync
+ msync
+
+ /* Map DCSR temporarily to physical address zero */
+ li r0, 0
+ lis r3, DCSRBAR_LAWAR@h
+ ori r3, r3, DCSRBAR_LAWAR@l
+
+ stw r0, 0xc00(r7) /* LAWBARH0 */
+ stw r0, 0xc04(r7) /* LAWBARL0 */
+ sync
+ stw r3, 0xc08(r7) /* LAWAR0 */
+
+ /* Read back from LAWAR to ensure the update is complete. */
+ lwz r3, 0xc08(r7) /* LAWAR0 */
+ isync
+
+ /* Create a TLB entry for DCSR at zero */
+
+ addi r9, r8, 1
+ lis r0, MAS0_TLBSEL(1)@h
+ rlwimi r0, r9, 16, MAS0_ESEL_MSK
+ lis r1, FSL_BOOKE_MAS1(1, 1, 0, 0, BOOKE_PAGESZ_1M)@h
+ ori r1, r1, FSL_BOOKE_MAS1(1, 1, 0, 0, BOOKE_PAGESZ_1M)@l
+ li r6, 0 /* DCSR effective address */
+ ori r2, r6, MAS2_I|MAS2_G
+ li r3, MAS3_SW|MAS3_SR
+ li r4, 0
+ mtspr MAS0, r0
+ mtspr MAS1, r1
+ mtspr MAS2, r2
+ mtspr MAS3, r3
+ mtspr MAS7, r4
+ isync
+ tlbwe
+ isync
+ msync
+
+ /* enable the timebase */
+#define CTBENR 0xe2084
+ li r3, 1
+ addis r4, r7, CTBENR@ha
+ stw r3, CTBENR@l(r4)
+ lwz r3, CTBENR@l(r4)
+ twi 0,r3,0
+ isync
+
+ .macro erratum_set_ccsr offset value
+ addis r3, r7, \offset@ha
+ lis r4, \value@h
+ addi r3, r3, \offset@l
+ ori r4, r4, \value@l
+ bl erratum_set_value
+ .endm
+
+ .macro erratum_set_dcsr offset value
+ addis r3, r6, \offset@ha
+ lis r4, \value@h
+ addi r3, r3, \offset@l
+ ori r4, r4, \value@l
+ bl erratum_set_value
+ .endm
+
+ erratum_set_dcsr 0xb0e08 0xe0201800
+ erratum_set_dcsr 0xb0e18 0xe0201800
+ erratum_set_dcsr 0xb0e38 0xe0400000
+ erratum_set_dcsr 0xb0008 0x00900000
+ erratum_set_dcsr 0xb0e40 0xe00a0000
+ erratum_set_ccsr 0x18600 CONFIG_SYS_FSL_CORENET_SNOOPVEC_COREONLY
+ erratum_set_ccsr 0x10f00 0x415e5000
+ erratum_set_ccsr 0x11f00 0x415e5000
+
+ /* Make temp mapping uncacheable again, if it was initially */
+ bl 2f
+2: mflr r3
+ tlbsx 0, r3
+ mfspr r4, MAS2
+ rlwimi r4, r15, 0, MAS2_I
+ rlwimi r4, r15, 0, MAS2_G
+ mtspr MAS2, r4
+ isync
+ tlbwe
+ isync
+ msync
+
+ /* Clear the cache */
+ lis r3,(L1CSR1_ICFI|L1CSR1_ICLFR)@h
+ ori r3,r3,(L1CSR1_ICFI|L1CSR1_ICLFR)@l
+ sync
+ isync
+ mtspr SPRN_L1CSR1,r3
+ isync
+2: sync
+ mfspr r4,SPRN_L1CSR1
+ and. r4,r4,r3
+ bne 2b
+
+ lis r3,(L1CSR1_CPE|L1CSR1_ICE)@h
+ ori r3,r3,(L1CSR1_CPE|L1CSR1_ICE)@l
+ sync
+ isync
+ mtspr SPRN_L1CSR1,r3
+ isync
+2: sync
+ mfspr r4,SPRN_L1CSR1
+ and. r4,r4,r3
+ beq 2b
+
+ /* Remove temporary mappings */
+ lis r0, MAS0_TLBSEL(1)@h
+ rlwimi r0, r9, 16, MAS0_ESEL_MSK
+ li r3, 0
+ mtspr MAS0, r0
+ mtspr MAS1, r3
+ isync
+ tlbwe
+ isync
+ msync
+
+ li r3, 0
+ stw r3, 0xc08(r7) /* LAWAR0 */
+ lwz r3, 0xc08(r7)
+ isync
+
+ lis r0, MAS0_TLBSEL(1)@h
+ rlwimi r0, r8, 16, MAS0_ESEL_MSK
+ li r3, 0
+ mtspr MAS0, r0
+ mtspr MAS1, r3
+ isync
+ tlbwe
+ isync
+ msync
+
+ b 9f
+
+ /* r3 = addr, r4 = value, clobbers r5, r11, r12 */
+erratum_set_value:
+ /* Lock two cache lines into I-Cache */
+ sync
+ mfspr r11, SPRN_L1CSR1
+ rlwinm r11, r11, 0, ~L1CSR1_ICUL
+ sync
+ isync
+ mtspr SPRN_L1CSR1, r11
+ isync
+
+ mflr r12
+ bl 5f
+5: mflr r5
+ addi r5, r5, 2f - 5b
+ icbtls 0, 0, r5
+ addi r5, r5, 64
+
+ sync
+ mfspr r11, SPRN_L1CSR1
+3: andi. r11, r11, L1CSR1_ICUL
+ bne 3b
+
+ icbtls 0, 0, r5
+ addi r5, r5, 64
+
+ sync
+ mfspr r11, SPRN_L1CSR1
+3: andi. r11, r11, L1CSR1_ICUL
+ bne 3b
+
+ b 2f
+ .align 6
+ /* Inside a locked cacheline, wait a while, write, then wait a while */
+2: sync
+
+ mfspr r5, SPRN_TBRL
+ addis r11, r5, 0x10000@h /* wait 65536 timebase ticks */
+4: mfspr r5, SPRN_TBRL
+ subf. r5, r5, r11
+ bgt 4b
+
+ stw r4, 0(r3)
+
+ mfspr r5, SPRN_TBRL
+ addis r11, r5, 0x10000@h /* wait 65536 timebase ticks */
+4: mfspr r5, SPRN_TBRL
+ subf. r5, r5, r11
+ bgt 4b
+
+ sync
+
+ /*
+ * Fill out the rest of this cache line and the next with nops,
+ * to ensure that nothing outside the locked area will be
+ * fetched due to a branch.
+ */
+ .rept 19
+ nop
+ .endr
+
+ sync
+ mfspr r11, SPRN_L1CSR1
+ rlwinm r11, r11, 0, ~L1CSR1_ICUL
+ sync
+ isync
+ mtspr SPRN_L1CSR1, r11
+ isync
+
+ mtlr r12
+ blr
+
+9:
+#endif
+
+create_init_ram_area:
+ lis r6,FSL_BOOKE_MAS0(1, 15, 0)@h
+ ori r6,r6,FSL_BOOKE_MAS0(1, 15, 0)@l
+
+#ifdef NOR_BOOT
+ /* create a temp mapping in AS=1 to the 4M boot window */
+ create_tlb1_entry 15, \
+ 1, BOOKE_PAGESZ_4M, \
+ CONFIG_SYS_MONITOR_BASE & 0xffc00000, MAS2_I|MAS2_G, \
+ 0xffc00000, MAS3_SX|MAS3_SW|MAS3_SR, \
+ 0, r6
+
+#elif !defined(CONFIG_SYS_RAMBOOT) && defined(CONFIG_SECURE_BOOT)
+ /* create a temp mapping in AS = 1 for Flash mapping
+ * created by PBL for ISBC code
+ */
+ create_tlb1_entry 15, \
+ 1, BOOKE_PAGESZ_1M, \
+ CONFIG_SYS_MONITOR_BASE & 0xfff00000, MAS2_I|MAS2_G, \
+ CONFIG_SYS_PBI_FLASH_WINDOW & 0xfff00000, MAS3_SX|MAS3_SW|MAS3_SR, \
+ 0, r6
+#else
+ /*
+ * create a temp mapping in AS=1 to the 1M CONFIG_SYS_MONITOR_BASE space, the main
+ * image has been relocated to CONFIG_SYS_MONITOR_BASE on the second stage.
+ */
+ create_tlb1_entry 15, \
+ 1, BOOKE_PAGESZ_1M, \
+ CONFIG_SYS_MONITOR_BASE & 0xfff00000, MAS2_I|MAS2_G, \
+ CONFIG_SYS_MONITOR_BASE & 0xfff00000, MAS3_SX|MAS3_SW|MAS3_SR, \
+ 0, r6
+#endif
+
+ /* create a temp mapping in AS=1 to the stack */
+#if defined(CONFIG_SYS_INIT_RAM_ADDR_PHYS_LOW) && \
+ defined(CONFIG_SYS_INIT_RAM_ADDR_PHYS_HIGH)
+ create_tlb1_entry 14, \
+ 1, BOOKE_PAGESZ_16K, \
+ CONFIG_SYS_INIT_RAM_ADDR, 0, \
+ CONFIG_SYS_INIT_RAM_ADDR_PHYS_LOW, MAS3_SX|MAS3_SW|MAS3_SR, \
+ CONFIG_SYS_INIT_RAM_ADDR_PHYS_HIGH, r6
+
+#else
+ create_tlb1_entry 14, \
+ 1, BOOKE_PAGESZ_16K, \
+ CONFIG_SYS_INIT_RAM_ADDR, 0, \
+ CONFIG_SYS_INIT_RAM_ADDR, MAS3_SX|MAS3_SW|MAS3_SR, \
+ 0, r6
+#endif
+
+ lis r6,MSR_IS|MSR_DS|MSR_DE@h
+ ori r6,r6,MSR_IS|MSR_DS|MSR_DE@l
+ lis r7,switch_as@h
+ ori r7,r7,switch_as@l
+
+ mtspr SPRN_SRR0,r7
+ mtspr SPRN_SRR1,r6
+ rfi
+
+switch_as:
+/* L1 DCache is used for initial RAM */
+
+ /* Allocate Initial RAM in data cache.
+ */
+ lis r3,CONFIG_SYS_INIT_RAM_ADDR@h
+ ori r3,r3,CONFIG_SYS_INIT_RAM_ADDR@l
+ mfspr r2, L1CFG0
+ andi. r2, r2, 0x1ff
+ /* cache size * 1024 / (2 * L1 line size) */
+ slwi r2, r2, (10 - 1 - L1_CACHE_SHIFT)
+ mtctr r2
+ li r0,0
+1:
+ dcbz r0,r3
+ dcbtls 0,r0,r3
+ addi r3,r3,CONFIG_SYS_CACHELINE_SIZE
+ bdnz 1b
+
+ /* Jump out the last 4K page and continue to 'normal' start */
+#if defined(CONFIG_SYS_RAMBOOT) || defined(CONFIG_SPL)
+ /* We assume that we're already running at the address we're linked at */
+ b _start_cont
+#else
+ /* Calculate absolute address in FLASH and jump there */
+ /*--------------------------------------------------------------*/
+ lis r3,CONFIG_SYS_MONITOR_BASE@h
+ ori r3,r3,CONFIG_SYS_MONITOR_BASE@l
+ addi r3,r3,_start_cont - _start + _START_OFFSET
+ mtlr r3
+ blr
+#endif
+
+ .text
+ .globl _start
+_start:
+ .long 0x27051956 /* U-BOOT Magic Number */
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION_STRING, "\0"
+
+ .align 4
+ .globl _start_cont
+_start_cont:
+ /* Setup the stack in initial RAM,could be L2-as-SRAM or L1 dcache*/
+ lis r3,(CONFIG_SYS_INIT_RAM_ADDR)@h
+ ori r3,r3,((CONFIG_SYS_INIT_SP_OFFSET-16)&~0xf)@l /* Align to 16 */
+ li r0,0
+ stw r0,0(r3) /* Terminate Back Chain */
+ stw r0,+4(r3) /* NULL return address. */
+ mr r1,r3 /* Transfer to SP(r1) */
+
+ GET_GOT
+ bl cpu_init_early_f
+
+ /* switch back to AS = 0 */
+ lis r3,(MSR_CE|MSR_ME|MSR_DE)@h
+ ori r3,r3,(MSR_CE|MSR_ME|MSR_DE)@l
+ mtmsr r3
+ isync
+
+ bl cpu_init_f
+ bl board_init_f
+ isync
+
+ /* NOTREACHED - board_init_f() does not return */
+
+#ifndef MINIMAL_SPL
+ . = EXC_OFF_SYS_RESET
+ .globl _start_of_vectors
+_start_of_vectors:
+
+/* Critical input. */
+ CRIT_EXCEPTION(0x0100, CriticalInput, CritcalInputException)
+
+/* Machine check */
+ MCK_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. */
+ STD_EXCEPTION(0x0300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+ STD_EXCEPTION(0x0400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+ STD_EXCEPTION(0x0500, ExtInterrupt, ExtIntException)
+
+/* Alignment exception. */
+ . = 0x0600
+Alignment:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+ . = 0x0700
+ProgramCheck:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+ MSR_KERNEL, COPY_EE)
+
+ /* No FPU on MPC85xx. This exception is not supposed to happen.
+ */
+ STD_EXCEPTION(0x0800, FPUnavailable, UnknownException)
+
+ . = 0x0900
+/*
+ * r0 - SYSCALL number
+ * r3-... arguments
+ */
+SystemCall:
+ addis r11,r0,0 /* get functions table addr */
+ ori r11,r11,0 /* Note: this code is patched in trap_init */
+ addis r12,r0,0 /* get number of functions */
+ ori r12,r12,0
+
+ cmplw 0,r0,r12
+ bge 1f
+
+ rlwinm r0,r0,2,0,31 /* fn_addr = fn_tbl[r0] */
+ add r11,r11,r0
+ lwz r11,0(r11)
+
+ li r20,0xd00-4 /* Get stack pointer */
+ lwz r12,0(r20)
+ subi r12,r12,12 /* Adjust stack pointer */
+ li r0,0xc00+_end_back-SystemCall
+ cmplw 0,r0,r12 /* Check stack overflow */
+ bgt 1f
+ stw r12,0(r20)
+
+ mflr r0
+ stw r0,0(r12)
+ mfspr r0,SRR0
+ stw r0,4(r12)
+ mfspr r0,SRR1
+ stw r0,8(r12)
+
+ li r12,0xc00+_back-SystemCall
+ mtlr r12
+ mtspr SRR0,r11
+
+1: SYNC
+ rfi
+_back:
+
+ mfmsr r11 /* Disable interrupts */
+ li r12,0
+ ori r12,r12,MSR_EE
+ andc r11,r11,r12
+ SYNC /* Some chip revs need this... */
+ mtmsr r11
+ SYNC
+
+ li r12,0xd00-4 /* restore regs */
+ lwz r12,0(r12)
+
+ lwz r11,0(r12)
+ mtlr r11
+ lwz r11,4(r12)
+ mtspr SRR0,r11
+ lwz r11,8(r12)
+ mtspr SRR1,r11
+
+ addi r12,r12,12 /* Adjust stack pointer */
+ li r20,0xd00-4
+ stw r12,0(r20)
+
+ SYNC
+ rfi
+_end_back:
+
+ STD_EXCEPTION(0x0a00, Decrementer, timer_interrupt)
+ STD_EXCEPTION(0x0b00, IntervalTimer, UnknownException)
+ STD_EXCEPTION(0x0c00, WatchdogTimer, UnknownException)
+
+ STD_EXCEPTION(0x0d00, DataTLBError, UnknownException)
+ STD_EXCEPTION(0x0e00, InstructionTLBError, UnknownException)
+
+ CRIT_EXCEPTION(0x0f00, DebugBreakpoint, DebugException )
+
+ .globl _end_of_vectors
+_end_of_vectors:
+
+
+ . = . + (0x100 - ( . & 0xff )) /* align for debug */
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+ .globl transfer_to_handler
+transfer_to_handler:
+ stw r22,_NIP(r21)
+ lis r22,MSR_POW@h
+ andc r23,r23,r22
+ stw r23,_MSR(r21)
+ SAVE_GPR(7, r21)
+ SAVE_4GPRS(8, r21)
+ SAVE_8GPRS(12, r21)
+ SAVE_8GPRS(24, r21)
+
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ mtspr SPRG2,r22 /* r1 is now kernel sp */
+
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
+
+int_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+
+crit_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SPRN_CSRR0,r2
+ mtspr SPRN_CSRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfci
+
+mck_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SPRN_MCSRR0,r2
+ mtspr SPRN_MCSRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfmci
+
+/* Cache functions.
+*/
+.globl flush_icache
+flush_icache:
+.globl invalidate_icache
+invalidate_icache:
+ mfspr r0,L1CSR1
+ ori r0,r0,L1CSR1_ICFI
+ msync
+ isync
+ mtspr L1CSR1,r0
+ isync
+ blr /* entire I cache */
+
+.globl invalidate_dcache
+invalidate_dcache:
+ mfspr r0,L1CSR0
+ ori r0,r0,L1CSR0_DCFI
+ msync
+ isync
+ mtspr L1CSR0,r0
+ isync
+ blr
+
+ .globl icache_enable
+icache_enable:
+ mflr r8
+ bl invalidate_icache
+ mtlr r8
+ isync
+ mfspr r4,L1CSR1
+ ori r4,r4,0x0001
+ oris r4,r4,0x0001
+ mtspr L1CSR1,r4
+ isync
+ blr
+
+ .globl icache_disable
+icache_disable:
+ mfspr r0,L1CSR1
+ lis r3,0
+ ori r3,r3,L1CSR1_ICE
+ andc r0,r0,r3
+ mtspr L1CSR1,r0
+ isync
+ blr
+
+ .globl icache_status
+icache_status:
+ mfspr r3,L1CSR1
+ andi. r3,r3,L1CSR1_ICE
+ blr
+
+ .globl dcache_enable
+dcache_enable:
+ mflr r8
+ bl invalidate_dcache
+ mtlr r8
+ isync
+ mfspr r0,L1CSR0
+ ori r0,r0,0x0001
+ oris r0,r0,0x0001
+ msync
+ isync
+ mtspr L1CSR0,r0
+ isync
+ blr
+
+ .globl dcache_disable
+dcache_disable:
+ mfspr r3,L1CSR0
+ lis r4,0
+ ori r4,r4,L1CSR0_DCE
+ andc r3,r3,r4
+ mtspr L1CSR0,r3
+ isync
+ blr
+
+ .globl dcache_status
+dcache_status:
+ mfspr r3,L1CSR0
+ andi. r3,r3,L1CSR0_DCE
+ blr
+
+ .globl get_pir
+get_pir:
+ mfspr r3,PIR
+ blr
+
+ .globl get_pvr
+get_pvr:
+ mfspr r3,PVR
+ blr
+
+ .globl get_svr
+get_svr:
+ mfspr r3,SVR
+ blr
+
+ .globl wr_tcr
+wr_tcr:
+ mtspr TCR,r3
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: in8 */
+/* Description: Input 8 bits */
+/*------------------------------------------------------------------------------- */
+ .globl in8
+in8:
+ lbz r3,0x0000(r3)
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: out8 */
+/* Description: Output 8 bits */
+/*------------------------------------------------------------------------------- */
+ .globl out8
+out8:
+ stb r4,0x0000(r3)
+ sync
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: out16 */
+/* Description: Output 16 bits */
+/*------------------------------------------------------------------------------- */
+ .globl out16
+out16:
+ sth r4,0x0000(r3)
+ sync
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: out16r */
+/* Description: Byte reverse and output 16 bits */
+/*------------------------------------------------------------------------------- */
+ .globl out16r
+out16r:
+ sthbrx r4,r0,r3
+ sync
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: out32 */
+/* Description: Output 32 bits */
+/*------------------------------------------------------------------------------- */
+ .globl out32
+out32:
+ stw r4,0x0000(r3)
+ sync
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: out32r */
+/* Description: Byte reverse and output 32 bits */
+/*------------------------------------------------------------------------------- */
+ .globl out32r
+out32r:
+ stwbrx r4,r0,r3
+ sync
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: in16 */
+/* Description: Input 16 bits */
+/*------------------------------------------------------------------------------- */
+ .globl in16
+in16:
+ lhz r3,0x0000(r3)
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: in16r */
+/* Description: Input 16 bits and byte reverse */
+/*------------------------------------------------------------------------------- */
+ .globl in16r
+in16r:
+ lhbrx r3,r0,r3
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: in32 */
+/* Description: Input 32 bits */
+/*------------------------------------------------------------------------------- */
+ .globl in32
+in32:
+ lwz 3,0x0000(3)
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: in32r */
+/* Description: Input 32 bits and byte reverse */
+/*------------------------------------------------------------------------------- */
+ .globl in32r
+in32r:
+ lwbrx r3,r0,r3
+ blr
+#endif /* !MINIMAL_SPL */
+
+/*------------------------------------------------------------------------------*/
+
+/*
+ * void write_tlb(mas0, mas1, mas2, mas3, mas7)
+ */
+ .globl write_tlb
+write_tlb:
+ mtspr MAS0,r3
+ mtspr MAS1,r4
+ mtspr MAS2,r5
+ mtspr MAS3,r6
+#ifdef CONFIG_ENABLE_36BIT_PHYS
+ mtspr MAS7,r7
+#endif
+ li r3,0
+#ifdef CONFIG_SYS_BOOK3E_HV
+ mtspr MAS8,r3
+#endif
+ isync
+ tlbwe
+ msync
+ isync
+ blr
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+ .globl relocate_code
+relocate_code:
+ mr r1,r3 /* Set new stack pointer */
+ mr r9,r4 /* Save copy of Init Data pointer */
+ mr r10,r5 /* Save copy of Destination Address */
+
+ GET_GOT
+ mr r3,r5 /* Destination Address */
+ lis r4,CONFIG_SYS_MONITOR_BASE@h /* Source Address */
+ ori r4,r4,CONFIG_SYS_MONITOR_BASE@l
+ lwz r5,GOT(__init_end)
+ sub r5,r5,r4
+ li r6,CONFIG_SYS_CACHELINE_SIZE /* Cache Line Size */
+
+ /*
+ * Fix GOT pointer:
+ *
+ * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+ *
+ * Offset:
+ */
+ sub r15,r10,r4
+
+ /* First our own GOT */
+ add r12,r12,r15
+ /* the the one used by the C code */
+ add r30,r30,r15
+
+ /*
+ * Now relocate code
+ */
+
+ cmplw cr1,r3,r4
+ addi r0,r5,3
+ srwi. r0,r0,2
+ beq cr1,4f /* In place copy is not necessary */
+ beq 7f /* Protect against 0 count */
+ mtctr r0
+ bge cr1,2f
+
+ la r8,-4(r4)
+ la r7,-4(r3)
+1: lwzu r0,4(r8)
+ stwu r0,4(r7)
+ bdnz 1b
+ b 4f
+
+2: slwi r0,r0,2
+ add r8,r4,r0
+ add r7,r3,r0
+3: lwzu r0,-4(r8)
+ stwu r0,-4(r7)
+ bdnz 3b
+
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4: cmpwi r6,0
+ add r5,r3,r5
+ beq 7f /* Always flush prefetch queue in any case */
+ subi r0,r6,1
+ andc r3,r3,r0
+ mr r4,r3
+5: dcbst 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 5b
+ sync /* Wait for all dcbst to complete on bus */
+ mr r4,r3
+6: icbi 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 6b
+7: sync /* Wait for all icbi to complete on bus */
+ isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+ addi r0,r10,in_ram - _start + _START_OFFSET
+
+ /*
+ * As IVPR is going to point RAM address,
+ * Make sure IVOR15 has valid opcode to support debugger
+ */
+ mtspr IVOR15,r0
+
+ /*
+ * Re-point the IVPR at RAM
+ */
+ mtspr IVPR,r10
+
+ mtlr r0
+ blr /* NEVER RETURNS! */
+ .globl in_ram
+in_ram:
+
+ /*
+ * Relocation Function, r12 point to got2+0x8000
+ *
+ * Adjust got2 pointers, no need to check for 0, this code
+ * already puts a few entries in the table.
+ */
+ li r0,__got2_entries@sectoff@l
+ la r3,GOT(_GOT2_TABLE_)
+ lwz r11,GOT(_GOT2_TABLE_)
+ mtctr r0
+ sub r11,r3,r11
+ addi r3,r3,-4
+1: lwzu r0,4(r3)
+ cmpwi r0,0
+ beq- 2f
+ add r0,r0,r11
+ stw r0,0(r3)
+2: bdnz 1b
+
+ /*
+ * Now adjust the fixups and the pointers to the fixups
+ * in case we need to move ourselves again.
+ */
+ li r0,__fixup_entries@sectoff@l
+ lwz r3,GOT(_FIXUP_TABLE_)
+ cmpwi r0,0
+ mtctr r0
+ addi r3,r3,-4
+ beq 4f
+3: lwzu r4,4(r3)
+ lwzux r0,r4,r11
+ cmpwi r0,0
+ add r0,r0,r11
+ stw r4,0(r3)
+ beq- 5f
+ stw r0,0(r4)
+5: bdnz 3b
+4:
+clear_bss:
+ /*
+ * Now clear BSS segment
+ */
+ lwz r3,GOT(__bss_start)
+ lwz r4,GOT(__bss_end)
+
+ cmplw 0,r3,r4
+ beq 6f
+
+ li r0,0
+5:
+ stw r0,0(r3)
+ addi r3,r3,4
+ cmplw 0,r3,r4
+ blt 5b
+6:
+
+ mr r3,r9 /* Init Data pointer */
+ mr r4,r10 /* Destination Address */
+ bl board_init_r
+
+#ifndef MINIMAL_SPL
+ /*
+ * Copy exception vector code to low memory
+ *
+ * r3: dest_addr
+ * r7: source address, r8: end address, r9: target address
+ */
+ .globl trap_init
+trap_init:
+ mflr r4 /* save link register */
+ GET_GOT
+ lwz r7,GOT(_start_of_vectors)
+ lwz r8,GOT(_end_of_vectors)
+
+ li r9,0x100 /* reset vector always at 0x100 */
+
+ cmplw 0,r7,r8
+ bgelr /* return if r7>=r8 - just in case */
+1:
+ lwz r0,0(r7)
+ stw r0,0(r9)
+ addi r7,r7,4
+ addi r9,r9,4
+ cmplw 0,r7,r8
+ bne 1b
+
+ /*
+ * relocate `hdlr' and `int_return' entries
+ */
+ li r7,.L_CriticalInput - _start + _START_OFFSET
+ bl trap_reloc
+ li r7,.L_MachineCheck - _start + _START_OFFSET
+ bl trap_reloc
+ li r7,.L_DataStorage - _start + _START_OFFSET
+ bl trap_reloc
+ li r7,.L_InstStorage - _start + _START_OFFSET
+ bl trap_reloc
+ li r7,.L_ExtInterrupt - _start + _START_OFFSET
+ bl trap_reloc
+ li r7,.L_Alignment - _start + _START_OFFSET
+ bl trap_reloc
+ li r7,.L_ProgramCheck - _start + _START_OFFSET
+ bl trap_reloc
+ li r7,.L_FPUnavailable - _start + _START_OFFSET
+ bl trap_reloc
+ li r7,.L_Decrementer - _start + _START_OFFSET
+ bl trap_reloc
+ li r7,.L_IntervalTimer - _start + _START_OFFSET
+ li r8,_end_of_vectors - _start + _START_OFFSET
+2:
+ bl trap_reloc
+ addi r7,r7,0x100 /* next exception vector */
+ cmplw 0,r7,r8
+ blt 2b
+
+ /* Update IVORs as per relocated vector table address */
+ li r7,0x0100
+ mtspr IVOR0,r7 /* 0: Critical input */
+ li r7,0x0200
+ mtspr IVOR1,r7 /* 1: Machine check */
+ li r7,0x0300
+ mtspr IVOR2,r7 /* 2: Data storage */
+ li r7,0x0400
+ mtspr IVOR3,r7 /* 3: Instruction storage */
+ li r7,0x0500
+ mtspr IVOR4,r7 /* 4: External interrupt */
+ li r7,0x0600
+ mtspr IVOR5,r7 /* 5: Alignment */
+ li r7,0x0700
+ mtspr IVOR6,r7 /* 6: Program check */
+ li r7,0x0800
+ mtspr IVOR7,r7 /* 7: floating point unavailable */
+ li r7,0x0900
+ mtspr IVOR8,r7 /* 8: System call */
+ /* 9: Auxiliary processor unavailable(unsupported) */
+ li r7,0x0a00
+ mtspr IVOR10,r7 /* 10: Decrementer */
+ li r7,0x0b00
+ mtspr IVOR11,r7 /* 11: Interval timer */
+ li r7,0x0c00
+ mtspr IVOR12,r7 /* 12: Watchdog timer */
+ li r7,0x0d00
+ mtspr IVOR13,r7 /* 13: Data TLB error */
+ li r7,0x0e00
+ mtspr IVOR14,r7 /* 14: Instruction TLB error */
+ li r7,0x0f00
+ mtspr IVOR15,r7 /* 15: Debug */
+
+ lis r7,0x0
+ mtspr IVPR,r7
+
+ mtlr r4 /* restore link register */
+ blr
+
+.globl unlock_ram_in_cache
+unlock_ram_in_cache:
+ /* invalidate the INIT_RAM section */
+ lis r3,(CONFIG_SYS_INIT_RAM_ADDR & ~(CONFIG_SYS_CACHELINE_SIZE-1))@h
+ ori r3,r3,(CONFIG_SYS_INIT_RAM_ADDR & ~(CONFIG_SYS_CACHELINE_SIZE-1))@l
+ mfspr r4,L1CFG0
+ andi. r4,r4,0x1ff
+ slwi r4,r4,(10 - 1 - L1_CACHE_SHIFT)
+ mtctr r4
+1: dcbi r0,r3
+ dcblc r0,r3
+ addi r3,r3,CONFIG_SYS_CACHELINE_SIZE
+ bdnz 1b
+ sync
+
+ /* Invalidate the TLB entries for the cache */
+ lis r3,CONFIG_SYS_INIT_RAM_ADDR@h
+ ori r3,r3,CONFIG_SYS_INIT_RAM_ADDR@l
+ tlbivax 0,r3
+ addi r3,r3,0x1000
+ tlbivax 0,r3
+ addi r3,r3,0x1000
+ tlbivax 0,r3
+ addi r3,r3,0x1000
+ tlbivax 0,r3
+ isync
+ blr
+
+.globl flush_dcache
+flush_dcache:
+ mfspr r3,SPRN_L1CFG0
+
+ rlwinm r5,r3,9,3 /* Extract cache block size */
+ twlgti r5,1 /* Only 32 and 64 byte cache blocks
+ * are currently defined.
+ */
+ li r4,32
+ subfic r6,r5,2 /* r6 = log2(1KiB / cache block size) -
+ * log2(number of ways)
+ */
+ slw r5,r4,r5 /* r5 = cache block size */
+
+ rlwinm r7,r3,0,0xff /* Extract number of KiB in the cache */
+ mulli r7,r7,13 /* An 8-way cache will require 13
+ * loads per set.
+ */
+ slw r7,r7,r6
+
+ /* save off HID0 and set DCFA */
+ mfspr r8,SPRN_HID0
+ ori r9,r8,HID0_DCFA@l
+ mtspr SPRN_HID0,r9
+ isync
+
+ lis r4,0
+ mtctr r7
+
+1: lwz r3,0(r4) /* Load... */
+ add r4,r4,r5
+ bdnz 1b
+
+ msync
+ lis r4,0
+ mtctr r7
+
+1: dcbf 0,r4 /* ...and flush. */
+ add r4,r4,r5
+ bdnz 1b
+
+ /* restore HID0 */
+ mtspr SPRN_HID0,r8
+ isync
+
+ blr
+
+.globl setup_ivors
+setup_ivors:
+
+#include "fixed_ivor.S"
+ blr
+#endif /* !MINIMAL_SPL */
diff --git a/arch/powerpc/cpu/mpc85xx/t1040_ids.c b/arch/powerpc/cpu/mpc85xx/t1040_ids.c
new file mode 100644
index 0000000..ed61599
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/t1040_ids.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_portals.h>
+#include <asm/fsl_liodn.h>
+
+#ifdef CONFIG_SYS_DPAA_QBMAN
+struct qportal_info qp_info[CONFIG_SYS_QMAN_NUM_PORTALS] = {
+ /* dqrr liodn, frame data liodn, liodn off, sdest */
+ SET_QP_INFO(1, 27, 1, 0),
+ SET_QP_INFO(2, 28, 1, 0),
+ SET_QP_INFO(3, 29, 1, 1),
+ SET_QP_INFO(4, 30, 1, 1),
+ SET_QP_INFO(5, 31, 1, 2),
+ SET_QP_INFO(6, 32, 1, 2),
+ SET_QP_INFO(7, 33, 1, 3),
+ SET_QP_INFO(8, 34, 1, 3),
+ SET_QP_INFO(9, 35, 1, 0),
+ SET_QP_INFO(10, 36, 1, 0),
+ SET_QP_INFO(11, 37, 1, 1),
+ SET_QP_INFO(12, 38, 1, 1),
+ SET_QP_INFO(13, 39, 1, 2),
+ SET_QP_INFO(14, 40, 1, 2),
+ SET_QP_INFO(15, 41, 1, 3),
+ SET_QP_INFO(16, 42, 1, 3),
+ SET_QP_INFO(17, 43, 1, 0),
+ SET_QP_INFO(18, 44, 1, 0),
+ SET_QP_INFO(19, 45, 1, 1),
+ SET_QP_INFO(20, 46, 1, 1),
+ SET_QP_INFO(21, 47, 1, 2),
+ SET_QP_INFO(22, 48, 1, 2),
+ SET_QP_INFO(23, 49, 1, 3),
+ SET_QP_INFO(24, 50, 1, 3),
+ SET_QP_INFO(25, 51, 1, 0),
+};
+#endif
+
+struct srio_liodn_id_table srio_liodn_tbl[] = {
+ SET_SRIO_LIODN_1(1, 307),
+ SET_SRIO_LIODN_1(2, 387),
+};
+int srio_liodn_tbl_sz = ARRAY_SIZE(srio_liodn_tbl);
+
+struct liodn_id_table liodn_tbl[] = {
+#ifdef CONFIG_SYS_DPAA_QBMAN
+ SET_QMAN_LIODN(62),
+ SET_BMAN_LIODN(63),
+#endif
+
+ SET_SDHC_LIODN(1, 552),
+
+ SET_USB_LIODN(1, "fsl-usb2-mph", 553),
+
+ SET_PCI_LIODN("fsl,qoriq-pcie-v2.2", 1, 148),
+
+ SET_DMA_LIODN(1, 147),
+ SET_DMA_LIODN(2, 227),
+
+ SET_GUTS_LIODN("fsl,rapidio-delta", 199, rio1liodnr, 0),
+ SET_GUTS_LIODN(NULL, 200, rio2liodnr, 0),
+ SET_GUTS_LIODN(NULL, 201, rio1maintliodnr, 0),
+ SET_GUTS_LIODN(NULL, 202, rio2maintliodnr, 0),
+
+ /* SET_NEXUS_LIODN(557), -- not yet implemented */
+};
+int liodn_tbl_sz = ARRAY_SIZE(liodn_tbl);
+
+#ifdef CONFIG_SYS_DPAA_FMAN
+struct liodn_id_table fman1_liodn_tbl[] = {
+ SET_FMAN_RX_1G_LIODN(1, 0, 88),
+ SET_FMAN_RX_1G_LIODN(1, 1, 89),
+ SET_FMAN_RX_1G_LIODN(1, 2, 90),
+ SET_FMAN_RX_1G_LIODN(1, 3, 91),
+ SET_FMAN_RX_1G_LIODN(1, 4, 92),
+ SET_FMAN_RX_1G_LIODN(1, 5, 93),
+ SET_FMAN_RX_10G_LIODN(1, 0, 94),
+ SET_FMAN_RX_10G_LIODN(1, 1, 95),
+};
+int fman1_liodn_tbl_sz = ARRAY_SIZE(fman1_liodn_tbl);
+#endif
+
+struct liodn_id_table sec_liodn_tbl[] = {
+ SET_SEC_JR_LIODN_ENTRY(0, 454, 458),
+ SET_SEC_JR_LIODN_ENTRY(1, 455, 459),
+ SET_SEC_JR_LIODN_ENTRY(2, 456, 460),
+ SET_SEC_JR_LIODN_ENTRY(3, 457, 461),
+ SET_SEC_RTIC_LIODN_ENTRY(a, 453),
+ SET_SEC_RTIC_LIODN_ENTRY(b, 549),
+ SET_SEC_RTIC_LIODN_ENTRY(c, 550),
+ SET_SEC_RTIC_LIODN_ENTRY(d, 551),
+ SET_SEC_DECO_LIODN_ENTRY(0, 541, 610),
+ SET_SEC_DECO_LIODN_ENTRY(1, 542, 611),
+};
+int sec_liodn_tbl_sz = ARRAY_SIZE(sec_liodn_tbl);
+
+#ifdef CONFIG_SYS_DPAA_RMAN
+struct liodn_id_table rman_liodn_tbl[] = {
+ /* Set RMan block 0-3 liodn offset */
+ SET_RMAN_LIODN(0, 678),
+ SET_RMAN_LIODN(1, 679),
+ SET_RMAN_LIODN(2, 680),
+ SET_RMAN_LIODN(3, 681),
+};
+int rman_liodn_tbl_sz = ARRAY_SIZE(rman_liodn_tbl);
+#endif
+
+struct liodn_id_table liodn_bases[] = {
+ [FSL_HW_PORTAL_SEC] = SET_LIODN_BASE_2(462, 558),
+#ifdef CONFIG_SYS_DPAA_FMAN
+ [FSL_HW_PORTAL_FMAN1] = SET_LIODN_BASE_1(973),
+#endif
+#ifdef CONFIG_SYS_DPAA_RMAN
+ [FSL_HW_PORTAL_RMAN] = SET_LIODN_BASE_1(922),
+#endif
+};
diff --git a/arch/powerpc/cpu/mpc85xx/t1040_serdes.c b/arch/powerpc/cpu/mpc85xx/t1040_serdes.c
new file mode 100644
index 0000000..19add9f
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/t1040_serdes.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_serdes.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include "fsl_corenet2_serdes.h"
+
+static u8 serdes_cfg_tbl[MAX_SERDES][0xC4][SRDS_MAX_LANES] = {
+ { /* SerDes 1 */
+ [0x69] = {PCIE1, SGMII_FM1_DTSEC3, QSGMII_SW1_A, QSGMII_SW1_B,
+ PCIE2, PCIE3, SGMII_FM1_DTSEC4, SATA1},
+ [0x66] = {PCIE1, SGMII_FM1_DTSEC3, QSGMII_SW1_A, QSGMII_SW1_B,
+ PCIE2, PCIE3, PCIE4, SATA1},
+ [0x67] = {PCIE1, SGMII_FM1_DTSEC3, QSGMII_SW1_A, QSGMII_SW1_B,
+ PCIE2, PCIE3, PCIE4, SGMII_FM1_DTSEC5},
+ [0x60] = {PCIE1, SGMII_FM1_DTSEC3, QSGMII_SW1_A, QSGMII_SW1_B,
+ PCIE2, PCIE2, PCIE2, PCIE2},
+ [0x8D] = {PCIE1, SGMII_SW1_DTSEC3, SGMII_SW1_DTSEC1, SGMII_SW1_DTSEC2,
+ PCIE2, SGMII_SW1_DTSEC6, SGMII_SW1_DTSEC4, SGMII_SW1_DTSEC5},
+ [0x89] = {PCIE1, SGMII_SW1_DTSEC3, SGMII_SW1_DTSEC1, SGMII_SW1_DTSEC2,
+ PCIE2, PCIE3, SGMII_SW1_DTSEC4, SATA1},
+ [0x86] = {PCIE1, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ PCIE2, PCIE3, PCIE4, SATA1},
+ [0x87] = {PCIE1, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ PCIE2, PCIE3, PCIE4, SGMII_FM1_DTSEC5},
+ [0xA7] = {PCIE1, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ PCIE2, PCIE3, PCIE4, SGMII_FM1_DTSEC5},
+ [0xAA] = {PCIE1, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ PCIE2, PCIE3, SGMII_FM1_DTSEC4, SGMII_FM1_DTSEC5},
+ [0x40] = {PCIE1, PCIE1, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ PCIE2, PCIE2, PCIE2, PCIE2},
+ [0x06] = {PCIE1, PCIE1, PCIE1, PCIE1,
+ PCIE2, PCIE3, PCIE4, SATA1},
+ [0x08] = {PCIE1, PCIE1, PCIE1, PCIE1,
+ PCIE2, PCIE3, SATA2, SATA1},
+ [0x8F] = {PCIE1, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ AURORA, NONE, SGMII_FM1_DTSEC4, SGMII_FM1_DTSEC5},
+ [0x85] = {PCIE1, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ PCIE2, PCIE2, SGMII_FM1_DTSEC4, SGMII_FM1_DTSEC5},
+ [0xA5] = {PCIE1, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ PCIE2, PCIE2, SGMII_FM1_DTSEC4, SGMII_FM1_DTSEC5},
+ [0x00] = {PCIE1, PCIE1, PCIE1, PCIE1,
+ PCIE2, PCIE2, PCIE2, PCIE2},
+ },
+ {
+ },
+ {
+ },
+ {
+ },
+};
+
+
+enum srds_prtcl serdes_get_prtcl(int serdes, int cfg, int lane)
+{
+ return serdes_cfg_tbl[serdes][cfg][lane];
+}
+
+int is_serdes_prtcl_valid(int serdes, u32 prtcl)
+{
+ int i;
+
+ if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl[serdes]))
+ return 0;
+
+ for (i = 0; i < SRDS_MAX_LANES; i++) {
+ if (serdes_cfg_tbl[serdes][prtcl][i] != NONE)
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc85xx/t4240_ids.c b/arch/powerpc/cpu/mpc85xx/t4240_ids.c
new file mode 100644
index 0000000..a8f16b1
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/t4240_ids.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_portals.h>
+#include <asm/fsl_liodn.h>
+
+#ifdef CONFIG_SYS_DPAA_QBMAN
+struct qportal_info qp_info[CONFIG_SYS_QMAN_NUM_PORTALS] = {
+ /* dqrr liodn, frame data liodn, liodn off, sdest */
+ SET_QP_INFO(1, 27, 1, 0),
+ SET_QP_INFO(2, 28, 1, 0),
+ SET_QP_INFO(3, 29, 1, 1),
+ SET_QP_INFO(4, 30, 1, 1),
+ SET_QP_INFO(5, 31, 1, 2),
+ SET_QP_INFO(6, 32, 1, 2),
+ SET_QP_INFO(7, 33, 1, 3),
+ SET_QP_INFO(8, 34, 1, 3),
+ SET_QP_INFO(9, 35, 1, 4),
+ SET_QP_INFO(10, 36, 1, 4),
+ SET_QP_INFO(11, 37, 1, 5),
+ SET_QP_INFO(12, 38, 1, 5),
+ SET_QP_INFO(13, 39, 1, 6),
+ SET_QP_INFO(14, 40, 1, 6),
+ SET_QP_INFO(15, 41, 1, 7),
+ SET_QP_INFO(16, 42, 1, 7),
+ SET_QP_INFO(17, 43, 1, 8),
+ SET_QP_INFO(18, 44, 1, 8),
+ SET_QP_INFO(19, 45, 1, 9),
+ SET_QP_INFO(20, 46, 1, 9),
+ SET_QP_INFO(21, 47, 1, 10),
+ SET_QP_INFO(22, 48, 1, 10),
+ SET_QP_INFO(23, 49, 1, 11),
+ SET_QP_INFO(24, 50, 1, 11),
+ SET_QP_INFO(65, 89, 1, 0),
+ SET_QP_INFO(66, 90, 1, 0),
+ SET_QP_INFO(67, 91, 1, 1),
+ SET_QP_INFO(68, 92, 1, 1),
+ SET_QP_INFO(69, 93, 1, 2),
+ SET_QP_INFO(70, 94, 1, 2),
+ SET_QP_INFO(71, 95, 1, 3),
+ SET_QP_INFO(72, 96, 1, 3),
+ SET_QP_INFO(73, 97, 1, 4),
+ SET_QP_INFO(74, 98, 1, 4),
+ SET_QP_INFO(75, 99, 1, 5),
+ SET_QP_INFO(76, 100, 1, 5),
+ SET_QP_INFO(77, 101, 1, 6),
+ SET_QP_INFO(78, 102, 1, 6),
+ SET_QP_INFO(79, 103, 1, 7),
+ SET_QP_INFO(80, 104, 1, 7),
+ SET_QP_INFO(81, 105, 1, 8),
+ SET_QP_INFO(82, 106, 1, 8),
+ SET_QP_INFO(83, 107, 1, 9),
+ SET_QP_INFO(84, 108, 1, 9),
+ SET_QP_INFO(85, 109, 1, 10),
+ SET_QP_INFO(86, 110, 1, 10),
+ SET_QP_INFO(87, 111, 1, 11),
+ SET_QP_INFO(88, 112, 1, 11),
+ SET_QP_INFO(25, 51, 1, 0),
+ SET_QP_INFO(26, 52, 1, 0),
+};
+#endif
+
+struct srio_liodn_id_table srio_liodn_tbl[] = {
+ SET_SRIO_LIODN_1(1, 307),
+ SET_SRIO_LIODN_1(2, 387),
+};
+int srio_liodn_tbl_sz = ARRAY_SIZE(srio_liodn_tbl);
+
+struct liodn_id_table liodn_tbl[] = {
+#ifdef CONFIG_SYS_DPAA_QBMAN
+ SET_QMAN_LIODN(62),
+ SET_BMAN_LIODN(63),
+#endif
+
+ SET_SDHC_LIODN(1, 552),
+
+ SET_PME_LIODN(117),
+
+ SET_USB_LIODN(1, "fsl-usb2-mph", 553),
+ SET_USB_LIODN(2, "fsl-usb2-dr", 554),
+
+ SET_SATA_LIODN(1, 555),
+ SET_SATA_LIODN(2, 556),
+
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 1, 148),
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 2, 228),
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 3, 308),
+ SET_PCI_LIODN(CONFIG_SYS_FSL_PCIE_COMPAT, 4, 388),
+
+ SET_DMA_LIODN(1, 147),
+ SET_DMA_LIODN(2, 227),
+
+ SET_GUTS_LIODN("fsl,rapidio-delta", 199, rio1liodnr, 0),
+ SET_GUTS_LIODN(NULL, 200, rio2liodnr, 0),
+ SET_GUTS_LIODN(NULL, 201, rio1maintliodnr, 0),
+ SET_GUTS_LIODN(NULL, 202, rio2maintliodnr, 0),
+
+#ifdef CONFIG_SYS_PMAN
+ SET_PMAN_LIODN(1, 513),
+ SET_PMAN_LIODN(2, 514),
+ SET_PMAN_LIODN(3, 515),
+#endif
+
+ /* SET_NEXUS_LIODN(557), -- not yet implemented */
+};
+int liodn_tbl_sz = ARRAY_SIZE(liodn_tbl);
+
+#ifdef CONFIG_SYS_DPAA_FMAN
+struct liodn_id_table fman1_liodn_tbl[] = {
+ SET_FMAN_RX_1G_LIODN(1, 0, 88),
+ SET_FMAN_RX_1G_LIODN(1, 1, 89),
+ SET_FMAN_RX_1G_LIODN(1, 2, 90),
+ SET_FMAN_RX_1G_LIODN(1, 3, 91),
+ SET_FMAN_RX_1G_LIODN(1, 4, 92),
+ SET_FMAN_RX_1G_LIODN(1, 5, 93),
+ SET_FMAN_RX_10G_LIODN(1, 0, 94),
+ SET_FMAN_RX_10G_LIODN(1, 1, 95),
+};
+int fman1_liodn_tbl_sz = ARRAY_SIZE(fman1_liodn_tbl);
+#if (CONFIG_SYS_NUM_FMAN == 2)
+struct liodn_id_table fman2_liodn_tbl[] = {
+ SET_FMAN_RX_1G_LIODN(2, 0, 88),
+ SET_FMAN_RX_1G_LIODN(2, 1, 89),
+ SET_FMAN_RX_1G_LIODN(2, 2, 90),
+ SET_FMAN_RX_1G_LIODN(2, 3, 91),
+ SET_FMAN_RX_1G_LIODN(2, 4, 92),
+ SET_FMAN_RX_1G_LIODN(2, 5, 93),
+ SET_FMAN_RX_10G_LIODN(2, 0, 94),
+ SET_FMAN_RX_10G_LIODN(2, 1, 95),
+};
+int fman2_liodn_tbl_sz = ARRAY_SIZE(fman2_liodn_tbl);
+#endif
+#endif
+
+struct liodn_id_table sec_liodn_tbl[] = {
+ SET_SEC_JR_LIODN_ENTRY(0, 454, 458),
+ SET_SEC_JR_LIODN_ENTRY(1, 455, 459),
+ SET_SEC_JR_LIODN_ENTRY(2, 456, 460),
+ SET_SEC_JR_LIODN_ENTRY(3, 457, 461),
+ SET_SEC_RTIC_LIODN_ENTRY(a, 453),
+ SET_SEC_RTIC_LIODN_ENTRY(b, 549),
+ SET_SEC_RTIC_LIODN_ENTRY(c, 550),
+ SET_SEC_RTIC_LIODN_ENTRY(d, 551),
+ SET_SEC_DECO_LIODN_ENTRY(0, 541, 610),
+ SET_SEC_DECO_LIODN_ENTRY(1, 542, 611),
+ SET_SEC_DECO_LIODN_ENTRY(2, 543, 612),
+ SET_SEC_DECO_LIODN_ENTRY(3, 544, 613),
+ SET_SEC_DECO_LIODN_ENTRY(4, 545, 614),
+ SET_SEC_DECO_LIODN_ENTRY(5, 546, 615),
+ SET_SEC_DECO_LIODN_ENTRY(6, 547, 616),
+ SET_SEC_DECO_LIODN_ENTRY(7, 548, 617),
+};
+int sec_liodn_tbl_sz = ARRAY_SIZE(sec_liodn_tbl);
+
+#ifdef CONFIG_SYS_DPAA_RMAN
+struct liodn_id_table rman_liodn_tbl[] = {
+ /* Set RMan block 0-3 liodn offset */
+ SET_RMAN_LIODN(0, 678),
+ SET_RMAN_LIODN(1, 679),
+ SET_RMAN_LIODN(2, 680),
+ SET_RMAN_LIODN(3, 681),
+};
+int rman_liodn_tbl_sz = ARRAY_SIZE(rman_liodn_tbl);
+#endif
+
+struct liodn_id_table liodn_bases[] = {
+#ifdef CONFIG_SYS_DPAA_DCE
+ [FSL_HW_PORTAL_DCE] = SET_LIODN_BASE_2(618, 694),
+#endif
+ [FSL_HW_PORTAL_SEC] = SET_LIODN_BASE_2(462, 558),
+#ifdef CONFIG_SYS_DPAA_FMAN
+ [FSL_HW_PORTAL_FMAN1] = SET_LIODN_BASE_1(973),
+#if (CONFIG_SYS_NUM_FMAN == 2)
+ [FSL_HW_PORTAL_FMAN2] = SET_LIODN_BASE_1(1069),
+#endif
+#endif
+#ifdef CONFIG_SYS_DPAA_PME
+ [FSL_HW_PORTAL_PME] = SET_LIODN_BASE_2(770, 846),
+#endif
+#ifdef CONFIG_SYS_DPAA_RMAN
+ [FSL_HW_PORTAL_RMAN] = SET_LIODN_BASE_1(922),
+#endif
+};
diff --git a/arch/powerpc/cpu/mpc85xx/t4240_serdes.c b/arch/powerpc/cpu/mpc85xx/t4240_serdes.c
new file mode 100644
index 0000000..c001780
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/t4240_serdes.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_serdes.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include "fsl_corenet2_serdes.h"
+
+struct serdes_config {
+ u32 protocol;
+ u8 lanes[SRDS_MAX_LANES];
+};
+
+#ifdef CONFIG_PPC_T4240
+static const struct serdes_config serdes1_cfg_tbl[] = {
+ /* SerDes 1 */
+ {1, {XAUI_FM1_MAC9, XAUI_FM1_MAC9,
+ XAUI_FM1_MAC9, XAUI_FM1_MAC9,
+ XAUI_FM1_MAC10, XAUI_FM1_MAC10,
+ XAUI_FM1_MAC10, XAUI_FM1_MAC10}},
+ {2, {HIGIG_FM1_MAC9, HIGIG_FM1_MAC9,
+ HIGIG_FM1_MAC9, HIGIG_FM1_MAC9,
+ HIGIG_FM1_MAC10, HIGIG_FM1_MAC10,
+ HIGIG_FM1_MAC10, HIGIG_FM1_MAC10}},
+ {4, {HIGIG_FM1_MAC9, HIGIG_FM1_MAC9,
+ HIGIG_FM1_MAC9, HIGIG_FM1_MAC9,
+ HIGIG_FM1_MAC10, HIGIG_FM1_MAC10,
+ HIGIG_FM1_MAC10, HIGIG_FM1_MAC10}},
+ {28, {SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6,
+ SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC9,
+ SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4}},
+ {36, {SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6,
+ SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC9,
+ SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4}},
+ {38, {NONE, NONE, QSGMII_FM1_B, NONE,
+ NONE, NONE, QSGMII_FM1_A, NONE}},
+ {40, {SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6,
+ SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC9,
+ NONE, NONE, QSGMII_FM1_A, NONE}},
+ {46, {SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6,
+ SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC9,
+ NONE, NONE, QSGMII_FM1_A, NONE}},
+ {48, {SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6,
+ SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC9,
+ NONE, NONE, QSGMII_FM1_A, NONE}},
+ {}
+};
+static const struct serdes_config serdes2_cfg_tbl[] = {
+ /* SerDes 2 */
+ {1, {XAUI_FM2_MAC9, XAUI_FM2_MAC9,
+ XAUI_FM2_MAC9, XAUI_FM2_MAC9,
+ XAUI_FM2_MAC10, XAUI_FM2_MAC10,
+ XAUI_FM2_MAC10, XAUI_FM2_MAC10}},
+ {2, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ HIGIG_FM2_MAC10, HIGIG_FM2_MAC10,
+ HIGIG_FM2_MAC10, HIGIG_FM2_MAC10}},
+ {4, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ HIGIG_FM2_MAC10, HIGIG_FM2_MAC10,
+ HIGIG_FM2_MAC10, HIGIG_FM2_MAC10}},
+ {7, {XAUI_FM2_MAC9, XAUI_FM2_MAC9,
+ XAUI_FM2_MAC9, XAUI_FM2_MAC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4}},
+ {13, {XAUI_FM2_MAC9, XAUI_FM2_MAC9,
+ XAUI_FM2_MAC9, XAUI_FM2_MAC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4}},
+ {14, {XAUI_FM2_MAC9, XAUI_FM2_MAC9,
+ XAUI_FM2_MAC9, XAUI_FM2_MAC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4}},
+ {16, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4}},
+ {22, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4}},
+ {23, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4}},
+ {25, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4}},
+ {26, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4}},
+ {28, {SGMII_FM2_DTSEC5, SGMII_FM2_DTSEC6,
+ SGMII_FM2_DTSEC10, SGMII_FM2_DTSEC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4}},
+ {36, {SGMII_FM2_DTSEC5, SGMII_FM2_DTSEC6,
+ SGMII_FM2_DTSEC10, SGMII_FM2_DTSEC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4}},
+ {38, {NONE, NONE, QSGMII_FM2_B, NONE,
+ NONE, NONE, QSGMII_FM1_A, NONE}},
+ {40, {SGMII_FM2_DTSEC5, SGMII_FM2_DTSEC6,
+ SGMII_FM2_DTSEC10, SGMII_FM2_DTSEC9,
+ NONE, NONE, QSGMII_FM1_A, NONE}},
+ {46, {SGMII_FM2_DTSEC5, SGMII_FM2_DTSEC6,
+ SGMII_FM2_DTSEC10, SGMII_FM2_DTSEC9,
+ NONE, NONE, QSGMII_FM1_A, NONE}},
+ {48, {SGMII_FM2_DTSEC5, SGMII_FM2_DTSEC6,
+ SGMII_FM2_DTSEC10, SGMII_FM2_DTSEC9,
+ NONE, NONE, QSGMII_FM1_A, NONE}},
+ {50, {XAUI_FM2_MAC9, XAUI_FM2_MAC9,
+ XAUI_FM2_MAC9, XAUI_FM2_MAC9,
+ NONE, NONE, QSGMII_FM1_A, NONE}},
+ {52, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ NONE, NONE, QSGMII_FM1_A, NONE}},
+ {54, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ NONE, NONE, QSGMII_FM1_A, NONE}},
+ {56, {XFI_FM1_MAC9, XFI_FM1_MAC10,
+ XFI_FM2_MAC10, XFI_FM2_MAC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4}},
+ {57, {XFI_FM1_MAC9, XFI_FM1_MAC10,
+ XFI_FM2_MAC10, XFI_FM2_MAC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4}},
+ {}
+};
+static const struct serdes_config serdes3_cfg_tbl[] = {
+ /* SerDes 3 */
+ {2, {PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1}},
+ {4, {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2}},
+ {6, {PCIE1, PCIE1, PCIE1, PCIE1, SRIO1, SRIO1, SRIO1, SRIO1}},
+ {8, {PCIE1, PCIE1, PCIE1, PCIE1, SRIO1, NONE, NONE, NONE}},
+ {9, {INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN,
+ INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN}},
+ {10, {INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN,
+ INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN}},
+ {12, {INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN,
+ PCIE2, PCIE2, PCIE2, PCIE2}},
+ {14, {INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN,
+ PCIE2, PCIE2, PCIE2, PCIE2}},
+ {16, {INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN,
+ SRIO1, SRIO1, SRIO1, SRIO1}},
+ {17, {INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN,
+ SRIO1, SRIO1, SRIO1, SRIO1}},
+ {19, {INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN,
+ SRIO1, SRIO1, SRIO1, SRIO1}},
+ {20, {INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN,
+ SRIO1, SRIO1, SRIO1, SRIO1}},
+ {}
+};
+static const struct serdes_config serdes4_cfg_tbl[] = {
+ /* SerDes 4 */
+ {2, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3}},
+ {4, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, PCIE4, PCIE4}},
+ {6, {PCIE3, PCIE3, PCIE3, PCIE3, SRIO2, SRIO2, SRIO2, SRIO2}},
+ {8, {PCIE3, PCIE3, PCIE3, PCIE3, SRIO2, SRIO2, SRIO2, SRIO2}},
+ {10, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, SATA1, SATA2} },
+ {12, {PCIE3, PCIE3, PCIE3, PCIE3, AURORA, AURORA, SATA1, SATA2} },
+ {14, {PCIE3, PCIE3, PCIE3, PCIE3, AURORA, AURORA, SRIO2, SRIO2}},
+ {16, {PCIE3, PCIE3, PCIE3, PCIE3, AURORA, AURORA, SRIO2, SRIO2}},
+ {18, {PCIE3, PCIE3, PCIE3, PCIE3, AURORA, AURORA, AURORA, AURORA}},
+ {}
+};
+#elif defined(CONFIG_PPC_T4160)
+static const struct serdes_config serdes1_cfg_tbl[] = {
+ /* SerDes 1 */
+ {1, {XAUI_FM1_MAC9, XAUI_FM1_MAC9,
+ XAUI_FM1_MAC9, XAUI_FM1_MAC9,
+ XAUI_FM1_MAC10, XAUI_FM1_MAC10,
+ XAUI_FM1_MAC10, XAUI_FM1_MAC10} },
+ {2, {HIGIG_FM1_MAC9, HIGIG_FM1_MAC9,
+ HIGIG_FM1_MAC9, HIGIG_FM1_MAC9,
+ HIGIG_FM1_MAC10, HIGIG_FM1_MAC10,
+ HIGIG_FM1_MAC10, HIGIG_FM1_MAC10} },
+ {4, {HIGIG_FM1_MAC9, HIGIG_FM1_MAC9,
+ HIGIG_FM1_MAC9, HIGIG_FM1_MAC9,
+ HIGIG_FM1_MAC10, HIGIG_FM1_MAC10,
+ HIGIG_FM1_MAC10, HIGIG_FM1_MAC10} },
+ {28, {SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6,
+ SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC9,
+ SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4} },
+ {36, {SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6,
+ SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC9,
+ SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2,
+ SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4} },
+ {38, {NONE, NONE, QSGMII_FM1_B, NONE,
+ NONE, NONE, QSGMII_FM1_A, NONE} },
+ {}
+};
+static const struct serdes_config serdes2_cfg_tbl[] = {
+ /* SerDes 2 */
+ {7, {XAUI_FM2_MAC9, XAUI_FM2_MAC9,
+ XAUI_FM2_MAC9, XAUI_FM2_MAC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4} },
+ {13, {XAUI_FM2_MAC9, XAUI_FM2_MAC9,
+ XAUI_FM2_MAC9, XAUI_FM2_MAC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4} },
+ {16, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4} },
+ {22, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4} },
+ {25, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4} },
+ {26, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ NONE, NONE} },
+ {28, {SGMII_FM2_DTSEC5, SGMII_FM2_DTSEC6,
+ SGMII_FM2_DTSEC10, SGMII_FM2_DTSEC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4} },
+ {36, {SGMII_FM2_DTSEC5, SGMII_FM2_DTSEC6,
+ SGMII_FM2_DTSEC10, SGMII_FM2_DTSEC9,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4} },
+ {38, {NONE, NONE, QSGMII_FM2_B, NONE,
+ NONE, QSGMII_FM1_A, NONE, NONE} },
+ {40, {SGMII_FM2_DTSEC5, SGMII_FM2_DTSEC6,
+ SGMII_FM2_DTSEC10, SGMII_FM2_DTSEC9,
+ NONE, QSGMII_FM1_A, NONE, NONE} },
+ {46, {SGMII_FM2_DTSEC5, SGMII_FM2_DTSEC6,
+ SGMII_FM2_DTSEC10, SGMII_FM2_DTSEC9,
+ NONE, QSGMII_FM1_A, NONE, NONE} },
+ {48, {SGMII_FM2_DTSEC5, SGMII_FM2_DTSEC6,
+ SGMII_FM2_DTSEC10, SGMII_FM2_DTSEC9,
+ NONE, QSGMII_FM1_A, NONE, NONE} },
+ {50, {XAUI_FM2_MAC9, XAUI_FM2_MAC9,
+ XAUI_FM2_MAC9, XAUI_FM2_MAC9,
+ NONE, NONE, NONE, NONE} },
+ {52, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ NONE, NONE, NONE, NONE} },
+ {54, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
+ NONE, NONE, NONE, NONE} },
+ {56, {NONE, XFI_FM1_MAC10,
+ XFI_FM2_MAC10, NONE,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4} },
+ {57, {NONE, XFI_FM1_MAC10,
+ XFI_FM2_MAC10, NONE,
+ SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
+ NONE, NONE} },
+ {}
+};
+static const struct serdes_config serdes3_cfg_tbl[] = {
+ /* SerDes 3 */
+ {2, {PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1} },
+ {4, {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2} },
+ {6, {PCIE1, PCIE1, PCIE1, PCIE1, SRIO1, SRIO1, SRIO1, SRIO1} },
+ {8, {PCIE1, PCIE1, PCIE1, PCIE1, SRIO1, NONE, NONE, NONE} },
+ {9, {INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN,
+ INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN} },
+ {10, {INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN,
+ INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN} },
+ {12, {INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN,
+ PCIE2, PCIE2, PCIE2, PCIE2} },
+ {14, {INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN,
+ PCIE2, PCIE2, PCIE2, PCIE2} },
+ {16, {INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN,
+ SRIO1, SRIO1, SRIO1, SRIO1} },
+ {17, {INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN,
+ SRIO1, SRIO1, SRIO1, SRIO1} },
+ {19, {INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN,
+ SRIO1, SRIO1, SRIO1, SRIO1} },
+ {20, {INTERLAKEN, INTERLAKEN, INTERLAKEN, INTERLAKEN,
+ NONE, NONE, NONE, NONE} },
+ {}
+};
+static const struct serdes_config serdes4_cfg_tbl[] = {
+ /* SerDes 4 */
+ {4, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, PCIE4, PCIE4} },
+ {6, {SRIO2, SRIO2, SRIO2, SRIO2, SRIO2, SRIO2, SRIO2, SRIO2} },
+ {8, {SRIO2, SRIO2, SRIO2, SRIO2, SRIO2, SRIO2, SRIO2, SRIO2} },
+ {10, {PCIE3, PCIE3, PCIE3, PCIE3, SATA1, SATA1, SATA2, SATA2} },
+ {12, {AURORA, AURORA, AURORA, AURORA, SATA1, SATA1, SATA2, SATA2} },
+ {14, {AURORA, AURORA, AURORA, AURORA, SRIO2, SRIO2, SRIO2, SRIO2} },
+ {16, {AURORA, AURORA, AURORA, AURORA, SRIO2, SRIO2, SRIO2, SRIO2} },
+ {18, {AURORA, AURORA, AURORA, AURORA, AURORA, AURORA, AURORA, AURORA} },
+ {}
+}
+;
+#else
+#error "Need to define SerDes protocol"
+#endif
+static const struct serdes_config *serdes_cfg_tbl[] = {
+ serdes1_cfg_tbl,
+ serdes2_cfg_tbl,
+ serdes3_cfg_tbl,
+ serdes4_cfg_tbl,
+};
+
+enum srds_prtcl serdes_get_prtcl(int serdes, int cfg, int lane)
+{
+ const struct serdes_config *ptr;
+
+ if (serdes >= ARRAY_SIZE(serdes_cfg_tbl))
+ return 0;
+
+ ptr = serdes_cfg_tbl[serdes];
+ while (ptr->protocol) {
+ if (ptr->protocol == cfg)
+ return ptr->lanes[lane];
+ ptr++;
+ }
+ return 0;
+}
+
+int is_serdes_prtcl_valid(int serdes, u32 prtcl)
+{
+ int i;
+ const struct serdes_config *ptr;
+
+ if (serdes >= ARRAY_SIZE(serdes_cfg_tbl))
+ return 0;
+
+ ptr = serdes_cfg_tbl[serdes];
+ while (ptr->protocol) {
+ if (ptr->protocol == prtcl)
+ break;
+ ptr++;
+ }
+
+ if (!ptr->protocol)
+ return 0;
+
+ for (i = 0; i < SRDS_MAX_LANES; i++) {
+ if (ptr->lanes[i] != NONE)
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc85xx/tlb.c b/arch/powerpc/cpu/mpc85xx/tlb.c
new file mode 100644
index 0000000..0dff37f
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/tlb.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#ifdef CONFIG_ADDR_MAP
+#include <addr_map.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void invalidate_tlb(u8 tlb)
+{
+ if (tlb == 0)
+ mtspr(MMUCSR0, 0x4);
+ if (tlb == 1)
+ mtspr(MMUCSR0, 0x2);
+}
+
+void init_tlbs(void)
+{
+ int i;
+
+ for (i = 0; i < num_tlb_entries; i++) {
+ write_tlb(tlb_table[i].mas0,
+ tlb_table[i].mas1,
+ tlb_table[i].mas2,
+ tlb_table[i].mas3,
+ tlb_table[i].mas7);
+ }
+
+ return ;
+}
+
+#if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_SPL_BUILD)
+void read_tlbcam_entry(int idx, u32 *valid, u32 *tsize, unsigned long *epn,
+ phys_addr_t *rpn)
+{
+ u32 _mas1;
+
+ mtspr(MAS0, FSL_BOOKE_MAS0(1, idx, 0));
+ asm volatile("tlbre;isync");
+ _mas1 = mfspr(MAS1);
+
+ *valid = (_mas1 & MAS1_VALID);
+ *tsize = (_mas1 >> 7) & 0x1f;
+ *epn = mfspr(MAS2) & MAS2_EPN;
+ *rpn = mfspr(MAS3) & MAS3_RPN;
+#ifdef CONFIG_ENABLE_36BIT_PHYS
+ *rpn |= ((u64)mfspr(MAS7)) << 32;
+#endif
+}
+
+void print_tlbcam(void)
+{
+ int i;
+ unsigned int num_cam = mfspr(SPRN_TLB1CFG) & 0xfff;
+
+ /* walk all the entries */
+ printf("TLBCAM entries\n");
+ for (i = 0; i < num_cam; i++) {
+ unsigned long epn;
+ u32 tsize, valid;
+ phys_addr_t rpn;
+
+ read_tlbcam_entry(i, &valid, &tsize, &epn, &rpn);
+ printf("entry %02d: V: %d EPN 0x%08x RPN 0x%08llx size:",
+ i, (valid == 0) ? 0 : 1, (unsigned int)epn,
+ (unsigned long long)rpn);
+ print_size(TSIZE_TO_BYTES(tsize), "\n");
+ }
+}
+
+static inline void use_tlb_cam(u8 idx)
+{
+ int i = idx / 32;
+ int bit = idx % 32;
+
+ gd->arch.used_tlb_cams[i] |= (1 << bit);
+}
+
+static inline void free_tlb_cam(u8 idx)
+{
+ int i = idx / 32;
+ int bit = idx % 32;
+
+ gd->arch.used_tlb_cams[i] &= ~(1 << bit);
+}
+
+void init_used_tlb_cams(void)
+{
+ int i;
+ unsigned int num_cam = mfspr(SPRN_TLB1CFG) & 0xfff;
+
+ for (i = 0; i < ((CONFIG_SYS_NUM_TLBCAMS+31)/32); i++)
+ gd->arch.used_tlb_cams[i] = 0;
+
+ /* walk all the entries */
+ for (i = 0; i < num_cam; i++) {
+ mtspr(MAS0, FSL_BOOKE_MAS0(1, i, 0));
+ asm volatile("tlbre;isync");
+ if (mfspr(MAS1) & MAS1_VALID)
+ use_tlb_cam(i);
+ }
+}
+
+int find_free_tlbcam(void)
+{
+ int i;
+ u32 idx;
+
+ for (i = 0; i < ((CONFIG_SYS_NUM_TLBCAMS+31)/32); i++) {
+ idx = ffz(gd->arch.used_tlb_cams[i]);
+
+ if (idx != 32)
+ break;
+ }
+
+ idx += i * 32;
+
+ if (idx >= CONFIG_SYS_NUM_TLBCAMS)
+ return -1;
+
+ return idx;
+}
+
+void set_tlb(u8 tlb, u32 epn, u64 rpn,
+ u8 perms, u8 wimge,
+ u8 ts, u8 esel, u8 tsize, u8 iprot)
+{
+ u32 _mas0, _mas1, _mas2, _mas3, _mas7;
+
+ if (tlb == 1)
+ use_tlb_cam(esel);
+
+ if ((mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1 &&
+ tsize & 1) {
+ printf("%s: bad tsize %d on entry %d at 0x%08x\n",
+ __func__, tsize, tlb, epn);
+ return;
+ }
+
+ _mas0 = FSL_BOOKE_MAS0(tlb, esel, 0);
+ _mas1 = FSL_BOOKE_MAS1(1, iprot, 0, ts, tsize);
+ _mas2 = FSL_BOOKE_MAS2(epn, wimge);
+ _mas3 = FSL_BOOKE_MAS3(rpn, 0, perms);
+ _mas7 = FSL_BOOKE_MAS7(rpn);
+
+ write_tlb(_mas0, _mas1, _mas2, _mas3, _mas7);
+
+#ifdef CONFIG_ADDR_MAP
+ if ((tlb == 1) && (gd->flags & GD_FLG_RELOC))
+ addrmap_set_entry(epn, rpn, TSIZE_TO_BYTES(tsize), esel);
+#endif
+}
+
+void disable_tlb(u8 esel)
+{
+ u32 _mas0, _mas1, _mas2, _mas3;
+
+ free_tlb_cam(esel);
+
+ _mas0 = FSL_BOOKE_MAS0(1, esel, 0);
+ _mas1 = 0;
+ _mas2 = 0;
+ _mas3 = 0;
+
+ mtspr(MAS0, _mas0);
+ mtspr(MAS1, _mas1);
+ mtspr(MAS2, _mas2);
+ mtspr(MAS3, _mas3);
+#ifdef CONFIG_ENABLE_36BIT_PHYS
+ mtspr(MAS7, 0);
+#endif
+ asm volatile("isync;msync;tlbwe;isync");
+
+#ifdef CONFIG_ADDR_MAP
+ if (gd->flags & GD_FLG_RELOC)
+ addrmap_set_entry(0, 0, 0, esel);
+#endif
+}
+
+static void tlbsx (const volatile unsigned *addr)
+{
+ __asm__ __volatile__ ("tlbsx 0,%0" : : "r" (addr), "m" (*addr));
+}
+
+/* return -1 if we didn't find anything */
+int find_tlb_idx(void *addr, u8 tlbsel)
+{
+ u32 _mas0, _mas1;
+
+ /* zero out Search PID, AS */
+ mtspr(MAS6, 0);
+
+ tlbsx(addr);
+
+ _mas0 = mfspr(MAS0);
+ _mas1 = mfspr(MAS1);
+
+ /* we found something, and its in the TLB we expect */
+ if ((MAS1_VALID & _mas1) &&
+ (MAS0_TLBSEL(tlbsel) == (_mas0 & MAS0_TLBSEL_MSK))) {
+ return ((_mas0 & MAS0_ESEL_MSK) >> 16);
+ }
+
+ return -1;
+}
+
+#ifdef CONFIG_ADDR_MAP
+void init_addr_map(void)
+{
+ int i;
+ unsigned int num_cam = mfspr(SPRN_TLB1CFG) & 0xfff;
+
+ /* walk all the entries */
+ for (i = 0; i < num_cam; i++) {
+ unsigned long epn;
+ u32 tsize, valid;
+ phys_addr_t rpn;
+
+ read_tlbcam_entry(i, &valid, &tsize, &epn, &rpn);
+ if (valid & MAS1_VALID)
+ addrmap_set_entry(epn, rpn, TSIZE_TO_BYTES(tsize), i);
+ }
+
+ return ;
+}
+#endif
+
+unsigned int
+setup_ddr_tlbs_phys(phys_addr_t p_addr, unsigned int memsize_in_meg)
+{
+ int i;
+ unsigned int tlb_size;
+ unsigned int wimge = MAS2_M;
+ unsigned int ram_tlb_address = (unsigned int)CONFIG_SYS_DDR_SDRAM_BASE;
+ unsigned int max_cam, tsize_mask;
+ u64 size, memsize = (u64)memsize_in_meg << 20;
+
+#ifdef CONFIG_SYS_PPC_DDR_WIMGE
+ wimge = CONFIG_SYS_PPC_DDR_WIMGE;
+#endif
+ size = min(memsize, CONFIG_MAX_MEM_MAPPED);
+ if ((mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1) {
+ /* Convert (4^max) kB to (2^max) bytes */
+ max_cam = ((mfspr(SPRN_TLB1CFG) >> 16) & 0xf) * 2 + 10;
+ tsize_mask = ~1U;
+ } else {
+ /* Convert (2^max) kB to (2^max) bytes */
+ max_cam = __ilog2(mfspr(SPRN_TLB1PS)) + 10;
+ tsize_mask = ~0U;
+ }
+
+ for (i = 0; size && i < 8; i++) {
+ int ram_tlb_index = find_free_tlbcam();
+ u32 camsize = __ilog2_u64(size) & tsize_mask;
+ u32 align = __ilog2(ram_tlb_address) & tsize_mask;
+
+ if (ram_tlb_index == -1)
+ break;
+
+ if (align == -2) align = max_cam;
+ if (camsize > align)
+ camsize = align;
+
+ if (camsize > max_cam)
+ camsize = max_cam;
+
+ tlb_size = camsize - 10;
+
+ set_tlb(1, ram_tlb_address, p_addr,
+ MAS3_SX|MAS3_SW|MAS3_SR, wimge,
+ 0, ram_tlb_index, tlb_size, 1);
+
+ size -= 1ULL << camsize;
+ memsize -= 1ULL << camsize;
+ ram_tlb_address += 1UL << camsize;
+ p_addr += 1UL << camsize;
+ }
+
+ if (memsize)
+ print_size(memsize, " left unmapped\n");
+ return memsize_in_meg;
+}
+
+unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg)
+{
+ return
+ setup_ddr_tlbs_phys(CONFIG_SYS_DDR_SDRAM_BASE, memsize_in_meg);
+}
+
+/* Invalidate the DDR TLBs for the requested size */
+void clear_ddr_tlbs_phys(phys_addr_t p_addr, unsigned int memsize_in_meg)
+{
+ u32 vstart = CONFIG_SYS_DDR_SDRAM_BASE;
+ unsigned long epn;
+ u32 tsize, valid, ptr;
+ phys_addr_t rpn = 0;
+ int ddr_esel;
+ u64 memsize = (u64)memsize_in_meg << 20;
+
+ ptr = vstart;
+
+ while (ptr < (vstart + memsize)) {
+ ddr_esel = find_tlb_idx((void *)ptr, 1);
+ if (ddr_esel != -1) {
+ read_tlbcam_entry(ddr_esel, &valid, &tsize, &epn, &rpn);
+ disable_tlb(ddr_esel);
+ }
+ ptr += TSIZE_TO_BYTES(tsize);
+ }
+}
+
+void clear_ddr_tlbs(unsigned int memsize_in_meg)
+{
+ clear_ddr_tlbs_phys(CONFIG_SYS_DDR_SDRAM_BASE, memsize_in_meg);
+}
+
+
+#endif /* not SPL */
diff --git a/arch/powerpc/cpu/mpc85xx/traps.c b/arch/powerpc/cpu/mpc85xx/traps.c
new file mode 100644
index 0000000..476ae93
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/traps.c
@@ -0,0 +1,313 @@
+/*
+ * linux/arch/powerpc/kernel/traps.c
+ *
+ * Copyright 2007 Freescale Semiconductor.
+ * Copyright (C) 2003 Motorola
+ * Modified by Xianghua Xiao(x.xiao@motorola.com)
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+/*
+ * End of addressable memory. This may be less than the actual
+ * amount of memory on the system if we're unable to keep all
+ * the memory mapped in.
+ */
+extern ulong get_effective_memsize(void);
+#define END_OF_MEM (gd->bd->bi_memstart + get_effective_memsize())
+
+static __inline__ void set_tsr(unsigned long val)
+{
+ asm volatile("mtspr 0x150, %0" : : "r" (val));
+}
+
+static __inline__ unsigned long get_esr(void)
+{
+ unsigned long val;
+ asm volatile("mfspr %0, 0x03e" : "=r" (val) :);
+ return val;
+}
+
+#define ESR_MCI 0x80000000
+#define ESR_PIL 0x08000000
+#define ESR_PPR 0x04000000
+#define ESR_PTR 0x02000000
+#define ESR_DST 0x00800000
+#define ESR_DIZ 0x00400000
+#define ESR_U0F 0x00008000
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+/*
+ * Trap & Exception support
+ */
+
+static void print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ printf("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ printf("\n");
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *)*sp;
+ }
+ printf("\n");
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ int i;
+
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+ regs->msr&MSR_IR ? 1 : 0,
+ regs->msr&MSR_DR ? 1 : 0);
+
+ printf("\n");
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0)
+ {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7)
+ {
+ printf("\n");
+ }
+ }
+}
+
+
+static void _exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void CritcalInputException(struct pt_regs *regs)
+{
+ panic("Critical Input Exception");
+}
+
+int machinecheck_count = 0;
+int machinecheck_error = 0;
+void MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup;
+ unsigned int mcsr, mcsrr0, mcsrr1, mcar;
+
+ /* Probing PCI using config cycles cause this exception
+ * when a device is not present. Catch it and return to
+ * the PCI exception handler.
+ */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ return;
+ }
+
+ mcsrr0 = mfspr(SPRN_MCSRR0);
+ mcsrr1 = mfspr(SPRN_MCSRR1);
+ mcsr = mfspr(SPRN_MCSR);
+ mcar = mfspr(SPRN_MCAR);
+
+ machinecheck_count++;
+ machinecheck_error=1;
+
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ printf("Machine check in kernel mode.\n");
+ printf("Caused by (from mcsr): ");
+ printf("mcsr = 0x%08x\n", mcsr);
+ if (mcsr & 0x80000000)
+ printf("Machine check input pin\n");
+ if (mcsr & 0x40000000)
+ printf("Instruction cache parity error\n");
+ if (mcsr & 0x20000000)
+ printf("Data cache push parity error\n");
+ if (mcsr & 0x10000000)
+ printf("Data cache parity error\n");
+ if (mcsr & 0x00000080)
+ printf("Bus instruction address error\n");
+ if (mcsr & 0x00000040)
+ printf("Bus Read address error\n");
+ if (mcsr & 0x00000020)
+ printf("Bus Write address error\n");
+ if (mcsr & 0x00000010)
+ printf("Bus Instruction data bus error\n");
+ if (mcsr & 0x00000008)
+ printf("Bus Read data bus error\n");
+ if (mcsr & 0x00000004)
+ printf("Bus Write bus error\n");
+ if (mcsr & 0x00000002)
+ printf("Bus Instruction parity error\n");
+ if (mcsr & 0x00000001)
+ printf("Bus Read parity error\n");
+
+ show_regs(regs);
+ printf("MCSR=0x%08x \tMCSRR0=0x%08x \nMCSRR1=0x%08x \tMCAR=0x%08x\n",
+ mcsr, mcsrr0, mcsrr1, mcar);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ if (machinecheck_count > 10) {
+ panic("machine check count too high\n");
+ }
+
+ if (machinecheck_count > 1) {
+ regs->nip += 4; /* skip offending instruction */
+ printf("Skipping current instr, Returning to 0x%08lx\n",
+ regs->nip);
+ } else {
+ printf("Returning back to 0x%08lx\n",regs->nip);
+ }
+}
+
+void AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void ProgramCheckException(struct pt_regs *regs)
+{
+ long esr_val;
+
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ show_regs(regs);
+
+ esr_val = get_esr();
+ if( esr_val & ESR_PIL )
+ printf( "** Illegal Instruction **\n" );
+ else if( esr_val & ESR_PPR )
+ printf( "** Privileged Instruction **\n" );
+ else if( esr_val & ESR_PTR )
+ printf( "** Trap Instruction **\n" );
+
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void PITException(struct pt_regs *regs)
+{
+ /*
+ * Reset PIT interrupt
+ */
+ set_tsr(0x0c000000);
+
+ /*
+ * Call timer_interrupt routine in interrupts.c
+ */
+ timer_interrupt(NULL);
+}
+
+void UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+void ExtIntException(struct pt_regs *regs)
+{
+ volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR);
+
+ uint vect;
+
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ printf("External Interrupt Exception at PC: %lx, SR: %lx, vector=%lx",
+ regs->nip, regs->msr, regs->trap);
+ vect = pic->iack0;
+ printf(" irq IACK0@%05x=%d\n",(int)&pic->iack0,vect);
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+}
+
+void DebugException(struct pt_regs *regs)
+{
+ printf("Debugger trap at @ %lx\n", regs->nip );
+ show_regs(regs);
+#if defined(CONFIG_CMD_BEDBUG)
+ do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading. If not present, return -1, otherwise
+ * return 0.
+ */
+int addr_probe(uint *addr)
+{
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc85xx/u-boot-nand.lds b/arch/powerpc/cpu/mpc85xx/u-boot-nand.lds
new file mode 100644
index 0000000..65106f5
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/u-boot-nand.lds
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2009-2012 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+PHDRS
+{
+ text PT_LOAD;
+ bss PT_LOAD;
+}
+
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .text :
+ {
+ *(.text*)
+ } :text
+ _etext = .;
+ PROVIDE (etext = .);
+ .rodata :
+ {
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ } :text
+
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x00FF) & 0xFFFFFF00;
+ _erotext = .;
+ PROVIDE (erotext = .);
+ .reloc :
+ {
+ _GOT2_TABLE_ = .;
+ KEEP(*(.got2))
+ KEEP(*(.got))
+ PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
+ _FIXUP_TABLE_ = .;
+ KEEP(*(.fixup))
+ }
+ __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
+ __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+ .data :
+ {
+ *(.data*)
+ *(.sdata*)
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+
+ . = .;
+
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+ . = .;
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ . = ALIGN(256);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(256);
+ __init_end = .;
+
+ .bootpg ADDR(.text) - 0x1000 :
+ {
+ KEEP(arch/powerpc/cpu/mpc85xx/start.o (.bootpg))
+ } :text = 0xffff
+
+ . = ADDR(.text) + 0x80000;
+
+ __bss_start = .;
+ .bss (NOLOAD) :
+ {
+ *(.sbss*)
+ *(.bss*)
+ *(COMMON)
+ } :bss
+
+ . = ALIGN(4);
+ __bss_end = . ;
+ PROVIDE (end = .);
+}
diff --git a/arch/powerpc/cpu/mpc85xx/u-boot-nand_spl.lds b/arch/powerpc/cpu/mpc85xx/u-boot-nand_spl.lds
new file mode 100644
index 0000000..80cd980
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/u-boot-nand_spl.lds
@@ -0,0 +1,85 @@
+/*
+ * (C) Copyright 2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de
+ *
+ * Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "config.h" /* CONFIG_BOARDDIR */
+
+OUTPUT_ARCH(powerpc)
+SECTIONS
+{
+ . = 0xfff00000;
+ .text : {
+ *(.text*)
+ }
+ _etext = .;
+
+ .reloc : {
+ _GOT2_TABLE_ = .;
+ KEEP(*(.got2))
+ KEEP(*(.got))
+ PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
+ _FIXUP_TABLE_ = .;
+ KEEP(*(.fixup))
+ }
+ __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
+ __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+ . = ALIGN(8);
+ .data : {
+ *(.rodata*)
+ *(.data*)
+ *(.sdata*)
+ }
+ _edata = .;
+
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+ . = ALIGN(8);
+ __init_begin = .;
+ __init_end = .;
+#if defined(CONFIG_FSL_IFC) /* Restrict bootpg at 4K boundry for IFC */
+ .bootpg ADDR(.text) + 0x1000 :
+ {
+ start.o (.bootpg)
+ }
+#define RESET_VECTOR_OFFSET 0x1ffc /* IFC has 8K sram */
+#elif defined(CONFIG_FSL_ELBC)
+#define RESET_VECTOR_OFFSET 0xffc /* LBC has 4k sram */
+#else
+#error unknown NAND controller
+#endif
+ .resetvec ADDR(.text) + RESET_VECTOR_OFFSET : {
+ KEEP(*(.resetvec))
+ } = 0xffff
+
+ __bss_start = .;
+ .bss : {
+ *(.sbss*)
+ *(.bss*)
+ }
+ __bss_end = .;
+}
+ASSERT(__init_end <= (0xfff00000 + RESET_VECTOR_OFFSET), "NAND bootstrap too big");
diff --git a/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds b/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds
new file mode 100644
index 0000000..20284ed
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds
@@ -0,0 +1,103 @@
+/*
+ * (C) Copyright 2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de
+ *
+ * Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "config.h" /* CONFIG_BOARDDIR */
+
+OUTPUT_ARCH(powerpc)
+#ifdef CONFIG_SYS_MPC85XX_NO_RESETVEC
+PHDRS
+{
+ text PT_LOAD;
+ bss PT_LOAD;
+}
+#endif
+SECTIONS
+{
+ . = CONFIG_SPL_TEXT_BASE;
+ .text : {
+ *(.text*)
+ }
+ _etext = .;
+
+ .reloc : {
+ _GOT2_TABLE_ = .;
+ KEEP(*(.got2))
+ KEEP(*(.got))
+ PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
+ _FIXUP_TABLE_ = .;
+ KEEP(*(.fixup))
+ }
+ __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
+ __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+ . = ALIGN(8);
+ .data : {
+ *(.rodata*)
+ *(.data*)
+ *(.sdata*)
+ }
+ _edata = .;
+
+ . = ALIGN(8);
+ __init_begin = .;
+ __init_end = .;
+/* FIXME for non-NAND SPL */
+#if defined(CONFIG_FSL_IFC) /* Restrict bootpg at 4K boundry for IFC */
+ .bootpg ADDR(.text) + 0x1000 :
+ {
+ arch/powerpc/cpu/mpc85xx/start.o (.bootpg)
+ }
+#define RESET_VECTOR_OFFSET 0x1ffc /* IFC has 8K sram */
+#elif defined(CONFIG_FSL_ELBC)
+#define RESET_VECTOR_OFFSET 0xffc /* LBC has 4k sram */
+#else
+#error unknown NAND controller
+#endif
+#ifdef CONFIG_SYS_MPC85XX_NO_RESETVEC
+ .bootpg ADDR(.text) - 0x1000 :
+ {
+ KEEP(*(.bootpg))
+ } :text = 0xffff
+#else
+ .resetvec ADDR(.text) + RESET_VECTOR_OFFSET : {
+ KEEP(*(.resetvec))
+ } = 0xffff
+#endif
+
+ /*
+ * Make sure that the bss segment isn't linked at 0x0, otherwise its
+ * address won't be updated during relocation fixups.
+ */
+ . |= 0x10;
+
+ . = ALIGN(4);
+ __bss_start = .;
+ .bss : {
+ *(.sbss*)
+ *(.bss*)
+ }
+ . = ALIGN(4);
+ __bss_end = .;
+}
diff --git a/arch/powerpc/cpu/mpc85xx/u-boot.lds b/arch/powerpc/cpu/mpc85xx/u-boot.lds
new file mode 100644
index 0000000..2643563
--- /dev/null
+++ b/arch/powerpc/cpu/mpc85xx/u-boot.lds
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2007-2009, 2011 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "config.h" /* CONFIG_BOARDDIR */
+
+#ifdef CONFIG_RESET_VECTOR_ADDRESS
+#define RESET_VECTOR_ADDRESS CONFIG_RESET_VECTOR_ADDRESS
+#else
+#define RESET_VECTOR_ADDRESS 0xfffffffc
+#endif
+
+OUTPUT_ARCH(powerpc)
+
+PHDRS
+{
+ text PT_LOAD;
+ bss PT_LOAD;
+}
+
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .text :
+ {
+ *(.text*)
+ } :text
+ _etext = .;
+ PROVIDE (etext = .);
+ .rodata :
+ {
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ } :text
+
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x00FF) & 0xFFFFFF00;
+ _erotext = .;
+ PROVIDE (erotext = .);
+ .reloc :
+ {
+ _GOT2_TABLE_ = .;
+ KEEP(*(.got2))
+ KEEP(*(.got))
+ PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
+ _FIXUP_TABLE_ = .;
+ KEEP(*(.fixup))
+ }
+ __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
+ __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+ .data :
+ {
+ *(.data*)
+ *(.sdata*)
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+
+ . = .;
+
+ . = ALIGN(4);
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+ . = .;
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ . = ALIGN(256);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(256);
+ __init_end = .;
+
+#ifdef CONFIG_SYS_MPC85XX_NO_RESETVEC
+ .bootpg ADDR(.text) - 0x1000 :
+ {
+ KEEP(arch/powerpc/cpu/mpc85xx/start.o (.bootpg))
+ } :text = 0xffff
+ . = ADDR(.text) + 0x80000;
+#else
+ .bootpg RESET_VECTOR_ADDRESS - 0xffc :
+ {
+ arch/powerpc/cpu/mpc85xx/start.o (.bootpg)
+ } :text = 0xffff
+
+ .resetvec RESET_VECTOR_ADDRESS :
+ {
+ KEEP(*(.resetvec))
+ } :text = 0xffff
+
+ . = RESET_VECTOR_ADDRESS + 0x4;
+
+ /*
+ * Make sure that the bss segment isn't linked at 0x0, otherwise its
+ * address won't be updated during relocation fixups. Note that
+ * this is a temporary fix. Code to dynamically the fixup the bss
+ * location will be added in the future. When the bss relocation
+ * fixup code is present this workaround should be removed.
+ */
+#if (RESET_VECTOR_ADDRESS == 0xfffffffc)
+ . |= 0x10;
+#endif
+#endif
+
+ __bss_start = .;
+ .bss (NOLOAD) :
+ {
+ *(.sbss*)
+ *(.bss*)
+ *(COMMON)
+ } :bss
+
+ . = ALIGN(4);
+ __bss_end = . ;
+ PROVIDE (end = .);
+}
diff --git a/arch/powerpc/cpu/mpc86xx/Makefile b/arch/powerpc/cpu/mpc86xx/Makefile
new file mode 100644
index 0000000..b4ef286
--- /dev/null
+++ b/arch/powerpc/cpu/mpc86xx/Makefile
@@ -0,0 +1,65 @@
+#
+# Copyright 2007 Freescale Semiconductor, Inc.
+# (C) Copyright 2002,2003 Motorola Inc.
+# Xianghua Xiao,X.Xiao@motorola.com
+#
+# (C) Copyright 2004 Freescale Semiconductor. (MC86xx Port)
+# Jeff Brown
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(CPU).o
+
+SSTART = start.o
+CSTART = traps.o
+
+SOBJS-y += cache.o
+SOBJS-$(CONFIG_MP) += release.o
+
+COBJS-y += cpu.o
+COBJS-y += cpu_init.o
+# 8610 & 8641 are identical w/regards to DDR
+COBJS-$(CONFIG_MPC8610) += ddr-8641.o
+COBJS-$(CONFIG_MPC8641) += ddr-8641.o
+COBJS-$(CONFIG_OF_LIBFDT) += fdt.o
+COBJS-y += interrupts.o
+COBJS-$(CONFIG_MP) += mp.o
+COBJS-$(CONFIG_MPC8610) += mpc8610_serdes.o
+COBJS-$(CONFIG_MPC8641) += mpc8641_serdes.o
+COBJS-y += speed.o
+
+SRCS := $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
+START := $(addprefix $(obj),$(SSTART) $(CSTART))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/powerpc/cpu/mpc86xx/cache.S b/arch/powerpc/cpu/mpc86xx/cache.S
new file mode 100644
index 0000000..0bb058b
--- /dev/null
+++ b/arch/powerpc/cpu/mpc86xx/cache.S
@@ -0,0 +1,378 @@
+#include <config.h>
+#include <mpc86xx.h>
+#include <version.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#ifndef CACHE_LINE_SIZE
+# define CACHE_LINE_SIZE L1_CACHE_BYTES
+#endif
+
+#if CACHE_LINE_SIZE == 128
+#define LG_CACHE_LINE_SIZE 7
+#elif CACHE_LINE_SIZE == 32
+#define LG_CACHE_LINE_SIZE 5
+#elif CACHE_LINE_SIZE == 16
+#define LG_CACHE_LINE_SIZE 4
+#elif CACHE_LINE_SIZE == 8
+#define LG_CACHE_LINE_SIZE 3
+#else
+# error "Invalid cache line size!"
+#endif
+
+/*
+ * Most of this code is taken from 74xx_7xx/cache.S
+ * and then cleaned up a bit
+ */
+
+/*
+ * Invalidate L1 instruction cache.
+ */
+_GLOBAL(invalidate_l1_instruction_cache)
+ /* use invalidate-all bit in HID0 */
+ mfspr r3,HID0
+ ori r3,r3,HID0_ICFI
+ mtspr HID0,r3
+ isync
+ blr
+
+/*
+ * Invalidate L1 data cache.
+ */
+_GLOBAL(invalidate_l1_data_cache)
+ mfspr r3,HID0
+ ori r3,r3,HID0_DCFI
+ mtspr HID0,r3
+ isync
+ blr
+
+/*
+ * Flush data cache.
+ */
+_GLOBAL(flush_dcache)
+ lis r3,0
+ lis r5,CACHE_LINE_SIZE
+flush:
+ cmp 0,1,r3,r5
+ bge done
+ lwz r5,0(r3)
+ lis r5,CACHE_LINE_SIZE
+ addi r3,r3,0x4
+ b flush
+done:
+ blr
+/*
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
+ * This is a no-op on the 601.
+ *
+ * flush_icache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(flush_icache_range)
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,LG_CACHE_LINE_SIZE
+ beqlr
+ mtctr r4
+ mr r6,r3
+1: dcbst 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ mtctr r4
+2: icbi 0,r6
+ addi r6,r6,CACHE_LINE_SIZE
+ bdnz 2b
+ sync /* additional sync needed on g4 */
+ isync
+ blr
+/*
+ * Write any modified data cache blocks out to memory.
+ * Does not invalidate the corresponding cache lines (especially for
+ * any corresponding instruction cache).
+ *
+ * clean_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(clean_dcache_range)
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5 /* align r3 down to cache line */
+ subf r4,r3,r4 /* r4 = offset of stop from start of cache line */
+ add r4,r4,r5 /* r4 += cache_line_size-1 */
+ srwi. r4,r4,LG_CACHE_LINE_SIZE /* r4 = number of cache lines to flush */
+ beqlr /* if r4 == 0 return */
+ mtctr r4 /* ctr = r4 */
+
+ sync
+1: dcbst 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ blr
+
+/*
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
+ *
+ * flush_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(flush_dcache_range)
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,LG_CACHE_LINE_SIZE
+ beqlr
+ mtctr r4
+
+ sync
+1: dcbf 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbf's to get to ram */
+ blr
+
+/*
+ * Like above, but invalidate the D-cache. This is used by the 8xx
+ * to invalidate the cache so the PPC core doesn't get stale data
+ * from the CPM (no cache snooping here :-).
+ *
+ * invalidate_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(invalidate_dcache_range)
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,LG_CACHE_LINE_SIZE
+ beqlr
+ mtctr r4
+
+ sync
+1: dcbi 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbi's to get to ram */
+ blr
+
+/*
+ * Flush a particular page from the data cache to RAM.
+ * Note: this is necessary because the instruction cache does *not*
+ * snoop from the data cache.
+ *
+ * void __flush_page_to_ram(void *page)
+ */
+_GLOBAL(__flush_page_to_ram)
+ rlwinm r3,r3,0,0,19 /* Get page base address */
+ li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
+ mtctr r4
+ mr r6,r3
+0: dcbst 0,r3 /* Write line to ram */
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 0b
+ sync
+ mtctr r4
+1: icbi 0,r6
+ addi r6,r6,CACHE_LINE_SIZE
+ bdnz 1b
+ sync
+ isync
+ blr
+
+/*
+ * Flush a particular page from the instruction cache.
+ * Note: this is necessary because the instruction cache does *not*
+ * snoop from the data cache.
+ *
+ * void __flush_icache_page(void *page)
+ */
+_GLOBAL(__flush_icache_page)
+ li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
+ mtctr r4
+1: icbi 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync
+ isync
+ blr
+
+/*
+ * Clear a page using the dcbz instruction, which doesn't cause any
+ * memory traffic (except to write out any cache lines which get
+ * displaced). This only works on cacheable memory.
+ */
+_GLOBAL(clear_page)
+ li r0,4096/CACHE_LINE_SIZE
+ mtctr r0
+1: dcbz 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ blr
+
+/*
+ * Enable L1 Instruction cache
+ */
+_GLOBAL(icache_enable)
+ mfspr r3, HID0
+ li r5, HID0_ICFI|HID0_ILOCK
+ andc r3, r3, r5
+ ori r3, r3, HID0_ICE
+ ori r5, r3, HID0_ICFI
+ mtspr HID0, r5
+ mtspr HID0, r3
+ isync
+ blr
+
+/*
+ * Disable L1 Instruction cache
+ */
+_GLOBAL(icache_disable)
+ mflr r4
+ bl invalidate_l1_instruction_cache /* uses r3 */
+ sync
+ mtlr r4
+ mfspr r3, HID0
+ li r5, 0
+ ori r5, r5, HID0_ICE
+ andc r3, r3, r5
+ mtspr HID0, r3
+ isync
+ blr
+
+/*
+ * Is instruction cache enabled?
+ */
+_GLOBAL(icache_status)
+ mfspr r3, HID0
+ andi. r3, r3, HID0_ICE
+ blr
+
+
+_GLOBAL(l1dcache_enable)
+ mfspr r3, HID0
+ li r5, HID0_DCFI|HID0_DLOCK
+ andc r3, r3, r5
+ mtspr HID0, r3 /* no invalidate, unlock */
+ ori r3, r3, HID0_DCE
+ ori r5, r3, HID0_DCFI
+ mtspr HID0, r5 /* enable + invalidate */
+ mtspr HID0, r3 /* enable */
+ sync
+ blr
+
+/*
+ * Enable data cache(s) - L1 and optionally L2
+ * Calls l2cache_enable. LR saved in r5
+ */
+_GLOBAL(dcache_enable)
+ mfspr r3, HID0
+ li r5, HID0_DCFI|HID0_DLOCK
+ andc r3, r3, r5
+ mtspr HID0, r3 /* no invalidate, unlock */
+ ori r3, r3, HID0_DCE
+ ori r5, r3, HID0_DCFI
+ mtspr HID0, r5 /* enable + invalidate */
+ mtspr HID0, r3 /* enable */
+ sync
+#ifdef CONFIG_SYS_L2
+ mflr r5
+ bl l2cache_enable /* uses r3 and r4 */
+ sync
+ mtlr r5
+#endif
+ blr
+
+
+/*
+ * Disable data cache(s) - L1 and optionally L2
+ * Calls flush_dcache and l2cache_disable_no_flush.
+ * LR saved in r4
+ */
+_GLOBAL(dcache_disable)
+ mflr r4 /* save link register */
+ bl flush_dcache /* uses r3 and r5 */
+ sync
+ mfspr r3, HID0
+ li r5, HID0_DCFI|HID0_DLOCK
+ andc r3, r3, r5
+ mtspr HID0, r3 /* no invalidate, unlock */
+ li r5, HID0_DCE|HID0_DCFI
+ andc r3, r3, r5 /* no enable, no invalidate */
+ mtspr HID0, r3
+ sync
+#ifdef CONFIG_SYS_L2
+ bl l2cache_disable_no_flush /* uses r3 */
+#endif
+ mtlr r4 /* restore link register */
+ blr
+
+/*
+ * Is data cache enabled?
+ */
+_GLOBAL(dcache_status)
+ mfspr r3, HID0
+ andi. r3, r3, HID0_DCE
+ blr
+
+/*
+ * Invalidate L2 cache using L2I, assume L2 is enabled
+ */
+_GLOBAL(l2cache_invalidate)
+ mfspr r3, l2cr
+ rlwinm. r3, r3, 0, 0, 0
+ beq 1f
+
+ mfspr r3, l2cr
+ rlwinm r3, r3, 0, 1, 31
+
+#ifdef CONFIG_ALTIVEC
+ dssall
+#endif
+ sync
+ mtspr l2cr, r3
+ sync
+1: mfspr r3, l2cr
+ oris r3, r3, L2CR_L2I@h
+ mtspr l2cr, r3
+
+invl2:
+ mfspr r3, l2cr
+ andis. r3, r3, L2CR_L2I@h
+ bne invl2
+ blr
+
+/*
+ * Enable L2 cache
+ * Calls l2cache_invalidate. LR is saved in r4
+ */
+_GLOBAL(l2cache_enable)
+ mflr r4 /* save link register */
+ bl l2cache_invalidate /* uses r3 */
+ sync
+ lis r3, L2_ENABLE@h
+ ori r3, r3, L2_ENABLE@l
+ mtspr l2cr, r3
+ isync
+ mtlr r4 /* restore link register */
+ blr
+
+/*
+ * Disable L2 cache
+ * Calls flush_dcache. LR is saved in r4
+ */
+_GLOBAL(l2cache_disable)
+ mflr r4 /* save link register */
+ bl flush_dcache /* uses r3 and r5 */
+ sync
+ mtlr r4 /* restore link register */
+l2cache_disable_no_flush: /* provide way to disable L2 w/o flushing */
+ lis r3, L2_INIT@h
+ ori r3, r3, L2_INIT@l
+ mtspr l2cr, r3
+ isync
+ blr
diff --git a/arch/powerpc/cpu/mpc86xx/config.mk b/arch/powerpc/cpu/mpc86xx/config.mk
new file mode 100644
index 0000000..92ff7bf
--- /dev/null
+++ b/arch/powerpc/cpu/mpc86xx/config.mk
@@ -0,0 +1,27 @@
+#
+# (C) Copyright 2004 Freescale Semiconductor.
+# Jeff Brown
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_RELFLAGS += -meabi
+
+PLATFORM_CPPFLAGS += -ffixed-r2 -mstring
+PLATFORM_CPPFLAGS += -maltivec -mabi=altivec -msoft-float
diff --git a/arch/powerpc/cpu/mpc86xx/cpu.c b/arch/powerpc/cpu/mpc86xx/cpu.c
new file mode 100644
index 0000000..5ed3eb2
--- /dev/null
+++ b/arch/powerpc/cpu/mpc86xx/cpu.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2006,2009-2010 Freescale Semiconductor, Inc.
+ * Jeff Brown
+ * Srikanth Srinivasan (srikanth.srinivasan@freescale.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <asm/cache.h>
+#include <asm/mmu.h>
+#include <mpc86xx.h>
+#include <asm/fsl_law.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Default board reset function
+ */
+static void
+__board_reset(void)
+{
+ /* Do nothing */
+}
+void board_reset(void) __attribute__((weak, alias("__board_reset")));
+
+
+int
+checkcpu(void)
+{
+ sys_info_t sysinfo;
+ uint pvr, svr;
+ uint major, minor;
+ char buf1[32], buf2[32];
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile ccsr_gur_t *gur = &immap->im_gur;
+ struct cpu_type *cpu;
+ uint msscr0 = mfspr(MSSCR0);
+
+ svr = get_svr();
+ major = SVR_MAJ(svr);
+ minor = SVR_MIN(svr);
+
+ if (cpu_numcores() > 1) {
+#ifndef CONFIG_MP
+ puts("Unicore software on multiprocessor system!!\n"
+ "To enable mutlticore build define CONFIG_MP\n");
+#endif
+ }
+ puts("CPU: ");
+
+ cpu = gd->arch.cpu;
+
+ puts(cpu->name);
+
+ printf(", Version: %d.%d, (0x%08x)\n", major, minor, svr);
+ puts("Core: ");
+
+ pvr = get_pvr();
+ major = PVR_E600_MAJ(pvr);
+ minor = PVR_E600_MIN(pvr);
+
+ printf("e600 Core %d", (msscr0 & 0x20) ? 1 : 0);
+ if (gur->pordevsr & MPC86xx_PORDEVSR_CORE1TE)
+ puts("\n Core1Translation Enabled");
+ debug(" (MSSCR0=%x, PORDEVSR=%x)", msscr0, gur->pordevsr);
+
+ printf(", Version: %d.%d, (0x%08x)\n", major, minor, pvr);
+
+ get_sys_info(&sysinfo);
+
+ puts("Clock Configuration:\n");
+ printf(" CPU:%-4s MHz, ", strmhz(buf1, sysinfo.freqProcessor));
+ printf("MPX:%-4s MHz\n", strmhz(buf1, sysinfo.freqSystemBus));
+ printf(" DDR:%-4s MHz (%s MT/s data rate), ",
+ strmhz(buf1, sysinfo.freqSystemBus / 2),
+ strmhz(buf2, sysinfo.freqSystemBus));
+
+ if (sysinfo.freqLocalBus > LCRR_CLKDIV) {
+ printf("LBC:%-4s MHz\n", strmhz(buf1, sysinfo.freqLocalBus));
+ } else {
+ printf("LBC: unknown (LCRR[CLKDIV] = 0x%02lx)\n",
+ sysinfo.freqLocalBus);
+ }
+
+ puts("L1: D-cache 32 KB enabled\n");
+ puts(" I-cache 32 KB enabled\n");
+
+ puts("L2: ");
+ if (get_l2cr() & 0x80000000) {
+#if defined(CONFIG_MPC8610)
+ puts("256");
+#elif defined(CONFIG_MPC8641)
+ puts("512");
+#endif
+ puts(" KB enabled\n");
+ } else {
+ puts("Disabled\n");
+ }
+
+ return 0;
+}
+
+
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+ volatile ccsr_gur_t *gur = &immap->im_gur;
+
+ /* Attempt board-specific reset */
+ board_reset();
+
+ /* Next try asserting HRESET_REQ */
+ out_be32(&gur->rstcr, MPC86xx_RSTCR_HRST_REQ);
+
+ while (1)
+ ;
+
+ return 1;
+}
+
+
+/*
+ * Get timebase clock frequency
+ */
+unsigned long
+get_tbclk(void)
+{
+ sys_info_t sys_info;
+
+ get_sys_info(&sys_info);
+ return (sys_info.freqSystemBus + 3L) / 4L;
+}
+
+
+#if defined(CONFIG_WATCHDOG)
+void
+watchdog_reset(void)
+{
+#if defined(CONFIG_MPC8610)
+ /*
+ * This actually feed the hard enabled watchdog.
+ */
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+ volatile ccsr_wdt_t *wdt = &immap->im_wdt;
+ volatile ccsr_gur_t *gur = &immap->im_gur;
+ u32 tmp = gur->pordevsr;
+
+ if (tmp & 0x4000) {
+ wdt->swsrr = 0x556c;
+ wdt->swsrr = 0xaa39;
+ }
+#endif
+}
+#endif /* CONFIG_WATCHDOG */
+
+/*
+ * Print out the state of various machine registers.
+ * Currently prints out LAWs, BR0/OR0, and BATs
+ */
+void mpc86xx_reginfo(void)
+{
+ print_bats();
+ print_laws();
+ print_lbc_regs();
+}
+
+/*
+ * Set the DDR BATs to reflect the actual size of DDR.
+ *
+ * dram_size is the actual size of DDR, in bytes
+ *
+ * Note: we assume that CONFIG_MAX_MEM_MAPPED is 2G or smaller as we only
+ * are using a single BAT to cover DDR.
+ *
+ * If this is not true, (e.g. CONFIG_MAX_MEM_MAPPED is 2GB but HID0_XBSEN
+ * is not defined) then we might have a situation where U-Boot will attempt
+ * to relocated itself outside of the region mapped by DBAT0.
+ * This will cause a machine check.
+ *
+ * Currently we are limited to power of two sized DDR since we only use a
+ * single bat. If a non-power of two size is used that is less than
+ * CONFIG_MAX_MEM_MAPPED u-boot will crash.
+ *
+ */
+void setup_ddr_bat(phys_addr_t dram_size)
+{
+ unsigned long batu, bl;
+
+ bl = TO_BATU_BL(min(dram_size, CONFIG_MAX_MEM_MAPPED));
+
+ if (BATU_SIZE(bl) != dram_size) {
+ u64 sz = (u64)dram_size - BATU_SIZE(bl);
+ print_size(sz, " left unmapped\n");
+ }
+
+ batu = bl | BATU_VS | BATU_VP;
+ write_bat(DBAT0, batu, CONFIG_SYS_DBAT0L);
+ write_bat(IBAT0, batu, CONFIG_SYS_IBAT0L);
+}
diff --git a/arch/powerpc/cpu/mpc86xx/cpu_init.c b/arch/powerpc/cpu/mpc86xx/cpu_init.c
new file mode 100644
index 0000000..0375df2
--- /dev/null
+++ b/arch/powerpc/cpu/mpc86xx/cpu_init.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2004,2009-2011 Freescale Semiconductor, Inc.
+ * Jeff Brown
+ * Srikanth Srinivasan (srikanth.srinivasan@freescale.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * cpu_init.c - low level cpu init
+ */
+
+#include <config.h>
+#include <common.h>
+#include <mpc86xx.h>
+#include <asm/mmu.h>
+#include <asm/fsl_law.h>
+#include <asm/fsl_serdes.h>
+#include <asm/mp.h>
+
+extern void srio_init(void);
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Breathe some life into the CPU...
+ *
+ * Set up the memory map
+ * initialize a bunch of registers
+ */
+
+void cpu_init_f(void)
+{
+ /* Pointer is writable since we allocated a register for it */
+ gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+
+ /* Clear initial global data */
+ memset ((void *) gd, 0, sizeof (gd_t));
+
+#ifdef CONFIG_FSL_LAW
+ init_laws();
+#endif
+
+ setup_bats();
+
+ init_early_memctl_regs();
+
+#if defined(CONFIG_FSL_DMA)
+ dma_init();
+#endif
+
+ /* enable the timebase bit in HID0 */
+ set_hid0(get_hid0() | 0x4000000);
+
+ /* enable EMCP, SYNCBE | ABE bits in HID1 */
+ set_hid1(get_hid1() | 0x80000C00);
+}
+
+/*
+ * initialize higher level parts of CPU like timers
+ */
+int cpu_init_r(void)
+{
+ /* needs to be in ram since code uses global static vars */
+ fsl_serdes_init();
+
+#ifdef CONFIG_SYS_SRIO
+ srio_init();
+#endif
+
+#if defined(CONFIG_MP)
+ setup_mp();
+#endif
+ return 0;
+}
+
+#ifdef CONFIG_ADDR_MAP
+/* Initialize address mapping array */
+void init_addr_map(void)
+{
+ int i;
+ ppc_bat_t bat = DBAT0;
+ phys_size_t size;
+ unsigned long upper, lower;
+
+ for (i = 0; i < CONFIG_SYS_NUM_ADDR_MAP; i++, bat++) {
+ if (read_bat(bat, &upper, &lower) != -1) {
+ if (!BATU_VALID(upper))
+ size = 0;
+ else
+ size = BATU_SIZE(upper);
+ addrmap_set_entry(BATU_VADDR(upper), BATL_PADDR(lower),
+ size, i);
+ }
+#ifdef CONFIG_HIGH_BATS
+ /* High bats are not contiguous with low BAT numbers */
+ if (bat == DBAT3)
+ bat = DBAT4 - 1;
+#endif
+ }
+}
+#endif
diff --git a/arch/powerpc/cpu/mpc86xx/ddr-8641.c b/arch/powerpc/cpu/mpc86xx/ddr-8641.c
new file mode 100644
index 0000000..92ba26d
--- /dev/null
+++ b/arch/powerpc/cpu/mpc86xx/ddr-8641.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 4)
+#error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
+#endif
+
+void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
+ unsigned int ctrl_num)
+{
+ unsigned int i;
+ volatile ccsr_ddr_t *ddr;
+
+ switch (ctrl_num) {
+ case 0:
+ ddr = (void *)CONFIG_SYS_MPC8xxx_DDR_ADDR;
+ break;
+ case 1:
+ ddr = (void *)CONFIG_SYS_MPC8xxx_DDR2_ADDR;
+ break;
+ default:
+ printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num);
+ return;
+ }
+
+ for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+ if (i == 0) {
+ out_be32(&ddr->cs0_bnds, regs->cs[i].bnds);
+ out_be32(&ddr->cs0_config, regs->cs[i].config);
+
+ } else if (i == 1) {
+ out_be32(&ddr->cs1_bnds, regs->cs[i].bnds);
+ out_be32(&ddr->cs1_config, regs->cs[i].config);
+
+ } else if (i == 2) {
+ out_be32(&ddr->cs2_bnds, regs->cs[i].bnds);
+ out_be32(&ddr->cs2_config, regs->cs[i].config);
+
+ } else if (i == 3) {
+ out_be32(&ddr->cs3_bnds, regs->cs[i].bnds);
+ out_be32(&ddr->cs3_config, regs->cs[i].config);
+ }
+ }
+
+ out_be32(&ddr->timing_cfg_3, regs->timing_cfg_3);
+ out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0);
+ out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1);
+ out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
+ out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
+ out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode);
+ out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2);
+ out_be32(&ddr->sdram_mode_cntl, regs->ddr_sdram_md_cntl);
+ out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
+ out_be32(&ddr->sdram_data_init, regs->ddr_data_init);
+ out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl);
+ out_be32(&ddr->init_addr, regs->ddr_init_addr);
+ out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
+
+ debug("before go\n");
+
+ /*
+ * 200 painful micro-seconds must elapse between
+ * the DDR clock setup and the DDR config enable.
+ */
+ udelay(200);
+ asm volatile("sync;isync");
+
+ out_be32(&ddr->sdram_cfg, regs->ddr_sdram_cfg);
+
+ /*
+ * Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done
+ */
+ while (in_be32(&ddr->sdram_cfg_2) & 0x10) {
+ udelay(10000); /* throttle polling rate */
+ }
+}
diff --git a/arch/powerpc/cpu/mpc86xx/fdt.c b/arch/powerpc/cpu/mpc86xx/fdt.c
new file mode 100644
index 0000000..26a65c5
--- /dev/null
+++ b/arch/powerpc/cpu/mpc86xx/fdt.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2008, 2011 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+#include <asm/mp.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+extern void ft_fixup_num_cores(void *blob);
+extern void ft_srio_setup(void *blob);
+
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+#ifdef CONFIG_MP
+ int off;
+ u32 bootpg = determine_mp_bootpg(NULL);
+#endif
+
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "timebase-frequency", bd->bi_busfreq / 4, 1);
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "bus-frequency", bd->bi_busfreq, 1);
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "clock-frequency", bd->bi_intfreq, 1);
+ do_fixup_by_prop_u32(blob, "device_type", "soc", 4,
+ "bus-frequency", bd->bi_busfreq, 1);
+
+#if defined(CONFIG_MPC8641)
+ do_fixup_by_compat_u32(blob, "fsl,mpc8641-localbus",
+ "bus-frequency", gd->arch.lbc_clk, 1);
+#endif
+ do_fixup_by_compat_u32(blob, "fsl,elbc",
+ "bus-frequency", gd->arch.lbc_clk, 1);
+
+ fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+
+#if defined(CONFIG_HAS_ETH0) || defined(CONFIG_HAS_ETH1) \
+ || defined(CONFIG_HAS_ETH2) || defined(CONFIG_HAS_ETH3)
+ fdt_fixup_ethernet(blob);
+#endif
+
+#ifdef CONFIG_SYS_NS16550
+ do_fixup_by_compat_u32(blob, "ns16550",
+ "clock-frequency", CONFIG_SYS_NS16550_CLK, 1);
+#endif
+
+#ifdef CONFIG_MP
+ /* Reserve the boot page so OSes dont use it */
+ off = fdt_add_mem_rsv(blob, bootpg, (u64)4096);
+ if (off < 0)
+ printf("%s: %s\n", __FUNCTION__, fdt_strerror(off));
+
+ ft_fixup_num_cores(blob);
+#endif
+
+#ifdef CONFIG_SYS_SRIO
+ ft_srio_setup(blob);
+#endif
+}
diff --git a/arch/powerpc/cpu/mpc86xx/interrupts.c b/arch/powerpc/cpu/mpc86xx/interrupts.c
new file mode 100644
index 0000000..aff1f6d
--- /dev/null
+++ b/arch/powerpc/cpu/mpc86xx/interrupts.c
@@ -0,0 +1,131 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002 (440 port)
+ * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com
+ *
+ * (C) Copyright 2003 Motorola Inc. (MPC85xx port)
+ * Xianghua Xiao (X.Xiao@motorola.com)
+ *
+ * (C) Copyright 2004, 2007 Freescale Semiconductor. (MPC86xx Port)
+ * Jeff Brown
+ * Srikanth Srinivasan (srikanth.srinivasan@freescale.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc86xx.h>
+#include <command.h>
+#include <asm/processor.h>
+#ifdef CONFIG_POST
+#include <post.h>
+#endif
+
+int interrupt_init_cpu(unsigned long *decrementer_count)
+{
+ volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+ volatile ccsr_pic_t *pic = &immr->im_pic;
+
+#ifdef CONFIG_POST
+ /*
+ * The POST word is stored in the PIC's TFRR register which gets
+ * cleared when the PIC is reset. Save it off so we can restore it
+ * later.
+ */
+ ulong post_word = post_word_load();
+#endif
+
+ pic->gcr = MPC86xx_PICGCR_RST;
+ while (pic->gcr & MPC86xx_PICGCR_RST)
+ ;
+ pic->gcr = MPC86xx_PICGCR_MODE;
+
+ *decrementer_count = get_tbclk() / CONFIG_SYS_HZ;
+ debug("interrupt init: tbclk() = %ld MHz, decrementer_count = %ld\n",
+ (get_tbclk() / 1000000),
+ *decrementer_count);
+
+#ifdef CONFIG_INTERRUPTS
+
+ pic->iivpr1 = 0x810001; /* 50220 enable mcm interrupts */
+ debug("iivpr1@%p = %x\n", &pic->iivpr1, pic->iivpr1);
+
+ pic->iivpr2 = 0x810002; /* 50240 enable ddr interrupts */
+ debug("iivpr2@%p = %x\n", &pic->iivpr2, pic->iivpr2);
+
+ pic->iivpr3 = 0x810003; /* 50260 enable lbc interrupts */
+ debug("iivpr3@%p = %x\n", &pic->iivpr3, pic->iivpr3);
+
+#if defined(CONFIG_PCI1) || defined(CONFIG_PCIE1)
+ pic->iivpr8 = 0x810008; /* enable pcie1 interrupts */
+ debug("iivpr8@%p = %x\n", &pic->iivpr8, pic->iivpr8);
+#endif
+#if defined(CONFIG_PCI2) || defined(CONFIG_PCIE2)
+ pic->iivpr9 = 0x810009; /* enable pcie2 interrupts */
+ debug("iivpr9@%p = %x\n", &pic->iivpr9, pic->iivpr9);
+#endif
+
+ pic->ctpr = 0; /* 40080 clear current task priority register */
+#endif
+
+#ifdef CONFIG_POST
+ post_word_store(post_word);
+#endif
+
+ return 0;
+}
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * Trivial implementation - no need to be really accurate.
+ */
+void timer_interrupt_cpu(struct pt_regs *regs)
+{
+ /* nothing to do here */
+}
+
+/*
+ * Install and free a interrupt handler. Not implemented yet.
+ */
+void irq_install_handler(int vec, interrupt_handler_t *handler, void *arg)
+{
+}
+
+void irq_free_handler(int vec)
+{
+}
+
+/*
+ * irqinfo - print information about PCI devices,not implemented.
+ */
+int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ return 0;
+}
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt(struct pt_regs *regs)
+{
+ puts("external_interrupt (oops!)\n");
+}
diff --git a/arch/powerpc/cpu/mpc86xx/mp.c b/arch/powerpc/cpu/mpc86xx/mp.c
new file mode 100644
index 0000000..de705f0
--- /dev/null
+++ b/arch/powerpc/cpu/mpc86xx/mp.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2008-2010 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <ioports.h>
+#include <lmb.h>
+#include <asm/io.h>
+#include <asm/mp.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int cpu_reset(int nr)
+{
+ /* dummy function so common/cmd_mp.c will build
+ * should be implemented in the future, when cpu_release()
+ * is supported. Be aware there may be a similiar bug
+ * as exists on MPC85xx w/its PIC having a timing window
+ * associated to resetting the core */
+ return 1;
+}
+
+int cpu_status(int nr)
+{
+ /* dummy function so common/cmd_mp.c will build */
+ return 0;
+}
+
+int cpu_disable(int nr)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_CCSRBAR;
+ volatile ccsr_gur_t *gur = &immap->im_gur;
+
+ switch (nr) {
+ case 0:
+ setbits_be32(&gur->devdisr, MPC86xx_DEVDISR_CPU0);
+ break;
+ case 1:
+ setbits_be32(&gur->devdisr, MPC86xx_DEVDISR_CPU1);
+ break;
+ default:
+ printf("Invalid cpu number for disable %d\n", nr);
+ return 1;
+ }
+
+ return 0;
+}
+
+int is_core_disabled(int nr) {
+ immap_t *immap = (immap_t *) CONFIG_SYS_CCSRBAR;
+ ccsr_gur_t *gur = &immap->im_gur;
+ u32 devdisr = in_be32(&gur->devdisr);
+
+ switch (nr) {
+ case 0:
+ return (devdisr & MPC86xx_DEVDISR_CPU0);
+ case 1:
+ return (devdisr & MPC86xx_DEVDISR_CPU1);
+ default:
+ printf("Invalid cpu number for disable %d\n", nr);
+ }
+
+ return 0;
+}
+
+int cpu_release(int nr, int argc, char * const argv[])
+{
+ /* dummy function so common/cmd_mp.c will build
+ * should be implemented in the future */
+ return 1;
+}
+
+u32 determine_mp_bootpg(unsigned int *pagesize)
+{
+ if (pagesize)
+ *pagesize = 4096;
+
+ /* if we have 4G or more of memory, put the boot page at 4Gb-1M */
+ if ((u64)gd->ram_size > 0xfffff000)
+ return (0xfff00000);
+
+ return (gd->ram_size - (1024 * 1024));
+}
+
+void cpu_mp_lmb_reserve(struct lmb *lmb)
+{
+ u32 bootpg = determine_mp_bootpg(NULL);
+
+ /* tell u-boot we stole a page */
+ lmb_reserve(lmb, bootpg, 4096);
+}
+
+/*
+ * Copy the code for other cpus to execute into an
+ * aligned location accessible via BPTR
+ */
+void setup_mp(void)
+{
+ extern ulong __secondary_start_page;
+ ulong fixup = (ulong)&__secondary_start_page;
+ u32 bootpg = determine_mp_bootpg(NULL);
+ u32 bootpg_va;
+
+ if (bootpg >= CONFIG_SYS_MAX_DDR_BAT_SIZE) {
+ /* We're not covered by the DDR mapping, set up BAT */
+ write_bat(DBAT7, CONFIG_SYS_SCRATCH_VA | BATU_BL_128K |
+ BATU_VS | BATU_VP,
+ bootpg | BATL_PP_RW | BATL_MEMCOHERENCE);
+ bootpg_va = CONFIG_SYS_SCRATCH_VA;
+ } else {
+ bootpg_va = bootpg;
+ }
+
+ memcpy((void *)bootpg_va, (void *)fixup, 4096);
+ flush_cache(bootpg_va, 4096);
+
+ /* remove the temporary BAT mapping */
+ if (bootpg >= CONFIG_SYS_MAX_DDR_BAT_SIZE)
+ write_bat(DBAT7, 0, 0);
+
+ /* If the physical location of bootpg is not at fff00000, set BPTR */
+ if (bootpg != 0xfff00000)
+ out_be32((uint *)(CONFIG_SYS_CCSRBAR + 0x20), 0x80000000 |
+ (bootpg >> 12));
+}
diff --git a/arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c b/arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c
new file mode 100644
index 0000000..0342e34
--- /dev/null
+++ b/arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/immap_86xx.h>
+#include <asm/fsl_serdes.h>
+
+#define SRDS1_MAX_LANES 4
+#define SRDS2_MAX_LANES 4
+
+static u32 serdes1_prtcl_map, serdes2_prtcl_map;
+
+static u8 serdes1_cfg_tbl[][SRDS1_MAX_LANES] = {
+ [0x1] = {PCIE1, PCIE1, PCIE1, PCIE1},
+ [0x4] = {PCIE1, PCIE1, PCIE1, PCIE1},
+ [0x7] = {NONE, NONE, NONE, NONE},
+};
+
+static u8 serdes2_cfg_tbl[][SRDS2_MAX_LANES] = {
+ [0x0] = {PCIE2, PCIE2, PCIE2, PCIE2},
+ [0x4] = {PCIE2, PCIE2, PCIE2, PCIE2},
+ [0x7] = {NONE, NONE, NONE, NONE},
+};
+
+int is_serdes_configured(enum srds_prtcl device)
+{
+ int ret = (1 << device) & serdes1_prtcl_map;
+
+ if (ret)
+ return ret;
+
+ return (1 << device) & serdes2_prtcl_map;
+}
+
+void fsl_serdes_init(void)
+{
+ immap_t *immap = (immap_t *) CONFIG_SYS_CCSRBAR;
+ ccsr_gur_t *gur = &immap->im_gur;
+ u32 pordevsr = in_be32(&gur->pordevsr);
+ u32 srds_cfg = (pordevsr & MPC8610_PORDEVSR_IO_SEL) >>
+ MPC8610_PORDEVSR_IO_SEL_SHIFT;
+ int lane;
+
+ debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg);
+
+ if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);
+ return;
+ }
+ for (lane = 0; lane < SRDS1_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes1_cfg_tbl[srds_cfg][lane];
+ serdes1_prtcl_map |= (1 << lane_prtcl);
+ }
+
+ if (srds_cfg >= ARRAY_SIZE(serdes2_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);
+ return;
+ }
+
+ for (lane = 0; lane < SRDS2_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes2_cfg_tbl[srds_cfg][lane];
+ serdes2_prtcl_map |= (1 << lane_prtcl);
+ }
+}
diff --git a/arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c b/arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c
new file mode 100644
index 0000000..21c5ddb
--- /dev/null
+++ b/arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/immap_86xx.h>
+#include <asm/fsl_serdes.h>
+
+#define SRDS1_MAX_LANES 4
+#define SRDS2_MAX_LANES 4
+
+static u32 serdes1_prtcl_map, serdes2_prtcl_map;
+
+static u8 serdes1_cfg_tbl[][SRDS1_MAX_LANES] = {
+ [0x2] = {PCIE1, PCIE1, PCIE1, PCIE1},
+ [0x3] = {PCIE1, PCIE1, PCIE1, PCIE1},
+ [0x5] = {PCIE1, PCIE1, PCIE1, PCIE1},
+ [0x6] = {PCIE1, PCIE1, PCIE1, PCIE1},
+ [0x7] = {PCIE1, PCIE1, PCIE1, PCIE1},
+ [0xf] = {PCIE1, PCIE1, PCIE1, PCIE1},
+};
+
+static u8 serdes2_cfg_tbl[][SRDS2_MAX_LANES] = {
+ [0x3] = {PCIE2, PCIE2, PCIE2, PCIE2},
+ [0x5] = {SRIO1, SRIO1, SRIO1, SRIO1},
+ [0x6] = {SRIO1, SRIO1, SRIO1, SRIO1},
+ [0x7] = {SRIO1, SRIO1, SRIO1, SRIO1},
+ [0x9] = {SRIO1, SRIO1, SRIO1, SRIO1},
+ [0xa] = {SRIO1, SRIO1, SRIO1, SRIO1},
+ [0xb] = {SRIO1, SRIO1, SRIO1, SRIO1},
+ [0xe] = {PCIE2, PCIE2, PCIE2, PCIE2},
+ [0xf] = {PCIE2, PCIE2, PCIE2, PCIE2},
+};
+
+int is_serdes_configured(enum srds_prtcl device)
+{
+ int ret = (1 << device) & serdes1_prtcl_map;
+
+ if (ret)
+ return ret;
+
+ return (1 << device) & serdes2_prtcl_map;
+}
+
+void fsl_serdes_init(void)
+{
+ immap_t *immap = (immap_t *) CONFIG_SYS_CCSRBAR;
+ ccsr_gur_t *gur = &immap->im_gur;
+ u32 pordevsr = in_be32(&gur->pordevsr);
+ u32 srds_cfg = (pordevsr & MPC8641_PORDEVSR_IO_SEL) >>
+ MPC8641_PORDEVSR_IO_SEL_SHIFT;
+ int lane;
+
+ debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg);
+
+ if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);
+ return;
+ }
+ for (lane = 0; lane < SRDS1_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes1_cfg_tbl[srds_cfg][lane];
+ serdes1_prtcl_map |= (1 << lane_prtcl);
+ }
+
+ if (srds_cfg >= ARRAY_SIZE(serdes2_cfg_tbl)) {
+ printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg);
+ return;
+ }
+
+ for (lane = 0; lane < SRDS2_MAX_LANES; lane++) {
+ enum srds_prtcl lane_prtcl = serdes2_cfg_tbl[srds_cfg][lane];
+ serdes2_prtcl_map |= (1 << lane_prtcl);
+ }
+}
diff --git a/arch/powerpc/cpu/mpc86xx/release.S b/arch/powerpc/cpu/mpc86xx/release.S
new file mode 100644
index 0000000..67a6f2b
--- /dev/null
+++ b/arch/powerpc/cpu/mpc86xx/release.S
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2004, 2007, 2008 Freescale Semiconductor.
+ * Srikanth Srinivasan <srikanth.srinivaan@freescale.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <config.h>
+#include <mpc86xx.h>
+#include <version.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+/* If this is a multi-cpu system then we need to handle the
+ * 2nd cpu. The assumption is that the 2nd cpu is being
+ * held in boot holdoff mode until the 1st cpu unlocks it
+ * from Linux. We'll do some basic cpu init and then pass
+ * it to the Linux Reset Vector.
+ * Sri: Much of this initialization is not required. Linux
+ * rewrites the bats, and the sprs and also enables the L1 cache.
+ *
+ * Core 0 must copy this to a 1M aligned region and set BPTR
+ * to point to it.
+ */
+ .align 12
+.globl __secondary_start_page
+__secondary_start_page:
+ .space 0x100 /* space over to reset vector loc */
+ mfspr r0, MSSCR0
+ andi. r0, r0, 0x0020
+ rlwinm r0,r0,27,31,31
+ mtspr PIR, r0
+
+ /* Invalidate BATs */
+ li r0, 0
+ mtspr IBAT0U, r0
+ mtspr IBAT1U, r0
+ mtspr IBAT2U, r0
+ mtspr IBAT3U, r0
+ mtspr IBAT4U, r0
+ mtspr IBAT5U, r0
+ mtspr IBAT6U, r0
+ mtspr IBAT7U, r0
+ isync
+ mtspr DBAT0U, r0
+ mtspr DBAT1U, r0
+ mtspr DBAT2U, r0
+ mtspr DBAT3U, r0
+ mtspr DBAT4U, r0
+ mtspr DBAT5U, r0
+ mtspr DBAT6U, r0
+ mtspr DBAT7U, r0
+ isync
+ sync
+
+ /* enable extended addressing */
+ mfspr r0, HID0
+ lis r0, (HID0_HIGH_BAT_EN | HID0_XBSEN | HID0_XAEN)@h
+ ori r0, r0, (HID0_HIGH_BAT_EN | HID0_XBSEN | HID0_XAEN)@l
+ mtspr HID0, r0
+ sync
+ isync
+
+#ifdef CONFIG_SYS_L2
+ /* init the L2 cache */
+ addis r3, r0, L2_INIT@h
+ ori r3, r3, L2_INIT@l
+ sync
+ mtspr l2cr, r3
+#ifdef CONFIG_ALTIVEC
+ dssall
+#endif
+ /* invalidate the L2 cache */
+ mfspr r3, l2cr
+ rlwinm. r3, r3, 0, 0, 0
+ beq 1f
+
+ mfspr r3, l2cr
+ rlwinm r3, r3, 0, 1, 31
+
+#ifdef CONFIG_ALTIVEC
+ dssall
+#endif
+ sync
+ mtspr l2cr, r3
+ sync
+1: mfspr r3, l2cr
+ oris r3, r3, L2CR_L2I@h
+ mtspr l2cr, r3
+
+invl2:
+ mfspr r3, l2cr
+ andis. r3, r3, L2CR_L2I@h
+ bne invl2
+ sync
+#endif
+
+ /* enable and invalidate the data cache */
+ mfspr r3, HID0
+ li r5, HID0_DCFI|HID0_DLOCK
+ andc r3, r3, r5
+ mtspr HID0, r3 /* no invalidate, unlock */
+ ori r3, r3, HID0_DCE
+ ori r5, r3, HID0_DCFI
+ mtspr HID0, r5 /* enable + invalidate */
+ mtspr HID0, r3 /* enable */
+ sync
+#ifdef CONFIG_SYS_L2
+ sync
+ lis r3, L2_ENABLE@h
+ ori r3, r3, L2_ENABLE@l
+ mtspr l2cr, r3
+ isync
+ sync
+#endif
+
+ /* enable and invalidate the instruction cache*/
+ mfspr r3, HID0
+ li r5, HID0_ICFI|HID0_ILOCK
+ andc r3, r3, r5
+ ori r3, r3, HID0_ICE
+ ori r5, r3, HID0_ICFI
+ mtspr HID0, r5
+ mtspr HID0, r3
+ isync
+ sync
+
+ /* TBEN in HID0 */
+ mfspr r4, HID0
+ oris r4, r4, 0x0400
+ mtspr HID0, r4
+ sync
+ isync
+
+ /* MCP|SYNCBE|ABE in HID1 */
+ mfspr r4, HID1
+ oris r4, r4, 0x8000
+ ori r4, r4, 0x0C00
+ mtspr HID1, r4
+ sync
+ isync
+
+ lis r3, CONFIG_LINUX_RESET_VEC@h
+ ori r3, r3, CONFIG_LINUX_RESET_VEC@l
+ mtlr r3
+ blr
+
+ /* Never Returns, Running in Linux Now */
diff --git a/arch/powerpc/cpu/mpc86xx/speed.c b/arch/powerpc/cpu/mpc86xx/speed.c
new file mode 100644
index 0000000..18c1eea
--- /dev/null
+++ b/arch/powerpc/cpu/mpc86xx/speed.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2004 Freescale Semiconductor.
+ * Jeff Brown
+ * Srikanth Srinivasan (srikanth.srinivasan@freescale.com)
+ *
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc86xx.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* used in some defintiions of CONFIG_SYS_CLK_FREQ */
+extern unsigned long get_board_sys_clk(unsigned long dummy);
+
+void get_sys_info(sys_info_t *sysInfo)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile ccsr_gur_t *gur = &immap->im_gur;
+ uint plat_ratio, e600_ratio;
+ uint lcrr_div;
+
+ plat_ratio = (gur->porpllsr) & 0x0000003e;
+ plat_ratio >>= 1;
+
+ switch (plat_ratio) {
+ case 0x0:
+ sysInfo->freqSystemBus = 16 * CONFIG_SYS_CLK_FREQ;
+ break;
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0c:
+ case 0x10:
+ sysInfo->freqSystemBus = plat_ratio * CONFIG_SYS_CLK_FREQ;
+ break;
+ default:
+ sysInfo->freqSystemBus = 0;
+ break;
+ }
+
+ e600_ratio = (gur->porpllsr) & 0x003f0000;
+ e600_ratio >>= 16;
+
+ switch (e600_ratio) {
+ case 0x10:
+ sysInfo->freqProcessor = 2 * sysInfo->freqSystemBus;
+ break;
+ case 0x19:
+ sysInfo->freqProcessor = 5 * sysInfo->freqSystemBus / 2;
+ break;
+ case 0x20:
+ sysInfo->freqProcessor = 3 * sysInfo->freqSystemBus;
+ break;
+ case 0x39:
+ sysInfo->freqProcessor = 7 * sysInfo->freqSystemBus / 2;
+ break;
+ case 0x28:
+ sysInfo->freqProcessor = 4 * sysInfo->freqSystemBus;
+ break;
+ case 0x1d:
+ sysInfo->freqProcessor = 9 * sysInfo->freqSystemBus / 2;
+ break;
+ default:
+ sysInfo->freqProcessor = e600_ratio + sysInfo->freqSystemBus;
+ break;
+ }
+
+#if defined(CONFIG_SYS_LBC_LCRR)
+ /* We will program LCRR to this value later */
+ lcrr_div = CONFIG_SYS_LBC_LCRR & LCRR_CLKDIV;
+#else
+ lcrr_div = in_be32(&immap->im_lbc.lcrr) & LCRR_CLKDIV;
+#endif
+ if (lcrr_div == 2 || lcrr_div == 4 || lcrr_div == 8) {
+ sysInfo->freqLocalBus = sysInfo->freqSystemBus / (lcrr_div * 2);
+ } else {
+ /* In case anyone cares what the unknown value is */
+ sysInfo->freqLocalBus = lcrr_div;
+ }
+}
+
+
+/*
+ * Measure CPU clock speed (core clock GCLK1, GCLK2)
+ * (Approx. GCLK frequency in Hz)
+ */
+
+int get_clocks(void)
+{
+ sys_info_t sys_info;
+
+ get_sys_info(&sys_info);
+ gd->cpu_clk = sys_info.freqProcessor;
+ gd->bus_clk = sys_info.freqSystemBus;
+ gd->arch.lbc_clk = sys_info.freqLocalBus;
+
+ /*
+ * The base clock for I2C depends on the actual SOC. Unfortunately,
+ * there is no pattern that can be used to determine the frequency, so
+ * the only choice is to look up the actual SOC number and use the value
+ * for that SOC. This information is taken from application note
+ * AN2919.
+ */
+#ifdef CONFIG_MPC8610
+ gd->arch.i2c1_clk = sys_info.freqSystemBus;
+#else
+ gd->arch.i2c1_clk = sys_info.freqSystemBus / 2;
+#endif
+ gd->arch.i2c2_clk = gd->arch.i2c1_clk;
+
+ if (gd->cpu_clk != 0)
+ return 0;
+ else
+ return 1;
+}
+
+
+/*
+ * get_bus_freq
+ * Return system bus freq in Hz
+ */
+
+ulong get_bus_freq(ulong dummy)
+{
+ ulong val;
+ sys_info_t sys_info;
+
+ get_sys_info(&sys_info);
+ val = sys_info.freqSystemBus;
+
+ return val;
+}
diff --git a/arch/powerpc/cpu/mpc86xx/start.S b/arch/powerpc/cpu/mpc86xx/start.S
new file mode 100644
index 0000000..20dfb9e
--- /dev/null
+++ b/arch/powerpc/cpu/mpc86xx/start.S
@@ -0,0 +1,1008 @@
+/*
+ * Copyright 2004, 2007, 2011 Freescale Semiconductor.
+ * Srikanth Srinivasan <srikanth.srinivaan@freescale.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* U-Boot - Startup Code for 86xx PowerPC based Embedded Boards
+ *
+ *
+ * The processor starts at 0xfff00100 and the code is executed
+ * from flash. The code is organized to be at an other address
+ * in memory, but as long we don't jump around before relocating.
+ * board_init lies at a quite high address and when the cpu has
+ * jumped there, everything is ok.
+ */
+#include <asm-offsets.h>
+#include <config.h>
+#include <mpc86xx.h>
+#include <version.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+#include <asm/u-boot.h>
+
+/*
+ * Need MSR_DR | MSR_IR enabled to access I/O (printf) in exceptions
+ */
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+ START_GOT
+ GOT_ENTRY(_GOT2_TABLE_)
+ GOT_ENTRY(_FIXUP_TABLE_)
+
+ GOT_ENTRY(_start)
+ GOT_ENTRY(_start_of_vectors)
+ GOT_ENTRY(_end_of_vectors)
+ GOT_ENTRY(transfer_to_handler)
+
+ GOT_ENTRY(__init_end)
+ GOT_ENTRY(__bss_end)
+ GOT_ENTRY(__bss_start)
+ END_GOT
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+ .text
+ .long 0x27051956 /* U-Boot Magic Number */
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION_STRING, "\0"
+
+ . = EXC_OFF_SYS_RESET
+ .globl _start
+_start:
+ b boot_cold
+
+ /* the boot code is located below the exception table */
+
+ .globl _start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. */
+ STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+ STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+ STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+ . = 0x600
+Alignment:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+ . = 0x700
+ProgramCheck:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+ MSR_KERNEL, COPY_EE)
+
+ STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+ /* I guess we could implement decrementer, and may have
+ * to someday for timekeeping.
+ */
+ STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+ STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+ STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+ STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+ STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+ STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+ STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+ STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException)
+ STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
+ STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
+ STD_EXCEPTION(0x1500, Reserved5, UnknownException)
+ STD_EXCEPTION(0x1600, Reserved6, UnknownException)
+ STD_EXCEPTION(0x1700, Reserved7, UnknownException)
+ STD_EXCEPTION(0x1800, Reserved8, UnknownException)
+ STD_EXCEPTION(0x1900, Reserved9, UnknownException)
+ STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
+ STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
+ STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1d00, InstructionBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
+
+ .globl _end_of_vectors
+_end_of_vectors:
+
+ . = 0x2000
+
+boot_cold:
+ /*
+ * NOTE: Only Cpu 0 will ever come here. Other cores go to an
+ * address specified by the BPTR
+ */
+1:
+#ifdef CONFIG_SYS_RAMBOOT
+ /* disable everything */
+ li r0, 0
+ mtspr HID0, r0
+ sync
+ mtmsr 0
+#endif
+
+ /* Invalidate BATs */
+ bl invalidate_bats
+ sync
+ /* Invalidate all of TLB before MMU turn on */
+ bl clear_tlbs
+ sync
+
+#ifdef CONFIG_SYS_L2
+ /* init the L2 cache */
+ lis r3, L2_INIT@h
+ ori r3, r3, L2_INIT@l
+ mtspr l2cr, r3
+ /* invalidate the L2 cache */
+ bl l2cache_invalidate
+ sync
+#endif
+
+ /*
+ * Calculate absolute address in FLASH and jump there
+ *------------------------------------------------------*/
+ lis r3, CONFIG_SYS_MONITOR_BASE_EARLY@h
+ ori r3, r3, CONFIG_SYS_MONITOR_BASE_EARLY@l
+ addi r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
+ mtlr r3
+ blr
+
+in_flash:
+ /* let the C-code set up the rest */
+ /* */
+ /* Be careful to keep code relocatable ! */
+ /*------------------------------------------------------*/
+ /* perform low-level init */
+
+ /* enable extended addressing */
+ bl enable_ext_addr
+
+ /* setup the bats */
+ bl early_bats
+
+ /*
+ * Cache must be enabled here for stack-in-cache trick.
+ * This means we need to enable the BATS.
+ * Cache should be turned on after BATs, since by default
+ * everything is write-through.
+ */
+
+ /* enable address translation */
+ mfmsr r5
+ ori r5, r5, (MSR_IR | MSR_DR)
+ lis r3,addr_trans_enabled@h
+ ori r3, r3, addr_trans_enabled@l
+ mtspr SPRN_SRR0,r3
+ mtspr SPRN_SRR1,r5
+ rfi
+
+addr_trans_enabled:
+ /* enable and invalidate the data cache */
+/* bl l1dcache_enable */
+ bl dcache_enable
+ sync
+
+#if 1
+ bl icache_enable
+#endif
+
+#ifdef CONFIG_SYS_INIT_RAM_LOCK
+ bl lock_ram_in_cache
+ sync
+#endif
+
+#if (CONFIG_SYS_CCSRBAR_DEFAULT != CONFIG_SYS_CCSRBAR)
+ bl setup_ccsrbar
+#endif
+
+ /* set up the stack pointer in our newly created
+ * cache-ram (r1) */
+ lis r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@h
+ ori r1, r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET)@l
+
+ li r0, 0 /* Make room for stack frame header and */
+ stwu r0, -4(r1) /* clear final stack frame so that */
+ stwu r0, -4(r1) /* stack backtraces terminate cleanly */
+
+ GET_GOT /* initialize GOT access */
+
+ /* run low-level CPU init code (from Flash) */
+ bl cpu_init_f
+ sync
+
+#ifdef RUN_DIAG
+
+ /* Load PX_AUX register address in r4 */
+ lis r4, PIXIS_BASE@h
+ ori r4, r4, 0x6
+ /* Load contents of PX_AUX in r3 bits 24 to 31*/
+ lbz r3, 0(r4)
+
+ /* Mask and obtain the bit in r3 */
+ rlwinm. r3, r3, 0, 24, 24
+ /* If not zero, jump and continue with u-boot */
+ bne diag_done
+
+ /* Load back contents of PX_AUX in r3 bits 24 to 31 */
+ lbz r3, 0(r4)
+ /* Set the MSB of the register value */
+ ori r3, r3, 0x80
+ /* Write value in r3 back to PX_AUX */
+ stb r3, 0(r4)
+
+ /* Get the address to jump to in r3*/
+ lis r3, CONFIG_SYS_DIAG_ADDR@h
+ ori r3, r3, CONFIG_SYS_DIAG_ADDR@l
+
+ /* Load the LR with the branch address */
+ mtlr r3
+
+ /* Branch to diagnostic */
+ blr
+
+diag_done:
+#endif
+
+/* bl l2cache_enable */
+
+ /* run 1st part of board init code (from Flash) */
+ bl board_init_f
+ sync
+
+ /* NOTREACHED - board_init_f() does not return */
+
+ .globl invalidate_bats
+invalidate_bats:
+
+ li r0, 0
+ /* invalidate BATs */
+ mtspr IBAT0U, r0
+ mtspr IBAT1U, r0
+ mtspr IBAT2U, r0
+ mtspr IBAT3U, r0
+ mtspr IBAT4U, r0
+ mtspr IBAT5U, r0
+ mtspr IBAT6U, r0
+ mtspr IBAT7U, r0
+
+ isync
+ mtspr DBAT0U, r0
+ mtspr DBAT1U, r0
+ mtspr DBAT2U, r0
+ mtspr DBAT3U, r0
+ mtspr DBAT4U, r0
+ mtspr DBAT5U, r0
+ mtspr DBAT6U, r0
+ mtspr DBAT7U, r0
+
+ isync
+ sync
+ blr
+
+#define CONFIG_BAT_PAIR(n) \
+ lis r4, CONFIG_SYS_IBAT##n##L@h; \
+ ori r4, r4, CONFIG_SYS_IBAT##n##L@l; \
+ lis r3, CONFIG_SYS_IBAT##n##U@h; \
+ ori r3, r3, CONFIG_SYS_IBAT##n##U@l; \
+ mtspr IBAT##n##L, r4; \
+ mtspr IBAT##n##U, r3; \
+ lis r4, CONFIG_SYS_DBAT##n##L@h; \
+ ori r4, r4, CONFIG_SYS_DBAT##n##L@l; \
+ lis r3, CONFIG_SYS_DBAT##n##U@h; \
+ ori r3, r3, CONFIG_SYS_DBAT##n##U@l; \
+ mtspr DBAT##n##L, r4; \
+ mtspr DBAT##n##U, r3;
+
+/*
+ * setup_bats:
+ *
+ * Set up the final BAT registers now that setup is done.
+ *
+ * Assumes that:
+ * 1) Address translation is enabled upon entry
+ * 2) The boot rom is still accessible via 1:1 translation
+ */
+ .globl setup_bats
+setup_bats:
+ mflr r5
+ sync
+
+ /*
+ * When we disable address translation, we will get 1:1 (VA==PA)
+ * translation. The only place we know for sure is safe for that is
+ * the bootrom where we originally started out. Pop back into there.
+ */
+ lis r4, CONFIG_SYS_MONITOR_BASE_EARLY@h
+ ori r4, r4, CONFIG_SYS_MONITOR_BASE_EARLY@l
+ addi r4, r4, trans_disabled - _start + EXC_OFF_SYS_RESET
+
+ /* disable address translation */
+ mfmsr r3
+ rlwinm r3, r3, 0, 28, 25
+ mtspr SRR0, r4
+ mtspr SRR1, r3
+ rfi
+
+trans_disabled:
+#if defined(CONFIG_SYS_DBAT0U) && defined(CONFIG_SYS_DBAT0L) \
+ && defined(CONFIG_SYS_IBAT0U) && defined(CONFIG_SYS_IBAT0L)
+ CONFIG_BAT_PAIR(0)
+#endif
+ CONFIG_BAT_PAIR(1)
+ CONFIG_BAT_PAIR(2)
+ CONFIG_BAT_PAIR(3)
+ CONFIG_BAT_PAIR(4)
+ CONFIG_BAT_PAIR(5)
+ CONFIG_BAT_PAIR(6)
+ CONFIG_BAT_PAIR(7)
+
+ sync
+ isync
+
+ /* Turn translation back on and return */
+ mfmsr r3
+ ori r3, r3, (MSR_IR | MSR_DR)
+ mtspr SPRN_SRR0,r5
+ mtspr SPRN_SRR1,r3
+ rfi
+
+/*
+ * early_bats:
+ *
+ * Set up bats needed early on - this is usually the BAT for the
+ * stack-in-cache, the Flash, and CCSR space
+ */
+ .globl early_bats
+early_bats:
+ /* IBAT 3 */
+ lis r4, CONFIG_SYS_IBAT3L@h
+ ori r4, r4, CONFIG_SYS_IBAT3L@l
+ lis r3, CONFIG_SYS_IBAT3U@h
+ ori r3, r3, CONFIG_SYS_IBAT3U@l
+ mtspr IBAT3L, r4
+ mtspr IBAT3U, r3
+ isync
+
+ /* DBAT 3 */
+ lis r4, CONFIG_SYS_DBAT3L@h
+ ori r4, r4, CONFIG_SYS_DBAT3L@l
+ lis r3, CONFIG_SYS_DBAT3U@h
+ ori r3, r3, CONFIG_SYS_DBAT3U@l
+ mtspr DBAT3L, r4
+ mtspr DBAT3U, r3
+ isync
+
+ /* IBAT 5 */
+ lis r4, CONFIG_SYS_IBAT5L@h
+ ori r4, r4, CONFIG_SYS_IBAT5L@l
+ lis r3, CONFIG_SYS_IBAT5U@h
+ ori r3, r3, CONFIG_SYS_IBAT5U@l
+ mtspr IBAT5L, r4
+ mtspr IBAT5U, r3
+ isync
+
+ /* DBAT 5 */
+ lis r4, CONFIG_SYS_DBAT5L@h
+ ori r4, r4, CONFIG_SYS_DBAT5L@l
+ lis r3, CONFIG_SYS_DBAT5U@h
+ ori r3, r3, CONFIG_SYS_DBAT5U@l
+ mtspr DBAT5L, r4
+ mtspr DBAT5U, r3
+ isync
+
+ /* IBAT 6 */
+ lis r4, CONFIG_SYS_IBAT6L_EARLY@h
+ ori r4, r4, CONFIG_SYS_IBAT6L_EARLY@l
+ lis r3, CONFIG_SYS_IBAT6U_EARLY@h
+ ori r3, r3, CONFIG_SYS_IBAT6U_EARLY@l
+ mtspr IBAT6L, r4
+ mtspr IBAT6U, r3
+ isync
+
+ /* DBAT 6 */
+ lis r4, CONFIG_SYS_DBAT6L_EARLY@h
+ ori r4, r4, CONFIG_SYS_DBAT6L_EARLY@l
+ lis r3, CONFIG_SYS_DBAT6U_EARLY@h
+ ori r3, r3, CONFIG_SYS_DBAT6U_EARLY@l
+ mtspr DBAT6L, r4
+ mtspr DBAT6U, r3
+ isync
+
+#if(CONFIG_SYS_CCSRBAR_DEFAULT != CONFIG_SYS_CCSRBAR)
+ /* IBAT 7 */
+ lis r4, CONFIG_SYS_CCSR_DEFAULT_IBATL@h
+ ori r4, r4, CONFIG_SYS_CCSR_DEFAULT_IBATL@l
+ lis r3, CONFIG_SYS_CCSR_DEFAULT_IBATU@h
+ ori r3, r3, CONFIG_SYS_CCSR_DEFAULT_IBATU@l
+ mtspr IBAT7L, r4
+ mtspr IBAT7U, r3
+ isync
+
+ /* DBAT 7 */
+ lis r4, CONFIG_SYS_CCSR_DEFAULT_DBATL@h
+ ori r4, r4, CONFIG_SYS_CCSR_DEFAULT_DBATL@l
+ lis r3, CONFIG_SYS_CCSR_DEFAULT_DBATU@h
+ ori r3, r3, CONFIG_SYS_CCSR_DEFAULT_DBATU@l
+ mtspr DBAT7L, r4
+ mtspr DBAT7U, r3
+ isync
+#endif
+ blr
+
+ .globl clear_tlbs
+clear_tlbs:
+ addis r3, 0, 0x0000
+ addis r5, 0, 0x4
+ isync
+tlblp:
+ tlbie r3
+ sync
+ addi r3, r3, 0x1000
+ cmp 0, 0, r3, r5
+ blt tlblp
+ blr
+
+ .globl disable_addr_trans
+disable_addr_trans:
+ /* disable address translation */
+ mflr r4
+ mfmsr r3
+ andi. r0, r3, (MSR_IR | MSR_DR)
+ beqlr
+ andc r3, r3, r0
+ mtspr SRR0, r4
+ mtspr SRR1, r3
+ rfi
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+ .globl transfer_to_handler
+transfer_to_handler:
+ stw r22,_NIP(r21)
+ lis r22,MSR_POW@h
+ andc r23,r23,r22
+ stw r23,_MSR(r21)
+ SAVE_GPR(7, r21)
+ SAVE_4GPRS(8, r21)
+ SAVE_8GPRS(12, r21)
+ SAVE_8GPRS(24, r21)
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ mtspr SPRG2,r22 /* r1 is now kernel sp */
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
+
+int_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+
+ .globl dc_read
+dc_read:
+ blr
+
+ .globl get_pvr
+get_pvr:
+ mfspr r3, PVR
+ blr
+
+ .globl get_svr
+get_svr:
+ mfspr r3, SVR
+ blr
+
+
+/*
+ * Function: in8
+ * Description: Input 8 bits
+ */
+ .globl in8
+in8:
+ lbz r3,0x0000(r3)
+ blr
+
+/*
+ * Function: out8
+ * Description: Output 8 bits
+ */
+ .globl out8
+out8:
+ stb r4,0x0000(r3)
+ blr
+
+/*
+ * Function: out16
+ * Description: Output 16 bits
+ */
+ .globl out16
+out16:
+ sth r4,0x0000(r3)
+ blr
+
+/*
+ * Function: out16r
+ * Description: Byte reverse and output 16 bits
+ */
+ .globl out16r
+out16r:
+ sthbrx r4,r0,r3
+ blr
+
+/*
+ * Function: out32
+ * Description: Output 32 bits
+ */
+ .globl out32
+out32:
+ stw r4,0x0000(r3)
+ blr
+
+/*
+ * Function: out32r
+ * Description: Byte reverse and output 32 bits
+ */
+ .globl out32r
+out32r:
+ stwbrx r4,r0,r3
+ blr
+
+/*
+ * Function: in16
+ * Description: Input 16 bits
+ */
+ .globl in16
+in16:
+ lhz r3,0x0000(r3)
+ blr
+
+/*
+ * Function: in16r
+ * Description: Input 16 bits and byte reverse
+ */
+ .globl in16r
+in16r:
+ lhbrx r3,r0,r3
+ blr
+
+/*
+ * Function: in32
+ * Description: Input 32 bits
+ */
+ .globl in32
+in32:
+ lwz 3,0x0000(3)
+ blr
+
+/*
+ * Function: in32r
+ * Description: Input 32 bits and byte reverse
+ */
+ .globl in32r
+in32r:
+ lwbrx r3,r0,r3
+ blr
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+ .globl relocate_code
+relocate_code:
+
+ mr r1, r3 /* Set new stack pointer */
+ mr r9, r4 /* Save copy of Global Data pointer */
+ mr r10, r5 /* Save copy of Destination Address */
+
+ GET_GOT
+ mr r3, r5 /* Destination Address */
+ lis r4, CONFIG_SYS_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CONFIG_SYS_MONITOR_BASE@l
+ lwz r5, GOT(__init_end)
+ sub r5, r5, r4
+ li r6, CONFIG_SYS_CACHELINE_SIZE /* Cache Line Size */
+
+ /*
+ * Fix GOT pointer:
+ *
+ * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+ *
+ * Offset:
+ */
+ sub r15, r10, r4
+
+ /* First our own GOT */
+ add r12, r12, r15
+ /* then the one used by the C code */
+ add r30, r30, r15
+
+ /*
+ * Now relocate code
+ */
+ cmplw cr1,r3,r4
+ addi r0,r5,3
+ srwi. r0,r0,2
+ beq cr1,4f /* In place copy is not necessary */
+ beq 7f /* Protect against 0 count */
+ mtctr r0
+ bge cr1,2f
+
+ la r8,-4(r4)
+ la r7,-4(r3)
+1: lwzu r0,4(r8)
+ stwu r0,4(r7)
+ bdnz 1b
+ b 4f
+
+2: slwi r0,r0,2
+ add r8,r4,r0
+ add r7,r3,r0
+3: lwzu r0,-4(r8)
+ stwu r0,-4(r7)
+ bdnz 3b
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4: cmpwi r6,0
+ add r5,r3,r5
+ beq 7f /* Always flush prefetch queue in any case */
+ subi r0,r6,1
+ andc r3,r3,r0
+ mr r4,r3
+5: dcbst 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 5b
+ sync /* Wait for all dcbst to complete on bus */
+ mr r4,r3
+6: icbi 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 6b
+7: sync /* Wait for all icbi to complete on bus */
+ isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+ addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+ mtlr r0
+ blr
+
+in_ram:
+ /*
+ * Relocation Function, r12 point to got2+0x8000
+ *
+ * Adjust got2 pointers, no need to check for 0, this code
+ * already puts a few entries in the table.
+ */
+ li r0,__got2_entries@sectoff@l
+ la r3,GOT(_GOT2_TABLE_)
+ lwz r11,GOT(_GOT2_TABLE_)
+ mtctr r0
+ sub r11,r3,r11
+ addi r3,r3,-4
+1: lwzu r0,4(r3)
+ cmpwi r0,0
+ beq- 2f
+ add r0,r0,r11
+ stw r0,0(r3)
+2: bdnz 1b
+
+ /*
+ * Now adjust the fixups and the pointers to the fixups
+ * in case we need to move ourselves again.
+ */
+ li r0,__fixup_entries@sectoff@l
+ lwz r3,GOT(_FIXUP_TABLE_)
+ cmpwi r0,0
+ mtctr r0
+ addi r3,r3,-4
+ beq 4f
+3: lwzu r4,4(r3)
+ lwzux r0,r4,r11
+ cmpwi r0,0
+ add r0,r0,r11
+ stw r4,0(r3)
+ beq- 5f
+ stw r0,0(r4)
+5: bdnz 3b
+4:
+/* clear_bss: */
+ /*
+ * Now clear BSS segment
+ */
+ lwz r3,GOT(__bss_start)
+ lwz r4,GOT(__bss_end)
+
+ cmplw 0, r3, r4
+ beq 6f
+
+ li r0, 0
+5:
+ stw r0, 0(r3)
+ addi r3, r3, 4
+ cmplw 0, r3, r4
+ bne 5b
+6:
+ mr r3, r9 /* Init Date pointer */
+ mr r4, r10 /* Destination Address */
+ bl board_init_r
+
+ /* not reached - end relocate_code */
+/*-----------------------------------------------------------------------*/
+
+ /*
+ * Copy exception vector code to low memory
+ *
+ * r3: dest_addr
+ * r7: source address, r8: end address, r9: target address
+ */
+ .globl trap_init
+trap_init:
+ mflr r4 /* save link register */
+ GET_GOT
+ lwz r7, GOT(_start)
+ lwz r8, GOT(_end_of_vectors)
+
+ li r9, 0x100 /* reset vector always at 0x100 */
+
+ cmplw 0, r7, r8
+ bgelr /* return if r7>=r8 - just in case */
+1:
+ lwz r0, 0(r7)
+ stw r0, 0(r9)
+ addi r7, r7, 4
+ addi r9, r9, 4
+ cmplw 0, r7, r8
+ bne 1b
+
+ /*
+ * relocate `hdlr' and `int_return' entries
+ */
+ li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+ li r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 2b
+
+ li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+ li r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 3b
+
+ li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+ li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 4b
+
+ /* enable execptions from RAM vectors */
+ mfmsr r7
+ li r8,MSR_IP
+ andc r7,r7,r8
+ ori r7,r7,MSR_ME /* Enable Machine Check */
+ mtmsr r7
+
+ mtlr r4 /* restore link register */
+ blr
+
+.globl enable_ext_addr
+enable_ext_addr:
+ mfspr r0, HID0
+ lis r0, (HID0_HIGH_BAT_EN | HID0_XBSEN | HID0_XAEN)@h
+ ori r0, r0, (HID0_HIGH_BAT_EN | HID0_XBSEN | HID0_XAEN)@l
+ mtspr HID0, r0
+ sync
+ isync
+ blr
+
+#if (CONFIG_SYS_CCSRBAR_DEFAULT != CONFIG_SYS_CCSRBAR)
+.globl setup_ccsrbar
+setup_ccsrbar:
+ /* Special sequence needed to update CCSRBAR itself */
+ lis r4, CONFIG_SYS_CCSRBAR_DEFAULT@h
+ ori r4, r4, CONFIG_SYS_CCSRBAR_DEFAULT@l
+
+ lis r5, CONFIG_SYS_CCSRBAR_PHYS_LOW@h
+ ori r5, r5, CONFIG_SYS_CCSRBAR_PHYS_LOW@l
+ srwi r5,r5,12
+ li r6, CONFIG_SYS_CCSRBAR_PHYS_HIGH@l
+ rlwimi r5,r6,20,8,11
+ stw r5, 0(r4) /* Store physical value of CCSR */
+ isync
+
+ lis r5, CONFIG_SYS_TEXT_BASE@h
+ ori r5,r5,CONFIG_SYS_TEXT_BASE@l
+ lwz r5, 0(r5)
+ isync
+
+ /* Use VA of CCSR to do read */
+ lis r3, CONFIG_SYS_CCSRBAR@h
+ lwz r5, CONFIG_SYS_CCSRBAR@l(r3)
+ isync
+
+ blr
+#endif
+
+#ifdef CONFIG_SYS_INIT_RAM_LOCK
+lock_ram_in_cache:
+ /* Allocate Initial RAM in data cache.
+ */
+ lis r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@h
+ ori r3, r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@l
+ li r4, ((CONFIG_SYS_INIT_RAM_SIZE & ~31) + \
+ (CONFIG_SYS_INIT_RAM_ADDR & 31) + 31) / 32
+ mtctr r4
+1:
+ dcbz r0, r3
+ addi r3, r3, 32
+ bdnz 1b
+#if 1
+/* Lock the data cache */
+ mfspr r0, HID0
+ ori r0, r0, 0x1000
+ sync
+ mtspr HID0, r0
+ sync
+ blr
+#endif
+#if 0
+ /* Lock the first way of the data cache */
+ mfspr r0, LDSTCR
+ ori r0, r0, 0x0080
+#if defined(CONFIG_ALTIVEC)
+ dssall
+#endif
+ sync
+ mtspr LDSTCR, r0
+ sync
+ isync
+ blr
+#endif
+
+.globl unlock_ram_in_cache
+unlock_ram_in_cache:
+ /* invalidate the INIT_RAM section */
+ lis r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@h
+ ori r3, r3, (CONFIG_SYS_INIT_RAM_ADDR & ~31)@l
+ li r4, ((CONFIG_SYS_INIT_RAM_SIZE & ~31) + \
+ (CONFIG_SYS_INIT_RAM_ADDR & 31) + 31) / 32
+ mtctr r4
+1: icbi r0, r3
+ addi r3, r3, 32
+ bdnz 1b
+ sync /* Wait for all icbi to complete on bus */
+ isync
+#if 1
+/* Unlock the data cache and invalidate it */
+ mfspr r0, HID0
+ li r3,0x1000
+ andc r0,r0,r3
+ li r3,0x0400
+ or r0,r0,r3
+ sync
+ mtspr HID0, r0
+ sync
+ blr
+#endif
+#if 0
+ /* Unlock the first way of the data cache */
+ mfspr r0, LDSTCR
+ li r3,0x0080
+ andc r0,r0,r3
+#ifdef CONFIG_ALTIVEC
+ dssall
+#endif
+ sync
+ mtspr LDSTCR, r0
+ sync
+ isync
+ li r3,0x0400
+ or r0,r0,r3
+ sync
+ mtspr HID0, r0
+ sync
+ blr
+#endif
+#endif
diff --git a/arch/powerpc/cpu/mpc86xx/traps.c b/arch/powerpc/cpu/mpc86xx/traps.c
new file mode 100644
index 0000000..50069d5
--- /dev/null
+++ b/arch/powerpc/cpu/mpc86xx/traps.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+/*
+ * End of addressable memory. This may be less than the actual
+ * amount of memory on the system if we're unable to keep all
+ * the memory mapped in.
+ */
+extern ulong get_effective_memsize(void);
+#define END_OF_MEM (gd->bd->bi_memstart + get_effective_memsize())
+
+/*
+ * Trap & Exception support
+ */
+
+static void print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ printf("Call backtrace: ");
+ while (sp) {
+ if ((uint) sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ printf("\n");
+ printf("%08lX ", i);
+ if (cnt > 32)
+ break;
+ sp = (unsigned long *)*sp;
+ }
+ printf("\n");
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ int i;
+
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS:"
+ " %p TRAP: %04lx DAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP:"
+ " %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr & MSR_EE ? 1 : 0,
+ regs->msr & MSR_PR ? 1 : 0, regs->msr & MSR_FP ? 1 : 0,
+ regs->msr & MSR_ME ? 1 : 0, regs->msr & MSR_IR ? 1 : 0,
+ regs->msr & MSR_DR ? 1 : 0);
+
+ printf("\n");
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0) {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7) {
+ printf("\n");
+ }
+ }
+}
+
+
+static void _exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception in kernel pc %lx signal %d", regs->nip, signr);
+}
+
+void MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup;
+
+ /* Probing PCI using config cycles cause this exception
+ * when a device is not present. Catch it and return to
+ * the PCI exception handler.
+ */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ return;
+ }
+
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler) (regs))
+ return;
+#endif
+
+ printf("Machine check in kernel mode.\n");
+ printf("Caused by (from msr): ");
+ printf("regs %p ", regs);
+ switch ( regs->msr & 0x001F0000) {
+ case (0x80000000>>11):
+ printf("MSS error. MSSSR0: %08x\n", mfspr(SPRN_MSSSR0));
+ break;
+ case (0x80000000>>12):
+ printf("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (0x80000000 >> 13):
+ printf("Transfer error ack signal\n");
+ break;
+ case (0x80000000 >> 14):
+ printf("Data parity signal\n");
+ break;
+ case (0x80000000 >> 15):
+ printf("Address parity signal\n");
+ break;
+ default:
+ printf("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("machine check");
+}
+
+void AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler) (regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void ProgramCheckException(struct pt_regs *regs)
+{
+ unsigned char *p = regs ? (unsigned char *)(regs->nip) : NULL;
+ int i, j;
+
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler) (regs))
+ return;
+#endif
+ show_regs(regs);
+
+ p = (unsigned char *)((unsigned long)p & 0xFFFFFFE0);
+ p -= 32;
+ for (i = 0; i < 256; i += 16) {
+ printf("%08x: ", (unsigned int)p + i);
+ for (j = 0; j < 16; j++) {
+ printf("%02x ", p[i + j]);
+ }
+ printf("\n");
+ }
+
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void SoftEmuException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler) (regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Software Emulation Exception");
+}
+
+void UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler) (regs))
+ return;
+#endif
+ printf("UnknownException regs@%lx\n", (ulong)regs);
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+/*
+ * Probe an address by reading.
+ * If not present, return -1,
+ * otherwise return 0.
+ */
+int addr_probe(uint *addr)
+{
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc86xx/u-boot.lds b/arch/powerpc/cpu/mpc86xx/u-boot.lds
new file mode 100644
index 0000000..7e357ba
--- /dev/null
+++ b/arch/powerpc/cpu/mpc86xx/u-boot.lds
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2006, 2007 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+OUTPUT_ARCH(powerpc)
+
+SECTIONS
+{
+
+ /* Read-only sections, merged into text segment: */
+ .text :
+ {
+ arch/powerpc/cpu/mpc86xx/start.o (.text*)
+ arch/powerpc/cpu/mpc86xx/traps.o (.text*)
+ *(.text*)
+ }
+ _etext = .;
+ PROVIDE (etext = .);
+ .rodata :
+ {
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ }
+
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x00FF) & 0xFFFFFF00;
+ _erotext = .;
+ PROVIDE (erotext = .);
+ .reloc :
+ {
+ _GOT2_TABLE_ = .;
+ KEEP(*(.got2))
+ KEEP(*(.got))
+ PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
+ _FIXUP_TABLE_ = .;
+ KEEP(*(.fixup))
+ }
+ __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
+ __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+ .data :
+ {
+ *(.data*)
+ *(.sdata*)
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+
+ . = .;
+
+ . = ALIGN(4);
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+ . = .;
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ . = ALIGN(256);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(256);
+ __init_end = .;
+
+ __bss_start = .;
+ .bss (NOLOAD) :
+ {
+ *(.bss*)
+ *(.sbss*)
+ *(COMMON)
+ . = ALIGN(4);
+ }
+ __bss_end = . ;
+ PROVIDE (end = .);
+}
diff --git a/arch/powerpc/cpu/mpc8xx/Makefile b/arch/powerpc/cpu/mpc8xx/Makefile
new file mode 100644
index 0000000..ef10e2d
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/Makefile
@@ -0,0 +1,65 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+# CFLAGS += -DET_DEBUG
+
+LIB = $(obj)lib$(CPU).o
+
+SSTART-y += start.o
+CSTART-y += traps.o
+COBJS-y += bedbug_860.o
+COBJS-y += commproc.o
+COBJS-y += cpu.o
+COBJS-y += cpu_init.o
+COBJS-y += fec.o
+COBJS-$(CONFIG_OF_LIBFDT) += fdt.o
+COBJS-y += i2c.o
+COBJS-y += interrupts.o
+COBJS-y += scc.o
+COBJS-y += serial.o
+COBJS-y += speed.o
+COBJS-y += spi.o
+COBJS-y += upatch.o
+COBJS-y += video.o
+SOBJS-y += kgdb.o
+SOBJS-y += plprcr_write.o
+
+SRCS := $(SSTART-y:.o=.S) $(CSTART-y:.o=.c) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
+START := $(addprefix $(obj),$(SSTART-y) $(CSTART-y))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/powerpc/cpu/mpc8xx/bedbug_860.c b/arch/powerpc/cpu/mpc8xx/bedbug_860.c
new file mode 100644
index 0000000..c0016f7
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/bedbug_860.c
@@ -0,0 +1,314 @@
+/*
+ * Bedbug Functions specific to the MPC860 chip
+ */
+
+#include <common.h>
+#include <command.h>
+#include <linux/ctype.h>
+#include <bedbug/bedbug.h>
+#include <bedbug/regs.h>
+#include <bedbug/ppc.h>
+#include <bedbug/type.h>
+
+#if defined(CONFIG_CMD_BEDBUG) && defined(CONFIG_8xx)
+
+#define MAX_BREAK_POINTS 2
+
+extern CPU_DEBUG_CTX bug_ctx;
+
+void bedbug860_init __P((void));
+void bedbug860_do_break __P((cmd_tbl_t*,int,int,char*const[]));
+void bedbug860_break_isr __P((struct pt_regs*));
+int bedbug860_find_empty __P((void));
+int bedbug860_set __P((int,unsigned long));
+int bedbug860_clear __P((int));
+
+
+/* ======================================================================
+ * Initialize the global bug_ctx structure for the MPC860. Clear all
+ * of the breakpoints.
+ * ====================================================================== */
+
+void bedbug860_init( void )
+{
+ int i;
+ /* -------------------------------------------------- */
+
+ bug_ctx.hw_debug_enabled = 0;
+ bug_ctx.stopped = 0;
+ bug_ctx.current_bp = 0;
+ bug_ctx.regs = NULL;
+
+ bug_ctx.do_break = bedbug860_do_break;
+ bug_ctx.break_isr = bedbug860_break_isr;
+ bug_ctx.find_empty = bedbug860_find_empty;
+ bug_ctx.set = bedbug860_set;
+ bug_ctx.clear = bedbug860_clear;
+
+ for( i = 1; i <= MAX_BREAK_POINTS; ++i )
+ (*bug_ctx.clear)( i );
+
+ puts ("BEDBUG:ready\n");
+ return;
+} /* bedbug_init_breakpoints */
+
+
+
+/* ======================================================================
+ * Set/clear/show one of the hardware breakpoints for the 860. The "off"
+ * string will disable a specific breakpoint. The "show" string will
+ * display the current breakpoints. Otherwise an address will set a
+ * breakpoint at that address. Setting a breakpoint uses the CPU-specific
+ * set routine which will assign a breakpoint number.
+ * ====================================================================== */
+
+void bedbug860_do_break (cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ long addr = 0; /* Address to break at */
+ int which_bp; /* Breakpoint number */
+ /* -------------------------------------------------- */
+
+ if (argc < 2) {
+ cmd_usage(cmdtp);
+ return;
+ }
+
+ /* Turn off a breakpoint */
+
+ if( strcmp( argv[ 1 ], "off" ) == 0 )
+ {
+ if( bug_ctx.hw_debug_enabled == 0 )
+ {
+ printf( "No breakpoints enabled\n" );
+ return;
+ }
+
+ which_bp = simple_strtoul( argv[ 2 ], NULL, 10 );
+
+ if( bug_ctx.clear )
+ (*bug_ctx.clear)( which_bp );
+
+ printf( "Breakpoint %d removed\n", which_bp );
+ return;
+ }
+
+ /* Show a list of breakpoints */
+
+ if( strcmp( argv[ 1 ], "show" ) == 0 )
+ {
+ for( which_bp = 1; which_bp <= MAX_BREAK_POINTS; ++which_bp )
+ {
+
+ switch( which_bp )
+ {
+ case 1: addr = GET_CMPA(); break;
+ case 2: addr = GET_CMPB(); break;
+ case 3: addr = GET_CMPC(); break;
+ case 4: addr = GET_CMPD(); break;
+ }
+
+ printf( "Breakpoint [%d]: ", which_bp );
+ if( addr == 0 )
+ printf( "NOT SET\n" );
+ else
+ disppc( (unsigned char *)addr, 0, 1, bedbug_puts, F_RADHEX );
+ }
+ return;
+ }
+
+ /* Set a breakpoint at the address */
+
+ if( !isdigit( argv[ 1 ][ 0 ])) {
+ cmd_usage(cmdtp);
+ return;
+ }
+
+ addr = simple_strtoul( argv[ 1 ], NULL, 16 ) & 0xfffffffc;
+
+ if(( bug_ctx.set ) && ( which_bp = (*bug_ctx.set)( 0, addr )) > 0 )
+ {
+ printf( "Breakpoint [%d]: ", which_bp );
+ disppc( (unsigned char *)addr, 0, 1, bedbug_puts, F_RADHEX );
+ }
+
+ return;
+} /* bedbug860_do_break */
+
+
+
+/* ======================================================================
+ * Handle a breakpoint. First determine which breakpoint was hit by
+ * looking at the DeBug Status Register (DBSR), clear the breakpoint
+ * and enter a mini main loop. Stay in the loop until the stopped flag
+ * in the debug context is cleared.
+ * ====================================================================== */
+
+void bedbug860_break_isr( struct pt_regs *regs )
+{
+ unsigned long addr; /* Address stopped at */
+ unsigned long cause; /* Address stopped at */
+ /* -------------------------------------------------- */
+
+ cause = GET_ICR();
+
+ if( !(cause & 0x00000004)) {
+ printf( "Not an instruction breakpoint (ICR 0x%08lx)\n", cause );
+ return;
+ }
+
+ addr = regs->nip;
+
+ if( addr == GET_CMPA() )
+ {
+ bug_ctx.current_bp = 1;
+ }
+ else if( addr == GET_CMPB() )
+ {
+ bug_ctx.current_bp = 2;
+ }
+ else if( addr == GET_CMPC() )
+ {
+ bug_ctx.current_bp = 3;
+ }
+ else if( addr == GET_CMPD() )
+ {
+ bug_ctx.current_bp = 4;
+ }
+
+ bedbug_main_loop( addr, regs );
+ return;
+} /* bedbug860_break_isr */
+
+
+
+/* ======================================================================
+ * Look through all of the hardware breakpoints available to see if one
+ * is unused.
+ * ====================================================================== */
+
+int bedbug860_find_empty( void )
+{
+ /* -------------------------------------------------- */
+
+ if( GET_CMPA() == 0 )
+ return 1;
+
+ if( GET_CMPB() == 0 )
+ return 2;
+
+ if( GET_CMPC() == 0 )
+ return 3;
+
+ if( GET_CMPD() == 0 )
+ return 4;
+
+ return 0;
+} /* bedbug860_find_empty */
+
+
+
+/* ======================================================================
+ * Set a breakpoint. If 'which_bp' is zero then find an unused breakpoint
+ * number, otherwise reassign the given breakpoint. If hardware debugging
+ * is not enabled, then turn it on via the MSR and DBCR0. Set the break
+ * address in the appropriate IACx register and enable proper address
+ * beakpoint in DBCR0.
+ * ====================================================================== */
+
+int bedbug860_set( int which_bp, unsigned long addr )
+{
+ /* -------------------------------------------------- */
+
+ /* Only look if which_bp == 0, else use which_bp */
+ if(( bug_ctx.find_empty ) && ( !which_bp ) &&
+ ( which_bp = (*bug_ctx.find_empty)()) == 0 )
+ {
+ printf( "All breakpoints in use\n" );
+ return 0;
+ }
+
+ if( which_bp < 1 || which_bp > MAX_BREAK_POINTS )
+ {
+ printf( "Invalid break point # %d\n", which_bp );
+ return 0;
+ }
+
+ if( ! bug_ctx.hw_debug_enabled )
+ {
+ bug_ctx.hw_debug_enabled = 1;
+ SET_DER( GET_DER() | 0x00000004 );
+ }
+
+ switch( which_bp )
+ {
+ case 1:
+ SET_CMPA( addr );
+ SET_ICTRL( GET_ICTRL() | 0x80080800 ); /* CTA=Equal,IW0=Match A,SIW0EN */
+ break;
+
+ case 2:
+ SET_CMPB( addr );
+ SET_ICTRL( GET_ICTRL() | 0x10020400 ); /* CTB=Equal,IW1=Match B,SIW1EN */
+ break;
+
+ case 3:
+ SET_CMPC( addr );
+ SET_ICTRL( GET_ICTRL() | 0x02008200 ); /* CTC=Equal,IW2=Match C,SIW2EN */
+ break;
+
+ case 4:
+ SET_CMPD( addr );
+ SET_ICTRL( GET_ICTRL() | 0x00404100 ); /* CTD=Equal,IW3=Match D,SIW3EN */
+ break;
+ }
+
+ return which_bp;
+} /* bedbug860_set */
+
+
+
+/* ======================================================================
+ * Disable a specific breakoint by setting the appropriate IACx register
+ * to zero and claring the instruction address breakpoint in DBCR0.
+ * ====================================================================== */
+
+int bedbug860_clear( int which_bp )
+{
+ /* -------------------------------------------------- */
+
+ if( which_bp < 1 || which_bp > MAX_BREAK_POINTS )
+ {
+ printf( "Invalid break point # (%d)\n", which_bp );
+ return -1;
+ }
+
+ switch( which_bp )
+ {
+ case 1:
+ SET_CMPA( 0 );
+ SET_ICTRL( GET_ICTRL() & ~0x80080800 ); /* CTA=Equal,IW0=Match A,SIW0EN */
+ break;
+
+ case 2:
+ SET_CMPB( 0 );
+ SET_ICTRL( GET_ICTRL() & ~0x10020400 ); /* CTB=Equal,IW1=Match B,SIW1EN */
+ break;
+
+ case 3:
+ SET_CMPC( 0 );
+ SET_ICTRL( GET_ICTRL() & ~0x02008200 ); /* CTC=Equal,IW2=Match C,SIW2EN */
+ break;
+
+ case 4:
+ SET_CMPD( 0 );
+ SET_ICTRL( GET_ICTRL() & ~0x00404100 ); /* CTD=Equal,IW3=Match D,SIW3EN */
+ break;
+ }
+
+ return 0;
+} /* bedbug860_clear */
+
+
+/* ====================================================================== */
+#endif
diff --git a/arch/powerpc/cpu/mpc8xx/commproc.c b/arch/powerpc/cpu/mpc8xx/commproc.c
new file mode 100644
index 0000000..a364782
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/commproc.c
@@ -0,0 +1,85 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <commproc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+
+int dpram_init (void)
+{
+ /* Reclaim the DP memory for our use. */
+ gd->arch.dp_alloc_base = CPM_DATAONLY_BASE;
+ gd->arch.dp_alloc_top = CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE;
+
+ return (0);
+}
+
+/* Allocate some memory from the dual ported ram. We may want to
+ * enforce alignment restrictions, but right now everyone is a good
+ * citizen.
+ */
+uint dpram_alloc (uint size)
+{
+ uint addr = gd->arch.dp_alloc_base;
+
+ if ((gd->arch.dp_alloc_base + size) >= gd->arch.dp_alloc_top)
+ return (CPM_DP_NOSPACE);
+
+ gd->arch.dp_alloc_base += size;
+
+ return addr;
+}
+
+uint dpram_base (void)
+{
+ return gd->arch.dp_alloc_base;
+}
+
+/* Allocate some memory from the dual ported ram. We may want to
+ * enforce alignment restrictions, but right now everyone is a good
+ * citizen.
+ */
+uint dpram_alloc_align (uint size, uint align)
+{
+ uint addr, mask = align - 1;
+
+ addr = (gd->arch.dp_alloc_base + mask) & ~mask;
+
+ if ((addr + size) >= gd->arch.dp_alloc_top)
+ return (CPM_DP_NOSPACE);
+
+ gd->arch.dp_alloc_base = addr + size;
+
+ return addr;
+}
+
+uint dpram_base_align (uint align)
+{
+ uint mask = align - 1;
+
+ return (gd->arch.dp_alloc_base + mask) & ~mask;
+}
+#endif /* CONFIG_SYS_ALLOC_DPRAM */
diff --git a/arch/powerpc/cpu/mpc8xx/config.mk b/arch/powerpc/cpu/mpc8xx/config.mk
new file mode 100644
index 0000000..aa61980
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/config.mk
@@ -0,0 +1,26 @@
+#
+# (C) Copyright 2000-2010
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_RELFLAGS += -meabi
+
+PLATFORM_CPPFLAGS += -DCONFIG_8xx -ffixed-r2 -mstring -mcpu=860 -msoft-float
diff --git a/arch/powerpc/cpu/mpc8xx/cpu.c b/arch/powerpc/cpu/mpc8xx/cpu.c
new file mode 100644
index 0000000..dc33eb3
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/cpu.c
@@ -0,0 +1,659 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * m8xx.c
+ *
+ * CPU specific code
+ *
+ * written or collected and sometimes rewritten by
+ * Magnus Damm <damm@bitsmart.com>
+ *
+ * minor modifications by
+ * Wolfgang Denk <wd@denx.de>
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mpc8xx.h>
+#include <commproc.h>
+#include <netdev.h>
+#include <asm/cache.h>
+#include <linux/compiler.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static char *cpu_warning = "\n " \
+ "*** Warning: CPU Core has Silicon Bugs -- Check the Errata ***";
+
+#if ((defined(CONFIG_MPC86x) || defined(CONFIG_MPC855)) && \
+ !defined(CONFIG_MPC862))
+
+static int check_CPU (long clock, uint pvr, uint immr)
+{
+ char *id_str =
+# if defined(CONFIG_MPC855)
+ "PC855";
+# elif defined(CONFIG_MPC860P)
+ "PC860P";
+# else
+ NULL;
+# endif
+ volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
+ uint k, m;
+ char buf[32];
+ char pre = 'X';
+ char *mid = "xx";
+ char *suf;
+
+ /* the highest 16 bits should be 0x0050 for a 860 */
+
+ if ((pvr >> 16) != 0x0050)
+ return -1;
+
+ k = (immr << 16) |
+ immap->im_cpm.cp_dparam16[PROFF_REVNUM / sizeof(u16)];
+ m = 0;
+ suf = "";
+
+ /*
+ * Some boards use sockets so different CPUs can be used.
+ * We have to check chip version in run time.
+ */
+ switch (k) {
+ case 0x00020001: pre = 'P'; break;
+ case 0x00030001: break;
+ case 0x00120003: suf = "A"; break;
+ case 0x00130003: suf = "A3"; break;
+
+ case 0x00200004: suf = "B"; break;
+
+ case 0x00300004: suf = "C"; break;
+ case 0x00310004: suf = "C1"; m = 1; break;
+
+ case 0x00200064: mid = "SR"; suf = "B"; break;
+ case 0x00300065: mid = "SR"; suf = "C"; break;
+ case 0x00310065: mid = "SR"; suf = "C1"; m = 1; break;
+ case 0x05010000: suf = "D3"; m = 1; break;
+ case 0x05020000: suf = "D4"; m = 1; break;
+ /* this value is not documented anywhere */
+ case 0x40000000: pre = 'P'; suf = "D"; m = 1; break;
+ /* MPC866P/MPC866T/MPC859T/MPC859DSL/MPC852T */
+ case 0x08010004: /* Rev. A.0 */
+ suf = "A";
+ /* fall through */
+ case 0x08000003: /* Rev. 0.3 */
+ pre = 'M'; m = 1;
+ if (id_str == NULL)
+ id_str =
+# if defined(CONFIG_MPC852T)
+ "PC852T";
+# elif defined(CONFIG_MPC859T)
+ "PC859T";
+# elif defined(CONFIG_MPC859DSL)
+ "PC859DSL";
+# elif defined(CONFIG_MPC866T)
+ "PC866T";
+# else
+ "PC866x"; /* Unknown chip from MPC866 family */
+# endif
+ break;
+ case 0x09000000: pre = 'M'; mid = suf = ""; m = 1;
+ if (id_str == NULL)
+ id_str = "PC885"; /* 870/875/880/885 */
+ break;
+
+ default: suf = NULL; break;
+ }
+
+ if (id_str == NULL)
+ id_str = "PC86x"; /* Unknown 86x chip */
+ if (suf)
+ printf ("%c%s%sZPnn%s", pre, id_str, mid, suf);
+ else
+ printf ("unknown M%s (0x%08x)", id_str, k);
+
+
+#if defined(CONFIG_SYS_8xx_CPUCLK_MIN) && defined(CONFIG_SYS_8xx_CPUCLK_MAX)
+ printf (" at %s MHz [%d.%d...%d.%d MHz]\n ",
+ strmhz (buf, clock),
+ CONFIG_SYS_8xx_CPUCLK_MIN / 1000000,
+ ((CONFIG_SYS_8xx_CPUCLK_MIN % 1000000) + 50000) / 100000,
+ CONFIG_SYS_8xx_CPUCLK_MAX / 1000000,
+ ((CONFIG_SYS_8xx_CPUCLK_MAX % 1000000) + 50000) / 100000
+ );
+#else
+ printf (" at %s MHz: ", strmhz (buf, clock));
+#endif
+ printf ("%u kB I-Cache %u kB D-Cache",
+ checkicache () >> 10,
+ checkdcache () >> 10
+ );
+
+ /* do we have a FEC (860T/P or 852/859/866/885)? */
+
+ immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
+ if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
+ printf (" FEC present");
+ }
+
+ if (!m) {
+ puts (cpu_warning);
+ }
+
+ putc ('\n');
+
+#ifdef DEBUG
+ if(clock != measure_gclk()) {
+ printf ("clock %ldHz != %dHz\n", clock, measure_gclk());
+ }
+#endif
+
+ return 0;
+}
+
+#elif defined(CONFIG_MPC862)
+
+static int check_CPU (long clock, uint pvr, uint immr)
+{
+ volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
+ uint k, m;
+ char buf[32];
+ char pre = 'X';
+ __maybe_unused char *mid = "xx";
+ char *suf;
+
+ /* the highest 16 bits should be 0x0050 for a 8xx */
+
+ if ((pvr >> 16) != 0x0050)
+ return -1;
+
+ k = (immr << 16) |
+ immap->im_cpm.cp_dparam16[PROFF_REVNUM / sizeof(u16)];
+ m = 0;
+
+ switch (k) {
+
+ /* this value is not documented anywhere */
+ case 0x06000000: mid = "P"; suf = "0"; break;
+ case 0x06010001: mid = "P"; suf = "A"; m = 1; break;
+ case 0x07000003: mid = "P"; suf = "B"; m = 1; break;
+ default: suf = NULL; break;
+ }
+
+#ifndef CONFIG_MPC857
+ if (suf)
+ printf ("%cPC862%sZPnn%s", pre, mid, suf);
+ else
+ printf ("unknown MPC862 (0x%08x)", k);
+#else
+ if (suf)
+ printf ("%cPC857TZPnn%s", pre, suf); /* only 857T tested right now! */
+ else
+ printf ("unknown MPC857 (0x%08x)", k);
+#endif
+
+ printf (" at %s MHz:", strmhz (buf, clock));
+
+ printf (" %u kB I-Cache", checkicache () >> 10);
+ printf (" %u kB D-Cache", checkdcache () >> 10);
+
+ /* lets check and see if we're running on a 862T (or P?) */
+
+ immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
+ if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
+ printf (" FEC present");
+ }
+
+ if (!m) {
+ puts (cpu_warning);
+ }
+
+ putc ('\n');
+
+ return 0;
+}
+
+#elif defined(CONFIG_MPC823)
+
+static int check_CPU (long clock, uint pvr, uint immr)
+{
+ volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
+ uint k, m;
+ char buf[32];
+ char *suf;
+
+ /* the highest 16 bits should be 0x0050 for a 8xx */
+
+ if ((pvr >> 16) != 0x0050)
+ return -1;
+
+ k = (immr << 16) |
+ in_be16(&immap->im_cpm.cp_dparam16[PROFF_REVNUM / sizeof(u16)]);
+ m = 0;
+
+ switch (k) {
+ /* MPC823 */
+ case 0x20000000: suf = "0"; break;
+ case 0x20010000: suf = "0.1"; break;
+ case 0x20020000: suf = "Z2/3"; break;
+ case 0x20020001: suf = "Z3"; break;
+ case 0x21000000: suf = "A"; break;
+ case 0x21010000: suf = "B"; m = 1; break;
+ case 0x21010001: suf = "B2"; m = 1; break;
+ /* MPC823E */
+ case 0x24010000: suf = NULL;
+ puts ("PPC823EZTnnB2");
+ m = 1;
+ break;
+ default:
+ suf = NULL;
+ printf ("unknown MPC823 (0x%08x)", k);
+ break;
+ }
+ if (suf)
+ printf ("PPC823ZTnn%s", suf);
+
+ printf (" at %s MHz:", strmhz (buf, clock));
+
+ printf (" %u kB I-Cache", checkicache () >> 10);
+ printf (" %u kB D-Cache", checkdcache () >> 10);
+
+ /* lets check and see if we're running on a 860T (or P?) */
+
+ immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
+ if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
+ puts (" FEC present");
+ }
+
+ if (!m) {
+ puts (cpu_warning);
+ }
+
+ putc ('\n');
+
+ return 0;
+}
+
+#elif defined(CONFIG_MPC850)
+
+static int check_CPU (long clock, uint pvr, uint immr)
+{
+ volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
+ uint k, m;
+ char buf[32];
+
+ /* the highest 16 bits should be 0x0050 for a 8xx */
+
+ if ((pvr >> 16) != 0x0050)
+ return -1;
+
+ k = (immr << 16) |
+ immap->im_cpm.cp_dparam16[PROFF_REVNUM / sizeof(u16)];
+ m = 0;
+
+ switch (k) {
+ case 0x20020001:
+ printf ("XPC850xxZT");
+ break;
+ case 0x21000065:
+ printf ("XPC850xxZTA");
+ break;
+ case 0x21010067:
+ printf ("XPC850xxZTB");
+ m = 1;
+ break;
+ case 0x21020068:
+ printf ("XPC850xxZTC");
+ m = 1;
+ break;
+ default:
+ printf ("unknown MPC850 (0x%08x)", k);
+ }
+ printf (" at %s MHz:", strmhz (buf, clock));
+
+ printf (" %u kB I-Cache", checkicache () >> 10);
+ printf (" %u kB D-Cache", checkdcache () >> 10);
+
+ /* lets check and see if we're running on a 850T (or P?) */
+
+ immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
+ if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
+ printf (" FEC present");
+ }
+
+ if (!m) {
+ puts (cpu_warning);
+ }
+
+ putc ('\n');
+
+ return 0;
+}
+#else
+#error CPU undefined
+#endif
+/* ------------------------------------------------------------------------- */
+
+int checkcpu (void)
+{
+ ulong clock = gd->cpu_clk;
+ uint immr = get_immr (0); /* Return full IMMR contents */
+ uint pvr = get_pvr ();
+
+ puts ("CPU: ");
+
+ /* 850 has PARTNUM 20 */
+ /* 801 has PARTNUM 10 */
+ return check_CPU (clock, pvr, immr);
+}
+
+/* ------------------------------------------------------------------------- */
+/* L1 i-cache */
+/* the standard 860 has 128 sets of 16 bytes in 2 ways (= 4 kB) */
+/* the 860 P (plus) has 256 sets of 16 bytes in 4 ways (= 16 kB) */
+
+int checkicache (void)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ u32 cacheon = rd_ic_cst () & IDC_ENABLED;
+
+#ifdef CONFIG_IP86x
+ u32 k = memctl->memc_br1 & ~0x00007fff; /* probe in flash memoryarea */
+#else
+ u32 k = memctl->memc_br0 & ~0x00007fff; /* probe in flash memoryarea */
+#endif
+ u32 m;
+ u32 lines = -1;
+
+ wr_ic_cst (IDC_UNALL);
+ wr_ic_cst (IDC_INVALL);
+ wr_ic_cst (IDC_DISABLE);
+ __asm__ volatile ("isync");
+
+ while (!((m = rd_ic_cst ()) & IDC_CERR2)) {
+ wr_ic_adr (k);
+ wr_ic_cst (IDC_LDLCK);
+ __asm__ volatile ("isync");
+
+ lines++;
+ k += 0x10; /* the number of bytes in a cacheline */
+ }
+
+ wr_ic_cst (IDC_UNALL);
+ wr_ic_cst (IDC_INVALL);
+
+ if (cacheon)
+ wr_ic_cst (IDC_ENABLE);
+ else
+ wr_ic_cst (IDC_DISABLE);
+
+ __asm__ volatile ("isync");
+
+ return lines << 4;
+};
+
+/* ------------------------------------------------------------------------- */
+/* L1 d-cache */
+/* the standard 860 has 128 sets of 16 bytes in 2 ways (= 4 kB) */
+/* the 860 P (plus) has 256 sets of 16 bytes in 2 ways (= 8 kB) */
+/* call with cache disabled */
+
+int checkdcache (void)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ u32 cacheon = rd_dc_cst () & IDC_ENABLED;
+
+#ifdef CONFIG_IP86x
+ u32 k = memctl->memc_br1 & ~0x00007fff; /* probe in flash memoryarea */
+#else
+ u32 k = memctl->memc_br0 & ~0x00007fff; /* probe in flash memoryarea */
+#endif
+ u32 m;
+ u32 lines = -1;
+
+ wr_dc_cst (IDC_UNALL);
+ wr_dc_cst (IDC_INVALL);
+ wr_dc_cst (IDC_DISABLE);
+
+ while (!((m = rd_dc_cst ()) & IDC_CERR2)) {
+ wr_dc_adr (k);
+ wr_dc_cst (IDC_LDLCK);
+ lines++;
+ k += 0x10; /* the number of bytes in a cacheline */
+ }
+
+ wr_dc_cst (IDC_UNALL);
+ wr_dc_cst (IDC_INVALL);
+
+ if (cacheon)
+ wr_dc_cst (IDC_ENABLE);
+ else
+ wr_dc_cst (IDC_DISABLE);
+
+ return lines << 4;
+};
+
+/* ------------------------------------------------------------------------- */
+
+void upmconfig (uint upm, uint * table, uint size)
+{
+ uint i;
+ uint addr = 0;
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+
+ for (i = 0; i < size; i++) {
+ memctl->memc_mdr = table[i]; /* (16-15) */
+ memctl->memc_mcr = addr | upm; /* (16-16) */
+ addr++;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+#ifndef CONFIG_LWMON
+
+int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong msr, addr;
+
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+ immap->im_clkrst.car_plprcr |= PLPRCR_CSR; /* Checkstop Reset enable */
+
+ /* Interrupts and MMU off */
+ __asm__ volatile ("mtspr 81, 0");
+ __asm__ volatile ("mfmsr %0":"=r" (msr));
+
+ msr &= ~0x1030;
+ __asm__ volatile ("mtmsr %0"::"r" (msr));
+
+ /*
+ * Trying to execute the next instruction at a non-existing address
+ * should cause a machine check, resulting in reset
+ */
+#ifdef CONFIG_SYS_RESET_ADDRESS
+ addr = CONFIG_SYS_RESET_ADDRESS;
+#else
+ /*
+ * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address, CONFIG_SYS_MONITOR_BASE
+ * - sizeof (ulong) is usually a valid address. Better pick an address
+ * known to be invalid on your system and assign it to CONFIG_SYS_RESET_ADDRESS.
+ * "(ulong)-1" used to be a good choice for many systems...
+ */
+ addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong);
+#endif
+ ((void (*)(void)) addr) ();
+ return 1;
+}
+
+#else /* CONFIG_LWMON */
+
+/*
+ * On the LWMON board, the MCLR reset input of the PIC's on the board
+ * uses a 47K/1n RC combination which has a 47us time constant. The
+ * low signal on the HRESET pin of the CPU is only 512 clocks = 8 us
+ * and thus too short to reset the external hardware. So we use the
+ * watchdog to reset the board.
+ */
+int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ /* prevent triggering the watchdog */
+ disable_interrupts ();
+
+ /* make sure the watchdog is running */
+ reset_8xx_watchdog ((immap_t *) CONFIG_SYS_IMMR);
+
+ /* wait for watchdog reset */
+ while (1) {};
+
+ /* NOTREACHED */
+ return 1;
+}
+
+#endif /* CONFIG_LWMON */
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Get timebase clock frequency (like cpu_clk in Hz)
+ *
+ * See sections 14.2 and 14.6 of the User's Manual
+ */
+unsigned long get_tbclk (void)
+{
+ uint immr = get_immr (0); /* Return full IMMR contents */
+ volatile immap_t *immap = (volatile immap_t *)(immr & 0xFFFF0000);
+ ulong oscclk, factor, pll;
+
+ if (immap->im_clkrst.car_sccr & SCCR_TBS) {
+ return (gd->cpu_clk / 16);
+ }
+
+ pll = immap->im_clkrst.car_plprcr;
+
+#define PLPRCR_val(a) ((pll & PLPRCR_ ## a ## _MSK) >> PLPRCR_ ## a ## _SHIFT)
+
+ /*
+ * For newer PQ1 chips (MPC866/87x/88x families), PLL multiplication
+ * factor is calculated as follows:
+ *
+ * MFN
+ * MFI + -------
+ * MFD + 1
+ * factor = -----------------
+ * (PDF + 1) * 2^S
+ *
+ * For older chips, it's just MF field of PLPRCR plus one.
+ */
+ if ((immr & 0x0FFF) >= MPC8xx_NEW_CLK) { /* MPC866/87x/88x series */
+ factor = (PLPRCR_val(MFI) + PLPRCR_val(MFN)/(PLPRCR_val(MFD)+1))/
+ (PLPRCR_val(PDF)+1) / (1<<PLPRCR_val(S));
+ } else {
+ factor = PLPRCR_val(MF)+1;
+ }
+
+ oscclk = gd->cpu_clk / factor;
+
+ if ((immap->im_clkrst.car_sccr & SCCR_RTSEL) == 0 || factor > 2) {
+ return (oscclk / 4);
+ }
+ return (oscclk / 16);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset (void)
+{
+ int re_enable = disable_interrupts ();
+
+ reset_8xx_watchdog ((immap_t *) CONFIG_SYS_IMMR);
+ if (re_enable)
+ enable_interrupts ();
+}
+#endif /* CONFIG_WATCHDOG */
+
+#if defined(CONFIG_WATCHDOG) || defined(CONFIG_LWMON)
+
+void reset_8xx_watchdog (volatile immap_t * immr)
+{
+# if defined(CONFIG_LWMON)
+ /*
+ * The LWMON board uses a MAX6301 Watchdog
+ * with the trigger pin connected to port PA.7
+ *
+ * (The old board version used a MAX706TESA Watchdog, which
+ * had to be handled exactly the same.)
+ */
+# define WATCHDOG_BIT 0x0100
+ immr->im_ioport.iop_papar &= ~(WATCHDOG_BIT); /* GPIO */
+ immr->im_ioport.iop_padir |= WATCHDOG_BIT; /* Output */
+ immr->im_ioport.iop_paodr &= ~(WATCHDOG_BIT); /* active output */
+
+ immr->im_ioport.iop_padat ^= WATCHDOG_BIT; /* Toggle WDI */
+# elif defined(CONFIG_KUP4K) || defined(CONFIG_KUP4X)
+ /*
+ * The KUP4 boards uses a TPS3705 Watchdog
+ * with the trigger pin connected to port PA.5
+ */
+# define WATCHDOG_BIT 0x0400
+ immr->im_ioport.iop_papar &= ~(WATCHDOG_BIT); /* GPIO */
+ immr->im_ioport.iop_padir |= WATCHDOG_BIT; /* Output */
+ immr->im_ioport.iop_paodr &= ~(WATCHDOG_BIT); /* active output */
+
+ immr->im_ioport.iop_padat ^= WATCHDOG_BIT; /* Toggle WDI */
+# else
+ /*
+ * All other boards use the MPC8xx Internal Watchdog
+ */
+ immr->im_siu_conf.sc_swsr = 0x556c; /* write magic1 */
+ immr->im_siu_conf.sc_swsr = 0xaa39; /* write magic2 */
+# endif /* CONFIG_LWMON */
+}
+#endif /* CONFIG_WATCHDOG */
+
+/*
+ * Initializes on-chip ethernet controllers.
+ * to override, implement board_eth_init()
+ */
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(SCC_ENET) && defined(CONFIG_CMD_NET)
+ scc_initialize(bis);
+#endif
+#if defined(FEC_ENET)
+ fec_initialize(bis);
+#endif
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc8xx/cpu_init.c b/arch/powerpc/cpu/mpc8xx/cpu_init.c
new file mode 100644
index 0000000..49b354d
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/cpu_init.c
@@ -0,0 +1,283 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+
+#include <mpc8xx.h>
+#include <commproc.h>
+
+#if defined(CONFIG_SYS_RTCSC) || defined(CONFIG_SYS_RMDS)
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+#if defined(CONFIG_SYS_I2C_UCODE_PATCH) || defined(CONFIG_SYS_SPI_UCODE_PATCH) || \
+ defined(CONFIG_SYS_SMC_UCODE_PATCH)
+void cpm_load_patch (volatile immap_t * immr);
+#endif
+
+/*
+ * Breath some life into the CPU...
+ *
+ * Set up the memory map,
+ * initialize a bunch of registers,
+ * initialize the UPM's
+ */
+void cpu_init_f (volatile immap_t * immr)
+{
+#ifndef CONFIG_MBX
+ volatile memctl8xx_t *memctl = &immr->im_memctl;
+# ifdef CONFIG_SYS_PLPRCR
+ ulong mfmask;
+# endif
+#endif
+ ulong reg;
+
+ /* SYPCR - contains watchdog control (11-9) */
+
+ immr->im_siu_conf.sc_sypcr = CONFIG_SYS_SYPCR;
+
+#if defined(CONFIG_WATCHDOG)
+ reset_8xx_watchdog (immr);
+#endif /* CONFIG_WATCHDOG */
+
+ /* SIUMCR - contains debug pin configuration (11-6) */
+#ifndef CONFIG_SVM_SC8xx
+ immr->im_siu_conf.sc_siumcr |= CONFIG_SYS_SIUMCR;
+#else
+ immr->im_siu_conf.sc_siumcr = CONFIG_SYS_SIUMCR;
+#endif
+ /* initialize timebase status and control register (11-26) */
+ /* unlock TBSCRK */
+
+ immr->im_sitk.sitk_tbscrk = KAPWR_KEY;
+ immr->im_sit.sit_tbscr = CONFIG_SYS_TBSCR;
+
+ /* initialize the PIT (11-31) */
+
+ immr->im_sitk.sitk_piscrk = KAPWR_KEY;
+ immr->im_sit.sit_piscr = CONFIG_SYS_PISCR;
+
+ /* System integration timers. Don't change EBDF! (15-27) */
+
+ immr->im_clkrstk.cark_sccrk = KAPWR_KEY;
+ reg = immr->im_clkrst.car_sccr;
+ reg &= SCCR_MASK;
+ reg |= CONFIG_SYS_SCCR;
+ immr->im_clkrst.car_sccr = reg;
+
+ /* PLL (CPU clock) settings (15-30) */
+
+ immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+
+#ifndef CONFIG_MBX /* MBX board does things different */
+
+ /* If CONFIG_SYS_PLPRCR (set in the various *_config.h files) tries to
+ * set the MF field, then just copy CONFIG_SYS_PLPRCR over car_plprcr,
+ * otherwise OR in CONFIG_SYS_PLPRCR so we do not change the current MF
+ * field value.
+ *
+ * For newer (starting MPC866) chips PLPRCR layout is different.
+ */
+#ifdef CONFIG_SYS_PLPRCR
+ if (get_immr(0xFFFF) >= MPC8xx_NEW_CLK)
+ mfmask = PLPRCR_MFACT_MSK;
+ else
+ mfmask = PLPRCR_MF_MSK;
+
+ if ((CONFIG_SYS_PLPRCR & mfmask) != 0)
+ reg = CONFIG_SYS_PLPRCR; /* reset control bits */
+ else {
+ reg = immr->im_clkrst.car_plprcr;
+ reg &= mfmask; /* isolate MF-related fields */
+ reg |= CONFIG_SYS_PLPRCR; /* reset control bits */
+ }
+ immr->im_clkrst.car_plprcr = reg;
+#endif
+
+ /*
+ * Memory Controller:
+ */
+
+ /* perform BR0 reset that MPC850 Rev. A can't guarantee */
+ reg = memctl->memc_br0;
+ reg &= BR_PS_MSK; /* Clear everything except Port Size bits */
+ reg |= BR_V; /* then add just the "Bank Valid" bit */
+ memctl->memc_br0 = reg;
+
+ /* Map banks 0 (and maybe 1) to the FLASH banks 0 (and 1) at
+ * preliminary addresses - these have to be modified later
+ * when FLASH size has been determined
+ *
+ * Depending on the size of the memory region defined by
+ * CONFIG_SYS_OR0_REMAP some boards (wide address mask) allow to map the
+ * CONFIG_SYS_MONITOR_BASE, while others (narrower address mask) can't
+ * map CONFIG_SYS_MONITOR_BASE.
+ *
+ * For example, for CONFIG_IVMS8, the CONFIG_SYS_MONITOR_BASE is
+ * 0xff000000, but CONFIG_SYS_OR0_REMAP's address mask is 0xfff80000.
+ *
+ * If BR0 wasn't loaded with address base 0xff000000, then BR0's
+ * base address remains as 0x00000000. However, the address mask
+ * have been narrowed to 512Kb, so CONFIG_SYS_MONITOR_BASE wasn't mapped
+ * into the Bank0.
+ *
+ * This is why CONFIG_IVMS8 and similar boards must load BR0 with
+ * CONFIG_SYS_BR0_PRELIM in advance.
+ *
+ * [Thanks to Michael Liao for this explanation.
+ * I owe him a free beer. - wd]
+ */
+
+#if defined(CONFIG_HERMES) || \
+ defined(CONFIG_ICU862) || \
+ defined(CONFIG_IP860) || \
+ defined(CONFIG_IVML24) || \
+ defined(CONFIG_IVMS8) || \
+ defined(CONFIG_LWMON) || \
+ defined(CONFIG_MHPC) || \
+ defined(CONFIG_R360MPI) || \
+ defined(CONFIG_RMU) || \
+ defined(CONFIG_RPXCLASSIC) || \
+ defined(CONFIG_RPXLITE) || \
+ defined(CONFIG_SPC1920) || \
+ defined(CONFIG_SPD823TS)
+
+ memctl->memc_br0 = CONFIG_SYS_BR0_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR0_REMAP)
+ memctl->memc_or0 = CONFIG_SYS_OR0_REMAP;
+#endif
+#if defined(CONFIG_SYS_OR1_REMAP)
+ memctl->memc_or1 = CONFIG_SYS_OR1_REMAP;
+#endif
+#if defined(CONFIG_SYS_OR5_REMAP)
+ memctl->memc_or5 = CONFIG_SYS_OR5_REMAP;
+#endif
+
+ /* now restrict to preliminary range */
+ memctl->memc_br0 = CONFIG_SYS_BR0_PRELIM;
+ memctl->memc_or0 = CONFIG_SYS_OR0_PRELIM;
+
+#if (defined(CONFIG_SYS_OR1_PRELIM) && defined(CONFIG_SYS_BR1_PRELIM))
+ memctl->memc_or1 = CONFIG_SYS_OR1_PRELIM;
+ memctl->memc_br1 = CONFIG_SYS_BR1_PRELIM;
+#endif
+
+#if defined(CONFIG_IP860) /* disable CS0 now that Flash is mapped on CS1 */
+ memctl->memc_br0 = 0;
+#endif
+
+#if defined(CONFIG_SYS_OR2_PRELIM) && defined(CONFIG_SYS_BR2_PRELIM)
+ memctl->memc_or2 = CONFIG_SYS_OR2_PRELIM;
+ memctl->memc_br2 = CONFIG_SYS_BR2_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR3_PRELIM) && defined(CONFIG_SYS_BR3_PRELIM)
+ memctl->memc_or3 = CONFIG_SYS_OR3_PRELIM;
+ memctl->memc_br3 = CONFIG_SYS_BR3_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR4_PRELIM) && defined(CONFIG_SYS_BR4_PRELIM)
+ memctl->memc_or4 = CONFIG_SYS_OR4_PRELIM;
+ memctl->memc_br4 = CONFIG_SYS_BR4_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR5_PRELIM) && defined(CONFIG_SYS_BR5_PRELIM)
+ memctl->memc_or5 = CONFIG_SYS_OR5_PRELIM;
+ memctl->memc_br5 = CONFIG_SYS_BR5_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR6_PRELIM) && defined(CONFIG_SYS_BR6_PRELIM)
+ memctl->memc_or6 = CONFIG_SYS_OR6_PRELIM;
+ memctl->memc_br6 = CONFIG_SYS_BR6_PRELIM;
+#endif
+
+#if defined(CONFIG_SYS_OR7_PRELIM) && defined(CONFIG_SYS_BR7_PRELIM)
+ memctl->memc_or7 = CONFIG_SYS_OR7_PRELIM;
+ memctl->memc_br7 = CONFIG_SYS_BR7_PRELIM;
+#endif
+
+#endif /* ! CONFIG_MBX */
+
+ /*
+ * Reset CPM
+ */
+ immr->im_cpm.cp_cpcr = CPM_CR_RST | CPM_CR_FLG;
+ do { /* Spin until command processed */
+ __asm__ ("eieio");
+ } while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+
+#ifdef CONFIG_MBX
+ /*
+ * on the MBX, things are a little bit different:
+ * - we need to read the VPD to get board information
+ * - the plprcr is set up dynamically
+ * - the memory controller is set up dynamically
+ */
+ mbx_init ();
+#endif /* CONFIG_MBX */
+
+#ifdef CONFIG_RPXCLASSIC
+ rpxclassic_init ();
+#endif
+
+#if defined(CONFIG_RPXLITE) && defined(CONFIG_ENV_IS_IN_NVRAM)
+ rpxlite_init ();
+#endif
+
+#ifdef CONFIG_SYS_RCCR /* must be done before cpm_load_patch() */
+ /* write config value */
+ immr->im_cpm.cp_rccr = CONFIG_SYS_RCCR;
+#endif
+
+#if defined(CONFIG_SYS_I2C_UCODE_PATCH) || defined(CONFIG_SYS_SPI_UCODE_PATCH) || \
+ defined(CONFIG_SYS_SMC_UCODE_PATCH)
+ cpm_load_patch (immr); /* load mpc8xx microcode patch */
+#endif
+}
+
+/*
+ * initialize higher level parts of CPU like timers
+ */
+int cpu_init_r (void)
+{
+#if defined(CONFIG_SYS_RTCSC) || defined(CONFIG_SYS_RMDS)
+ bd_t *bd = gd->bd;
+ volatile immap_t *immr = (volatile immap_t *) (bd->bi_immr_base);
+#endif
+
+#ifdef CONFIG_SYS_RTCSC
+ /* Unlock RTSC register */
+ immr->im_sitk.sitk_rtcsck = KAPWR_KEY;
+ /* write config value */
+ immr->im_sit.sit_rtcsc = CONFIG_SYS_RTCSC;
+#endif
+
+#ifdef CONFIG_SYS_RMDS
+ /* write config value */
+ immr->im_cpm.cp_rmds = CONFIG_SYS_RMDS;
+#endif
+ return (0);
+}
diff --git a/arch/powerpc/cpu/mpc8xx/fdt.c b/arch/powerpc/cpu/mpc8xx/fdt.c
new file mode 100644
index 0000000..7edd7e4
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/fdt.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2008 (C) Bryan O'Donoghue
+ *
+ * Code copied & edited from Freescale mpc85xx stuff.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "timebase-frequency", get_tbclk(), 1);
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "bus-frequency", bd->bi_busfreq, 1);
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
+ "clock-frequency", bd->bi_intfreq, 1);
+ do_fixup_by_compat_u32(blob, "fsl,cpm-brg", "clock-frequency",
+ gd->arch.brg_clk, 1);
+
+ /* Fixup ethernet MAC addresses */
+ fdt_fixup_ethernet(blob);
+
+ fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+}
diff --git a/arch/powerpc/cpu/mpc8xx/fec.c b/arch/powerpc/cpu/mpc8xx/fec.c
new file mode 100644
index 0000000..d7c9090
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/fec.c
@@ -0,0 +1,1029 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <commproc.h>
+#include <net.h>
+#include <command.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#undef ET_DEBUG
+
+#if defined(CONFIG_CMD_NET) && \
+ (defined(FEC_ENET) || defined(CONFIG_ETHER_ON_FEC1) || defined(CONFIG_ETHER_ON_FEC2))
+
+/* compatibility test, if only FEC_ENET defined assume ETHER on FEC1 */
+#if defined(FEC_ENET) && !defined(CONFIG_ETHER_ON_FEC1) && !defined(CONFIG_ETHER_ON_FEC2)
+#define CONFIG_ETHER_ON_FEC1 1
+#endif
+
+/* define WANT_MII when MII support is required */
+#if defined(CONFIG_SYS_DISCOVER_PHY) || defined(CONFIG_FEC1_PHY) || defined(CONFIG_FEC2_PHY)
+#define WANT_MII
+#else
+#undef WANT_MII
+#endif
+
+#if defined(WANT_MII)
+#include <miiphy.h>
+
+#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
+#error "CONFIG_MII has to be defined!"
+#endif
+
+#endif
+
+#if defined(CONFIG_RMII) && !defined(WANT_MII)
+#error RMII support is unusable without a working PHY.
+#endif
+
+#ifdef CONFIG_SYS_DISCOVER_PHY
+static int mii_discover_phy(struct eth_device *dev);
+#endif
+
+int fec8xx_miiphy_read(const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value);
+int fec8xx_miiphy_write(const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value);
+
+static struct ether_fcc_info_s
+{
+ int ether_index;
+ int fecp_offset;
+ int phy_addr;
+ int actual_phy_addr;
+ int initialized;
+}
+ ether_fcc_info[] = {
+#if defined(CONFIG_ETHER_ON_FEC1)
+ {
+ 0,
+ offsetof(immap_t, im_cpm.cp_fec1),
+#if defined(CONFIG_FEC1_PHY)
+ CONFIG_FEC1_PHY,
+#else
+ -1, /* discover */
+#endif
+ -1,
+ 0,
+
+ },
+#endif
+#if defined(CONFIG_ETHER_ON_FEC2)
+ {
+ 1,
+ offsetof(immap_t, im_cpm.cp_fec2),
+#if defined(CONFIG_FEC2_PHY)
+ CONFIG_FEC2_PHY,
+#else
+ -1,
+#endif
+ -1,
+ 0,
+ },
+#endif
+};
+
+/* Ethernet Transmit and Receive Buffers */
+#define DBUF_LENGTH 1520
+
+#define TX_BUF_CNT 2
+
+#define TOUT_LOOP 100
+
+#define PKT_MAXBUF_SIZE 1518
+#define PKT_MINBUF_SIZE 64
+#define PKT_MAXBLR_SIZE 1520
+
+#ifdef __GNUC__
+static char txbuf[DBUF_LENGTH] __attribute__ ((aligned(8)));
+#else
+#error txbuf must be aligned.
+#endif
+
+static uint rxIdx; /* index of the current RX buffer */
+static uint txIdx; /* index of the current TX buffer */
+
+/*
+ * FEC Ethernet Tx and Rx buffer descriptors allocated at the
+ * immr->udata_bd address on Dual-Port RAM
+ * Provide for Double Buffering
+ */
+
+typedef volatile struct CommonBufferDescriptor {
+ cbd_t rxbd[PKTBUFSRX]; /* Rx BD */
+ cbd_t txbd[TX_BUF_CNT]; /* Tx BD */
+} RTXBD;
+
+static RTXBD *rtx = NULL;
+
+static int fec_send(struct eth_device *dev, void *packet, int length);
+static int fec_recv(struct eth_device* dev);
+static int fec_init(struct eth_device* dev, bd_t * bd);
+static void fec_halt(struct eth_device* dev);
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+static void __mii_init(void);
+#endif
+
+int fec_initialize(bd_t *bis)
+{
+ struct eth_device* dev;
+ struct ether_fcc_info_s *efis;
+ int i;
+
+ for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++) {
+
+ dev = malloc(sizeof(*dev));
+ if (dev == NULL)
+ hang();
+
+ memset(dev, 0, sizeof(*dev));
+
+ /* for FEC1 make sure that the name of the interface is the same
+ as the old one for compatibility reasons */
+ if (i == 0) {
+ sprintf (dev->name, "FEC");
+ } else {
+ sprintf (dev->name, "FEC%d",
+ ether_fcc_info[i].ether_index + 1);
+ }
+
+ efis = &ether_fcc_info[i];
+
+ /*
+ * reset actual phy addr
+ */
+ efis->actual_phy_addr = -1;
+
+ dev->priv = efis;
+ dev->init = fec_init;
+ dev->halt = fec_halt;
+ dev->send = fec_send;
+ dev->recv = fec_recv;
+
+ eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_register(dev->name,
+ fec8xx_miiphy_read, fec8xx_miiphy_write);
+#endif
+ }
+ return 1;
+}
+
+static int fec_send(struct eth_device *dev, void *packet, int length)
+{
+ int j, rc;
+ struct ether_fcc_info_s *efis = dev->priv;
+ volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset);
+
+ /* section 16.9.23.3
+ * Wait for ready
+ */
+ j = 0;
+ while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
+ udelay(1);
+ j++;
+ }
+ if (j>=TOUT_LOOP) {
+ printf("TX not ready\n");
+ }
+
+ rtx->txbd[txIdx].cbd_bufaddr = (uint)packet;
+ rtx->txbd[txIdx].cbd_datlen = length;
+ rtx->txbd[txIdx].cbd_sc |= BD_ENET_TX_READY | BD_ENET_TX_LAST;
+ __asm__ ("eieio");
+
+ /* Activate transmit Buffer Descriptor polling */
+ fecp->fec_x_des_active = 0x01000000; /* Descriptor polling active */
+
+ j = 0;
+ while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
+#if defined(CONFIG_ICU862)
+ udelay(10);
+#else
+ udelay(1);
+#endif
+ j++;
+ }
+ if (j>=TOUT_LOOP) {
+ printf("TX timeout\n");
+ }
+#ifdef ET_DEBUG
+ printf("%s[%d] %s: cycles: %d status: %x retry cnt: %d\n",
+ __FILE__,__LINE__,__FUNCTION__,j,rtx->txbd[txIdx].cbd_sc,
+ (rtx->txbd[txIdx].cbd_sc & 0x003C)>>2);
+#endif
+ /* return only status bits */;
+ rc = (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_STATS);
+
+ txIdx = (txIdx + 1) % TX_BUF_CNT;
+
+ return rc;
+}
+
+static int fec_recv (struct eth_device *dev)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ volatile fec_t *fecp =
+ (volatile fec_t *) (CONFIG_SYS_IMMR + efis->fecp_offset);
+ int length;
+
+ for (;;) {
+ /* section 16.9.23.2 */
+ if (rtx->rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
+ length = -1;
+ break; /* nothing received - leave for() loop */
+ }
+
+ length = rtx->rxbd[rxIdx].cbd_datlen;
+
+ if (rtx->rxbd[rxIdx].cbd_sc & 0x003f) {
+#ifdef ET_DEBUG
+ printf ("%s[%d] err: %x\n",
+ __FUNCTION__, __LINE__,
+ rtx->rxbd[rxIdx].cbd_sc);
+#endif
+ } else {
+ uchar *rx = NetRxPackets[rxIdx];
+
+ length -= 4;
+
+#if defined(CONFIG_CMD_CDP)
+ if ((rx[0] & 1) != 0
+ && memcmp ((uchar *) rx, NetBcastAddr, 6) != 0
+ && !is_cdp_packet((uchar *)rx))
+ rx = NULL;
+#endif
+ /*
+ * Pass the packet up to the protocol layers.
+ */
+ if (rx != NULL)
+ NetReceive (rx, length);
+ }
+
+ /* Give the buffer back to the FEC. */
+ rtx->rxbd[rxIdx].cbd_datlen = 0;
+
+ /* wrap around buffer index when necessary */
+ if ((rxIdx + 1) >= PKTBUFSRX) {
+ rtx->rxbd[PKTBUFSRX - 1].cbd_sc =
+ (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
+ rxIdx = 0;
+ } else {
+ rtx->rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
+ rxIdx++;
+ }
+
+ __asm__ ("eieio");
+
+ /* Try to fill Buffer Descriptors */
+ fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */
+ }
+
+ return length;
+}
+
+/**************************************************************
+ *
+ * FEC Ethernet Initialization Routine
+ *
+ *************************************************************/
+
+#define FEC_ECNTRL_PINMUX 0x00000004
+#define FEC_ECNTRL_ETHER_EN 0x00000002
+#define FEC_ECNTRL_RESET 0x00000001
+
+#define FEC_RCNTRL_BC_REJ 0x00000010
+#define FEC_RCNTRL_PROM 0x00000008
+#define FEC_RCNTRL_MII_MODE 0x00000004
+#define FEC_RCNTRL_DRT 0x00000002
+#define FEC_RCNTRL_LOOP 0x00000001
+
+#define FEC_TCNTRL_FDEN 0x00000004
+#define FEC_TCNTRL_HBC 0x00000002
+#define FEC_TCNTRL_GTS 0x00000001
+
+#define FEC_RESET_DELAY 50
+
+#if defined(CONFIG_RMII)
+
+static inline void fec_10Mbps(struct eth_device *dev)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ int fecidx = efis->ether_index;
+ uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008;
+
+ if ((unsigned int)fecidx >= 2)
+ hang();
+
+ ((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_cptr |= mask;
+}
+
+static inline void fec_100Mbps(struct eth_device *dev)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ int fecidx = efis->ether_index;
+ uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008;
+
+ if ((unsigned int)fecidx >= 2)
+ hang();
+
+ ((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_cptr &= ~mask;
+}
+
+#endif
+
+static inline void fec_full_duplex(struct eth_device *dev)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset);
+
+ fecp->fec_r_cntrl &= ~FEC_RCNTRL_DRT;
+ fecp->fec_x_cntrl |= FEC_TCNTRL_FDEN; /* FD enable */
+}
+
+static inline void fec_half_duplex(struct eth_device *dev)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset);
+
+ fecp->fec_r_cntrl |= FEC_RCNTRL_DRT;
+ fecp->fec_x_cntrl &= ~FEC_TCNTRL_FDEN; /* FD disable */
+}
+
+static void fec_pin_init(int fecidx)
+{
+ bd_t *bd = gd->bd;
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ /*
+ * Set MII speed to 2.5 MHz or slightly below.
+ *
+ * According to the MPC860T (Rev. D) Fast ethernet controller user
+ * manual (6.2.14),
+ * the MII management interface clock must be less than or equal
+ * to 2.5 MHz.
+ * This MDC frequency is equal to system clock / (2 * MII_SPEED).
+ * Then MII_SPEED = system_clock / 2 * 2,5 MHz.
+ *
+ * All MII configuration is done via FEC1 registers:
+ */
+ immr->im_cpm.cp_fec1.fec_mii_speed = ((bd->bi_intfreq + 4999999) / 5000000) << 1;
+
+#if defined(CONFIG_NETTA) || defined(CONFIG_NETPHONE) || defined(CONFIG_NETTA2)
+ {
+ volatile fec_t *fecp;
+
+ /*
+ * only two FECs please
+ */
+ if ((unsigned int)fecidx >= 2)
+ hang();
+
+ if (fecidx == 0)
+ fecp = &immr->im_cpm.cp_fec1;
+ else
+ fecp = &immr->im_cpm.cp_fec2;
+
+ /* our PHYs are the limit at 2.5 MHz */
+ fecp->fec_mii_speed <<= 1;
+ }
+#endif
+
+#if defined(CONFIG_MPC885_FAMILY) && defined(WANT_MII)
+ /* use MDC for MII */
+ immr->im_ioport.iop_pdpar |= 0x0080;
+ immr->im_ioport.iop_pddir &= ~0x0080;
+#endif
+
+ if (fecidx == 0) {
+#if defined(CONFIG_ETHER_ON_FEC1)
+
+#if defined(CONFIG_MPC885_FAMILY) /* MPC87x/88x have got 2 FECs and different pinout */
+
+#if !defined(CONFIG_RMII)
+
+ immr->im_ioport.iop_papar |= 0xf830;
+ immr->im_ioport.iop_padir |= 0x0830;
+ immr->im_ioport.iop_padir &= ~0xf000;
+
+ immr->im_cpm.cp_pbpar |= 0x00001001;
+ immr->im_cpm.cp_pbdir &= ~0x00001001;
+
+ immr->im_ioport.iop_pcpar |= 0x000c;
+ immr->im_ioport.iop_pcdir &= ~0x000c;
+
+ immr->im_cpm.cp_pepar |= 0x00000003;
+ immr->im_cpm.cp_pedir |= 0x00000003;
+ immr->im_cpm.cp_peso &= ~0x00000003;
+
+ immr->im_cpm.cp_cptr &= ~0x00000100;
+
+#else
+
+#if !defined(CONFIG_FEC1_PHY_NORXERR)
+ immr->im_ioport.iop_papar |= 0x1000;
+ immr->im_ioport.iop_padir &= ~0x1000;
+#endif
+ immr->im_ioport.iop_papar |= 0xe810;
+ immr->im_ioport.iop_padir |= 0x0810;
+ immr->im_ioport.iop_padir &= ~0xe000;
+
+ immr->im_cpm.cp_pbpar |= 0x00000001;
+ immr->im_cpm.cp_pbdir &= ~0x00000001;
+
+ immr->im_cpm.cp_cptr |= 0x00000100;
+ immr->im_cpm.cp_cptr &= ~0x00000050;
+
+#endif /* !CONFIG_RMII */
+
+#elif !defined(CONFIG_ICU862)
+ /*
+ * Configure all of port D for MII.
+ */
+ immr->im_ioport.iop_pdpar = 0x1fff;
+
+ /*
+ * Bits moved from Rev. D onward
+ */
+ if ((get_immr(0) & 0xffff) < 0x0501)
+ immr->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */
+ else
+ immr->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */
+#else
+ /*
+ * Configure port A for MII.
+ */
+
+#if defined(CONFIG_ICU862) && defined(CONFIG_SYS_DISCOVER_PHY)
+
+ /*
+ * On the ICU862 board the MII-MDC pin is routed to PD8 pin
+ * * of CPU, so for this board we need to configure Utopia and
+ * * enable PD8 to MII-MDC function
+ */
+ immr->im_ioport.iop_pdpar |= 0x4080;
+#endif
+
+ /*
+ * Has Utopia been configured?
+ */
+ if (immr->im_ioport.iop_pdpar & (0x8000 >> 1)) {
+ /*
+ * YES - Use MUXED mode for UTOPIA bus.
+ * This frees Port A for use by MII (see 862UM table 41-6).
+ */
+ immr->im_ioport.utmode &= ~0x80;
+ } else {
+ /*
+ * NO - set SPLIT mode for UTOPIA bus.
+ *
+ * This doesn't really effect UTOPIA (which isn't
+ * enabled anyway) but just tells the 862
+ * to use port A for MII (see 862UM table 41-6).
+ */
+ immr->im_ioport.utmode |= 0x80;
+ }
+#endif /* !defined(CONFIG_ICU862) */
+
+#endif /* CONFIG_ETHER_ON_FEC1 */
+ } else if (fecidx == 1) {
+
+#if defined(CONFIG_ETHER_ON_FEC2)
+
+#if defined(CONFIG_MPC885_FAMILY) /* MPC87x/88x have got 2 FECs and different pinout */
+
+#if !defined(CONFIG_RMII)
+ immr->im_cpm.cp_pepar |= 0x0003fffc;
+ immr->im_cpm.cp_pedir |= 0x0003fffc;
+ immr->im_cpm.cp_peso &= ~0x000087fc;
+ immr->im_cpm.cp_peso |= 0x00037800;
+
+ immr->im_cpm.cp_cptr &= ~0x00000080;
+#else
+
+#if !defined(CONFIG_FEC2_PHY_NORXERR)
+ immr->im_cpm.cp_pepar |= 0x00000010;
+ immr->im_cpm.cp_pedir |= 0x00000010;
+ immr->im_cpm.cp_peso &= ~0x00000010;
+#endif
+ immr->im_cpm.cp_pepar |= 0x00039620;
+ immr->im_cpm.cp_pedir |= 0x00039620;
+ immr->im_cpm.cp_peso |= 0x00031000;
+ immr->im_cpm.cp_peso &= ~0x00008620;
+
+ immr->im_cpm.cp_cptr |= 0x00000080;
+ immr->im_cpm.cp_cptr &= ~0x00000028;
+#endif /* CONFIG_RMII */
+
+#endif /* CONFIG_MPC885_FAMILY */
+
+#endif /* CONFIG_ETHER_ON_FEC2 */
+
+ }
+}
+
+static int fec_reset(volatile fec_t *fecp)
+{
+ int i;
+
+ /* Whack a reset.
+ * A delay is required between a reset of the FEC block and
+ * initialization of other FEC registers because the reset takes
+ * some time to complete. If you don't delay, subsequent writes
+ * to FEC registers might get killed by the reset routine which is
+ * still in progress.
+ */
+
+ fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET;
+ for (i = 0;
+ (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
+ ++i) {
+ udelay (1);
+ }
+ if (i == FEC_RESET_DELAY)
+ return -1;
+
+ return 0;
+}
+
+static int fec_init (struct eth_device *dev, bd_t * bd)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ volatile fec_t *fecp =
+ (volatile fec_t *) (CONFIG_SYS_IMMR + efis->fecp_offset);
+ int i;
+
+ if (efis->ether_index == 0) {
+#if defined(CONFIG_FADS) /* FADS family uses FPGA (BCSR) to control PHYs */
+#if defined(CONFIG_MPC885ADS)
+ *(vu_char *) BCSR5 &= ~(BCSR5_MII1_EN | BCSR5_MII1_RST);
+#else
+ /* configure FADS for fast (FEC) ethernet, half-duplex */
+ /* The LXT970 needs about 50ms to recover from reset, so
+ * wait for it by discovering the PHY before leaving eth_init().
+ */
+ {
+ volatile uint *bcsr4 = (volatile uint *) BCSR4;
+
+ *bcsr4 = (*bcsr4 & ~(BCSR4_FETH_EN | BCSR4_FETHCFG1))
+ | (BCSR4_FETHCFG0 | BCSR4_FETHFDE |
+ BCSR4_FETHRST);
+
+ /* reset the LXT970 PHY */
+ *bcsr4 &= ~BCSR4_FETHRST;
+ udelay (10);
+ *bcsr4 |= BCSR4_FETHRST;
+ udelay (10);
+ }
+#endif /* CONFIG_MPC885ADS */
+#endif /* CONFIG_FADS */
+ }
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ /* the MII interface is connected to FEC1
+ * so for the miiphy_xxx function to work we must
+ * call mii_init since fec_halt messes the thing up
+ */
+ if (efis->ether_index != 0)
+ __mii_init();
+#endif
+
+ if (fec_reset(fecp) < 0)
+ printf ("FEC_RESET_DELAY timeout\n");
+
+ /* We use strictly polling mode only
+ */
+ fecp->fec_imask = 0;
+
+ /* Clear any pending interrupt
+ */
+ fecp->fec_ievent = 0xffc0;
+
+ /* No need to set the IVEC register */
+
+ /* Set station address
+ */
+#define ea dev->enetaddr
+ fecp->fec_addr_low = (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
+ fecp->fec_addr_high = (ea[4] << 8) | (ea[5]);
+#undef ea
+
+#if defined(CONFIG_CMD_CDP)
+ /*
+ * Turn on multicast address hash table
+ */
+ fecp->fec_hash_table_high = 0xffffffff;
+ fecp->fec_hash_table_low = 0xffffffff;
+#else
+ /* Clear multicast address hash table
+ */
+ fecp->fec_hash_table_high = 0;
+ fecp->fec_hash_table_low = 0;
+#endif
+
+ /* Set maximum receive buffer size.
+ */
+ fecp->fec_r_buff_size = PKT_MAXBLR_SIZE;
+
+ /* Set maximum frame length
+ */
+ fecp->fec_r_hash = PKT_MAXBUF_SIZE;
+
+ /*
+ * Setup Buffers and Buffer Desriptors
+ */
+ rxIdx = 0;
+ txIdx = 0;
+
+ if (!rtx) {
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+ rtx = (RTXBD *) (immr->im_cpm.cp_dpmem +
+ dpram_alloc_align (sizeof (RTXBD), 8));
+#else
+ rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + CPM_FEC_BASE);
+#endif
+ }
+ /*
+ * Setup Receiver Buffer Descriptors (13.14.24.18)
+ * Settings:
+ * Empty, Wrap
+ */
+ for (i = 0; i < PKTBUFSRX; i++) {
+ rtx->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
+ rtx->rxbd[i].cbd_datlen = 0; /* Reset */
+ rtx->rxbd[i].cbd_bufaddr = (uint) NetRxPackets[i];
+ }
+ rtx->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+ /*
+ * Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19)
+ * Settings:
+ * Last, Tx CRC
+ */
+ for (i = 0; i < TX_BUF_CNT; i++) {
+ rtx->txbd[i].cbd_sc = BD_ENET_TX_LAST | BD_ENET_TX_TC;
+ rtx->txbd[i].cbd_datlen = 0; /* Reset */
+ rtx->txbd[i].cbd_bufaddr = (uint) (&txbuf[0]);
+ }
+ rtx->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+ /* Set receive and transmit descriptor base
+ */
+ fecp->fec_r_des_start = (unsigned int) (&rtx->rxbd[0]);
+ fecp->fec_x_des_start = (unsigned int) (&rtx->txbd[0]);
+
+ /* Enable MII mode
+ */
+#if 0 /* Full duplex mode */
+ fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE;
+ fecp->fec_x_cntrl = FEC_TCNTRL_FDEN;
+#else /* Half duplex mode */
+ fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE | FEC_RCNTRL_DRT;
+ fecp->fec_x_cntrl = 0;
+#endif
+
+ /* Enable big endian and don't care about SDMA FC.
+ */
+ fecp->fec_fun_code = 0x78000000;
+
+ /*
+ * Setup the pin configuration of the FEC
+ */
+ fec_pin_init (efis->ether_index);
+
+ rxIdx = 0;
+ txIdx = 0;
+
+ /*
+ * Now enable the transmit and receive processing
+ */
+ fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
+
+ if (efis->phy_addr == -1) {
+#ifdef CONFIG_SYS_DISCOVER_PHY
+ /*
+ * wait for the PHY to wake up after reset
+ */
+ efis->actual_phy_addr = mii_discover_phy (dev);
+
+ if (efis->actual_phy_addr == -1) {
+ printf ("Unable to discover phy!\n");
+ return -1;
+ }
+#else
+ efis->actual_phy_addr = -1;
+#endif
+ } else {
+ efis->actual_phy_addr = efis->phy_addr;
+ }
+
+#if defined(CONFIG_MII) && defined(CONFIG_RMII)
+ /*
+ * adapt the RMII speed to the speed of the phy
+ */
+ if (miiphy_speed (dev->name, efis->actual_phy_addr) == _100BASET) {
+ fec_100Mbps (dev);
+ } else {
+ fec_10Mbps (dev);
+ }
+#endif
+
+#if defined(CONFIG_MII)
+ /*
+ * adapt to the half/full speed settings
+ */
+ if (miiphy_duplex (dev->name, efis->actual_phy_addr) == FULL) {
+ fec_full_duplex (dev);
+ } else {
+ fec_half_duplex (dev);
+ }
+#endif
+
+ /* And last, try to fill Rx Buffer Descriptors */
+ fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */
+
+ efis->initialized = 1;
+
+ return 0;
+}
+
+
+static void fec_halt(struct eth_device* dev)
+{
+ struct ether_fcc_info_s *efis = dev->priv;
+ volatile fec_t *fecp = (volatile fec_t *)(CONFIG_SYS_IMMR + efis->fecp_offset);
+ int i;
+
+ /* avoid halt if initialized; mii gets stuck otherwise */
+ if (!efis->initialized)
+ return;
+
+ /* Whack a reset.
+ * A delay is required between a reset of the FEC block and
+ * initialization of other FEC registers because the reset takes
+ * some time to complete. If you don't delay, subsequent writes
+ * to FEC registers might get killed by the reset routine which is
+ * still in progress.
+ */
+
+ fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET;
+ for (i = 0;
+ (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
+ ++i) {
+ udelay (1);
+ }
+ if (i == FEC_RESET_DELAY) {
+ printf ("FEC_RESET_DELAY timeout\n");
+ return;
+ }
+
+ efis->initialized = 0;
+}
+
+#if defined(CONFIG_SYS_DISCOVER_PHY) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+
+/* Make MII read/write commands for the FEC.
+*/
+
+#define mk_mii_read(ADDR, REG) (0x60020000 | ((ADDR << 23) | \
+ (REG & 0x1f) << 18))
+
+#define mk_mii_write(ADDR, REG, VAL) (0x50020000 | ((ADDR << 23) | \
+ (REG & 0x1f) << 18) | \
+ (VAL & 0xffff))
+
+/* Interrupt events/masks.
+*/
+#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */
+#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */
+#define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */
+#define FEC_ENET_GRA ((uint)0x10000000) /* Graceful stop complete */
+#define FEC_ENET_TXF ((uint)0x08000000) /* Full frame transmitted */
+#define FEC_ENET_TXB ((uint)0x04000000) /* A buffer was transmitted */
+#define FEC_ENET_RXF ((uint)0x02000000) /* Full frame received */
+#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */
+#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */
+#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */
+
+/* PHY identification
+ */
+#define PHY_ID_LXT970 0x78100000 /* LXT970 */
+#define PHY_ID_LXT971 0x001378e0 /* LXT971 and 972 */
+#define PHY_ID_82555 0x02a80150 /* Intel 82555 */
+#define PHY_ID_QS6612 0x01814400 /* QS6612 */
+#define PHY_ID_AMD79C784 0x00225610 /* AMD 79C784 */
+#define PHY_ID_LSI80225 0x0016f870 /* LSI 80225 */
+#define PHY_ID_LSI80225B 0x0016f880 /* LSI 80225/B */
+#define PHY_ID_DM9161 0x0181B880 /* Davicom DM9161 */
+#define PHY_ID_KSM8995M 0x00221450 /* MICREL KS8995MA */
+
+/* send command to phy using mii, wait for result */
+static uint
+mii_send(uint mii_cmd)
+{
+ uint mii_reply;
+ volatile fec_t *ep;
+ int cnt;
+
+ ep = &(((immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_fec);
+
+ ep->fec_mii_data = mii_cmd; /* command to phy */
+
+ /* wait for mii complete */
+ cnt = 0;
+ while (!(ep->fec_ievent & FEC_ENET_MII)) {
+ if (++cnt > 1000) {
+ printf("mii_send STUCK!\n");
+ break;
+ }
+ }
+ mii_reply = ep->fec_mii_data; /* result from phy */
+ ep->fec_ievent = FEC_ENET_MII; /* clear MII complete */
+#if 0
+ printf("%s[%d] %s: sent=0x%8.8x, reply=0x%8.8x\n",
+ __FILE__,__LINE__,__FUNCTION__,mii_cmd,mii_reply);
+#endif
+ return (mii_reply & 0xffff); /* data read from phy */
+}
+#endif
+
+#if defined(CONFIG_SYS_DISCOVER_PHY)
+static int mii_discover_phy(struct eth_device *dev)
+{
+#define MAX_PHY_PASSES 11
+ uint phyno;
+ int pass;
+ uint phytype;
+ int phyaddr;
+
+ phyaddr = -1; /* didn't find a PHY yet */
+ for (pass = 1; pass <= MAX_PHY_PASSES && phyaddr < 0; ++pass) {
+ if (pass > 1) {
+ /* PHY may need more time to recover from reset.
+ * The LXT970 needs 50ms typical, no maximum is
+ * specified, so wait 10ms before try again.
+ * With 11 passes this gives it 100ms to wake up.
+ */
+ udelay(10000); /* wait 10ms */
+ }
+ for (phyno = 0; phyno < 32 && phyaddr < 0; ++phyno) {
+ phytype = mii_send(mk_mii_read(phyno, MII_PHYSID2));
+#ifdef ET_DEBUG
+ printf("PHY type 0x%x pass %d type ", phytype, pass);
+#endif
+ if (phytype != 0xffff) {
+ phyaddr = phyno;
+ phytype |= mii_send(mk_mii_read(phyno,
+ MII_PHYSID1)) << 16;
+
+#ifdef ET_DEBUG
+ printf("PHY @ 0x%x pass %d type ",phyno,pass);
+ switch (phytype & 0xfffffff0) {
+ case PHY_ID_LXT970:
+ printf("LXT970\n");
+ break;
+ case PHY_ID_LXT971:
+ printf("LXT971\n");
+ break;
+ case PHY_ID_82555:
+ printf("82555\n");
+ break;
+ case PHY_ID_QS6612:
+ printf("QS6612\n");
+ break;
+ case PHY_ID_AMD79C784:
+ printf("AMD79C784\n");
+ break;
+ case PHY_ID_LSI80225B:
+ printf("LSI L80225/B\n");
+ break;
+ case PHY_ID_DM9161:
+ printf("Davicom DM9161\n");
+ break;
+ case PHY_ID_KSM8995M:
+ printf("MICREL KS8995M\n");
+ break;
+ default:
+ printf("0x%08x\n", phytype);
+ break;
+ }
+#endif
+ }
+ }
+ }
+ if (phyaddr < 0) {
+ printf("No PHY device found.\n");
+ }
+ return phyaddr;
+}
+#endif /* CONFIG_SYS_DISCOVER_PHY */
+
+#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && !defined(CONFIG_BITBANGMII)
+
+/****************************************************************************
+ * mii_init -- Initialize the MII via FEC 1 for MII command without ethernet
+ * This function is a subset of eth_init
+ ****************************************************************************
+ */
+static void __mii_init(void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ volatile fec_t *fecp = &(immr->im_cpm.cp_fec);
+
+ if (fec_reset(fecp) < 0)
+ printf ("FEC_RESET_DELAY timeout\n");
+
+ /* We use strictly polling mode only
+ */
+ fecp->fec_imask = 0;
+
+ /* Clear any pending interrupt
+ */
+ fecp->fec_ievent = 0xffc0;
+
+ /* Now enable the transmit and receive processing
+ */
+ fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
+}
+
+void mii_init (void)
+{
+ int i;
+
+ __mii_init();
+
+ /* Setup the pin configuration of the FEC(s)
+ */
+ for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++)
+ fec_pin_init(ether_fcc_info[i].ether_index);
+}
+
+/*****************************************************************************
+ * Read and write a MII PHY register, routines used by MII Utilities
+ *
+ * FIXME: These routines are expected to return 0 on success, but mii_send
+ * does _not_ return an error code. Maybe 0xFFFF means error, i.e.
+ * no PHY connected...
+ * For now always return 0.
+ * FIXME: These routines only work after calling eth_init() at least once!
+ * Otherwise they hang in mii_send() !!! Sorry!
+ *****************************************************************************/
+
+int fec8xx_miiphy_read(const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value)
+{
+ short rdreg; /* register working value */
+
+#ifdef MII_DEBUG
+ printf ("miiphy_read(0x%x) @ 0x%x = ", reg, addr);
+#endif
+ rdreg = mii_send(mk_mii_read(addr, reg));
+
+ *value = rdreg;
+#ifdef MII_DEBUG
+ printf ("0x%04x\n", *value);
+#endif
+ return 0;
+}
+
+int fec8xx_miiphy_write(const char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value)
+{
+#ifdef MII_DEBUG
+ printf ("miiphy_write(0x%x) @ 0x%x = ", reg, addr);
+#endif
+ (void)mii_send(mk_mii_write(addr, reg, value));
+
+#ifdef MII_DEBUG
+ printf ("0x%04x\n", value);
+#endif
+ return 0;
+}
+#endif
+
+#endif
diff --git a/arch/powerpc/cpu/mpc8xx/fec.h b/arch/powerpc/cpu/mpc8xx/fec.h
new file mode 100644
index 0000000..a49417c
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/fec.h
@@ -0,0 +1,28 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _FEC_H_
+#define _FEC_H_
+
+
+#endif /* _FEC_H_ */
diff --git a/arch/powerpc/cpu/mpc8xx/i2c.c b/arch/powerpc/cpu/mpc8xx/i2c.c
new file mode 100644
index 0000000..3e5ea3a
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/i2c.c
@@ -0,0 +1,704 @@
+/*
+ * (C) Copyright 2000
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ *
+ * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Back ported to the 8xx platform (from the 8260 platform) by
+ * Murray.Jensen@cmst.csiro.au, 27-Jan-01.
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_HARD_I2C
+
+#include <commproc.h>
+#include <i2c.h>
+#ifdef CONFIG_LWMON
+#include <watchdog.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* tx/rx timeout (we need the i2c early, so we don't use get_timer()) */
+#define TOUT_LOOP 1000000
+
+#define NUM_RX_BDS 4
+#define NUM_TX_BDS 4
+#define MAX_TX_SPACE 256
+#define I2C_RXTX_LEN 128 /* maximum tx/rx buffer length */
+
+typedef struct I2C_BD {
+ unsigned short status;
+ unsigned short length;
+ unsigned char *addr;
+} I2C_BD;
+
+#define BD_I2C_TX_START 0x0400 /* special status for i2c: Start condition */
+
+#define BD_I2C_TX_CL 0x0001 /* collision error */
+#define BD_I2C_TX_UN 0x0002 /* underflow error */
+#define BD_I2C_TX_NAK 0x0004 /* no acknowledge error */
+#define BD_I2C_TX_ERR (BD_I2C_TX_NAK|BD_I2C_TX_UN|BD_I2C_TX_CL)
+
+#define BD_I2C_RX_ERR BD_SC_OV
+
+typedef void (*i2c_ecb_t) (int, int); /* error callback function */
+
+/* This structure keeps track of the bd and buffer space usage. */
+typedef struct i2c_state {
+ int rx_idx; /* index to next free Rx BD */
+ int tx_idx; /* index to next free Tx BD */
+ void *rxbd; /* pointer to next free Rx BD */
+ void *txbd; /* pointer to next free Tx BD */
+ int tx_space; /* number of Tx bytes left */
+ unsigned char *tx_buf; /* pointer to free Tx area */
+ i2c_ecb_t err_cb; /* error callback function */
+} i2c_state_t;
+
+
+/* flags for i2c_send() and i2c_receive() */
+#define I2CF_ENABLE_SECONDARY 0x01 /* secondary_address is valid */
+#define I2CF_START_COND 0x02 /* tx: generate start condition */
+#define I2CF_STOP_COND 0x04 /* tx: generate stop condition */
+
+/* return codes */
+#define I2CERR_NO_BUFFERS 0x01 /* no more BDs or buffer space */
+#define I2CERR_MSG_TOO_LONG 0x02 /* tried to send/receive to much data */
+#define I2CERR_TIMEOUT 0x03 /* timeout in i2c_doio() */
+#define I2CERR_QUEUE_EMPTY 0x04 /* i2c_doio called without send/receive */
+
+/* error callback flags */
+#define I2CECB_RX_ERR 0x10 /* this is a receive error */
+#define I2CECB_RX_ERR_OV 0x02 /* receive overrun error */
+#define I2CECB_RX_MASK 0x0f /* mask for error bits */
+#define I2CECB_TX_ERR 0x20 /* this is a transmit error */
+#define I2CECB_TX_CL 0x01 /* transmit collision error */
+#define I2CECB_TX_UN 0x02 /* transmit underflow error */
+#define I2CECB_TX_NAK 0x04 /* transmit no ack error */
+#define I2CECB_TX_MASK 0x0f /* mask for error bits */
+#define I2CECB_TIMEOUT 0x40 /* this is a timeout error */
+
+/*
+ * Returns the best value of I2BRG to meet desired clock speed of I2C with
+ * input parameters (clock speed, filter, and predivider value).
+ * It returns computer speed value and the difference between it and desired
+ * speed.
+ */
+static inline int
+i2c_roundrate(int hz, int speed, int filter, int modval,
+ int *brgval, int *totspeed)
+{
+ int moddiv = 1 << (5 - (modval & 3)), brgdiv, div;
+
+ debug("\t[I2C] trying hz=%d, speed=%d, filter=%d, modval=%d\n",
+ hz, speed, filter, modval);
+
+ div = moddiv * speed;
+ brgdiv = (hz + div - 1) / div;
+
+ debug("\t\tmoddiv=%d, brgdiv=%d\n", moddiv, brgdiv);
+
+ *brgval = ((brgdiv + 1) / 2) - 3 - (2 * filter);
+
+ if ((*brgval < 0) || (*brgval > 255)) {
+ debug("\t\trejected brgval=%d\n", *brgval);
+ return -1;
+ }
+
+ brgdiv = 2 * (*brgval + 3 + (2 * filter));
+ div = moddiv * brgdiv;
+ *totspeed = hz / div;
+
+ debug("\t\taccepted brgval=%d, totspeed=%d\n", *brgval, *totspeed);
+
+ return 0;
+}
+
+/*
+ * Sets the I2C clock predivider and divider to meet required clock speed.
+ */
+static int i2c_setrate(int hz, int speed)
+{
+ immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile i2c8xx_t *i2c = (i2c8xx_t *) & immap->im_i2c;
+ int brgval,
+ modval, /* 0-3 */
+ bestspeed_diff = speed,
+ bestspeed_brgval = 0,
+ bestspeed_modval = 0,
+ bestspeed_filter = 0,
+ totspeed,
+ filter = 0; /* Use this fixed value */
+
+ for (modval = 0; modval < 4; modval++) {
+ if (i2c_roundrate
+ (hz, speed, filter, modval, &brgval, &totspeed) == 0) {
+ int diff = speed - totspeed;
+
+ if ((diff >= 0) && (diff < bestspeed_diff)) {
+ bestspeed_diff = diff;
+ bestspeed_modval = modval;
+ bestspeed_brgval = brgval;
+ bestspeed_filter = filter;
+ }
+ }
+ }
+
+ debug("[I2C] Best is:\n");
+ debug("[I2C] CPU=%dhz RATE=%d F=%d I2MOD=%08x I2BRG=%08x DIFF=%dhz\n",
+ hz,
+ speed,
+ bestspeed_filter,
+ bestspeed_modval,
+ bestspeed_brgval,
+ bestspeed_diff);
+
+ i2c->i2c_i2mod |=
+ ((bestspeed_modval & 3) << 1) | (bestspeed_filter << 3);
+ i2c->i2c_i2brg = bestspeed_brgval & 0xff;
+
+ debug("[I2C] i2mod=%08x i2brg=%08x\n",
+ i2c->i2c_i2mod,
+ i2c->i2c_i2brg);
+
+ return 1;
+}
+
+void i2c_init(int speed, int slaveaddr)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cp = (cpm8xx_t *)&immap->im_cpm;
+ volatile i2c8xx_t *i2c = (i2c8xx_t *)&immap->im_i2c;
+ volatile iic_t *iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+ ulong rbase, tbase;
+ volatile I2C_BD *rxbd, *txbd;
+ uint dpaddr;
+
+#ifdef CONFIG_SYS_I2C_INIT_BOARD
+ /* call board specific i2c bus reset routine before accessing the */
+ /* environment, which might be in a chip on that bus. For details */
+ /* about this problem see doc/I2C_Edge_Conditions. */
+ i2c_init_board();
+#endif
+
+#ifdef CONFIG_SYS_I2C_UCODE_PATCH
+ iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase];
+#else
+ /* Disable relocation */
+ iip->iic_rpbase = 0;
+#endif
+
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+ dpaddr = iip->iic_rbase;
+ if (dpaddr == 0) {
+ /* need to allocate dual port ram */
+ dpaddr = dpram_alloc_align((NUM_RX_BDS * sizeof(I2C_BD)) +
+ (NUM_TX_BDS * sizeof(I2C_BD)) +
+ MAX_TX_SPACE, 8);
+ }
+#else
+ dpaddr = CPM_I2C_BASE;
+#endif
+
+ /*
+ * initialise data in dual port ram:
+ *
+ * dpaddr->rbase -> rx BD (NUM_RX_BDS * sizeof(I2C_BD) bytes)
+ * tbase -> tx BD (NUM_TX_BDS * sizeof(I2C_BD) bytes)
+ * tx buffer (MAX_TX_SPACE bytes)
+ */
+
+ rbase = dpaddr;
+ tbase = rbase + NUM_RX_BDS * sizeof(I2C_BD);
+
+ /* Initialize Port B I2C pins. */
+ cp->cp_pbpar |= 0x00000030;
+ cp->cp_pbdir |= 0x00000030;
+ cp->cp_pbodr |= 0x00000030;
+
+ /* Disable interrupts */
+ i2c->i2c_i2mod = 0x00;
+ i2c->i2c_i2cmr = 0x00;
+ i2c->i2c_i2cer = 0xff;
+ i2c->i2c_i2add = slaveaddr;
+
+ /*
+ * Set the I2C BRG Clock division factor from desired i2c rate
+ * and current CPU rate (we assume sccr dfbgr field is 0;
+ * divide BRGCLK by 1)
+ */
+ debug("[I2C] Setting rate...\n");
+ i2c_setrate(gd->cpu_clk, CONFIG_SYS_I2C_SPEED);
+
+ /* Set I2C controller in master mode */
+ i2c->i2c_i2com = 0x01;
+
+ /* Set SDMA bus arbitration level to 5 (SDCR) */
+ immap->im_siu_conf.sc_sdcr = 0x0001;
+
+ /* Initialize Tx/Rx parameters */
+ iip->iic_rbase = rbase;
+ iip->iic_tbase = tbase;
+ rxbd = (I2C_BD *) ((unsigned char *) &cp->cp_dpmem[iip->iic_rbase]);
+ txbd = (I2C_BD *) ((unsigned char *) &cp->cp_dpmem[iip->iic_tbase]);
+
+ debug("[I2C] rbase = %04x\n", iip->iic_rbase);
+ debug("[I2C] tbase = %04x\n", iip->iic_tbase);
+ debug("[I2C] rxbd = %08x\n", (int)rxbd);
+ debug("[I2C] txbd = %08x\n", (int)txbd);
+
+ /* Set big endian byte order */
+ iip->iic_tfcr = 0x10;
+ iip->iic_rfcr = 0x10;
+
+ /* Set maximum receive size. */
+ iip->iic_mrblr = I2C_RXTX_LEN;
+
+#ifdef CONFIG_SYS_I2C_UCODE_PATCH
+ /*
+ * Initialize required parameters if using microcode patch.
+ */
+ iip->iic_rbptr = iip->iic_rbase;
+ iip->iic_tbptr = iip->iic_tbase;
+ iip->iic_rstate = 0;
+ iip->iic_tstate = 0;
+#else
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ do {
+ __asm__ __volatile__("eieio");
+ } while (cp->cp_cpcr & CPM_CR_FLG);
+#endif
+
+ /* Clear events and interrupts */
+ i2c->i2c_i2cer = 0xff;
+ i2c->i2c_i2cmr = 0x00;
+}
+
+static void i2c_newio(i2c_state_t *state)
+{
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cp = (cpm8xx_t *)&immap->im_cpm;
+ volatile iic_t *iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+
+ debug("[I2C] i2c_newio\n");
+
+#ifdef CONFIG_SYS_I2C_UCODE_PATCH
+ iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase];
+#endif
+ state->rx_idx = 0;
+ state->tx_idx = 0;
+ state->rxbd = (void *)&cp->cp_dpmem[iip->iic_rbase];
+ state->txbd = (void *)&cp->cp_dpmem[iip->iic_tbase];
+ state->tx_space = MAX_TX_SPACE;
+ state->tx_buf = (uchar *)state->txbd + NUM_TX_BDS * sizeof(I2C_BD);
+ state->err_cb = NULL;
+
+ debug("[I2C] rxbd = %08x\n", (int)state->rxbd);
+ debug("[I2C] txbd = %08x\n", (int)state->txbd);
+ debug("[I2C] tx_buf = %08x\n", (int)state->tx_buf);
+
+ /* clear the buffer memory */
+ memset((char *)state->tx_buf, 0, MAX_TX_SPACE);
+}
+
+static int
+i2c_send(i2c_state_t *state,
+ unsigned char address,
+ unsigned char secondary_address,
+ unsigned int flags, unsigned short size, unsigned char *dataout)
+{
+ volatile I2C_BD *txbd;
+ int i, j;
+
+ debug("[I2C] i2c_send add=%02d sec=%02d flag=%02d size=%d\n",
+ address, secondary_address, flags, size);
+
+ /* trying to send message larger than BD */
+ if (size > I2C_RXTX_LEN)
+ return I2CERR_MSG_TOO_LONG;
+
+ /* no more free bds */
+ if (state->tx_idx >= NUM_TX_BDS || state->tx_space < (2 + size))
+ return I2CERR_NO_BUFFERS;
+
+ txbd = (I2C_BD *) state->txbd;
+ txbd->addr = state->tx_buf;
+
+ debug("[I2C] txbd = %08x\n", (int)txbd);
+
+ if (flags & I2CF_START_COND) {
+ debug("[I2C] Formatting addresses...\n");
+ if (flags & I2CF_ENABLE_SECONDARY) {
+ /* Length of msg + dest addr */
+ txbd->length = size + 2;
+
+ txbd->addr[0] = address << 1;
+ txbd->addr[1] = secondary_address;
+ i = 2;
+ } else {
+ /* Length of msg + dest addr */
+ txbd->length = size + 1;
+ /* Write dest addr to BD */
+ txbd->addr[0] = address << 1;
+ i = 1;
+ }
+ } else {
+ txbd->length = size; /* Length of message */
+ i = 0;
+ }
+
+ /* set up txbd */
+ txbd->status = BD_SC_READY;
+ if (flags & I2CF_START_COND)
+ txbd->status |= BD_I2C_TX_START;
+ if (flags & I2CF_STOP_COND)
+ txbd->status |= BD_SC_LAST | BD_SC_WRAP;
+
+ /* Copy data to send into buffer */
+ debug("[I2C] copy data...\n");
+ for(j = 0; j < size; i++, j++)
+ txbd->addr[i] = dataout[j];
+
+ debug("[I2C] txbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n",
+ txbd->length,
+ txbd->status,
+ txbd->addr[0],
+ txbd->addr[1]);
+
+ /* advance state */
+ state->tx_buf += txbd->length;
+ state->tx_space -= txbd->length;
+ state->tx_idx++;
+ state->txbd = (void *) (txbd + 1);
+
+ return 0;
+}
+
+static int
+i2c_receive(i2c_state_t *state,
+ unsigned char address,
+ unsigned char secondary_address,
+ unsigned int flags,
+ unsigned short size_to_expect, unsigned char *datain)
+{
+ volatile I2C_BD *rxbd, *txbd;
+
+ debug("[I2C] i2c_receive %02d %02d %02d\n",
+ address, secondary_address, flags);
+
+ /* Expected to receive too much */
+ if (size_to_expect > I2C_RXTX_LEN)
+ return I2CERR_MSG_TOO_LONG;
+
+ /* no more free bds */
+ if (state->tx_idx >= NUM_TX_BDS || state->rx_idx >= NUM_RX_BDS
+ || state->tx_space < 2)
+ return I2CERR_NO_BUFFERS;
+
+ rxbd = (I2C_BD *) state->rxbd;
+ txbd = (I2C_BD *) state->txbd;
+
+ debug("[I2C] rxbd = %08x\n", (int)rxbd);
+ debug("[I2C] txbd = %08x\n", (int)txbd);
+
+ txbd->addr = state->tx_buf;
+
+ /* set up TXBD for destination address */
+ if (flags & I2CF_ENABLE_SECONDARY) {
+ txbd->length = 2;
+ txbd->addr[0] = address << 1; /* Write data */
+ txbd->addr[1] = secondary_address; /* Internal address */
+ txbd->status = BD_SC_READY;
+ } else {
+ txbd->length = 1 + size_to_expect;
+ txbd->addr[0] = (address << 1) | 0x01;
+ txbd->status = BD_SC_READY;
+ memset(&txbd->addr[1], 0, txbd->length);
+ }
+
+ /* set up rxbd for reception */
+ rxbd->status = BD_SC_EMPTY;
+ rxbd->length = size_to_expect;
+ rxbd->addr = datain;
+
+ txbd->status |= BD_I2C_TX_START;
+ if (flags & I2CF_STOP_COND) {
+ txbd->status |= BD_SC_LAST | BD_SC_WRAP;
+ rxbd->status |= BD_SC_WRAP;
+ }
+
+ debug("[I2C] txbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n",
+ txbd->length,
+ txbd->status,
+ txbd->addr[0],
+ txbd->addr[1]);
+ debug("[I2C] rxbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n",
+ rxbd->length,
+ rxbd->status,
+ rxbd->addr[0],
+ rxbd->addr[1]);
+
+ /* advance state */
+ state->tx_buf += txbd->length;
+ state->tx_space -= txbd->length;
+ state->tx_idx++;
+ state->txbd = (void *) (txbd + 1);
+ state->rx_idx++;
+ state->rxbd = (void *) (rxbd + 1);
+
+ return 0;
+}
+
+
+static int i2c_doio(i2c_state_t *state)
+{
+ volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cp = (cpm8xx_t *)&immap->im_cpm;
+ volatile i2c8xx_t *i2c = (i2c8xx_t *)&immap->im_i2c;
+ volatile iic_t *iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
+ volatile I2C_BD *txbd, *rxbd;
+ volatile int j = 0;
+
+ debug("[I2C] i2c_doio\n");
+
+#ifdef CONFIG_SYS_I2C_UCODE_PATCH
+ iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase];
+#endif
+
+ if (state->tx_idx <= 0 && state->rx_idx <= 0) {
+ debug("[I2C] No I/O is queued\n");
+ return I2CERR_QUEUE_EMPTY;
+ }
+
+ iip->iic_rbptr = iip->iic_rbase;
+ iip->iic_tbptr = iip->iic_tbase;
+
+ /* Enable I2C */
+ debug("[I2C] Enabling I2C...\n");
+ i2c->i2c_i2mod |= 0x01;
+
+ /* Begin transmission */
+ i2c->i2c_i2com |= 0x80;
+
+ /* Loop until transmit & receive completed */
+
+ if (state->tx_idx > 0) {
+ txbd = ((I2C_BD*)state->txbd) - 1;
+
+ debug("[I2C] Transmitting...(txbd=0x%08lx)\n",
+ (ulong)txbd);
+
+ while ((txbd->status & BD_SC_READY) && (j++ < TOUT_LOOP)) {
+ if (ctrlc())
+ return (-1);
+
+ __asm__ __volatile__("eieio");
+ }
+ }
+
+ if ((state->rx_idx > 0) && (j < TOUT_LOOP)) {
+ rxbd = ((I2C_BD*)state->rxbd) - 1;
+
+ debug("[I2C] Receiving...(rxbd=0x%08lx)\n",
+ (ulong)rxbd);
+
+ while ((rxbd->status & BD_SC_EMPTY) && (j++ < TOUT_LOOP)) {
+ if (ctrlc())
+ return (-1);
+
+ __asm__ __volatile__("eieio");
+ }
+ }
+
+ /* Turn off I2C */
+ i2c->i2c_i2mod &= ~0x01;
+
+ if (state->err_cb != NULL) {
+ int n, i, b;
+
+ /*
+ * if we have an error callback function, look at the
+ * error bits in the bd status and pass them back
+ */
+
+ if ((n = state->tx_idx) > 0) {
+ for (i = 0; i < n; i++) {
+ txbd = ((I2C_BD *) state->txbd) - (n - i);
+ if ((b = txbd->status & BD_I2C_TX_ERR) != 0)
+ (*state->err_cb) (I2CECB_TX_ERR | b,
+ i);
+ }
+ }
+
+ if ((n = state->rx_idx) > 0) {
+ for (i = 0; i < n; i++) {
+ rxbd = ((I2C_BD *) state->rxbd) - (n - i);
+ if ((b = rxbd->status & BD_I2C_RX_ERR) != 0)
+ (*state->err_cb) (I2CECB_RX_ERR | b,
+ i);
+ }
+ }
+
+ if (j >= TOUT_LOOP)
+ (*state->err_cb) (I2CECB_TIMEOUT, 0);
+ }
+
+ return (j >= TOUT_LOOP) ? I2CERR_TIMEOUT : 0;
+}
+
+static int had_tx_nak;
+
+static void i2c_test_callback(int flags, int xnum)
+{
+ if ((flags & I2CECB_TX_ERR) && (flags & I2CECB_TX_NAK))
+ had_tx_nak = 1;
+}
+
+int i2c_probe(uchar chip)
+{
+ i2c_state_t state;
+ int rc;
+ uchar buf[1];
+
+ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+ i2c_newio(&state);
+
+ state.err_cb = i2c_test_callback;
+ had_tx_nak = 0;
+
+ rc = i2c_receive(&state, chip, 0, I2CF_START_COND | I2CF_STOP_COND, 1,
+ buf);
+
+ if (rc != 0)
+ return (rc);
+
+ rc = i2c_doio(&state);
+
+ if ((rc != 0) && (rc != I2CERR_TIMEOUT))
+ return (rc);
+
+ return (had_tx_nak);
+}
+
+int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+ i2c_state_t state;
+ uchar xaddr[4];
+ int rc;
+
+#ifdef CONFIG_LWMON
+ WATCHDOG_RESET();
+#endif
+
+ xaddr[0] = (addr >> 24) & 0xFF;
+ xaddr[1] = (addr >> 16) & 0xFF;
+ xaddr[2] = (addr >> 8) & 0xFF;
+ xaddr[3] = addr & 0xFF;
+
+#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
+ /*
+ * EEPROM chips that implement "address overflow" are ones like
+ * Catalyst 24WC04/08/16 which has 9/10/11 bits of address and the
+ * extra bits end up in the "chip address" bit slots. This makes
+ * a 24WC08 (1Kbyte) chip look like four 256 byte chips.
+ *
+ * Note that we consider the length of the address field to still
+ * be one byte because the extra address bits are hidden in the
+ * chip address.
+ */
+ chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
+#endif
+
+ i2c_newio(&state);
+
+ rc = i2c_send(&state, chip, 0, I2CF_START_COND, alen,
+ &xaddr[4 - alen]);
+ if (rc != 0) {
+ printf("i2c_read: i2c_send failed (%d)\n", rc);
+ return 1;
+ }
+
+ rc = i2c_receive(&state, chip, 0, I2CF_STOP_COND, len, buffer);
+ if (rc != 0) {
+ printf("i2c_read: i2c_receive failed (%d)\n", rc);
+ return 1;
+ }
+
+ rc = i2c_doio(&state);
+ if (rc != 0) {
+ printf("i2c_read: i2c_doio failed (%d)\n", rc);
+ return 1;
+ }
+ return 0;
+}
+
+int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+ i2c_state_t state;
+ uchar xaddr[4];
+ int rc;
+
+ xaddr[0] = (addr >> 24) & 0xFF;
+ xaddr[1] = (addr >> 16) & 0xFF;
+ xaddr[2] = (addr >> 8) & 0xFF;
+ xaddr[3] = addr & 0xFF;
+
+#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
+ /*
+ * EEPROM chips that implement "address overflow" are ones like
+ * Catalyst 24WC04/08/16 which has 9/10/11 bits of address and the
+ * extra bits end up in the "chip address" bit slots. This makes
+ * a 24WC08 (1Kbyte) chip look like four 256 byte chips.
+ *
+ * Note that we consider the length of the address field to still
+ * be one byte because the extra address bits are hidden in the
+ * chip address.
+ */
+ chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
+#endif
+
+ i2c_newio(&state);
+
+ rc = i2c_send(&state, chip, 0, I2CF_START_COND, alen,
+ &xaddr[4 - alen]);
+ if (rc != 0) {
+ printf("i2c_write: first i2c_send failed (%d)\n", rc);
+ return 1;
+ }
+
+ rc = i2c_send(&state, 0, 0, I2CF_STOP_COND, len, buffer);
+ if (rc != 0) {
+ printf("i2c_write: second i2c_send failed (%d)\n", rc);
+ return 1;
+ }
+
+ rc = i2c_doio(&state);
+ if (rc != 0) {
+ printf("i2c_write: i2c_doio failed (%d)\n", rc);
+ return 1;
+ }
+ return 0;
+}
+
+#endif /* CONFIG_HARD_I2C */
diff --git a/arch/powerpc/cpu/mpc8xx/interrupts.c b/arch/powerpc/cpu/mpc8xx/interrupts.c
new file mode 100644
index 0000000..5daa6b2
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/interrupts.c
@@ -0,0 +1,294 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <mpc8xx_irq.h>
+#include <asm/processor.h>
+#include <commproc.h>
+
+/************************************************************************/
+
+/*
+ * CPM interrupt vector functions.
+ */
+struct interrupt_action {
+ interrupt_handler_t *handler;
+ void *arg;
+};
+
+static struct interrupt_action cpm_vecs[CPMVEC_NR];
+static struct interrupt_action irq_vecs[NR_IRQS];
+
+static void cpm_interrupt_init (void);
+static void cpm_interrupt (void *regs);
+
+/************************************************************************/
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ *decrementer_count = get_tbclk () / CONFIG_SYS_HZ;
+
+ /* disable all interrupts */
+ immr->im_siu_conf.sc_simask = 0;
+
+ /* Configure CPM interrupts */
+ cpm_interrupt_init ();
+
+ return (0);
+}
+
+/************************************************************************/
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt (struct pt_regs *regs)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ int irq;
+ ulong simask, newmask;
+ ulong vec, v_bit;
+
+ /*
+ * read the SIVEC register and shift the bits down
+ * to get the irq number
+ */
+ vec = immr->im_siu_conf.sc_sivec;
+ irq = vec >> 26;
+ v_bit = 0x80000000UL >> irq;
+
+ /*
+ * Read Interrupt Mask Register and Mask Interrupts
+ */
+ simask = immr->im_siu_conf.sc_simask;
+ newmask = simask & (~(0xFFFF0000 >> irq));
+ immr->im_siu_conf.sc_simask = newmask;
+
+ if (!(irq & 0x1)) { /* External Interrupt ? */
+ ulong siel;
+
+ /*
+ * Read Interrupt Edge/Level Register
+ */
+ siel = immr->im_siu_conf.sc_siel;
+
+ if (siel & v_bit) { /* edge triggered interrupt ? */
+ /*
+ * Rewrite SIPEND Register to clear interrupt
+ */
+ immr->im_siu_conf.sc_sipend = v_bit;
+ }
+ }
+
+ if (irq_vecs[irq].handler != NULL) {
+ irq_vecs[irq].handler (irq_vecs[irq].arg);
+ } else {
+ printf ("\nBogus External Interrupt IRQ %d Vector %ld\n",
+ irq, vec);
+ /* turn off the bogus interrupt to avoid it from now */
+ simask &= ~v_bit;
+ }
+ /*
+ * Re-Enable old Interrupt Mask
+ */
+ immr->im_siu_conf.sc_simask = simask;
+}
+
+/************************************************************************/
+
+/*
+ * CPM interrupt handler
+ */
+static void cpm_interrupt (void *regs)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ uint vec;
+
+ /*
+ * Get the vector by setting the ACK bit
+ * and then reading the register.
+ */
+ immr->im_cpic.cpic_civr = 1;
+ vec = immr->im_cpic.cpic_civr;
+ vec >>= 11;
+
+ if (cpm_vecs[vec].handler != NULL) {
+ (*cpm_vecs[vec].handler) (cpm_vecs[vec].arg);
+ } else {
+ immr->im_cpic.cpic_cimr &= ~(1 << vec);
+ printf ("Masking bogus CPM interrupt vector 0x%x\n", vec);
+ }
+ /*
+ * After servicing the interrupt,
+ * we have to remove the status indicator.
+ */
+ immr->im_cpic.cpic_cisr |= (1 << vec);
+}
+
+/*
+ * The CPM can generate the error interrupt when there is a race
+ * condition between generating and masking interrupts. All we have
+ * to do is ACK it and return. This is a no-op function so we don't
+ * need any special tests in the interrupt handler.
+ */
+static void cpm_error_interrupt (void *dummy)
+{
+}
+
+/************************************************************************/
+/*
+ * Install and free an interrupt handler
+ */
+void irq_install_handler (int vec, interrupt_handler_t * handler,
+ void *arg)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ if ((vec & CPMVEC_OFFSET) != 0) {
+ /* CPM interrupt */
+ vec &= 0xffff;
+ if (cpm_vecs[vec].handler != NULL) {
+ printf ("CPM interrupt 0x%x replacing 0x%x\n",
+ (uint) handler,
+ (uint) cpm_vecs[vec].handler);
+ }
+ cpm_vecs[vec].handler = handler;
+ cpm_vecs[vec].arg = arg;
+ immr->im_cpic.cpic_cimr |= (1 << vec);
+#if 0
+ printf ("Install CPM interrupt for vector %d ==> %p\n",
+ vec, handler);
+#endif
+ } else {
+ /* SIU interrupt */
+ if (irq_vecs[vec].handler != NULL) {
+ printf ("SIU interrupt %d 0x%x replacing 0x%x\n",
+ vec,
+ (uint) handler,
+ (uint) cpm_vecs[vec].handler);
+ }
+ irq_vecs[vec].handler = handler;
+ irq_vecs[vec].arg = arg;
+ immr->im_siu_conf.sc_simask |= 1 << (31 - vec);
+#if 0
+ printf ("Install SIU interrupt for vector %d ==> %p\n",
+ vec, handler);
+#endif
+ }
+}
+
+void irq_free_handler (int vec)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ if ((vec & CPMVEC_OFFSET) != 0) {
+ /* CPM interrupt */
+ vec &= 0xffff;
+#if 0
+ printf ("Free CPM interrupt for vector %d ==> %p\n",
+ vec, cpm_vecs[vec].handler);
+#endif
+ immr->im_cpic.cpic_cimr &= ~(1 << vec);
+ cpm_vecs[vec].handler = NULL;
+ cpm_vecs[vec].arg = NULL;
+ } else {
+ /* SIU interrupt */
+#if 0
+ printf ("Free CPM interrupt for vector %d ==> %p\n",
+ vec, cpm_vecs[vec].handler);
+#endif
+ immr->im_siu_conf.sc_simask &= ~(1 << (31 - vec));
+ irq_vecs[vec].handler = NULL;
+ irq_vecs[vec].arg = NULL;
+ }
+}
+
+/************************************************************************/
+
+static void cpm_interrupt_init (void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ /*
+ * Initialize the CPM interrupt controller.
+ */
+
+ immr->im_cpic.cpic_cicr =
+ (CICR_SCD_SCC4 |
+ CICR_SCC_SCC3 |
+ CICR_SCB_SCC2 |
+ CICR_SCA_SCC1) | ((CPM_INTERRUPT / 2) << 13) | CICR_HP_MASK;
+
+ immr->im_cpic.cpic_cimr = 0;
+
+ /*
+ * Install the error handler.
+ */
+ irq_install_handler (CPMVEC_ERROR, cpm_error_interrupt, NULL);
+
+ immr->im_cpic.cpic_cicr |= CICR_IEN;
+
+ /*
+ * Install the cpm interrupt handler
+ */
+ irq_install_handler (CPM_INTERRUPT, cpm_interrupt, NULL);
+}
+
+/************************************************************************/
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * Trivial implementation - no need to be really accurate.
+ */
+void timer_interrupt_cpu (struct pt_regs *regs)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+#if 0
+ printf ("*** Timer Interrupt *** ");
+#endif
+ /* Reset Timer Expired and Timers Interrupt Status */
+ immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+ __asm__ ("nop");
+ /*
+ Clear TEXPS (and TMIST on older chips). SPLSS (on older
+ chips) is cleared too.
+
+ Bitwise OR is a read-modify-write operation so ALL bits
+ which are cleared by writing `1' would be cleared by
+ operations like
+
+ immr->im_clkrst.car_plprcr |= PLPRCR_TEXPS;
+
+ The same can be achieved by simple writing of the PLPRCR
+ to itself. If a bit value should be preserved, read the
+ register, ZERO the bit and write, not OR, the result back.
+ */
+ immr->im_clkrst.car_plprcr = immr->im_clkrst.car_plprcr;
+}
+
+/************************************************************************/
diff --git a/arch/powerpc/cpu/mpc8xx/kgdb.S b/arch/powerpc/cpu/mpc8xx/kgdb.S
new file mode 100644
index 0000000..2cc8fe6
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/kgdb.S
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2000 Murray Jensen <Murray.Jensen@cmst.csiro.au>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <command.h>
+#include <mpc8xx.h>
+#include <version.h>
+
+#define CONFIG_8xx 1 /* needed for Linux kernel header files */
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#if defined(CONFIG_CMD_KGDB)
+
+ /*
+ * cache flushing routines for kgdb
+ */
+
+ .globl kgdb_flush_cache_all
+kgdb_flush_cache_all:
+ lis r3, IDC_INVALL@h
+ mtspr DC_CST, r3
+ sync
+ lis r3, IDC_INVALL@h
+ mtspr IC_CST, r3
+ SYNC
+ blr
+
+ .globl kgdb_flush_cache_range
+kgdb_flush_cache_range:
+ li r5,CONFIG_SYS_CACHELINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,CONFIG_SYS_CACHELINE_SHIFT
+ beqlr
+ mtctr r4
+ mr r6,r3
+1: dcbst 0,r3
+ addi r3,r3,CONFIG_SYS_CACHELINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ mtctr r4
+2: icbi 0,r6
+ addi r6,r6,CONFIG_SYS_CACHELINE_SIZE
+ bdnz 2b
+ SYNC
+ blr
+
+#endif
diff --git a/arch/powerpc/cpu/mpc8xx/plprcr_write.S b/arch/powerpc/cpu/mpc8xx/plprcr_write.S
new file mode 100644
index 0000000..e325671
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/plprcr_write.S
@@ -0,0 +1,135 @@
+/*
+ * (C) Copyright 2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <mpc8xx.h>
+#include <ppc_asm.tmpl>
+#include <asm/cache.h>
+
+#define CACHE_CMD_ENABLE 0x02000000
+#define CACHE_CMD_DISABLE 0x04000000
+#define CACHE_CMD_LOAD_LOCK 0x06000000
+#define CACHE_CMD_UNLOCK_LINE 0x08000000
+#define CACHE_CMD_UNLOCK_ALL 0x0A000000
+#define CACHE_CMD_INVALIDATE 0x0C000000
+#define SPEED_PLPRCR_WAIT_5CYC 150
+#define _CACHE_ALIGN_SIZE 16
+
+
+ .text
+ .align 2
+ .globl plprcr_write_866
+
+/*
+ * void plprcr_write_866 (long plprcr)
+ * Write PLPRCR, including workaround for device errata SIU4 and SIU9.
+ */
+
+plprcr_write_866:
+ mfspr r10, LR /* save the Link Register value */
+
+ /* turn instruction cache on (no MMU required for instructions)
+ */
+ lis r4, CACHE_CMD_ENABLE@h
+ ori r4, r4, CACHE_CMD_ENABLE@l
+ mtspr IC_CST, r4
+ isync
+
+ /* clear IC_CST error bits
+ */
+ mfspr r4, IC_CST
+
+ bl plprcr_here
+
+plprcr_here:
+ mflr r5
+
+ /* calculate relocation offset
+ */
+ lis r4, plprcr_here@h
+ ori r4, r4, plprcr_here@l
+ sub r5, r5, r4
+
+ /* calculate first address of this function
+ */
+ lis r6, plprcr_write_866@h
+ ori r6, r6, plprcr_write_866@l
+ add r6, r6, r5
+
+ /* calculate end address of this function
+ */
+ lis r7, plprcr_end@h
+ ori r7, r7, plprcr_end@l
+ add r7, r7, r5
+
+ /* load and lock code addresses
+ */
+ mr r5, r6
+
+plprcr_loop:
+ mtspr IC_ADR, r5
+ addi r5, r5, _CACHE_ALIGN_SIZE /* increment by one line */
+
+ lis r4, CACHE_CMD_LOAD_LOCK@h
+ ori r4, r4, CACHE_CMD_LOAD_LOCK@l
+ mtspr IC_CST, r4
+ isync
+
+ cmpw r5, r7
+ blt plprcr_loop
+
+ /* IC_CST error bits not evaluated
+ */
+
+ /* switch PLPRCR
+ */
+ mfspr r4, IMMR /* read IMMR */
+ rlwinm r4, r4, 0, 0, 15 /* only high 16 bits count */
+
+ /* write sequence according to MPC866 Errata
+ */
+ stw r3, PLPRCR(r4)
+ isync
+
+ lis r3, SPEED_PLPRCR_WAIT_5CYC@h
+ ori r3, r3, SPEED_PLPRCR_WAIT_5CYC@l
+
+plprcr_wait:
+ cmpwi r3, 0
+ beq plprcr_wait_end
+ nop
+ subi r3, r3, 1
+ b plprcr_wait
+
+plprcr_wait_end:
+
+ /* unlock instruction cache but leave it enabled
+ */
+ lis r4, CACHE_CMD_UNLOCK_ALL@h
+ ori r4, r4, CACHE_CMD_UNLOCK_ALL@l
+ mtspr IC_CST, r4
+ isync
+
+ mtspr LR, r10 /* restore original Link Register value */
+ blr
+
+plprcr_end:
diff --git a/arch/powerpc/cpu/mpc8xx/scc.c b/arch/powerpc/cpu/mpc8xx/scc.c
new file mode 100644
index 0000000..2ef77b4
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/scc.c
@@ -0,0 +1,558 @@
+/*
+ * File: scc.c
+ * Description:
+ * Basic ET HW initialization and packet RX/TX routines
+ *
+ * NOTE <<<IMPORTANT: PLEASE READ>>>:
+ * Do not cache Rx/Tx buffers!
+ */
+
+/*
+ * MPC823 <-> MC68160 Connections:
+ *
+ * Setup MPC823 to work with MC68160 Enhanced Ethernet
+ * Serial Tranceiver as follows:
+ *
+ * MPC823 Signal MC68160 Comments
+ * ------ ------ ------- --------
+ * PA-12 ETHTX --------> TX Eth. Port Transmit Data
+ * PB-18 E_TENA --------> TENA Eth. Transmit Port Enable
+ * PA-5 ETHTCK <-------- TCLK Eth. Port Transmit Clock
+ * PA-13 ETHRX <-------- RX Eth. Port Receive Data
+ * PC-8 E_RENA <-------- RENA Eth. Receive Enable
+ * PA-6 ETHRCK <-------- RCLK Eth. Port Receive Clock
+ * PC-9 E_CLSN <-------- CLSN Eth. Port Collision Indication
+ *
+ * FADS Board Signal MC68160 Comments
+ * ----------------- ------- --------
+ * (BCSR1) ETHEN* --------> CS2 Eth. Port Enable
+ * (BSCR4) TPSQEL* --------> TPSQEL Twisted Pair Signal Quality Error Test Enable
+ * (BCSR4) TPFLDL* --------> TPFLDL Twisted Pair Full-Duplex
+ * (BCSR4) ETHLOOP --------> LOOP Eth. Port Diagnostic Loop-Back
+ *
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <commproc.h>
+#include <net.h>
+#include <command.h>
+
+#if defined(CONFIG_CMD_NET) && defined(SCC_ENET)
+
+/* Ethernet Transmit and Receive Buffers */
+#define DBUF_LENGTH 1520
+
+#define TX_BUF_CNT 2
+
+#define TOUT_LOOP 10000 /* 10 ms to have a packet sent */
+
+static char txbuf[DBUF_LENGTH];
+
+static uint rxIdx; /* index of the current RX buffer */
+static uint txIdx; /* index of the current TX buffer */
+
+/*
+ * SCC Ethernet Tx and Rx buffer descriptors allocated at the
+ * immr->udata_bd address on Dual-Port RAM
+ * Provide for Double Buffering
+ */
+
+typedef volatile struct CommonBufferDescriptor {
+ cbd_t rxbd[PKTBUFSRX]; /* Rx BD */
+ cbd_t txbd[TX_BUF_CNT]; /* Tx BD */
+} RTXBD;
+
+static RTXBD *rtx;
+
+static int scc_send(struct eth_device *dev, void *packet, int length);
+static int scc_recv(struct eth_device* dev);
+static int scc_init (struct eth_device* dev, bd_t * bd);
+static void scc_halt(struct eth_device* dev);
+
+int scc_initialize(bd_t *bis)
+{
+ struct eth_device* dev;
+
+ dev = (struct eth_device*) malloc(sizeof *dev);
+ memset(dev, 0, sizeof *dev);
+
+ sprintf(dev->name, "SCC");
+ dev->iobase = 0;
+ dev->priv = 0;
+ dev->init = scc_init;
+ dev->halt = scc_halt;
+ dev->send = scc_send;
+ dev->recv = scc_recv;
+
+ eth_register(dev);
+
+ return 1;
+}
+
+static int scc_send(struct eth_device *dev, void *packet, int length)
+{
+ int i, j=0;
+#if 0
+ volatile char *in, *out;
+#endif
+
+ /* section 16.9.23.3
+ * Wait for ready
+ */
+#if 0
+ while (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY);
+ out = (char *)(rtx->txbd[txIdx].cbd_bufaddr);
+ in = packet;
+ for(i = 0; i < length; i++) {
+ *out++ = *in++;
+ }
+ rtx->txbd[txIdx].cbd_datlen = length;
+ rtx->txbd[txIdx].cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_LAST);
+ while (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) j++;
+
+#ifdef ET_DEBUG
+ printf("cycles: %d status: %x\n", j, rtx->txbd[txIdx].cbd_sc);
+#endif
+ i = (rtx->txbd[txIdx++].cbd_sc & BD_ENET_TX_STATS) /* return only status bits */;
+
+ /* wrap around buffer index when necessary */
+ if (txIdx >= TX_BUF_CNT) txIdx = 0;
+#endif
+
+ while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
+ udelay (1); /* will also trigger Wd if needed */
+ j++;
+ }
+ if (j>=TOUT_LOOP) printf("TX not ready\n");
+ rtx->txbd[txIdx].cbd_bufaddr = (uint)packet;
+ rtx->txbd[txIdx].cbd_datlen = length;
+ rtx->txbd[txIdx].cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_LAST |BD_ENET_TX_WRAP);
+ while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
+ udelay (1); /* will also trigger Wd if needed */
+ j++;
+ }
+ if (j>=TOUT_LOOP) printf("TX timeout\n");
+#ifdef ET_DEBUG
+ printf("cycles: %d status: %x\n", j, rtx->txbd[txIdx].cbd_sc);
+#endif
+ i = (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_STATS) /* return only status bits */;
+ return i;
+}
+
+static int scc_recv (struct eth_device *dev)
+{
+ int length;
+
+ for (;;) {
+ /* section 16.9.23.2 */
+ if (rtx->rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
+ length = -1;
+ break; /* nothing received - leave for() loop */
+ }
+
+ length = rtx->rxbd[rxIdx].cbd_datlen;
+
+ if (rtx->rxbd[rxIdx].cbd_sc & 0x003f) {
+#ifdef ET_DEBUG
+ printf ("err: %x\n", rtx->rxbd[rxIdx].cbd_sc);
+#endif
+ } else {
+ /* Pass the packet up to the protocol layers. */
+ NetReceive (NetRxPackets[rxIdx], length - 4);
+ }
+
+
+ /* Give the buffer back to the SCC. */
+ rtx->rxbd[rxIdx].cbd_datlen = 0;
+
+ /* wrap around buffer index when necessary */
+ if ((rxIdx + 1) >= PKTBUFSRX) {
+ rtx->rxbd[PKTBUFSRX - 1].cbd_sc =
+ (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
+ rxIdx = 0;
+ } else {
+ rtx->rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
+ rxIdx++;
+ }
+ }
+ return length;
+}
+
+/**************************************************************
+ *
+ * SCC Ethernet Initialization Routine
+ *
+ *************************************************************/
+
+static int scc_init (struct eth_device *dev, bd_t * bis)
+{
+
+ int i;
+ scc_enet_t *pram_ptr;
+
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+#if defined(CONFIG_LWMON)
+ reset_phy();
+#endif
+
+#ifdef CONFIG_FADS
+#if defined(CONFIG_MPC86xADS) || defined(CONFIG_MPC860T)
+ /* The MPC86xADS/FADS860T don't use the MODEM_EN or DATA_VOICE signals. */
+ *((uint *) BCSR4) &= ~BCSR4_ETHLOOP;
+ *((uint *) BCSR4) |= BCSR4_TFPLDL | BCSR4_TPSQEL;
+ *((uint *) BCSR1) &= ~BCSR1_ETHEN;
+#else
+ *((uint *) BCSR4) &= ~(BCSR4_ETHLOOP | BCSR4_MODEM_EN);
+ *((uint *) BCSR4) |= BCSR4_TFPLDL | BCSR4_TPSQEL | BCSR4_DATA_VOICE;
+ *((uint *) BCSR1) &= ~BCSR1_ETHEN;
+#endif
+#endif
+
+ pram_ptr = (scc_enet_t *) & (immr->im_cpm.cp_dparam[PROFF_ENET]);
+
+ rxIdx = 0;
+ txIdx = 0;
+
+ if (!rtx) {
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+ rtx = (RTXBD *) (immr->im_cpm.cp_dpmem +
+ dpram_alloc_align (sizeof (RTXBD), 8));
+#else
+ rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + CPM_SCC_BASE);
+#endif
+ }
+
+#if (defined(PA_ENET_RXD) && defined(PA_ENET_TXD))
+ /* Configure port A pins for Txd and Rxd.
+ */
+ immr->im_ioport.iop_papar |= (PA_ENET_RXD | PA_ENET_TXD);
+ immr->im_ioport.iop_padir &= ~(PA_ENET_RXD | PA_ENET_TXD);
+ immr->im_ioport.iop_paodr &= ~PA_ENET_TXD;
+#elif (defined(PB_ENET_RXD) && defined(PB_ENET_TXD))
+ /* Configure port B pins for Txd and Rxd.
+ */
+ immr->im_cpm.cp_pbpar |= (PB_ENET_RXD | PB_ENET_TXD);
+ immr->im_cpm.cp_pbdir &= ~(PB_ENET_RXD | PB_ENET_TXD);
+ immr->im_cpm.cp_pbodr &= ~PB_ENET_TXD;
+#else
+#error Configuration Error: exactly ONE of PA_ENET_[RT]XD, PB_ENET_[RT]XD must be defined
+#endif
+
+#if defined(PC_ENET_LBK)
+ /* Configure port C pins to disable External Loopback
+ */
+ immr->im_ioport.iop_pcpar &= ~PC_ENET_LBK;
+ immr->im_ioport.iop_pcdir |= PC_ENET_LBK;
+ immr->im_ioport.iop_pcso &= ~PC_ENET_LBK;
+ immr->im_ioport.iop_pcdat &= ~PC_ENET_LBK; /* Disable Loopback */
+#endif /* PC_ENET_LBK */
+
+ /* Configure port C pins to enable CLSN and RENA.
+ */
+ immr->im_ioport.iop_pcpar &= ~(PC_ENET_CLSN | PC_ENET_RENA);
+ immr->im_ioport.iop_pcdir &= ~(PC_ENET_CLSN | PC_ENET_RENA);
+ immr->im_ioport.iop_pcso |= (PC_ENET_CLSN | PC_ENET_RENA);
+
+ /* Configure port A for TCLK and RCLK.
+ */
+ immr->im_ioport.iop_papar |= (PA_ENET_TCLK | PA_ENET_RCLK);
+ immr->im_ioport.iop_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK);
+
+ /*
+ * Configure Serial Interface clock routing -- see section 16.7.5.3
+ * First, clear all SCC bits to zero, then set the ones we want.
+ */
+
+ immr->im_cpm.cp_sicr &= ~SICR_ENET_MASK;
+ immr->im_cpm.cp_sicr |= SICR_ENET_CLKRT;
+
+
+ /*
+ * Initialize SDCR -- see section 16.9.23.7
+ * SDMA configuration register
+ */
+ immr->im_siu_conf.sc_sdcr = 0x01;
+
+
+ /*
+ * Setup SCC Ethernet Parameter RAM
+ */
+
+ pram_ptr->sen_genscc.scc_rfcr = 0x18; /* Normal Operation and Mot byte ordering */
+ pram_ptr->sen_genscc.scc_tfcr = 0x18; /* Mot byte ordering, Normal access */
+
+ pram_ptr->sen_genscc.scc_mrblr = DBUF_LENGTH; /* max. ET package len 1520 */
+
+ pram_ptr->sen_genscc.scc_rbase = (unsigned int) (&rtx->rxbd[0]); /* Set RXBD tbl start at Dual Port */
+ pram_ptr->sen_genscc.scc_tbase = (unsigned int) (&rtx->txbd[0]); /* Set TXBD tbl start at Dual Port */
+
+ /*
+ * Setup Receiver Buffer Descriptors (13.14.24.18)
+ * Settings:
+ * Empty, Wrap
+ */
+
+ for (i = 0; i < PKTBUFSRX; i++) {
+ rtx->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
+ rtx->rxbd[i].cbd_datlen = 0; /* Reset */
+ rtx->rxbd[i].cbd_bufaddr = (uint) NetRxPackets[i];
+ }
+
+ rtx->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
+
+ /*
+ * Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19)
+ * Settings:
+ * Add PADs to Short FRAMES, Wrap, Last, Tx CRC
+ */
+
+ for (i = 0; i < TX_BUF_CNT; i++) {
+ rtx->txbd[i].cbd_sc =
+ (BD_ENET_TX_PAD | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+ rtx->txbd[i].cbd_datlen = 0; /* Reset */
+ rtx->txbd[i].cbd_bufaddr = (uint) (&txbuf[0]);
+ }
+
+ rtx->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
+
+ /*
+ * Enter Command: Initialize Rx Params for SCC
+ */
+
+ do { /* Spin until ready to issue command */
+ __asm__ ("eieio");
+ } while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+ /* Issue command */
+ immr->im_cpm.cp_cpcr =
+ ((CPM_CR_INIT_RX << 8) | (CPM_CR_ENET << 4) | CPM_CR_FLG);
+ do { /* Spin until command processed */
+ __asm__ ("eieio");
+ } while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+
+ /*
+ * Ethernet Specific Parameter RAM
+ * see table 13-16, pg. 660,
+ * pg. 681 (example with suggested settings)
+ */
+
+ pram_ptr->sen_cpres = ~(0x0); /* Preset CRC */
+ pram_ptr->sen_cmask = 0xdebb20e3; /* Constant Mask for CRC */
+ pram_ptr->sen_crcec = 0x0; /* Error Counter CRC (unused) */
+ pram_ptr->sen_alec = 0x0; /* Alignment Error Counter (unused) */
+ pram_ptr->sen_disfc = 0x0; /* Discard Frame Counter (unused) */
+ pram_ptr->sen_pads = 0x8888; /* Short Frame PAD Characters */
+
+ pram_ptr->sen_retlim = 15; /* Retry Limit Threshold */
+ pram_ptr->sen_maxflr = 1518; /* MAX Frame Length Register */
+ pram_ptr->sen_minflr = 64; /* MIN Frame Length Register */
+
+ pram_ptr->sen_maxd1 = DBUF_LENGTH; /* MAX DMA1 Length Register */
+ pram_ptr->sen_maxd2 = DBUF_LENGTH; /* MAX DMA2 Length Register */
+
+ pram_ptr->sen_gaddr1 = 0x0; /* Group Address Filter 1 (unused) */
+ pram_ptr->sen_gaddr2 = 0x0; /* Group Address Filter 2 (unused) */
+ pram_ptr->sen_gaddr3 = 0x0; /* Group Address Filter 3 (unused) */
+ pram_ptr->sen_gaddr4 = 0x0; /* Group Address Filter 4 (unused) */
+
+#define ea eth_get_dev()->enetaddr
+ pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4];
+ pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2];
+ pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0];
+#undef ea
+
+ pram_ptr->sen_pper = 0x0; /* Persistence (unused) */
+ pram_ptr->sen_iaddr1 = 0x0; /* Individual Address Filter 1 (unused) */
+ pram_ptr->sen_iaddr2 = 0x0; /* Individual Address Filter 2 (unused) */
+ pram_ptr->sen_iaddr3 = 0x0; /* Individual Address Filter 3 (unused) */
+ pram_ptr->sen_iaddr4 = 0x0; /* Individual Address Filter 4 (unused) */
+ pram_ptr->sen_taddrh = 0x0; /* Tmp Address (MSB) (unused) */
+ pram_ptr->sen_taddrm = 0x0; /* Tmp Address (unused) */
+ pram_ptr->sen_taddrl = 0x0; /* Tmp Address (LSB) (unused) */
+
+ /*
+ * Enter Command: Initialize Tx Params for SCC
+ */
+
+ do { /* Spin until ready to issue command */
+ __asm__ ("eieio");
+ } while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+ /* Issue command */
+ immr->im_cpm.cp_cpcr =
+ ((CPM_CR_INIT_TX << 8) | (CPM_CR_ENET << 4) | CPM_CR_FLG);
+ do { /* Spin until command processed */
+ __asm__ ("eieio");
+ } while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
+
+ /*
+ * Mask all Events in SCCM - we use polling mode
+ */
+ immr->im_cpm.cp_scc[SCC_ENET].scc_sccm = 0;
+
+ /*
+ * Clear Events in SCCE -- Clear bits by writing 1's
+ */
+
+ immr->im_cpm.cp_scc[SCC_ENET].scc_scce = ~(0x0);
+
+
+ /*
+ * Initialize GSMR High 32-Bits
+ * Settings: Normal Mode
+ */
+
+ immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrh = 0;
+
+ /*
+ * Initialize GSMR Low 32-Bits, but do not Enable Transmit/Receive
+ * Settings:
+ * TCI = Invert
+ * TPL = 48 bits
+ * TPP = Repeating 10's
+ * MODE = Ethernet
+ */
+
+ immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl = (SCC_GSMRL_TCI |
+ SCC_GSMRL_TPL_48 |
+ SCC_GSMRL_TPP_10 |
+ SCC_GSMRL_MODE_ENET);
+
+ /*
+ * Initialize the DSR -- see section 13.14.4 (pg. 513) v0.4
+ */
+
+ immr->im_cpm.cp_scc[SCC_ENET].scc_dsr = 0xd555;
+
+ /*
+ * Initialize the PSMR
+ * Settings:
+ * CRC = 32-Bit CCITT
+ * NIB = Begin searching for SFD 22 bits after RENA
+ * FDE = Full Duplex Enable
+ * LPB = Loopback Enable (Needed when FDE is set)
+ * BRO = Reject broadcast packets
+ * PROMISCOUS = Catch all packets regardless of dest. MAC adress
+ */
+ immr->im_cpm.cp_scc[SCC_ENET].scc_psmr = SCC_PSMR_ENCRC |
+ SCC_PSMR_NIB22 |
+#if defined(CONFIG_SCC_ENET_FULL_DUPLEX)
+ SCC_PSMR_FDE | SCC_PSMR_LPB |
+#endif
+#if defined(CONFIG_SCC_ENET_NO_BROADCAST)
+ SCC_PSMR_BRO |
+#endif
+#if defined(CONFIG_SCC_ENET_PROMISCOUS)
+ SCC_PSMR_PRO |
+#endif
+ 0;
+
+ /*
+ * Configure Ethernet TENA Signal
+ */
+
+#if (defined(PC_ENET_TENA) && !defined(PB_ENET_TENA))
+ immr->im_ioport.iop_pcpar |= PC_ENET_TENA;
+ immr->im_ioport.iop_pcdir &= ~PC_ENET_TENA;
+#elif (defined(PB_ENET_TENA) && !defined(PC_ENET_TENA))
+ immr->im_cpm.cp_pbpar |= PB_ENET_TENA;
+ immr->im_cpm.cp_pbdir |= PB_ENET_TENA;
+#else
+#error Configuration Error: exactly ONE of PB_ENET_TENA, PC_ENET_TENA must be defined
+#endif
+
+#if defined(CONFIG_ADS) && defined(CONFIG_MPC860)
+ /*
+ * Port C is used to control the PHY,MC68160.
+ */
+ immr->im_ioport.iop_pcdir |=
+ (PC_ENET_ETHLOOP | PC_ENET_TPFLDL | PC_ENET_TPSQEL);
+
+ immr->im_ioport.iop_pcdat |= PC_ENET_TPFLDL;
+ immr->im_ioport.iop_pcdat &= ~(PC_ENET_ETHLOOP | PC_ENET_TPSQEL);
+ *((uint *) BCSR1) &= ~BCSR1_ETHEN;
+#endif /* MPC860ADS */
+
+#ifdef CONFIG_RPXCLASSIC
+ *((uchar *) BCSR0) &= ~BCSR0_ETHLPBK;
+ *((uchar *) BCSR0) |= (BCSR0_ETHEN | BCSR0_COLTEST | BCSR0_FULLDPLX);
+#endif
+
+#ifdef CONFIG_RPXLITE
+ *((uchar *) BCSR0) |= BCSR0_ETHEN;
+#endif
+
+#if defined(CONFIG_QS860T)
+ /*
+ * PB27=FDE-, set output low for full duplex
+ * PB26=Link Test Enable, normally high output
+ */
+ immr->im_cpm.cp_pbdir |= 0x00000030;
+ immr->im_cpm.cp_pbdat |= 0x00000020;
+ immr->im_cpm.cp_pbdat &= ~0x00000010;
+#endif /* QS860T */
+
+#ifdef CONFIG_MBX
+ board_ether_init ();
+#endif
+
+#if defined(CONFIG_NETVIA)
+#if defined(PA_ENET_PDN)
+ immr->im_ioport.iop_papar &= ~PA_ENET_PDN;
+ immr->im_ioport.iop_padir |= PA_ENET_PDN;
+ immr->im_ioport.iop_padat |= PA_ENET_PDN;
+#elif defined(PB_ENET_PDN)
+ immr->im_cpm.cp_pbpar &= ~PB_ENET_PDN;
+ immr->im_cpm.cp_pbdir |= PB_ENET_PDN;
+ immr->im_cpm.cp_pbdat |= PB_ENET_PDN;
+#elif defined(PC_ENET_PDN)
+ immr->im_ioport.iop_pcpar &= ~PC_ENET_PDN;
+ immr->im_ioport.iop_pcdir |= PC_ENET_PDN;
+ immr->im_ioport.iop_pcdat |= PC_ENET_PDN;
+#elif defined(PD_ENET_PDN)
+ immr->im_ioport.iop_pdpar &= ~PD_ENET_PDN;
+ immr->im_ioport.iop_pddir |= PD_ENET_PDN;
+ immr->im_ioport.iop_pddat |= PD_ENET_PDN;
+#endif
+#endif
+
+ /*
+ * Set the ENT/ENR bits in the GSMR Low -- Enable Transmit/Receive
+ */
+
+ immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl |=
+ (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+ /*
+ * Work around transmit problem with first eth packet
+ */
+#if defined (CONFIG_FADS)
+ udelay (10000); /* wait 10 ms */
+#elif defined(CONFIG_RPXCLASSIC)
+ udelay (100000); /* wait 100 ms */
+#endif
+
+ return 1;
+}
+
+
+static void scc_halt (struct eth_device *dev)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl &=
+ ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+ immr->im_ioport.iop_pcso &= ~(PC_ENET_CLSN | PC_ENET_RENA);
+}
+
+#if 0
+void restart (void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+
+ immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl |=
+ (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+}
+#endif
+#endif
diff --git a/arch/powerpc/cpu/mpc8xx/serial.c b/arch/powerpc/cpu/mpc8xx/serial.c
new file mode 100644
index 0000000..00888e9
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/serial.c
@@ -0,0 +1,766 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <commproc.h>
+#include <command.h>
+#include <serial.h>
+#include <watchdog.h>
+#include <linux/compiler.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if !defined(CONFIG_8xx_CONS_NONE) /* No Console at all */
+
+#if defined(CONFIG_8xx_CONS_SMC1) /* Console on SMC1 */
+#define SMC_INDEX 0
+#define PROFF_SMC PROFF_SMC1
+#define CPM_CR_CH_SMC CPM_CR_CH_SMC1
+
+#elif defined(CONFIG_8xx_CONS_SMC2) /* Console on SMC2 */
+#define SMC_INDEX 1
+#define PROFF_SMC PROFF_SMC2
+#define CPM_CR_CH_SMC CPM_CR_CH_SMC2
+
+#endif /* CONFIG_8xx_CONS_SMCx */
+
+#if defined(CONFIG_8xx_CONS_SCC1) /* Console on SCC1 */
+#define SCC_INDEX 0
+#define PROFF_SCC PROFF_SCC1
+#define CPM_CR_CH_SCC CPM_CR_CH_SCC1
+
+#elif defined(CONFIG_8xx_CONS_SCC2) /* Console on SCC2 */
+#define SCC_INDEX 1
+#define PROFF_SCC PROFF_SCC2
+#define CPM_CR_CH_SCC CPM_CR_CH_SCC2
+
+#elif defined(CONFIG_8xx_CONS_SCC3) /* Console on SCC3 */
+#define SCC_INDEX 2
+#define PROFF_SCC PROFF_SCC3
+#define CPM_CR_CH_SCC CPM_CR_CH_SCC3
+
+#elif defined(CONFIG_8xx_CONS_SCC4) /* Console on SCC4 */
+#define SCC_INDEX 3
+#define PROFF_SCC PROFF_SCC4
+#define CPM_CR_CH_SCC CPM_CR_CH_SCC4
+
+#endif /* CONFIG_8xx_CONS_SCCx */
+
+#if !defined(CONFIG_SYS_SMC_RXBUFLEN)
+#define CONFIG_SYS_SMC_RXBUFLEN 1
+#define CONFIG_SYS_MAXIDLE 0
+#else
+#if !defined(CONFIG_SYS_MAXIDLE)
+#error "you must define CONFIG_SYS_MAXIDLE"
+#endif
+#endif
+
+typedef volatile struct serialbuffer {
+ cbd_t rxbd; /* Rx BD */
+ cbd_t txbd; /* Tx BD */
+ uint rxindex; /* index for next character to read */
+ volatile uchar rxbuf[CONFIG_SYS_SMC_RXBUFLEN];/* rx buffers */
+ volatile uchar txbuf; /* tx buffers */
+} serialbuffer_t;
+
+static void serial_setdivisor(volatile cpm8xx_t *cp)
+{
+ int divisor=(gd->cpu_clk + 8*gd->baudrate)/16/gd->baudrate;
+
+ if(divisor/16>0x1000) {
+ /* bad divisor, assume 50MHz clock and 9600 baud */
+ divisor=(50*1000*1000 + 8*9600)/16/9600;
+ }
+
+#ifdef CONFIG_SYS_BRGCLK_PRESCALE
+ divisor /= CONFIG_SYS_BRGCLK_PRESCALE;
+#endif
+
+ if(divisor<=0x1000) {
+ cp->cp_brgc1=((divisor-1)<<1) | CPM_BRG_EN;
+ } else {
+ cp->cp_brgc1=((divisor/16-1)<<1) | CPM_BRG_EN | CPM_BRG_DIV16;
+ }
+}
+
+#if (defined (CONFIG_8xx_CONS_SMC1) || defined (CONFIG_8xx_CONS_SMC2))
+
+/*
+ * Minimal serial functions needed to use one of the SMC ports
+ * as serial console interface.
+ */
+
+static void smc_setbrg (void)
+{
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cp = &(im->im_cpm);
+
+ /* Set up the baud rate generator.
+ * See 8xx_io/commproc.c for details.
+ *
+ * Wire BRG1 to SMCx
+ */
+
+ cp->cp_simode = 0x00000000;
+
+ serial_setdivisor(cp);
+}
+
+static int smc_init (void)
+{
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile smc_t *sp;
+ volatile smc_uart_t *up;
+ volatile cpm8xx_t *cp = &(im->im_cpm);
+#if (!defined(CONFIG_8xx_CONS_SMC1)) && (defined(CONFIG_MPC823) || defined(CONFIG_MPC850))
+ volatile iop8xx_t *ip = (iop8xx_t *)&(im->im_ioport);
+#endif
+ uint dpaddr;
+ volatile serialbuffer_t *rtx;
+
+ /* initialize pointers to SMC */
+
+ sp = (smc_t *) &(cp->cp_smc[SMC_INDEX]);
+ up = (smc_uart_t *) &cp->cp_dparam[PROFF_SMC];
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+ up = (smc_uart_t *) &cp->cp_dpmem[up->smc_rpbase];
+#else
+ /* Disable relocation */
+ up->smc_rpbase = 0;
+#endif
+
+ /* Disable transmitter/receiver. */
+ sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+
+ /* Enable SDMA. */
+ im->im_siu_conf.sc_sdcr = 1;
+
+ /* clear error conditions */
+#ifdef CONFIG_SYS_SDSR
+ im->im_sdma.sdma_sdsr = CONFIG_SYS_SDSR;
+#else
+ im->im_sdma.sdma_sdsr = 0x83;
+#endif
+
+ /* clear SDMA interrupt mask */
+#ifdef CONFIG_SYS_SDMR
+ im->im_sdma.sdma_sdmr = CONFIG_SYS_SDMR;
+#else
+ im->im_sdma.sdma_sdmr = 0x00;
+#endif
+
+#if defined(CONFIG_8xx_CONS_SMC1)
+ /* Use Port B for SMC1 instead of other functions. */
+ cp->cp_pbpar |= 0x000000c0;
+ cp->cp_pbdir &= ~0x000000c0;
+ cp->cp_pbodr &= ~0x000000c0;
+#else /* CONFIG_8xx_CONS_SMC2 */
+# if defined(CONFIG_MPC823) || defined(CONFIG_MPC850)
+ /* Use Port A for SMC2 instead of other functions. */
+ ip->iop_papar |= 0x00c0;
+ ip->iop_padir &= ~0x00c0;
+ ip->iop_paodr &= ~0x00c0;
+# else /* must be a 860 then */
+ /* Use Port B for SMC2 instead of other functions.
+ */
+ cp->cp_pbpar |= 0x00000c00;
+ cp->cp_pbdir &= ~0x00000c00;
+ cp->cp_pbodr &= ~0x00000c00;
+# endif
+#endif
+
+#if defined(CONFIG_FADS) || defined(CONFIG_ADS)
+ /* Enable RS232 */
+#if defined(CONFIG_8xx_CONS_SMC1)
+ *((uint *) BCSR1) &= ~BCSR1_RS232EN_1;
+#else
+ *((uint *) BCSR1) &= ~BCSR1_RS232EN_2;
+#endif
+#endif /* CONFIG_FADS */
+
+#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
+ /* Enable Monitor Port Transceiver */
+ *((uchar *) BCSR0) |= BCSR0_ENMONXCVR ;
+#endif /* CONFIG_RPXLITE */
+
+ /* Set the physical address of the host memory buffers in
+ * the buffer descriptors.
+ */
+
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+ /* allocate
+ * size of struct serialbuffer with bd rx/tx, buffer rx/tx and rx index
+ */
+ dpaddr = dpram_alloc_align((sizeof(serialbuffer_t)), 8);
+#else
+ dpaddr = CPM_SERIAL_BASE ;
+#endif
+
+ rtx = (serialbuffer_t *)&cp->cp_dpmem[dpaddr];
+ /* Allocate space for two buffer descriptors in the DP ram.
+ * For now, this address seems OK, but it may have to
+ * change with newer versions of the firmware.
+ * damm: allocating space after the two buffers for rx/tx data
+ */
+
+ rtx->rxbd.cbd_bufaddr = (uint) &rtx->rxbuf;
+ rtx->rxbd.cbd_sc = 0;
+
+ rtx->txbd.cbd_bufaddr = (uint) &rtx->txbuf;
+ rtx->txbd.cbd_sc = 0;
+
+ /* Set up the uart parameters in the parameter ram. */
+ up->smc_rbase = dpaddr;
+ up->smc_tbase = dpaddr+sizeof(cbd_t);
+ up->smc_rfcr = SMC_EB;
+ up->smc_tfcr = SMC_EB;
+#if defined (CONFIG_SYS_SMC_UCODE_PATCH)
+ up->smc_rbptr = up->smc_rbase;
+ up->smc_tbptr = up->smc_tbase;
+ up->smc_rstate = 0;
+ up->smc_tstate = 0;
+#endif
+
+#if defined(CONFIG_MBX)
+ board_serial_init();
+#endif /* CONFIG_MBX */
+
+ /* Set UART mode, 8 bit, no parity, one stop.
+ * Enable receive and transmit.
+ */
+ sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
+
+ /* Mask all interrupts and remove anything pending.
+ */
+ sp->smc_smcm = 0;
+ sp->smc_smce = 0xff;
+
+#ifdef CONFIG_SYS_SPC1920_SMC1_CLK4
+ /* clock source is PLD */
+
+ /* set freq to 19200 Baud */
+ *((volatile uchar *) CONFIG_SYS_SPC1920_PLD_BASE+6) = 0x3;
+ /* configure clk4 as input */
+ im->im_ioport.iop_pdpar |= 0x800;
+ im->im_ioport.iop_pddir &= ~0x800;
+
+ cp->cp_simode = ((cp->cp_simode & ~0xf000) | 0x7000);
+#else
+ /* Set up the baud rate generator */
+ smc_setbrg ();
+#endif
+
+ /* Make the first buffer the only buffer. */
+ rtx->txbd.cbd_sc |= BD_SC_WRAP;
+ rtx->rxbd.cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+ /* single/multi character receive. */
+ up->smc_mrblr = CONFIG_SYS_SMC_RXBUFLEN;
+ up->smc_maxidl = CONFIG_SYS_MAXIDLE;
+ rtx->rxindex = 0;
+
+ /* Initialize Tx/Rx parameters. */
+ while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
+ ;
+
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+ while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
+ ;
+
+ /* Enable transmitter/receiver. */
+ sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+
+ return (0);
+}
+
+static void
+smc_putc(const char c)
+{
+ volatile smc_uart_t *up;
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cpmp = &(im->im_cpm);
+ volatile serialbuffer_t *rtx;
+
+#ifdef CONFIG_MODEM_SUPPORT
+ if (gd->be_quiet)
+ return;
+#endif
+
+ if (c == '\n')
+ smc_putc ('\r');
+
+ up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+ up = (smc_uart_t *) &cpmp->cp_dpmem[up->smc_rpbase];
+#endif
+
+ rtx = (serialbuffer_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+ /* Wait for last character to go. */
+ rtx->txbuf = c;
+ rtx->txbd.cbd_datlen = 1;
+ rtx->txbd.cbd_sc |= BD_SC_READY;
+ __asm__("eieio");
+
+ while (rtx->txbd.cbd_sc & BD_SC_READY) {
+ WATCHDOG_RESET ();
+ __asm__("eieio");
+ }
+}
+
+static void
+smc_puts (const char *s)
+{
+ while (*s) {
+ smc_putc (*s++);
+ }
+}
+
+static int
+smc_getc(void)
+{
+ volatile smc_uart_t *up;
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cpmp = &(im->im_cpm);
+ volatile serialbuffer_t *rtx;
+ unsigned char c;
+
+ up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+ up = (smc_uart_t *) &cpmp->cp_dpmem[up->smc_rpbase];
+#endif
+ rtx = (serialbuffer_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+ /* Wait for character to show up. */
+ while (rtx->rxbd.cbd_sc & BD_SC_EMPTY)
+ WATCHDOG_RESET ();
+
+ /* the characters are read one by one,
+ * use the rxindex to know the next char to deliver
+ */
+ c = *(unsigned char *) (rtx->rxbd.cbd_bufaddr+rtx->rxindex);
+ rtx->rxindex++;
+
+ /* check if all char are readout, then make prepare for next receive */
+ if (rtx->rxindex >= rtx->rxbd.cbd_datlen) {
+ rtx->rxindex = 0;
+ rtx->rxbd.cbd_sc |= BD_SC_EMPTY;
+ }
+ return(c);
+}
+
+static int
+smc_tstc(void)
+{
+ volatile smc_uart_t *up;
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cpmp = &(im->im_cpm);
+ volatile serialbuffer_t *rtx;
+
+ up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+ up = (smc_uart_t *) &cpmp->cp_dpmem[up->smc_rpbase];
+#endif
+
+ rtx = (serialbuffer_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+ return !(rtx->rxbd.cbd_sc & BD_SC_EMPTY);
+}
+
+struct serial_device serial_smc_device =
+{
+ .name = "serial_smc",
+ .start = smc_init,
+ .stop = NULL,
+ .setbrg = smc_setbrg,
+ .getc = smc_getc,
+ .tstc = smc_tstc,
+ .putc = smc_putc,
+ .puts = smc_puts,
+};
+
+#endif /* CONFIG_8xx_CONS_SMC1 || CONFIG_8xx_CONS_SMC2 */
+
+#if defined(CONFIG_8xx_CONS_SCC1) || defined(CONFIG_8xx_CONS_SCC2) || \
+ defined(CONFIG_8xx_CONS_SCC3) || defined(CONFIG_8xx_CONS_SCC4)
+
+static void
+scc_setbrg (void)
+{
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cp = &(im->im_cpm);
+
+ /* Set up the baud rate generator.
+ * See 8xx_io/commproc.c for details.
+ *
+ * Wire BRG1 to SCCx
+ */
+
+ cp->cp_sicr &= ~(0x000000FF << (8 * SCC_INDEX));
+
+ serial_setdivisor(cp);
+}
+
+static int scc_init (void)
+{
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile scc_t *sp;
+ volatile scc_uart_t *up;
+ volatile cbd_t *tbdf, *rbdf;
+ volatile cpm8xx_t *cp = &(im->im_cpm);
+ uint dpaddr;
+#if (SCC_INDEX != 2) || !defined(CONFIG_MPC850)
+ volatile iop8xx_t *ip = (iop8xx_t *)&(im->im_ioport);
+#endif
+
+ /* initialize pointers to SCC */
+
+ sp = (scc_t *) &(cp->cp_scc[SCC_INDEX]);
+ up = (scc_uart_t *) &cp->cp_dparam[PROFF_SCC];
+
+#if defined(CONFIG_LWMON) && defined(CONFIG_8xx_CONS_SCC2)
+ { /* Disable Ethernet, enable Serial */
+ uchar c;
+
+ c = pic_read (0x61);
+ c &= ~0x40; /* enable COM3 */
+ c |= 0x80; /* disable Ethernet */
+ pic_write (0x61, c);
+
+ /* enable RTS2 */
+ cp->cp_pbpar |= 0x2000;
+ cp->cp_pbdat |= 0x2000;
+ cp->cp_pbdir |= 0x2000;
+ }
+#endif /* CONFIG_LWMON */
+
+ /* Disable transmitter/receiver. */
+ sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+#if (SCC_INDEX == 2) && defined(CONFIG_MPC850)
+ /*
+ * The MPC850 has SCC3 on Port B
+ */
+ cp->cp_pbpar |= 0x06;
+ cp->cp_pbdir &= ~0x06;
+ cp->cp_pbodr &= ~0x06;
+
+#elif (SCC_INDEX < 2) || !defined(CONFIG_IP860)
+ /*
+ * Standard configuration for SCC's is on Part A
+ */
+ ip->iop_papar |= ((3 << (2 * SCC_INDEX)));
+ ip->iop_padir &= ~((3 << (2 * SCC_INDEX)));
+ ip->iop_paodr &= ~((3 << (2 * SCC_INDEX)));
+#else
+ /*
+ * The IP860 has SCC3 and SCC4 on Port D
+ */
+ ip->iop_pdpar |= ((3 << (2 * SCC_INDEX)));
+#endif
+
+ /* Allocate space for two buffer descriptors in the DP ram. */
+
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+ dpaddr = dpram_alloc_align (sizeof(cbd_t)*2 + 2, 8) ;
+#else
+ dpaddr = CPM_SERIAL2_BASE ;
+#endif
+
+ /* Enable SDMA. */
+ im->im_siu_conf.sc_sdcr = 0x0001;
+
+ /* Set the physical address of the host memory buffers in
+ * the buffer descriptors.
+ */
+
+ rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr];
+ rbdf->cbd_bufaddr = (uint) (rbdf+2);
+ rbdf->cbd_sc = 0;
+ tbdf = rbdf + 1;
+ tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
+ tbdf->cbd_sc = 0;
+
+ /* Set up the baud rate generator. */
+ scc_setbrg ();
+
+ /* Set up the uart parameters in the parameter ram. */
+ up->scc_genscc.scc_rbase = dpaddr;
+ up->scc_genscc.scc_tbase = dpaddr+sizeof(cbd_t);
+
+ /* Initialize Tx/Rx parameters. */
+ while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
+ ;
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+
+ while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
+ ;
+
+ up->scc_genscc.scc_rfcr = SCC_EB | 0x05;
+ up->scc_genscc.scc_tfcr = SCC_EB | 0x05;
+
+ up->scc_genscc.scc_mrblr = 1; /* Single character receive */
+ up->scc_maxidl = 0; /* disable max idle */
+ up->scc_brkcr = 1; /* send one break character on stop TX */
+ up->scc_parec = 0;
+ up->scc_frmec = 0;
+ up->scc_nosec = 0;
+ up->scc_brkec = 0;
+ up->scc_uaddr1 = 0;
+ up->scc_uaddr2 = 0;
+ up->scc_toseq = 0;
+ up->scc_char1 = 0x8000;
+ up->scc_char2 = 0x8000;
+ up->scc_char3 = 0x8000;
+ up->scc_char4 = 0x8000;
+ up->scc_char5 = 0x8000;
+ up->scc_char6 = 0x8000;
+ up->scc_char7 = 0x8000;
+ up->scc_char8 = 0x8000;
+ up->scc_rccm = 0xc0ff;
+
+ /* Set low latency / small fifo. */
+ sp->scc_gsmrh = SCC_GSMRH_RFW;
+
+ /* Set SCC(x) clock mode to 16x
+ * See 8xx_io/commproc.c for details.
+ *
+ * Wire BRG1 to SCCn
+ */
+
+ /* Set UART mode, clock divider 16 on Tx and Rx */
+ sp->scc_gsmrl &= ~0xF;
+ sp->scc_gsmrl |=
+ (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+
+ sp->scc_psmr = 0;
+ sp->scc_psmr |= SCU_PSMR_CL;
+
+ /* Mask all interrupts and remove anything pending. */
+ sp->scc_sccm = 0;
+ sp->scc_scce = 0xffff;
+ sp->scc_dsr = 0x7e7e;
+ sp->scc_psmr = 0x3000;
+
+ /* Make the first buffer the only buffer. */
+ tbdf->cbd_sc |= BD_SC_WRAP;
+ rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+ /* Enable transmitter/receiver. */
+ sp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+ return (0);
+}
+
+static void
+scc_putc(const char c)
+{
+ volatile cbd_t *tbdf;
+ volatile char *buf;
+ volatile scc_uart_t *up;
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cpmp = &(im->im_cpm);
+
+#ifdef CONFIG_MODEM_SUPPORT
+ if (gd->be_quiet)
+ return;
+#endif
+
+ if (c == '\n')
+ scc_putc ('\r');
+
+ up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC];
+
+ tbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_tbase];
+
+ /* Wait for last character to go. */
+
+ buf = (char *)tbdf->cbd_bufaddr;
+
+ *buf = c;
+ tbdf->cbd_datlen = 1;
+ tbdf->cbd_sc |= BD_SC_READY;
+ __asm__("eieio");
+
+ while (tbdf->cbd_sc & BD_SC_READY) {
+ __asm__("eieio");
+ WATCHDOG_RESET ();
+ }
+}
+
+static void
+scc_puts (const char *s)
+{
+ while (*s) {
+ scc_putc (*s++);
+ }
+}
+
+static int
+scc_getc(void)
+{
+ volatile cbd_t *rbdf;
+ volatile unsigned char *buf;
+ volatile scc_uart_t *up;
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cpmp = &(im->im_cpm);
+ unsigned char c;
+
+ up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC];
+
+ rbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_rbase];
+
+ /* Wait for character to show up. */
+ buf = (unsigned char *)rbdf->cbd_bufaddr;
+
+ while (rbdf->cbd_sc & BD_SC_EMPTY)
+ WATCHDOG_RESET ();
+
+ c = *buf;
+ rbdf->cbd_sc |= BD_SC_EMPTY;
+
+ return(c);
+}
+
+static int
+scc_tstc(void)
+{
+ volatile cbd_t *rbdf;
+ volatile scc_uart_t *up;
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cpmp = &(im->im_cpm);
+
+ up = (scc_uart_t *)&cpmp->cp_dparam[PROFF_SCC];
+
+ rbdf = (cbd_t *)&cpmp->cp_dpmem[up->scc_genscc.scc_rbase];
+
+ return(!(rbdf->cbd_sc & BD_SC_EMPTY));
+}
+
+struct serial_device serial_scc_device =
+{
+ .name = "serial_scc",
+ .start = scc_init,
+ .stop = NULL,
+ .setbrg = scc_setbrg,
+ .getc = scc_getc,
+ .tstc = scc_tstc,
+ .putc = scc_putc,
+ .puts = scc_puts,
+};
+
+#endif /* CONFIG_8xx_CONS_SCCx */
+
+__weak struct serial_device *default_serial_console(void)
+{
+#if defined(CONFIG_8xx_CONS_SMC1) || defined(CONFIG_8xx_CONS_SMC2)
+ return &serial_smc_device;
+#else
+ return &serial_scc_device;
+#endif
+}
+
+void mpc8xx_serial_initialize(void)
+{
+#if defined(CONFIG_8xx_CONS_SMC1) || defined(CONFIG_8xx_CONS_SMC2)
+ serial_register(&serial_smc_device);
+#endif
+#if defined(CONFIG_8xx_CONS_SCC1) || defined(CONFIG_8xx_CONS_SCC2) || \
+ defined(CONFIG_8xx_CONS_SCC3) || defined(CONFIG_8xx_CONS_SCC4)
+ serial_register(&serial_scc_device);
+#endif
+}
+
+#ifdef CONFIG_MODEM_SUPPORT
+void disable_putc(void)
+{
+ gd->be_quiet = 1;
+}
+
+void enable_putc(void)
+{
+ gd->be_quiet = 0;
+}
+#endif
+
+#if defined(CONFIG_CMD_KGDB)
+
+void
+kgdb_serial_init(void)
+{
+ int i = -1;
+
+ if (strcmp(default_serial_console()->name, "serial_smc") == 0)
+ {
+#if defined(CONFIG_8xx_CONS_SMC1)
+ i = 1;
+#elif defined(CONFIG_8xx_CONS_SMC2)
+ i = 2;
+#endif
+ }
+ else if (strcmp(default_serial_console()->name, "serial_scc") == 0)
+ {
+#if defined(CONFIG_8xx_CONS_SCC1)
+ i = 1;
+#elif defined(CONFIG_8xx_CONS_SCC2)
+ i = 2;
+#elif defined(CONFIG_8xx_CONS_SCC3)
+ i = 3;
+#elif defined(CONFIG_8xx_CONS_SCC4)
+ i = 4;
+#endif
+ }
+
+ if (i >= 0)
+ {
+ serial_printf("[on %s%d] ", default_serial_console()->name, i);
+ }
+}
+
+void
+putDebugChar (int c)
+{
+ serial_putc (c);
+}
+
+void
+putDebugStr (const char *str)
+{
+ serial_puts (str);
+}
+
+int
+getDebugChar (void)
+{
+ return serial_getc();
+}
+
+void
+kgdb_interruptible (int yes)
+{
+ return;
+}
+#endif
+
+#endif /* CONFIG_8xx_CONS_NONE */
diff --git a/arch/powerpc/cpu/mpc8xx/speed.c b/arch/powerpc/cpu/mpc8xx/speed.c
new file mode 100644
index 0000000..091b49f
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/speed.c
@@ -0,0 +1,416 @@
+/*
+ * (C) Copyright 2000-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if !defined(CONFIG_8xx_CPUCLK_DEFAULT) || defined(CONFIG_SYS_MEASURE_CPUCLK) || defined(DEBUG)
+
+#define PITC_SHIFT 16
+#define PITR_SHIFT 16
+/* pitc values to time for 58/8192 seconds (about 70.8 milliseconds) */
+#define SPEED_PIT_COUNTS 58
+#define SPEED_PITC ((SPEED_PIT_COUNTS - 1) << PITC_SHIFT)
+#define SPEED_PITC_INIT ((SPEED_PIT_COUNTS + 1) << PITC_SHIFT)
+
+/* Access functions for the Machine State Register */
+static __inline__ unsigned long get_msr(void)
+{
+ unsigned long msr;
+
+ asm volatile("mfmsr %0" : "=r" (msr) :);
+ return msr;
+}
+
+static __inline__ void set_msr(unsigned long msr)
+{
+ asm volatile("mtmsr %0" : : "r" (msr));
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Measure CPU clock speed (core clock GCLK1, GCLK2),
+ * also determine bus clock speed (checking bus divider factor)
+ *
+ * (Approx. GCLK frequency in Hz)
+ *
+ * Initializes timer 2 and PIT, but disables them before return.
+ * [Use timer 2, because MPC823 CPUs mask 0.x do not have timers 3 and 4]
+ *
+ * When measuring the CPU clock against the PIT, we count cpu clocks
+ * for 58/8192 seconds with a prescale divide by 177 for the cpu clock.
+ * These strange values for the timing interval and prescaling are used
+ * because the formula for the CPU clock is:
+ *
+ * CPU clock = count * (177 * (8192 / 58))
+ *
+ * = count * 24999.7241
+ *
+ * which is very close to
+ *
+ * = count * 25000
+ *
+ * Since the count gives the CPU clock divided by 25000, we can get
+ * the CPU clock rounded to the nearest 0.1 MHz by
+ *
+ * CPU clock = ((count + 2) / 4) * 100000;
+ *
+ * The rounding is important since the measurement is sometimes going
+ * to be high or low by 0.025 MHz, depending on exactly how the clocks
+ * and counters interact. By rounding we get the exact answer for any
+ * CPU clock that is an even multiple of 0.1 MHz.
+ */
+
+unsigned long measure_gclk(void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ volatile cpmtimer8xx_t *timerp = &immr->im_cpmtimer;
+ ulong timer2_val;
+ ulong msr_val;
+
+#ifdef CONFIG_SYS_8XX_XIN
+ /* dont use OSCM, only use EXTCLK/512 */
+ immr->im_clkrst.car_sccr |= SCCR_RTSEL | SCCR_RTDIV;
+#else
+ immr->im_clkrst.car_sccr &= ~(SCCR_RTSEL | SCCR_RTDIV);
+#endif
+
+ /* Reset + Stop Timer 2, no cascading
+ */
+ timerp->cpmt_tgcr &= ~(TGCR_CAS2 | TGCR_RST2);
+
+ /* Keep stopped, halt in debug mode
+ */
+ timerp->cpmt_tgcr |= (TGCR_FRZ2 | TGCR_STP2);
+
+ /* Timer 2 setup:
+ * Output ref. interrupt disable, int. clock
+ * Prescale by 177. Note that prescaler divides by value + 1
+ * so we must subtract 1 here.
+ */
+ timerp->cpmt_tmr2 = ((177 - 1) << TMR_PS_SHIFT) | TMR_ICLK_IN_GEN;
+
+ timerp->cpmt_tcn2 = 0; /* reset state */
+ timerp->cpmt_tgcr |= TGCR_RST2; /* enable timer 2 */
+
+ /*
+ * PIT setup:
+ *
+ * We want to time for SPEED_PITC_COUNTS counts (of 8192 Hz),
+ * so the count value would be SPEED_PITC_COUNTS - 1.
+ * But there would be an uncertainty in the start time of 1/4
+ * count since when we enable the PIT the count is not
+ * synchronized to the 32768 Hz oscillator. The trick here is
+ * to start the count higher and wait until the PIT count
+ * changes to the required value before starting timer 2.
+ *
+ * One count high should be enough, but occasionally the start
+ * is off by 1 or 2 counts of 32768 Hz. With the start value
+ * set two counts high it seems very reliable.
+ */
+
+ immr->im_sitk.sitk_pitck = KAPWR_KEY; /* PIT initialization */
+ immr->im_sit.sit_pitc = SPEED_PITC_INIT;
+
+ immr->im_sitk.sitk_piscrk = KAPWR_KEY;
+ immr->im_sit.sit_piscr = CONFIG_SYS_PISCR;
+
+ /*
+ * Start measurement - disable interrupts, just in case
+ */
+ msr_val = get_msr ();
+ set_msr (msr_val & ~MSR_EE);
+
+ immr->im_sit.sit_piscr |= PISCR_PTE;
+
+ /* spin until get exact count when we want to start */
+ while (immr->im_sit.sit_pitr > SPEED_PITC);
+
+ timerp->cpmt_tgcr &= ~TGCR_STP2; /* Start Timer 2 */
+ while ((immr->im_sit.sit_piscr & PISCR_PS) == 0);
+ timerp->cpmt_tgcr |= TGCR_STP2; /* Stop Timer 2 */
+
+ /* re-enable external interrupts if they were on */
+ set_msr (msr_val);
+
+ /* Disable timer and PIT
+ */
+ timer2_val = timerp->cpmt_tcn2; /* save before reset timer */
+
+ timerp->cpmt_tgcr &= ~(TGCR_RST2 | TGCR_FRZ2 | TGCR_STP2);
+ immr->im_sit.sit_piscr &= ~PISCR_PTE;
+
+#if defined(CONFIG_SYS_8XX_XIN)
+ /* not using OSCM, using XIN, so scale appropriately */
+ return (((timer2_val + 2) / 4) * (CONFIG_SYS_8XX_XIN/512))/8192 * 100000L;
+#else
+ return ((timer2_val + 2) / 4) * 100000L; /* convert to Hz */
+#endif
+}
+
+#endif
+
+void get_brgclk(uint sccr)
+{
+ uint divider = 0;
+
+ switch((sccr&SCCR_DFBRG11)>>11){
+ case 0:
+ divider = 1;
+ break;
+ case 1:
+ divider = 4;
+ break;
+ case 2:
+ divider = 16;
+ break;
+ case 3:
+ divider = 64;
+ break;
+ }
+ gd->arch.brg_clk = gd->cpu_clk/divider;
+}
+
+#if !defined(CONFIG_8xx_CPUCLK_DEFAULT)
+
+/*
+ * get_clocks() fills in gd->cpu_clock depending on CONFIG_8xx_GCLK_FREQ
+ * or (if it is not defined) measure_gclk() (which uses the ref clock)
+ * from above.
+ */
+int get_clocks (void)
+{
+ uint immr = get_immr (0); /* Return full IMMR contents */
+ volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
+ uint sccr = immap->im_clkrst.car_sccr;
+ /*
+ * If for some reason measuring the gclk frequency won't
+ * work, we return the hardwired value.
+ * (For example, the cogent CMA286-60 CPU module has no
+ * separate oscillator for PITRTCLK)
+ */
+#if defined(CONFIG_8xx_GCLK_FREQ)
+ gd->cpu_clk = CONFIG_8xx_GCLK_FREQ;
+#elif defined(CONFIG_8xx_OSCLK)
+#define PLPRCR_val(a) ((pll & PLPRCR_ ## a ## _MSK) >> PLPRCR_ ## a ## _SHIFT)
+ uint pll = immap->im_clkrst.car_plprcr;
+ uint clk;
+
+ if ((immr & 0x0FFF) >= MPC8xx_NEW_CLK) { /* MPC866/87x/88x series */
+ clk = ((CONFIG_8xx_OSCLK / (PLPRCR_val(PDF)+1)) *
+ (PLPRCR_val(MFI) + PLPRCR_val(MFN) / (PLPRCR_val(MFD)+1))) /
+ (1<<PLPRCR_val(S));
+ } else {
+ clk = CONFIG_8xx_OSCLK * (PLPRCR_val(MF)+1);
+ }
+ if (pll & PLPRCR_CSRC) { /* Low frequency division factor is used */
+ gd->cpu_clk = clk / (2 << ((sccr >> 8) & 7));
+ } else { /* High frequency division factor is used */
+ gd->cpu_clk = clk / (1 << ((sccr >> 5) & 7));
+ }
+#else
+ gd->cpu_clk = measure_gclk();
+#endif /* CONFIG_8xx_GCLK_FREQ */
+
+ if ((sccr & SCCR_EBDF11) == 0) {
+ /* No Bus Divider active */
+ gd->bus_clk = gd->cpu_clk;
+ } else {
+ /* The MPC8xx has only one BDF: half clock speed */
+ gd->bus_clk = gd->cpu_clk / 2;
+ }
+
+ get_brgclk(sccr);
+
+ return (0);
+}
+
+#else /* CONFIG_8xx_CPUCLK_DEFAULT defined, use dynamic clock setting */
+
+static long init_pll_866 (long clk);
+
+/* This function sets up PLL (init_pll_866() is called) and
+ * fills gd->cpu_clk and gd->bus_clk according to the environment
+ * variable 'cpuclk' or to CONFIG_8xx_CPUCLK_DEFAULT (if 'cpuclk'
+ * contains invalid value).
+ * This functions requires an MPC866 or newer series CPU.
+ */
+int get_clocks_866 (void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ char tmp[64];
+ long cpuclk = 0;
+ long sccr_reg;
+
+ if (getenv_f("cpuclk", tmp, sizeof (tmp)) > 0)
+ cpuclk = simple_strtoul (tmp, NULL, 10) * 1000000;
+
+ if ((CONFIG_SYS_8xx_CPUCLK_MIN > cpuclk) || (CONFIG_SYS_8xx_CPUCLK_MAX < cpuclk))
+ cpuclk = CONFIG_8xx_CPUCLK_DEFAULT;
+
+ gd->cpu_clk = init_pll_866 (cpuclk);
+#if defined(CONFIG_SYS_MEASURE_CPUCLK)
+ gd->cpu_clk = measure_gclk ();
+#endif
+
+ get_brgclk(immr->im_clkrst.car_sccr);
+
+ /* if cpu clock <= 66 MHz then set bus division factor to 1,
+ * otherwise set it to 2
+ */
+ sccr_reg = immr->im_clkrst.car_sccr;
+ sccr_reg &= ~SCCR_EBDF11;
+
+ if (gd->cpu_clk <= 66000000) {
+ sccr_reg |= SCCR_EBDF00; /* bus division factor = 1 */
+ gd->bus_clk = gd->cpu_clk;
+ } else {
+ sccr_reg |= SCCR_EBDF01; /* bus division factor = 2 */
+ gd->bus_clk = gd->cpu_clk / 2;
+ }
+ immr->im_clkrst.car_sccr = sccr_reg;
+
+ return (0);
+}
+
+/* Adjust sdram refresh rate to actual CPU clock.
+ */
+int sdram_adjust_866 (void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ long mamr;
+
+ mamr = immr->im_memctl.memc_mamr;
+ mamr &= ~MAMR_PTA_MSK;
+ mamr |= ((gd->cpu_clk / CONFIG_SYS_PTA_PER_CLK) << MAMR_PTA_SHIFT);
+ immr->im_memctl.memc_mamr = mamr;
+
+ return (0);
+}
+
+/* Configure PLL for MPC866/859/885 CPU series
+ * PLL multiplication factor is set to the value nearest to the desired clk,
+ * assuming a oscclk of 10 MHz.
+ */
+static long init_pll_866 (long clk)
+{
+ extern void plprcr_write_866 (long);
+
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ long n, plprcr;
+ char mfi, mfn, mfd, s, pdf;
+ long step_mfi, step_mfn;
+
+ if (clk < 20000000) {
+ clk *= 2;
+ pdf = 1;
+ } else {
+ pdf = 0;
+ }
+
+ if (clk < 40000000) {
+ s = 2;
+ step_mfi = CONFIG_8xx_OSCLK / 4;
+ mfd = 7;
+ step_mfn = CONFIG_8xx_OSCLK / 30;
+ } else if (clk < 80000000) {
+ s = 1;
+ step_mfi = CONFIG_8xx_OSCLK / 2;
+ mfd = 14;
+ step_mfn = CONFIG_8xx_OSCLK / 30;
+ } else {
+ s = 0;
+ step_mfi = CONFIG_8xx_OSCLK;
+ mfd = 29;
+ step_mfn = CONFIG_8xx_OSCLK / 30;
+ }
+
+ /* Calculate integer part of multiplication factor
+ */
+ n = clk / step_mfi;
+ mfi = (char)n;
+
+ /* Calculate numerator of fractional part of multiplication factor
+ */
+ n = clk - (n * step_mfi);
+ mfn = (char)(n / step_mfn);
+
+ /* Calculate effective clk
+ */
+ n = ((mfi * step_mfi) + (mfn * step_mfn)) / (pdf + 1);
+
+ immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
+
+ plprcr = (immr->im_clkrst.car_plprcr & ~(PLPRCR_MFN_MSK
+ | PLPRCR_MFD_MSK | PLPRCR_S_MSK
+ | PLPRCR_MFI_MSK | PLPRCR_DBRMO
+ | PLPRCR_PDF_MSK))
+ | (mfn << PLPRCR_MFN_SHIFT)
+ | (mfd << PLPRCR_MFD_SHIFT)
+ | (s << PLPRCR_S_SHIFT)
+ | (mfi << PLPRCR_MFI_SHIFT)
+ | (pdf << PLPRCR_PDF_SHIFT);
+
+ if( (mfn > 0) && ((mfd / mfn) > 10) )
+ plprcr |= PLPRCR_DBRMO;
+
+ plprcr_write_866 (plprcr); /* set value using SIU4/9 workaround */
+ immr->im_clkrstk.cark_plprcrk = 0x00000000;
+
+ return (n);
+}
+
+#endif /* CONFIG_8xx_CPUCLK_DEFAULT */
+
+#if defined(CONFIG_TQM8xxL) && !defined(CONFIG_TQM866M) \
+ && !defined(CONFIG_TQM885D)
+/*
+ * Adjust sdram refresh rate to actual CPU clock
+ * and set timebase source according to actual CPU clock
+ */
+int adjust_sdram_tbs_8xx (void)
+{
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ long mamr;
+ long sccr;
+
+ mamr = immr->im_memctl.memc_mamr;
+ mamr &= ~MAMR_PTA_MSK;
+ mamr |= ((gd->cpu_clk / CONFIG_SYS_PTA_PER_CLK) << MAMR_PTA_SHIFT);
+ immr->im_memctl.memc_mamr = mamr;
+
+ if (gd->cpu_clk < 67000000) {
+ sccr = immr->im_clkrst.car_sccr;
+ sccr |= SCCR_TBS;
+ immr->im_clkrst.car_sccr = sccr;
+ }
+
+ return (0);
+}
+#endif /* CONFIG_TQM8xxL/M, !TQM866M, !TQM885D */
+
+/* ------------------------------------------------------------------------- */
diff --git a/arch/powerpc/cpu/mpc8xx/spi.c b/arch/powerpc/cpu/mpc8xx/spi.c
new file mode 100644
index 0000000..db34852
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/spi.c
@@ -0,0 +1,556 @@
+/*
+ * Copyright (c) 2001 Navin Boppuri / Prashant Patel
+ * <nboppuri@trinetcommunication.com>,
+ * <pmpatel@trinetcommunication.com>
+ * Copyright (c) 2001 Gerd Mennchen <Gerd.Mennchen@icn.siemens.de>
+ * Copyright (c) 2001 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * MPC8xx CPM SPI interface.
+ *
+ * Parts of this code are probably not portable and/or specific to
+ * the board which I used for the tests. Please send fixes/complaints
+ * to wd@denx.de
+ *
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <commproc.h>
+#include <linux/ctype.h>
+#include <malloc.h>
+#include <post.h>
+#include <serial.h>
+
+#if (defined(CONFIG_SPI)) || (CONFIG_POST & CONFIG_SYS_POST_SPI)
+
+/* Warning:
+ * You cannot enable DEBUG for early system initalization, i. e. when
+ * this driver is used to read environment parameters like "baudrate"
+ * from EEPROM which are used to initialize the serial port which is
+ * needed to print the debug messages...
+ */
+#undef DEBUG
+
+#define SPI_EEPROM_WREN 0x06
+#define SPI_EEPROM_RDSR 0x05
+#define SPI_EEPROM_READ 0x03
+#define SPI_EEPROM_WRITE 0x02
+
+/* ---------------------------------------------------------------
+ * Offset for initial SPI buffers in DPRAM:
+ * We need a 520 byte scratch DPRAM area to use at an early stage.
+ * It is used between the two initialization calls (spi_init_f()
+ * and spi_init_r()).
+ * The value 0xb00 makes it far enough from the start of the data
+ * area (as well as from the stack pointer).
+ * --------------------------------------------------------------- */
+#ifndef CONFIG_SYS_SPI_INIT_OFFSET
+#define CONFIG_SYS_SPI_INIT_OFFSET 0xB00
+#endif
+
+#ifdef DEBUG
+
+#define DPRINT(a) printf a;
+/* -----------------------------------------------
+ * Helper functions to peek into tx and rx buffers
+ * ----------------------------------------------- */
+static const char * const hex_digit = "0123456789ABCDEF";
+
+static char quickhex (int i)
+{
+ return hex_digit[i];
+}
+
+static void memdump (void *pv, int num)
+{
+ int i;
+ unsigned char *pc = (unsigned char *) pv;
+
+ for (i = 0; i < num; i++)
+ printf ("%c%c ", quickhex (pc[i] >> 4), quickhex (pc[i] & 0x0f));
+ printf ("\t");
+ for (i = 0; i < num; i++)
+ printf ("%c", isprint (pc[i]) ? pc[i] : '.');
+ printf ("\n");
+}
+#else /* !DEBUG */
+
+#define DPRINT(a)
+
+#endif /* DEBUG */
+
+/* -------------------
+ * Function prototypes
+ * ------------------- */
+void spi_init (void);
+
+ssize_t spi_read (uchar *, int, uchar *, int);
+ssize_t spi_write (uchar *, int, uchar *, int);
+ssize_t spi_xfer (size_t);
+
+/* -------------------
+ * Variables
+ * ------------------- */
+
+#define MAX_BUFFER 0x104
+
+/* ----------------------------------------------------------------------
+ * Initially we place the RX and TX buffers at a fixed location in DPRAM!
+ * ---------------------------------------------------------------------- */
+static uchar *rxbuf =
+ (uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem
+ [CONFIG_SYS_SPI_INIT_OFFSET];
+static uchar *txbuf =
+ (uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem
+ [CONFIG_SYS_SPI_INIT_OFFSET+MAX_BUFFER];
+
+/* **************************************************************************
+ *
+ * Function: spi_init_f
+ *
+ * Description: Init SPI-Controller (ROM part)
+ *
+ * return: ---
+ *
+ * *********************************************************************** */
+void spi_init_f (void)
+{
+ unsigned int dpaddr;
+
+ volatile spi_t *spi;
+ volatile immap_t *immr;
+ volatile cpm8xx_t *cp;
+ volatile cbd_t *tbdf, *rbdf;
+
+ immr = (immap_t *) CONFIG_SYS_IMMR;
+ cp = (cpm8xx_t *) &immr->im_cpm;
+
+#ifdef CONFIG_SYS_SPI_UCODE_PATCH
+ spi = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
+#else
+ spi = (spi_t *)&cp->cp_dparam[PROFF_SPI];
+ /* Disable relocation */
+ spi->spi_rpbase = 0;
+#endif
+
+/* 1 */
+ /* ------------------------------------------------
+ * Initialize Port B SPI pins -> page 34-8 MPC860UM
+ * (we are only in Master Mode !)
+ * ------------------------------------------------ */
+
+ /* --------------------------------------------
+ * GPIO or per. Function
+ * PBPAR[28] = 1 [0x00000008] -> PERI: (SPIMISO)
+ * PBPAR[29] = 1 [0x00000004] -> PERI: (SPIMOSI)
+ * PBPAR[30] = 1 [0x00000002] -> PERI: (SPICLK)
+ * PBPAR[31] = 0 [0x00000001] -> GPIO: (CS for PCUE/CCM-EEPROM)
+ * -------------------------------------------- */
+ cp->cp_pbpar |= 0x0000000E; /* set bits */
+ cp->cp_pbpar &= ~0x00000001; /* reset bit */
+
+ /* ----------------------------------------------
+ * In/Out or per. Function 0/1
+ * PBDIR[28] = 1 [0x00000008] -> PERI1: SPIMISO
+ * PBDIR[29] = 1 [0x00000004] -> PERI1: SPIMOSI
+ * PBDIR[30] = 1 [0x00000002] -> PERI1: SPICLK
+ * PBDIR[31] = 1 [0x00000001] -> GPIO OUT: CS for PCUE/CCM-EEPROM
+ * ---------------------------------------------- */
+ cp->cp_pbdir |= 0x0000000F;
+
+ /* ----------------------------------------------
+ * open drain or active output
+ * PBODR[28] = 1 [0x00000008] -> open drain: SPIMISO
+ * PBODR[29] = 0 [0x00000004] -> active output SPIMOSI
+ * PBODR[30] = 0 [0x00000002] -> active output: SPICLK
+ * PBODR[31] = 0 [0x00000001] -> active output: GPIO OUT: CS for PCUE/CCM
+ * ---------------------------------------------- */
+
+ cp->cp_pbodr |= 0x00000008;
+ cp->cp_pbodr &= ~0x00000007;
+
+ /* Initialize the parameter ram.
+ * We need to make sure many things are initialized to zero
+ */
+ spi->spi_rstate = 0;
+ spi->spi_rdp = 0;
+ spi->spi_rbptr = 0;
+ spi->spi_rbc = 0;
+ spi->spi_rxtmp = 0;
+ spi->spi_tstate = 0;
+ spi->spi_tdp = 0;
+ spi->spi_tbptr = 0;
+ spi->spi_tbc = 0;
+ spi->spi_txtmp = 0;
+
+ /* Allocate space for one transmit and one receive buffer
+ * descriptor in the DP ram
+ */
+#ifdef CONFIG_SYS_ALLOC_DPRAM
+ dpaddr = dpram_alloc_align (sizeof(cbd_t)*2, 8);
+#else
+ dpaddr = CPM_SPI_BASE;
+#endif
+
+/* 3 */
+ /* Set up the SPI parameters in the parameter ram */
+ spi->spi_rbase = dpaddr;
+ spi->spi_tbase = dpaddr + sizeof (cbd_t);
+
+ /***********IMPORTANT******************/
+
+ /*
+ * Setting transmit and receive buffer descriptor pointers
+ * initially to rbase and tbase. Only the microcode patches
+ * documentation talks about initializing this pointer. This
+ * is missing from the sample I2C driver. If you dont
+ * initialize these pointers, the kernel hangs.
+ */
+ spi->spi_rbptr = spi->spi_rbase;
+ spi->spi_tbptr = spi->spi_tbase;
+
+/* 4 */
+#ifdef CONFIG_SYS_SPI_UCODE_PATCH
+ /*
+ * Initialize required parameters if using microcode patch.
+ */
+ spi->spi_rstate = 0;
+ spi->spi_tstate = 0;
+#else
+ /* Init SPI Tx + Rx Parameters */
+ while (cp->cp_cpcr & CPM_CR_FLG)
+ ;
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SPI, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ while (cp->cp_cpcr & CPM_CR_FLG)
+ ;
+#endif /* CONFIG_SYS_SPI_UCODE_PATCH */
+
+/* 5 */
+ /* Set SDMA configuration register */
+ immr->im_siu_conf.sc_sdcr = 0x0001;
+
+/* 6 */
+ /* Set to big endian. */
+ spi->spi_tfcr = SMC_EB;
+ spi->spi_rfcr = SMC_EB;
+
+/* 7 */
+ /* Set maximum receive size. */
+ spi->spi_mrblr = MAX_BUFFER;
+
+/* 8 + 9 */
+ /* tx and rx buffer descriptors */
+ tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
+ rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
+
+ tbdf->cbd_sc &= ~BD_SC_READY;
+ rbdf->cbd_sc &= ~BD_SC_EMPTY;
+
+ /* Set the bd's rx and tx buffer address pointers */
+ rbdf->cbd_bufaddr = (ulong) rxbuf;
+ tbdf->cbd_bufaddr = (ulong) txbuf;
+
+/* 10 + 11 */
+ cp->cp_spim = 0; /* Mask all SPI events */
+ cp->cp_spie = SPI_EMASK; /* Clear all SPI events */
+
+ return;
+}
+
+/* **************************************************************************
+ *
+ * Function: spi_init_r
+ *
+ * Description: Init SPI-Controller (RAM part) -
+ * The malloc engine is ready and we can move our buffers to
+ * normal RAM
+ *
+ * return: ---
+ *
+ * *********************************************************************** */
+void spi_init_r (void)
+{
+ volatile cpm8xx_t *cp;
+ volatile spi_t *spi;
+ volatile immap_t *immr;
+ volatile cbd_t *tbdf, *rbdf;
+
+ immr = (immap_t *) CONFIG_SYS_IMMR;
+ cp = (cpm8xx_t *) &immr->im_cpm;
+
+#ifdef CONFIG_SYS_SPI_UCODE_PATCH
+ spi = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
+#else
+ spi = (spi_t *)&cp->cp_dparam[PROFF_SPI];
+ /* Disable relocation */
+ spi->spi_rpbase = 0;
+#endif
+
+ /* tx and rx buffer descriptors */
+ tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
+ rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
+
+ /* Allocate memory for RX and TX buffers */
+ rxbuf = (uchar *) malloc (MAX_BUFFER);
+ txbuf = (uchar *) malloc (MAX_BUFFER);
+
+ rbdf->cbd_bufaddr = (ulong) rxbuf;
+ tbdf->cbd_bufaddr = (ulong) txbuf;
+
+ return;
+}
+
+/****************************************************************************
+ * Function: spi_write
+ **************************************************************************** */
+ssize_t spi_write (uchar *addr, int alen, uchar *buffer, int len)
+{
+ int i;
+
+ memset(rxbuf, 0, MAX_BUFFER);
+ memset(txbuf, 0, MAX_BUFFER);
+ *txbuf = SPI_EEPROM_WREN; /* write enable */
+ spi_xfer(1);
+ memcpy(txbuf, addr, alen);
+ *txbuf = SPI_EEPROM_WRITE; /* WRITE memory array */
+ memcpy(alen + txbuf, buffer, len);
+ spi_xfer(alen + len);
+ /* ignore received data */
+ for (i = 0; i < 1000; i++) {
+ *txbuf = SPI_EEPROM_RDSR; /* read status */
+ txbuf[1] = 0;
+ spi_xfer(2);
+ if (!(rxbuf[1] & 1)) {
+ break;
+ }
+ udelay(1000);
+ }
+ if (i >= 1000) {
+ printf ("*** spi_write: Time out while writing!\n");
+ }
+
+ return len;
+}
+
+/****************************************************************************
+ * Function: spi_read
+ **************************************************************************** */
+ssize_t spi_read (uchar *addr, int alen, uchar *buffer, int len)
+{
+ memset(rxbuf, 0, MAX_BUFFER);
+ memset(txbuf, 0, MAX_BUFFER);
+ memcpy(txbuf, addr, alen);
+ *txbuf = SPI_EEPROM_READ; /* READ memory array */
+
+ /*
+ * There is a bug in 860T (?) that cuts the last byte of input
+ * if we're reading into DPRAM. The solution we choose here is
+ * to always read len+1 bytes (we have one extra byte at the
+ * end of the buffer).
+ */
+ spi_xfer(alen + len + 1);
+ memcpy(buffer, alen + rxbuf, len);
+
+ return len;
+}
+
+/****************************************************************************
+ * Function: spi_xfer
+ **************************************************************************** */
+ssize_t spi_xfer (size_t count)
+{
+ volatile immap_t *immr;
+ volatile cpm8xx_t *cp;
+ volatile spi_t *spi;
+ cbd_t *tbdf, *rbdf;
+ ushort loop;
+ int tm;
+
+ DPRINT (("*** spi_xfer entered ***\n"));
+
+ immr = (immap_t *) CONFIG_SYS_IMMR;
+ cp = (cpm8xx_t *) &immr->im_cpm;
+
+#ifdef CONFIG_SYS_SPI_UCODE_PATCH
+ spi = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
+#else
+ spi = (spi_t *)&cp->cp_dparam[PROFF_SPI];
+ /* Disable relocation */
+ spi->spi_rpbase = 0;
+#endif
+
+ tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
+ rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
+
+ /* Set CS for device */
+ cp->cp_pbdat &= ~0x0001;
+
+ /* Setting tx bd status and data length */
+ tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP;
+ tbdf->cbd_datlen = count;
+
+ DPRINT (("*** spi_xfer: Bytes to be xferred: %d ***\n",
+ tbdf->cbd_datlen));
+
+ /* Setting rx bd status and data length */
+ rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+ rbdf->cbd_datlen = 0; /* rx length has no significance */
+
+ loop = cp->cp_spmode & SPMODE_LOOP;
+ cp->cp_spmode = /*SPMODE_DIV16 |*/ /* BRG/16 mode not used here */
+ loop |
+ SPMODE_REV |
+ SPMODE_MSTR |
+ SPMODE_EN |
+ SPMODE_LEN(8) | /* 8 Bits per char */
+ SPMODE_PM(0x8) ; /* medium speed */
+ cp->cp_spim = 0; /* Mask all SPI events */
+ cp->cp_spie = SPI_EMASK; /* Clear all SPI events */
+
+ /* start spi transfer */
+ DPRINT (("*** spi_xfer: Performing transfer ...\n"));
+ cp->cp_spcom |= SPI_STR; /* Start transmit */
+
+ /* --------------------------------
+ * Wait for SPI transmit to get out
+ * or time out (1 second = 1000 ms)
+ * -------------------------------- */
+ for (tm=0; tm<1000; ++tm) {
+ if (cp->cp_spie & SPI_TXB) { /* Tx Buffer Empty */
+ DPRINT (("*** spi_xfer: Tx buffer empty\n"));
+ break;
+ }
+ if ((tbdf->cbd_sc & BD_SC_READY) == 0) {
+ DPRINT (("*** spi_xfer: Tx BD done\n"));
+ break;
+ }
+ udelay (1000);
+ }
+ if (tm >= 1000) {
+ printf ("*** spi_xfer: Time out while xferring to/from SPI!\n");
+ }
+ DPRINT (("*** spi_xfer: ... transfer ended\n"));
+
+#ifdef DEBUG
+ printf ("\nspi_xfer: txbuf after xfer\n");
+ memdump ((void *) txbuf, 16); /* dump of txbuf before transmit */
+ printf ("spi_xfer: rxbuf after xfer\n");
+ memdump ((void *) rxbuf, 16); /* dump of rxbuf after transmit */
+ printf ("\n");
+#endif
+
+ /* Clear CS for device */
+ cp->cp_pbdat |= 0x0001;
+
+ return count;
+}
+#endif /* CONFIG_SPI || (CONFIG_POST & CONFIG_SYS_POST_SPI) */
+
+/*
+ * SPI test
+ *
+ * The Serial Peripheral Interface (SPI) is tested in the local loopback mode.
+ * The interface is configured accordingly and several packets
+ * are transfered. The configurable test parameters are:
+ * TEST_MIN_LENGTH - minimum size of packet to transfer
+ * TEST_MAX_LENGTH - maximum size of packet to transfer
+ * TEST_NUM - number of tests
+ */
+
+#if CONFIG_POST & CONFIG_SYS_POST_SPI
+
+#define TEST_MIN_LENGTH 1
+#define TEST_MAX_LENGTH MAX_BUFFER
+#define TEST_NUM 1
+
+static void packet_fill (char * packet, int length)
+{
+ char c = (char) length;
+ int i;
+
+ for (i = 0; i < length; i++)
+ {
+ packet[i] = c++;
+ }
+}
+
+static int packet_check (char * packet, int length)
+{
+ char c = (char) length;
+ int i;
+
+ for (i = 0; i < length; i++) {
+ if (packet[i] != c++) return -1;
+ }
+
+ return 0;
+}
+
+int spi_post_test (int flags)
+{
+ int res = -1;
+ volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+ volatile cpm8xx_t *cp = (cpm8xx_t *) & immr->im_cpm;
+ int i;
+ int l;
+
+ spi_init_f ();
+ spi_init_r ();
+
+ cp->cp_spmode |= SPMODE_LOOP;
+
+ for (i = 0; i < TEST_NUM; i++) {
+ for (l = TEST_MIN_LENGTH; l <= TEST_MAX_LENGTH; l += 8) {
+ packet_fill ((char *)txbuf, l);
+
+ spi_xfer (l);
+
+ if (packet_check ((char *)rxbuf, l) < 0) {
+ goto Done;
+ }
+ }
+ }
+
+ res = 0;
+
+ Done:
+
+ cp->cp_spmode &= ~SPMODE_LOOP;
+
+ /*
+ * SCC2 parameter RAM space overlaps
+ * the SPI parameter RAM space. So we need to restore
+ * the SCC2 configuration if it is used by UART.
+ */
+
+#if !defined(CONFIG_8xx_CONS_NONE)
+ serial_reinit_all ();
+#endif
+
+ if (res != 0) {
+ post_log ("SPI test failed\n");
+ }
+
+ return res;
+}
+#endif /* CONFIG_POST & CONFIG_SYS_POST_SPI */
diff --git a/arch/powerpc/cpu/mpc8xx/start.S b/arch/powerpc/cpu/mpc8xx/start.S
new file mode 100644
index 0000000..5aa50c5
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/start.S
@@ -0,0 +1,669 @@
+/*
+ * Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2000,2001,2002 Wolfgang Denk <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* U-Boot - Startup Code for PowerPC based Embedded Boards
+ *
+ *
+ * The processor starts at 0x00000100 and the code is executed
+ * from flash. The code is organized to be at an other address
+ * in memory, but as long we don't jump around before relocating,
+ * board_init lies at a quite high address and when the cpu has
+ * jumped there, everything is ok.
+ * This works because the cpu gives the FLASH (CS0) the whole
+ * address space at startup, and board_init lies as a echo of
+ * the flash somewhere up there in the memory map.
+ *
+ * board_init will change CS0 to be positioned at the correct
+ * address and (s)dram will be positioned at address 0
+ */
+#include <asm-offsets.h>
+#include <config.h>
+#include <mpc8xx.h>
+#include <version.h>
+
+#define CONFIG_8xx 1 /* needed for Linux kernel header files */
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+#include <asm/u-boot.h>
+
+/* We don't want the MMU yet.
+*/
+#undef MSR_KERNEL
+#define MSR_KERNEL ( MSR_ME | MSR_RI ) /* Machine Check and Recoverable Interr. */
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+ START_GOT
+ GOT_ENTRY(_GOT2_TABLE_)
+ GOT_ENTRY(_FIXUP_TABLE_)
+
+ GOT_ENTRY(_start)
+ GOT_ENTRY(_start_of_vectors)
+ GOT_ENTRY(_end_of_vectors)
+ GOT_ENTRY(transfer_to_handler)
+
+ GOT_ENTRY(__init_end)
+ GOT_ENTRY(__bss_end)
+ GOT_ENTRY(__bss_start)
+ END_GOT
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+ .text
+ .long 0x27051956 /* U-Boot Magic Number */
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION_STRING, "\0"
+
+ . = EXC_OFF_SYS_RESET
+ .globl _start
+_start:
+ lis r3, CONFIG_SYS_IMMR@h /* position IMMR */
+ mtspr 638, r3
+
+ /* Initialize machine status; enable machine check interrupt */
+ /*----------------------------------------------------------------------*/
+ li r3, MSR_KERNEL /* Set ME, RI flags */
+ mtmsr r3
+ mtspr SRR1, r3 /* Make SRR1 match MSR */
+
+ mfspr r3, ICR /* clear Interrupt Cause Register */
+
+ /* Initialize debug port registers */
+ /*----------------------------------------------------------------------*/
+ xor r0, r0, r0 /* Clear R0 */
+ mtspr LCTRL1, r0 /* Initialize debug port regs */
+ mtspr LCTRL2, r0
+ mtspr COUNTA, r0
+ mtspr COUNTB, r0
+
+ /* Reset the caches */
+ /*----------------------------------------------------------------------*/
+
+ mfspr r3, IC_CST /* Clear error bits */
+ mfspr r3, DC_CST
+
+ lis r3, IDC_UNALL@h /* Unlock all */
+ mtspr IC_CST, r3
+ mtspr DC_CST, r3
+
+ lis r3, IDC_INVALL@h /* Invalidate all */
+ mtspr IC_CST, r3
+ mtspr DC_CST, r3
+
+ lis r3, IDC_DISABLE@h /* Disable data cache */
+ mtspr DC_CST, r3
+
+#if !defined(CONFIG_SYS_DELAYED_ICACHE)
+ /* On IP860 and PCU E,
+ * we cannot enable IC yet
+ */
+ lis r3, IDC_ENABLE@h /* Enable instruction cache */
+#endif
+ mtspr IC_CST, r3
+
+ /* invalidate all tlb's */
+ /*----------------------------------------------------------------------*/
+
+ tlbia
+ isync
+
+ /*
+ * Calculate absolute address in FLASH and jump there
+ *----------------------------------------------------------------------*/
+
+ lis r3, CONFIG_SYS_MONITOR_BASE@h
+ ori r3, r3, CONFIG_SYS_MONITOR_BASE@l
+ addi r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
+ mtlr r3
+ blr
+
+in_flash:
+
+ /* initialize some SPRs that are hard to access from C */
+ /*----------------------------------------------------------------------*/
+
+ lis r3, CONFIG_SYS_IMMR@h /* pass IMMR as arg1 to C routine */
+ ori r1, r3, CONFIG_SYS_INIT_SP_OFFSET /* set up the stack in internal DPRAM */
+ /* Note: R0 is still 0 here */
+ stwu r0, -4(r1) /* clear final stack frame so that */
+ stwu r0, -4(r1) /* stack backtraces terminate cleanly */
+
+ /*
+ * Disable serialized ifetch and show cycles
+ * (i.e. set processor to normal mode).
+ * This is also a silicon bug workaround, see errata
+ */
+
+ li r2, 0x0007
+ mtspr ICTRL, r2
+
+ /* Set up debug mode entry */
+
+ lis r2, CONFIG_SYS_DER@h
+ ori r2, r2, CONFIG_SYS_DER@l
+ mtspr DER, r2
+
+ /* let the C-code set up the rest */
+ /* */
+ /* Be careful to keep code relocatable ! */
+ /*----------------------------------------------------------------------*/
+
+ GET_GOT /* initialize GOT access */
+
+ /* r3: IMMR */
+ bl cpu_init_f /* run low-level CPU init code (from Flash) */
+
+ bl board_init_f /* run 1st part of board init code (from Flash) */
+
+ /* NOTREACHED - board_init_f() does not return */
+
+
+ .globl _start_of_vectors
+_start_of_vectors:
+
+/* Machine check */
+ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data Storage exception. "Never" generated on the 860. */
+ STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. "Never" generated on the 860. */
+ STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+ STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+ . = 0x600
+Alignment:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+ . = 0x700
+ProgramCheck:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+ MSR_KERNEL, COPY_EE)
+
+ /* No FPU on MPC8xx. This exception is not supposed to happen.
+ */
+ STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+
+ /* I guess we could implement decrementer, and may have
+ * to someday for timekeeping.
+ */
+ STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+ STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+ STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+ STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+ STD_EXCEPTION(0xd00, SingleStep, UnknownException)
+
+ STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+ STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+
+ /* On the MPC8xx, this is a software emulation interrupt. It occurs
+ * for all unimplemented and illegal instructions.
+ */
+ STD_EXCEPTION(0x1000, SoftEmu, SoftEmuException)
+
+ STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1300, InstructionTLBError, UnknownException)
+ STD_EXCEPTION(0x1400, DataTLBError, UnknownException)
+
+ STD_EXCEPTION(0x1500, Reserved5, UnknownException)
+ STD_EXCEPTION(0x1600, Reserved6, UnknownException)
+ STD_EXCEPTION(0x1700, Reserved7, UnknownException)
+ STD_EXCEPTION(0x1800, Reserved8, UnknownException)
+ STD_EXCEPTION(0x1900, Reserved9, UnknownException)
+ STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
+ STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
+
+ STD_EXCEPTION(0x1c00, DataBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1d00, InstructionBreakpoint, DebugException)
+ STD_EXCEPTION(0x1e00, PeripheralBreakpoint, UnknownException)
+ STD_EXCEPTION(0x1f00, DevPortBreakpoint, UnknownException)
+
+
+ .globl _end_of_vectors
+_end_of_vectors:
+
+
+ . = 0x2000
+
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+ .globl transfer_to_handler
+transfer_to_handler:
+ stw r22,_NIP(r21)
+ lis r22,MSR_POW@h
+ andc r23,r23,r22
+ stw r23,_MSR(r21)
+ SAVE_GPR(7, r21)
+ SAVE_4GPRS(8, r21)
+ SAVE_8GPRS(12, r21)
+ SAVE_8GPRS(24, r21)
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ mtspr SPRG2,r22 /* r1 is now kernel sp */
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
+
+int_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+
+/* Cache functions.
+*/
+ .globl icache_enable
+icache_enable:
+ SYNC
+ lis r3, IDC_INVALL@h
+ mtspr IC_CST, r3
+ lis r3, IDC_ENABLE@h
+ mtspr IC_CST, r3
+ blr
+
+ .globl icache_disable
+icache_disable:
+ SYNC
+ lis r3, IDC_DISABLE@h
+ mtspr IC_CST, r3
+ blr
+
+ .globl icache_status
+icache_status:
+ mfspr r3, IC_CST
+ srwi r3, r3, 31 /* >>31 => select bit 0 */
+ blr
+
+ .globl dcache_enable
+dcache_enable:
+#if 0
+ SYNC
+#endif
+#if 1
+ lis r3, 0x0400 /* Set cache mode with MMU off */
+ mtspr MD_CTR, r3
+#endif
+
+ lis r3, IDC_INVALL@h
+ mtspr DC_CST, r3
+#if 0
+ lis r3, DC_SFWT@h
+ mtspr DC_CST, r3
+#endif
+ lis r3, IDC_ENABLE@h
+ mtspr DC_CST, r3
+ blr
+
+ .globl dcache_disable
+dcache_disable:
+ SYNC
+ lis r3, IDC_DISABLE@h
+ mtspr DC_CST, r3
+ lis r3, IDC_INVALL@h
+ mtspr DC_CST, r3
+ blr
+
+ .globl dcache_status
+dcache_status:
+ mfspr r3, DC_CST
+ srwi r3, r3, 31 /* >>31 => select bit 0 */
+ blr
+
+ .globl dc_read
+dc_read:
+ mtspr DC_ADR, r3
+ mfspr r3, DC_DAT
+ blr
+
+/*
+ * unsigned int get_immr (unsigned int mask)
+ *
+ * return (mask ? (IMMR & mask) : IMMR);
+ */
+ .globl get_immr
+get_immr:
+ mr r4,r3 /* save mask */
+ mfspr r3, IMMR /* IMMR */
+ cmpwi 0,r4,0 /* mask != 0 ? */
+ beq 4f
+ and r3,r3,r4 /* IMMR & mask */
+4:
+ blr
+
+ .globl get_pvr
+get_pvr:
+ mfspr r3, PVR
+ blr
+
+
+ .globl wr_ic_cst
+wr_ic_cst:
+ mtspr IC_CST, r3
+ blr
+
+ .globl rd_ic_cst
+rd_ic_cst:
+ mfspr r3, IC_CST
+ blr
+
+ .globl wr_ic_adr
+wr_ic_adr:
+ mtspr IC_ADR, r3
+ blr
+
+
+ .globl wr_dc_cst
+wr_dc_cst:
+ mtspr DC_CST, r3
+ blr
+
+ .globl rd_dc_cst
+rd_dc_cst:
+ mfspr r3, DC_CST
+ blr
+
+ .globl wr_dc_adr
+wr_dc_adr:
+ mtspr DC_ADR, r3
+ blr
+
+/*------------------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = dest
+ * r4 = src
+ * r5 = length in bytes
+ * r6 = cachelinesize
+ */
+ .globl relocate_code
+relocate_code:
+ mr r1, r3 /* Set new stack pointer */
+ mr r9, r4 /* Save copy of Global Data pointer */
+ mr r10, r5 /* Save copy of Destination Address */
+
+ GET_GOT
+ mr r3, r5 /* Destination Address */
+ lis r4, CONFIG_SYS_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CONFIG_SYS_MONITOR_BASE@l
+ lwz r5, GOT(__init_end)
+ sub r5, r5, r4
+ li r6, CONFIG_SYS_CACHELINE_SIZE /* Cache Line Size */
+
+ /*
+ * Fix GOT pointer:
+ *
+ * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+ *
+ * Offset:
+ */
+ sub r15, r10, r4
+
+ /* First our own GOT */
+ add r12, r12, r15
+ /* then the one used by the C code */
+ add r30, r30, r15
+
+ /*
+ * Now relocate code
+ */
+
+ cmplw cr1,r3,r4
+ addi r0,r5,3
+ srwi. r0,r0,2
+ beq cr1,4f /* In place copy is not necessary */
+ beq 7f /* Protect against 0 count */
+ mtctr r0
+ bge cr1,2f
+
+ la r8,-4(r4)
+ la r7,-4(r3)
+1: lwzu r0,4(r8)
+ stwu r0,4(r7)
+ bdnz 1b
+ b 4f
+
+2: slwi r0,r0,2
+ add r8,r4,r0
+ add r7,r3,r0
+3: lwzu r0,-4(r8)
+ stwu r0,-4(r7)
+ bdnz 3b
+
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4: cmpwi r6,0
+ add r5,r3,r5
+ beq 7f /* Always flush prefetch queue in any case */
+ subi r0,r6,1
+ andc r3,r3,r0
+ mr r4,r3
+5: dcbst 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 5b
+ sync /* Wait for all dcbst to complete on bus */
+ mr r4,r3
+6: icbi 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 6b
+7: sync /* Wait for all icbi to complete on bus */
+ isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+ addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
+ mtlr r0
+ blr
+
+in_ram:
+
+ /*
+ * Relocation Function, r12 point to got2+0x8000
+ *
+ * Adjust got2 pointers, no need to check for 0, this code
+ * already puts a few entries in the table.
+ */
+ li r0,__got2_entries@sectoff@l
+ la r3,GOT(_GOT2_TABLE_)
+ lwz r11,GOT(_GOT2_TABLE_)
+ mtctr r0
+ sub r11,r3,r11
+ addi r3,r3,-4
+1: lwzu r0,4(r3)
+ cmpwi r0,0
+ beq- 2f
+ add r0,r0,r11
+ stw r0,0(r3)
+2: bdnz 1b
+
+ /*
+ * Now adjust the fixups and the pointers to the fixups
+ * in case we need to move ourselves again.
+ */
+ li r0,__fixup_entries@sectoff@l
+ lwz r3,GOT(_FIXUP_TABLE_)
+ cmpwi r0,0
+ mtctr r0
+ addi r3,r3,-4
+ beq 4f
+3: lwzu r4,4(r3)
+ lwzux r0,r4,r11
+ cmpwi r0,0
+ add r0,r0,r11
+ stw r4,0(r3)
+ beq- 5f
+ stw r0,0(r4)
+5: bdnz 3b
+4:
+clear_bss:
+ /*
+ * Now clear BSS segment
+ */
+ lwz r3,GOT(__bss_start)
+ lwz r4,GOT(__bss_end)
+
+ cmplw 0, r3, r4
+ beq 6f
+
+ li r0, 0
+5:
+ stw r0, 0(r3)
+ addi r3, r3, 4
+ cmplw 0, r3, r4
+ bne 5b
+6:
+
+ mr r3, r9 /* Global Data pointer */
+ mr r4, r10 /* Destination Address */
+ bl board_init_r
+
+ /*
+ * Copy exception vector code to low memory
+ *
+ * r3: dest_addr
+ * r7: source address, r8: end address, r9: target address
+ */
+ .globl trap_init
+trap_init:
+ mflr r4 /* save link register */
+ GET_GOT
+ lwz r7, GOT(_start)
+ lwz r8, GOT(_end_of_vectors)
+
+ li r9, 0x100 /* reset vector always at 0x100 */
+
+ cmplw 0, r7, r8
+ bgelr /* return if r7>=r8 - just in case */
+1:
+ lwz r0, 0(r7)
+ stw r0, 0(r9)
+ addi r7, r7, 4
+ addi r9, r9, 4
+ cmplw 0, r7, r8
+ bne 1b
+
+ /*
+ * relocate `hdlr' and `int_return' entries
+ */
+ li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
+ li r8, Alignment - _start + EXC_OFF_SYS_RESET
+2:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 2b
+
+ li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
+ bl trap_reloc
+
+ li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
+ li r8, SystemCall - _start + EXC_OFF_SYS_RESET
+3:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 3b
+
+ li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
+ li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
+4:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 4b
+
+ mtlr r4 /* restore link register */
+ blr
diff --git a/arch/powerpc/cpu/mpc8xx/traps.c b/arch/powerpc/cpu/mpc8xx/traps.c
new file mode 100644
index 0000000..f0ab78d
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/traps.c
@@ -0,0 +1,232 @@
+/*
+ * linux/arch/powerpc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+*/
+#define END_OF_MEM 0x02000000
+
+/*
+ * Trap & Exception support
+ */
+
+static void print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ printf("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ printf("\n");
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *)*sp;
+ }
+ printf("\n");
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ int i;
+
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+ regs->msr&MSR_IR ? 1 : 0,
+ regs->msr&MSR_DR ? 1 : 0);
+
+ printf("\n");
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0)
+ {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7)
+ {
+ printf("\n");
+ }
+ }
+}
+
+
+static void _exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
+}
+
+void MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup;
+
+ /* Probing PCI using config cycles cause this exception
+ * when a device is not present. Catch it and return to
+ * the PCI exception handler.
+ */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ return;
+ }
+
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ printf("Machine check in kernel mode.\n");
+ printf("Caused by (from msr): ");
+ printf("regs %p ",regs);
+ switch( regs->msr & 0x000F0000) {
+ case (0x80000000>>12):
+ printf("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (0x80000000>>13):
+ printf("Transfer error ack signal\n");
+ break;
+ case (0x80000000>>14):
+ printf("Data parity signal\n");
+ break;
+ case (0x80000000>>15):
+ printf("Address parity signal\n");
+ break;
+ default:
+ printf("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("machine check");
+}
+
+void AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void ProgramCheckException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void SoftEmuException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Software Emulation Exception");
+}
+
+
+void UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+void DebugException(struct pt_regs *regs)
+{
+ printf("Debugger trap at @ %lx\n", regs->nip );
+ show_regs(regs);
+#if defined(CONFIG_CMD_BEDBUG)
+ do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading. If not present, return -1, otherwise
+ * return 0.
+ */
+int addr_probe(uint *addr)
+{
+#if 0
+ int retval;
+
+ __asm__ __volatile__( \
+ "1: lwz %0,0(%1)\n" \
+ " eieio\n" \
+ " li %0,0\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,-1\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r" (retval) : "r"(addr));
+
+ return (retval);
+#endif
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc8xx/upatch.c b/arch/powerpc/cpu/mpc8xx/upatch.c
new file mode 100644
index 0000000..a8cb735
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/upatch.c
@@ -0,0 +1,194 @@
+#include <common.h>
+#include <commproc.h>
+
+#if defined(CONFIG_SYS_I2C_UCODE_PATCH) || defined(CONFIG_SYS_SPI_UCODE_PATCH) || \
+ defined(CONFIG_SYS_SMC_UCODE_PATCH)
+
+static void UcodeCopy (volatile cpm8xx_t *cpm);
+
+void cpm_load_patch (volatile immap_t *immr)
+{
+ immr->im_cpm.cp_rccr &= ~0x0003; /* Disable microcode program area */
+
+ UcodeCopy ((cpm8xx_t *)&immr->im_cpm); /* Copy ucode patch to DPRAM */
+#ifdef CONFIG_SYS_SPI_UCODE_PATCH
+ {
+ volatile spi_t *spi = (spi_t *) & immr->im_cpm.cp_dparam[PROFF_SPI];
+ /* Activate the microcode per the instructions in the microcode manual */
+ /* NOTE: We're only relocating the SPI parameters (not I2C). */
+ immr->im_cpm.cp_cpmcr1 = 0x802a; /* Write Trap register 1 value */
+ immr->im_cpm.cp_cpmcr2 = 0x8028; /* Write Trap register 2 value */
+ spi->spi_rpbase = CONFIG_SYS_SPI_DPMEM_OFFSET; /* Where to relocte SPI params */
+ }
+#endif
+
+#ifdef CONFIG_SYS_I2C_UCODE_PATCH
+ {
+ volatile iic_t *iip = (iic_t *) & immr->im_cpm.cp_dparam[PROFF_IIC];
+ /* Activate the microcode per the instructions in the microcode manual */
+ /* NOTE: We're only relocating the I2C parameters (not SPI). */
+ immr->im_cpm.cp_cpmcr3 = 0x802e; /* Write Trap register 3 value */
+ immr->im_cpm.cp_cpmcr4 = 0x802c; /* Write Trap register 4 value */
+ iip->iic_rpbase = CONFIG_SYS_I2C_DPMEM_OFFSET; /* Where to relocte I2C params */
+ }
+#endif
+
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+ {
+ volatile smc_uart_t *up = (smc_uart_t *) & immr->im_cpm.cp_dparam[PROFF_SMC1];
+ /* Activate the microcode per the instructions in the microcode manual */
+ /* NOTE: We're only relocating the SMC parameters. */
+ immr->im_cpm.cp_cpmcr1 = 0x8080; /* Write Trap register 1 value */
+ immr->im_cpm.cp_cpmcr2 = 0x8088; /* Write Trap register 2 value */
+ up->smc_rpbase = CONFIG_SYS_SMC_DPMEM_OFFSET; /* Where to relocte SMC params */
+ }
+#endif
+
+ /*
+ * Enable DPRAM microcode to execute from the first 512 bytes
+ * and a 256 byte extension of DPRAM.
+ */
+#ifdef CONFIG_SYS_SMC_UCODE_PATCH
+ immr->im_cpm.cp_rccr |= 0x0002;
+#else
+ immr->im_cpm.cp_rccr |= 0x0001;
+#endif
+}
+
+#if defined(CONFIG_SYS_I2C_UCODE_PATCH) || defined(CONFIG_SYS_SPI_UCODE_PATCh)
+static ulong patch_2000[] = {
+ 0x7FFFEFD9, 0x3FFD0000, 0x7FFB49F7, 0x7FF90000,
+ 0x5FEFADF7, 0x5F88ADF7, 0x5FEFAFF7, 0x5F88AFF7,
+ 0x3A9CFBC8, 0x77CAE1BB, 0xF4DE7FAD, 0xABAE9330,
+ 0x4E08FDCF, 0x6E0FAFF8, 0x7CCF76CF, 0xFDAFF9CF,
+ 0xABF88DC8, 0xAB5879F7, 0xB0927383, 0xDFD079F7,
+ 0xB090E6BB, 0xE5BBE74F, 0xB3FA6F0F, 0x6FFB76CE,
+ 0xEE0CF9CF, 0x2BFBEFEF, 0xCFEEF9CF, 0x76CEAD23,
+ 0x90B3DF99, 0x7FDDD0C1, 0x4BF847FD, 0x7CCF76CE,
+ 0xCFEF77CA, 0x7EAF7FAD, 0x7DFDF0B7, 0xEF7A7FCA,
+ 0x77CAFBC8, 0x6079E722, 0xFBC85FFF, 0xDFFF5FB3,
+ 0xFFFBFBC8, 0xF3C894A5, 0xE7C9EDF9, 0x7F9A7FAD,
+ 0x5F36AFE8, 0x5F5BFFDF, 0xDF95CB9E, 0xAF7D5FC3,
+ 0xAFED8C1B, 0x5FC3AFDD, 0x5FC5DF99, 0x7EFDB0B3,
+ 0x5FB3FFFE, 0xABAE5FB3, 0xFFFE5FD0, 0x600BE6BB,
+ 0x600B5FD0, 0xDFC827FB, 0xEFDF5FCA, 0xCFDE3A9C,
+ 0xE7C9EDF9, 0xF3C87F9E, 0x54CA7FED, 0x2D3A3637,
+ 0x756F7E9A, 0xF1CE37EF, 0x2E677FEE, 0x10EBADF8,
+ 0xEFDECFEA, 0xE52F7D9F, 0xE12BF1CE, 0x5F647E9A,
+ 0x4DF8CFEA, 0x5F717D9B, 0xEFEECFEA, 0x5F73E522,
+ 0xEFDE5F73, 0xCFDA0B61, 0x7385DF61, 0xE7C9EDF9,
+ 0x7E9A30D5, 0x1458BFFF, 0xF3C85FFF, 0xDFFFA7F8,
+ 0x5F5BBFFE, 0x7F7D10D0, 0x144D5F33, 0xBFFFAF78,
+ 0x5F5BBFFD, 0xA7F85F33, 0xBFFE77FD, 0x30BD4E08,
+ 0xFDCFE5FF, 0x6E0FAFF8, 0x7EEF7E9F, 0xFDEFF1CF,
+ 0x5F17ABF8, 0x0D5B5F5B, 0xFFEF79F7, 0x309EAFDD,
+ 0x5F3147F8, 0x5F31AFED, 0x7FDD50AF, 0x497847FD,
+ 0x7F9E7FED, 0x7DFD70A9, 0xEF7E7ECE, 0x6BA07F9E,
+ 0x2D227EFD, 0x30DB5F5B, 0xFFFD5F5B, 0xFFEF5F5B,
+ 0xFFDF0C9C, 0xAFED0A9A, 0xAFDD0C37, 0x5F37AFBD,
+ 0x7FBDB081, 0x5F8147F8,
+};
+
+static ulong patch_2F00[] = {
+ 0x3E303430, 0x34343737, 0xABBF9B99, 0x4B4FBDBD,
+ 0x59949334, 0x9FFF37FB, 0x9B177DD9, 0x936956BB,
+ 0xFBDD697B, 0xDD2FD113, 0x1DB9F7BB, 0x36313963,
+ 0x79373369, 0x3193137F, 0x7331737A, 0xF7BB9B99,
+ 0x9BB19795, 0x77FDFD3D, 0x573B773F, 0x737933F7,
+ 0xB991D115, 0x31699315, 0x31531694, 0xBF4FBDBD,
+ 0x35931497, 0x35376956, 0xBD697B9D, 0x96931313,
+ 0x19797937, 0x69350000,
+};
+#else
+
+static ulong patch_2000[] = {
+ 0x3fff0000, 0x3ffd0000, 0x3ffb0000, 0x3ff90000,
+ 0x5fefeff8, 0x5f91eff8, 0x3ff30000, 0x3ff10000,
+ 0x3a11e710, 0xedf0ccb9, 0xf318ed66, 0x7f0e5fe2,
+ 0x7fedbb38, 0x3afe7468, 0x7fedf4d8, 0x8ffbb92d,
+ 0xb83b77fd, 0xb0bb5eb9, 0xdfda7fed, 0x90bde74d,
+ 0x6f0dcbd3, 0xe7decfed, 0xcb50cfed, 0xcfeddf6d,
+ 0x914d4f74, 0x5eaedfcb, 0x9ee0e7df, 0xefbb6ffb,
+ 0xe7ef7f0e, 0x9ee57fed, 0xebb7effa, 0xeb30affb,
+ 0x7fea90b3, 0x7e0cf09f, 0xbffff318, 0x5fffdfff,
+ 0xac35efea, 0x7fce1fc1, 0xe2ff5fbd, 0xaffbe2ff,
+ 0x5fbfaffb, 0xf9a87d0f, 0xaef8770f, 0x7d0fb0a2,
+ 0xeffbbfff, 0xcfef5fba, 0x7d0fbfff, 0x5fba4cf8,
+ 0x7fddd09b, 0x49f847fd, 0x7efdf097, 0x7fedfffd,
+ 0x7dfdf093, 0xef7e7e1e, 0x5fba7f0e, 0x3a11e710,
+ 0xedf0cc87, 0xfb18ad0a, 0x1f85bbb8, 0x74283b7e,
+ 0x7375e4bb, 0x2ab64fb8, 0x5c7de4bb, 0x32fdffbf,
+ 0x5f0843f8, 0x7ce3e1bb, 0xe74f7ded, 0x6f0f4fe8,
+ 0xc7ba32be, 0x73f2efeb, 0x600b4f78, 0xe5bb760b,
+ 0x5388aef8, 0x4ef80b6a, 0xcfef9ee5, 0xabf8751f,
+ 0xefef5b88, 0x741f4fe8, 0x751e760d, 0x7fdb70dd,
+ 0x741cafce, 0xefcc7fce, 0x751e7088, 0x741ce7bb,
+ 0x334ecfed, 0xafdbefeb, 0xe5bb760b, 0x53ceaef8,
+ 0xafe8e7eb, 0x4bf8771e, 0x7e007fed, 0x4fcbe2cc,
+ 0x7fbc3085, 0x7b0f7a0f, 0x34b177fd, 0xb0e75e93,
+ 0xdf313e3b, 0xaf78741f, 0x741f30cc, 0xcfef5f08,
+ 0x741f3e88, 0xafb8771e, 0x5f437fed, 0x0bafe2cc,
+ 0x741ccfec, 0xe5ca53a9, 0x6fcb4f74, 0x5e89df27,
+ 0x2a923d14, 0x4b8fdf0c, 0x751f741c, 0x6c1eeffa,
+ 0xefea7fce, 0x6ffc309a, 0xefec3fca, 0x308fdf0a,
+ 0xadf85e7a, 0xaf7daefd, 0x5e7adf0a, 0x5e7aafdd,
+ 0x761f1088, 0x1e7c7efd, 0x3089fffe, 0x4908fb18,
+ 0x5fffdfff, 0xafbbf0f7, 0x4ef85f43, 0xadf81489,
+ 0x7a0f7089, 0xcfef5089, 0x7a0fdf0c, 0x5e7cafed,
+ 0xbc6e780f, 0xefef780f, 0xefef790f, 0xa7f85eeb,
+ 0xffef790f, 0xefef790f, 0x1489df0a, 0x5e7aadfd,
+ 0x5f09fffb, 0xe79aded9, 0xeff96079, 0x607ae79a,
+ 0xded8eff9, 0x60795edb, 0x607acfef, 0xefefefdf,
+ 0xefbfef7f, 0xeeffedff, 0xebffe7ff, 0xafefafdf,
+ 0xafbfaf7f, 0xaeffadff, 0xabffa7ff, 0x6fef6fdf,
+ 0x6fbf6f7f, 0x6eff6dff, 0x6bff67ff, 0x2fef2fdf,
+ 0x2fbf2f7f, 0x2eff2dff, 0x2bff27ff, 0x4e08fd1f,
+ 0xe5ff6e0f, 0xaff87eef, 0x7e0ffdef, 0xf11f6079,
+ 0xabf8f51e, 0x7e0af11c, 0x37cfae16, 0x7fec909a,
+ 0xadf8efdc, 0xcfeae52f, 0x7d0fe12b, 0xf11c6079,
+ 0x7e0a4df8, 0xcfea5ea0, 0x7d0befec, 0xcfea5ea2,
+ 0xe522efdc, 0x5ea2cfda, 0x4e08fd1f, 0x6e0faff8,
+ 0x7c1f761f, 0xfdeff91f, 0x6079abf8, 0x761cee00,
+ 0xf91f2bfb, 0xefefcfec, 0xf91f6079, 0x761c27fb,
+ 0xefdf5e83, 0xcfdc7fdd, 0x50f84bf8, 0x47fd7c1f,
+ 0x761ccfcf, 0x7eef7fed, 0x7dfd70ef, 0xef7e7f1e,
+ 0x771efb18, 0x6079e722, 0xe6bbe5bb, 0x2e66e5bb,
+ 0x600b2ee1, 0xe2bbe2bb, 0xe2bbe2bb, 0x2f5ee2bb,
+ 0xe2bb2ff9, 0x6079e2bb,
+};
+
+static ulong patch_2F00[] = {
+ 0x30303030, 0x3e3e3030, 0xaf79b9b3, 0xbaa3b979,
+ 0x9693369f, 0x79f79777, 0x97333fff, 0xfb3b9e9f,
+ 0x79b91d11, 0x9e13f3ff, 0x3f9b6bd9, 0xe173d136,
+ 0x695669d1, 0x697b3daf, 0x79b93a3a, 0x3f979f91,
+ 0x379ff976, 0xf99777fd, 0x9779737d, 0xe9d6bbf9,
+ 0xbfffd9df, 0x97f7fd97, 0x6f7b9bff, 0xf9bd9683,
+ 0x397db973, 0xd97b3b9f, 0xd7f9f733, 0x9993bb9e,
+ 0xe1f9ef93, 0x73773337, 0xb936917d, 0x11f87379,
+ 0xb979d336, 0x8b7ded73, 0x1b7d9337, 0x31f3f22f,
+ 0x3f2327ee, 0xeeeeeeee, 0xeeeeeeee, 0xeeeeeeee,
+ 0xeeeeee4b, 0xf4fbdbd2, 0x58bb1878, 0x577fdfd2,
+ 0xd573b773, 0xf7374b4f, 0xbdbd25b8, 0xb177d2d1,
+ 0x7376856b, 0xbfdd687b, 0xdd2fff8f, 0x78ffff8f,
+ 0xf22f0000,
+};
+#endif
+
+static void UcodeCopy (volatile cpm8xx_t *cpm)
+{
+ vu_long *p;
+ int i;
+
+ p = (vu_long *)&(cpm->cp_dpmem[0x0000]);
+ for (i=0; i < sizeof(patch_2000)/4; ++i) {
+ p[i] = patch_2000[i];
+ }
+
+ p = (vu_long *)&(cpm->cp_dpmem[0x0F00]);
+ for (i=0; i < sizeof(patch_2F00)/4; ++i) {
+ p[i] = patch_2F00[i];
+ }
+}
+
+#endif /* CONFIG_SYS_I2C_UCODE_PATCH, CONFIG_SYS_SPI_UCODE_PATCH */
diff --git a/arch/powerpc/cpu/mpc8xx/video.c b/arch/powerpc/cpu/mpc8xx/video.c
new file mode 100644
index 0000000..1bbf4cc
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/video.c
@@ -0,0 +1,1331 @@
+/*
+ * (C) Copyright 2000
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ * (C) Copyright 2002
+ * Wolfgang Denk, wd@denx.de
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* #define DEBUG */
+
+/************************************************************************/
+/* ** HEADER FILES */
+/************************************************************************/
+
+#include <stdarg.h>
+#include <common.h>
+#include <config.h>
+#include <version.h>
+#include <i2c.h>
+#include <linux/types.h>
+#include <stdio_dev.h>
+
+#ifdef CONFIG_VIDEO
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/************************************************************************/
+/* ** DEBUG SETTINGS */
+/************************************************************************/
+
+#if 0
+#define VIDEO_DEBUG_COLORBARS /* Force colorbars output */
+#endif
+
+/************************************************************************/
+/* ** VIDEO MODE SETTINGS */
+/************************************************************************/
+
+#if 0
+#define VIDEO_MODE_EXTENDED /* Allow screen size bigger than visible area */
+#define VIDEO_MODE_NTSC
+#endif
+
+#define VIDEO_MODE_PAL
+
+#if 0
+#define VIDEO_BLINK /* This enables cursor blinking (under construction) */
+#endif
+
+#define VIDEO_INFO /* Show U-Boot information */
+#define VIDEO_INFO_X VIDEO_LOGO_WIDTH+8
+#define VIDEO_INFO_Y 16
+
+/************************************************************************/
+/* ** VIDEO ENCODER CONSTANTS */
+/************************************************************************/
+
+#ifdef CONFIG_VIDEO_ENCODER_AD7176
+
+#include <video_ad7176.h> /* Sets encoder data, mode, and visible and active area */
+
+#define VIDEO_I2C 1
+#define VIDEO_I2C_ADDR CONFIG_VIDEO_ENCODER_AD7176_ADDR
+#endif
+
+#ifdef CONFIG_VIDEO_ENCODER_AD7177
+
+#include <video_ad7177.h> /* Sets encoder data, mode, and visible and active area */
+
+#define VIDEO_I2C 1
+#define VIDEO_I2C_ADDR CONFIG_VIDEO_ENCODER_AD7177_ADDR
+#endif
+
+#ifdef CONFIG_VIDEO_ENCODER_AD7179
+
+#include <video_ad7179.h> /* Sets encoder data, mode, and visible and active area */
+
+#define VIDEO_I2C 1
+#define VIDEO_I2C_ADDR CONFIG_VIDEO_ENCODER_AD7179_ADDR
+#endif
+
+/************************************************************************/
+/* ** VIDEO MODE CONSTANTS */
+/************************************************************************/
+
+#ifdef VIDEO_MODE_EXTENDED
+#define VIDEO_COLS VIDEO_ACTIVE_COLS
+#define VIDEO_ROWS VIDEO_ACTIVE_ROWS
+#else
+#define VIDEO_COLS VIDEO_VISIBLE_COLS
+#define VIDEO_ROWS VIDEO_VISIBLE_ROWS
+#endif
+
+#define VIDEO_PIXEL_SIZE (VIDEO_MODE_BPP/8)
+#define VIDEO_SIZE (VIDEO_ROWS*VIDEO_COLS*VIDEO_PIXEL_SIZE) /* Total size of buffer */
+#define VIDEO_PIX_BLOCKS (VIDEO_SIZE >> 2) /* Number of ints */
+#define VIDEO_LINE_LEN (VIDEO_COLS*VIDEO_PIXEL_SIZE) /* Number of bytes per line */
+#define VIDEO_BURST_LEN (VIDEO_COLS/8)
+
+#ifdef VIDEO_MODE_YUYV
+#define VIDEO_BG_COL 0x80D880D8 /* Background color in YUYV format */
+#else
+#define VIDEO_BG_COL 0xF8F8F8F8 /* Background color in RGB format */
+#endif
+
+/************************************************************************/
+/* ** FONT AND LOGO DATA */
+/************************************************************************/
+
+#include <video_font.h> /* Get font data, width and height */
+#include <video_font_data.h>
+
+#ifdef CONFIG_VIDEO_LOGO
+#include <video_logo.h> /* Get logo data, width and height */
+
+#define VIDEO_LOGO_WIDTH DEF_U_BOOT_LOGO_WIDTH
+#define VIDEO_LOGO_HEIGHT DEF_U_BOOT_LOGO_HEIGHT
+#define VIDEO_LOGO_ADDR &u_boot_logo
+#endif
+
+/************************************************************************/
+/* ** VIDEO CONTROLLER CONSTANTS */
+/************************************************************************/
+
+/* VCCR - VIDEO CONTROLLER CONFIGURATION REGISTER */
+
+#define VIDEO_VCCR_VON 0 /* Video controller ON */
+#define VIDEO_VCCR_CSRC 1 /* Clock source */
+#define VIDEO_VCCR_PDF 13 /* Pixel display format */
+#define VIDEO_VCCR_IEN 11 /* Interrupt enable */
+
+/* VSR - VIDEO STATUS REGISTER */
+
+#define VIDEO_VSR_CAS 6 /* Active set */
+#define VIDEO_VSR_EOF 0 /* End of frame */
+
+/* VCMR - VIDEO COMMAND REGISTER */
+
+#define VIDEO_VCMR_BD 0 /* Blank display */
+#define VIDEO_VCMR_ASEL 1 /* Active set selection */
+
+/* VBCB - VIDEO BACKGROUND COLOR BUFFER REGISTER */
+
+#define VIDEO_BCSR4_RESET_BIT 21 /* BCSR4 - Extern video encoder reset */
+#define VIDEO_BCSR4_EXTCLK_BIT 22 /* BCSR4 - Extern clock enable */
+#define VIDEO_BCSR4_VIDLED_BIT 23 /* BCSR4 - Video led disable */
+
+/************************************************************************/
+/* ** CONSOLE CONSTANTS */
+/************************************************************************/
+
+#ifdef CONFIG_VIDEO_LOGO
+#define CONSOLE_ROWS ((VIDEO_ROWS - VIDEO_LOGO_HEIGHT) / VIDEO_FONT_HEIGHT)
+#define VIDEO_LOGO_SKIP (VIDEO_COLS - VIDEO_LOGO_WIDTH)
+#else
+#define CONSOLE_ROWS (VIDEO_ROWS / VIDEO_FONT_HEIGHT)
+#endif
+
+#define CONSOLE_COLS (VIDEO_COLS / VIDEO_FONT_WIDTH)
+#define CONSOLE_ROW_SIZE (VIDEO_FONT_HEIGHT * VIDEO_LINE_LEN)
+#define CONSOLE_ROW_FIRST (video_console_address)
+#define CONSOLE_ROW_SECOND (video_console_address + CONSOLE_ROW_SIZE)
+#define CONSOLE_ROW_LAST (video_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE)
+#define CONSOLE_SIZE (CONSOLE_ROW_SIZE * CONSOLE_ROWS)
+#define CONSOLE_SCROLL_SIZE (CONSOLE_SIZE - CONSOLE_ROW_SIZE)
+
+/*
+ * Simple color definitions
+ */
+#define CONSOLE_COLOR_BLACK 0
+#define CONSOLE_COLOR_RED 1
+#define CONSOLE_COLOR_GREEN 2
+#define CONSOLE_COLOR_YELLOW 3
+#define CONSOLE_COLOR_BLUE 4
+#define CONSOLE_COLOR_MAGENTA 5
+#define CONSOLE_COLOR_CYAN 6
+#define CONSOLE_COLOR_GREY 13
+#define CONSOLE_COLOR_GREY2 14
+#define CONSOLE_COLOR_WHITE 15 /* Must remain last / highest */
+
+/************************************************************************/
+/* ** BITOPS MACROS */
+/************************************************************************/
+
+#define HISHORT(i) ((i >> 16)&0xffff)
+#define LOSHORT(i) (i & 0xffff)
+#define HICHAR(s) ((i >> 8)&0xff)
+#define LOCHAR(s) (i & 0xff)
+#define HI(c) ((c >> 4)&0xf)
+#define LO(c) (c & 0xf)
+#define SWAPINT(i) (HISHORT(i) | (LOSHORT(i) << 16))
+#define SWAPSHORT(s) (HICHAR(s) | (LOCHAR(s) << 8))
+#define SWAPCHAR(c) (HI(c) | (LO(c) << 4))
+#define BITMASK(b) (1 << (b))
+#define GETBIT(v,b) (((v) & BITMASK(b)) > 0)
+#define SETBIT(v,b,d) (v = (((d)>0) ? (v) | BITMASK(b): (v) & ~BITMASK(b)))
+
+/************************************************************************/
+/* ** STRUCTURES */
+/************************************************************************/
+
+typedef struct {
+ unsigned char V, Y1, U, Y2;
+} tYUYV;
+
+/* This structure is based on the Video Ram in the MPC823. */
+typedef struct VRAM {
+ unsigned hx:2, /* Horizontal sync */
+ vx:2, /* Vertical sync */
+ fx:2, /* Frame */
+ bx:2, /* Blank */
+ res1:6, /* Reserved */
+ vds:2, /* Video Data Select */
+ inter:1, /* Interrupt */
+ res2:2, /* Reserved */
+ lcyc:11, /* Loop/video cycles */
+ lp:1, /* Loop start/end */
+ lst:1; /* Last entry */
+} VRAM;
+
+/************************************************************************/
+/* ** VARIABLES */
+/************************************************************************/
+
+static int
+ video_panning_range_x = 0, /* Video mode invisible pixels x range */
+ video_panning_range_y = 0, /* Video mode invisible pixels y range */
+ video_panning_value_x = 0, /* Video mode x panning value (absolute) */
+ video_panning_value_y = 0, /* Video mode y panning value (absolute) */
+ video_panning_factor_x = 0, /* Video mode x panning value (-127 +127) */
+ video_panning_factor_y = 0, /* Video mode y panning value (-127 +127) */
+ console_col = 0, /* Cursor col */
+ console_row = 0, /* Cursor row */
+ video_palette[16]; /* Our palette */
+
+static const int video_font_draw_table[] =
+ { 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff };
+
+static char
+ video_color_fg = 0, /* Current fg color index (0-15) */
+ video_color_bg = 0, /* Current bg color index (0-15) */
+ video_enable = 0; /* Video has been initialized? */
+
+static void
+ *video_fb_address, /* Frame buffer address */
+ *video_console_address; /* Console frame buffer start address */
+
+/************************************************************************/
+/* ** MEMORY FUNCTIONS (32bit) */
+/************************************************************************/
+
+static void memsetl (int *p, int c, int v)
+{
+ while (c--)
+ *(p++) = v;
+}
+
+static void memcpyl (int *d, int *s, int c)
+{
+ while (c--)
+ *(d++) = *(s++);
+}
+
+/************************************************************************/
+/* ** VIDEO DRAWING AND COLOR FUNCTIONS */
+/************************************************************************/
+
+static int video_maprgb (int r, int g, int b)
+{
+#ifdef VIDEO_MODE_YUYV
+ unsigned int pR, pG, pB;
+ tYUYV YUYV;
+ unsigned int *ret = (unsigned int *) &YUYV;
+
+ /* Transform (0-255) components to (0-100) */
+
+ pR = r * 100 / 255;
+ pG = g * 100 / 255;
+ pB = b * 100 / 255;
+
+ /* Calculate YUV values (0-255) from RGB beetween 0-100 */
+
+ YUYV.Y1 = YUYV.Y2 = 209 * (pR + pG + pB) / 300 + 16;
+ YUYV.U = pR - (pG * 3 / 4) - (pB / 4) + 128;
+ YUYV.V = pB - (pR / 4) - (pG * 3 / 4) + 128;
+ return *ret;
+#endif
+#ifdef VIDEO_MODE_RGB
+ return ((r >> 3) << 11) | ((g > 2) << 6) | (b >> 3);
+#endif
+}
+
+static void video_setpalette (int color, int r, int g, int b)
+{
+ color &= 0xf;
+
+ video_palette[color] = video_maprgb (r, g, b);
+
+ /* Swap values if our panning offset is odd */
+ if (video_panning_value_x & 1)
+ video_palette[color] = SWAPINT (video_palette[color]);
+}
+
+static void video_fill (int color)
+{
+ memsetl (video_fb_address, VIDEO_PIX_BLOCKS, color);
+}
+
+static void video_setfgcolor (int i)
+{
+ video_color_fg = i & 0xf;
+}
+
+static void video_setbgcolor (int i)
+{
+ video_color_bg = i & 0xf;
+}
+
+static int video_pickcolor (int i)
+{
+ return video_palette[i & 0xf];
+}
+
+/* Absolute console plotting functions */
+
+#ifdef VIDEO_BLINK
+static void video_revchar (int xx, int yy)
+{
+ int rows;
+ u8 *dest;
+
+ dest = video_fb_address + yy * VIDEO_LINE_LEN + xx * 2;
+
+ for (rows = VIDEO_FONT_HEIGHT; rows--; dest += VIDEO_LINE_LEN) {
+ switch (VIDEO_FONT_WIDTH) {
+ case 16:
+ ((u32 *) dest)[6] ^= 0xffffffff;
+ ((u32 *) dest)[7] ^= 0xffffffff;
+ /* FALL THROUGH */
+ case 12:
+ ((u32 *) dest)[4] ^= 0xffffffff;
+ ((u32 *) dest)[5] ^= 0xffffffff;
+ /* FALL THROUGH */
+ case 8:
+ ((u32 *) dest)[2] ^= 0xffffffff;
+ ((u32 *) dest)[3] ^= 0xffffffff;
+ /* FALL THROUGH */
+ case 4:
+ ((u32 *) dest)[0] ^= 0xffffffff;
+ ((u32 *) dest)[1] ^= 0xffffffff;
+ }
+ }
+}
+#endif
+
+static void video_drawchars (int xx, int yy, unsigned char *s, int count)
+{
+ u8 *cdat, *dest, *dest0;
+ int rows, offset, c;
+ u32 eorx, fgx, bgx;
+
+ offset = yy * VIDEO_LINE_LEN + xx * 2;
+ dest0 = video_fb_address + offset;
+
+ fgx = video_pickcolor (video_color_fg);
+ bgx = video_pickcolor (video_color_bg);
+
+ if (xx & 1) {
+ fgx = SWAPINT (fgx);
+ bgx = SWAPINT (bgx);
+ }
+
+ eorx = fgx ^ bgx;
+
+ switch (VIDEO_FONT_WIDTH) {
+ case 4:
+ case 8:
+ while (count--) {
+ c = *s;
+ cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
+ for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
+ rows--;
+ dest += VIDEO_LINE_LEN) {
+ u8 bits = *cdat++;
+
+ ((u32 *) dest)[0] =
+ (video_font_draw_table[bits >> 6] & eorx) ^ bgx;
+ ((u32 *) dest)[1] =
+ (video_font_draw_table[bits >> 4 & 3] & eorx) ^ bgx;
+ if (VIDEO_FONT_WIDTH == 8) {
+ ((u32 *) dest)[2] =
+ (video_font_draw_table[bits >> 2 & 3] & eorx) ^ bgx;
+ ((u32 *) dest)[3] =
+ (video_font_draw_table[bits & 3] & eorx) ^ bgx;
+ }
+ }
+ dest0 += VIDEO_FONT_WIDTH * 2;
+ s++;
+ }
+ break;
+ case 12:
+ case 16:
+ while (count--) {
+ cdat = video_fontdata + (*s) * (VIDEO_FONT_HEIGHT << 1);
+ for (rows = VIDEO_FONT_HEIGHT, dest = dest0; rows--;
+ dest += VIDEO_LINE_LEN) {
+ u8 bits = *cdat++;
+
+ ((u32 *) dest)[0] =
+ (video_font_draw_table[bits >> 6] & eorx) ^ bgx;
+ ((u32 *) dest)[1] =
+ (video_font_draw_table[bits >> 4 & 3] & eorx) ^ bgx;
+ ((u32 *) dest)[2] =
+ (video_font_draw_table[bits >> 2 & 3] & eorx) ^ bgx;
+ ((u32 *) dest)[3] =
+ (video_font_draw_table[bits & 3] & eorx) ^ bgx;
+ bits = *cdat++;
+ ((u32 *) dest)[4] =
+ (video_font_draw_table[bits >> 6] & eorx) ^ bgx;
+ ((u32 *) dest)[5] =
+ (video_font_draw_table[bits >> 4 & 3] & eorx) ^ bgx;
+ if (VIDEO_FONT_WIDTH == 16) {
+ ((u32 *) dest)[6] =
+ (video_font_draw_table[bits >> 2 & 3] & eorx) ^ bgx;
+ ((u32 *) dest)[7] =
+ (video_font_draw_table[bits & 3] & eorx) ^ bgx;
+ }
+ }
+ s++;
+ dest0 += VIDEO_FONT_WIDTH * 2;
+ }
+ break;
+ }
+}
+
+static inline void video_drawstring (int xx, int yy, char *s)
+{
+ video_drawchars (xx, yy, (unsigned char *)s, strlen (s));
+}
+
+/* Relative to console plotting functions */
+
+static void video_putchars (int xx, int yy, unsigned char *s, int count)
+{
+#ifdef CONFIG_VIDEO_LOGO
+ video_drawchars (xx, yy + VIDEO_LOGO_HEIGHT, s, count);
+#else
+ video_drawchars (xx, yy, s, count);
+#endif
+}
+
+static void video_putchar (int xx, int yy, unsigned char c)
+{
+#ifdef CONFIG_VIDEO_LOGO
+ video_drawchars (xx, yy + VIDEO_LOGO_HEIGHT, &c, 1);
+#else
+ video_drawchars (xx, yy, &c, 1);
+#endif
+}
+
+static inline void video_putstring (int xx, int yy, unsigned char *s)
+{
+ video_putchars (xx, yy, (unsigned char *)s, strlen ((char *)s));
+}
+
+/************************************************************************/
+/* ** VIDEO CONTROLLER LOW-LEVEL FUNCTIONS */
+/************************************************************************/
+
+#if !defined(CONFIG_RRVISION)
+static void video_mode_dupefield (VRAM * source, VRAM * dest, int entries)
+{
+ int i;
+
+ for (i = 0; i < entries; i++) {
+ dest[i] = source[i]; /* Copy the entire record */
+ dest[i].fx = (!dest[i].fx) * 3; /* Negate field bit */
+ }
+
+ dest[0].lcyc++; /* Add a cycle to the first entry */
+ dest[entries - 1].lst = 1; /* Set end of ram entries */
+}
+#endif
+
+static void inline video_mode_addentry (VRAM * vr,
+ int Hx, int Vx, int Fx, int Bx,
+ int VDS, int INT, int LCYC, int LP, int LST)
+{
+ vr->hx = Hx;
+ vr->vx = Vx;
+ vr->fx = Fx;
+ vr->bx = Bx;
+ vr->vds = VDS;
+ vr->inter = INT;
+ vr->lcyc = LCYC;
+ vr->lp = LP;
+ vr->lst = LST;
+}
+
+#define ADDENTRY(a,b,c,d,e,f,g,h,i) video_mode_addentry(&vr[entry++],a,b,c,d,e,f,g,h,i)
+
+static int video_mode_generate (void)
+{
+ immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ VRAM *vr = (VRAM *) (((void *) immap) + 0xb00); /* Pointer to the VRAM table */
+ int DX, X1, X2, DY, Y1, Y2, entry = 0, fifo;
+
+ /* CHECKING PARAMETERS */
+
+ if (video_panning_factor_y < -128)
+ video_panning_factor_y = -128;
+
+ if (video_panning_factor_y > 128)
+ video_panning_factor_y = 128;
+
+ if (video_panning_factor_x < -128)
+ video_panning_factor_x = -128;
+
+ if (video_panning_factor_x > 128)
+ video_panning_factor_x = 128;
+
+ /* Setting panning */
+
+ DX = video_panning_range_x = (VIDEO_ACTIVE_COLS - VIDEO_COLS) * 2;
+ DY = video_panning_range_y = (VIDEO_ACTIVE_ROWS - VIDEO_ROWS) / 2;
+
+ video_panning_value_x = (video_panning_factor_x + 128) * DX / 256;
+ video_panning_value_y = (video_panning_factor_y + 128) * DY / 256;
+
+ /* We assume these are burst units (multiplied by 2, we need it pari) */
+ X1 = video_panning_value_x & 0xfffe;
+ X2 = DX - X1;
+
+ /* We assume these are field line units (divided by 2, we need it pari) */
+ Y1 = video_panning_value_y & 0xfffe;
+ Y2 = DY - Y1;
+
+ debug("X1=%d, X2=%d, Y1=%d, Y2=%d, DX=%d, DY=%d VIDEO_COLS=%d \n",
+ X1, X2, Y1, Y2, DX, DY, VIDEO_COLS);
+
+#ifdef VIDEO_MODE_NTSC
+/*
+ * Hx Vx Fx Bx VDS INT LCYC LP LST
+ *
+ * Retrace blanking
+ */
+ ADDENTRY (0, 0, 3, 0, 1, 0, 3, 1, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 243, 0, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 1440, 0, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 32, 1, 0);
+/*
+ * Vertical blanking
+ */
+ ADDENTRY (0, 0, 0, 0, 1, 0, 18, 1, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 243, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 1440, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 32, 1, 0);
+/*
+ * Odd field active area (TOP)
+ */
+ if (Y1 > 0) {
+ ADDENTRY (0, 0, 0, 0, 1, 0, Y1, 1, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 235, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, 1448, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 32, 1, 0);
+ }
+/*
+ * Odd field active area
+ */
+ ADDENTRY (0, 0, 0, 0, 1, 0, 240 - DY, 1, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 235, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, 8 + X1, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 0, 0, VIDEO_COLS * 2, 0, 0);
+
+ if (X2 > 0)
+ ADDENTRY (3, 0, 0, 3, 1, 0, X2, 0, 0);
+
+ ADDENTRY (3, 0, 0, 0, 1, 0, 32, 1, 0);
+
+/*
+ * Odd field active area (BOTTOM)
+ */
+ if (Y1 > 0) {
+ ADDENTRY (0, 0, 0, 0, 1, 0, Y2, 1, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 235, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, 1448, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 32, 1, 0);
+ }
+/*
+ * Vertical blanking
+ */
+ ADDENTRY (0, 0, 0, 0, 1, 0, 4, 1, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 243, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 1440, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 32, 1, 0);
+/*
+ * Vertical blanking
+ */
+ ADDENTRY (0, 0, 3, 0, 1, 0, 19, 1, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 243, 0, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 1440, 0, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 32, 1, 0);
+/*
+ * Even field active area (TOP)
+ */
+ if (Y1 > 0) {
+ ADDENTRY (0, 0, 3, 0, 1, 0, Y1, 1, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 235, 0, 0);
+ ADDENTRY (3, 0, 3, 3, 1, 0, 1448, 0, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 32, 1, 0);
+ }
+/*
+ * Even field active area (CENTER)
+ */
+ ADDENTRY (0, 0, 3, 0, 1, 0, 240 - DY, 1, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 235, 0, 0);
+ ADDENTRY (3, 0, 3, 3, 1, 0, 8 + X1, 0, 0);
+ ADDENTRY (3, 0, 3, 3, 0, 0, VIDEO_COLS * 2, 0, 0);
+
+ if (X2 > 0)
+ ADDENTRY (3, 0, 3, 3, 1, 0, X2, 0, 0);
+
+ ADDENTRY (3, 0, 3, 0, 1, 0, 32, 1, 0);
+/*
+ * Even field active area (BOTTOM)
+ */
+ if (Y1 > 0) {
+ ADDENTRY (0, 0, 3, 0, 1, 0, Y2, 1, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 235, 0, 0);
+ ADDENTRY (3, 0, 3, 3, 1, 0, 1448, 0, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 32, 1, 0);
+ }
+/*
+ * Vertical blanking
+ */
+ ADDENTRY (0, 0, 3, 0, 1, 0, 1, 1, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 243, 0, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 0, 1440, 0, 0);
+ ADDENTRY (3, 0, 3, 0, 1, 1, 32, 1, 1);
+#endif
+
+#ifdef VIDEO_MODE_PAL
+
+#if defined(CONFIG_RRVISION)
+
+#define HPW 160 /* horizontal pulse width (was 139) */
+#define VPW 2 /* vertical pulse width */
+#define HBP 104 /* horizontal back porch (was 112) */
+#define VBP 19 /* vertical back porch (was 19) */
+#define VID_R 240 /* number of rows */
+
+ debug ("[VIDEO CTRL] Starting to add controller entries...");
+/*
+ * Even field
+ */
+ ADDENTRY (0, 3, 0, 3, 1, 0, 2, 0, 0);
+ ADDENTRY (0, 0, 0, 3, 1, 0, HPW, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 0, 0);
+
+ ADDENTRY (0, 0, 0, 3, 1, 0, VPW, 1, 0);
+ ADDENTRY (0, 0, 0, 3, 1, 0, HPW-1, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 1, 0);
+
+ ADDENTRY (0, 3, 0, 3, 1, 0, VBP, 1, 0);
+ ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 1, 0);
+/*
+ * Active area
+ */
+ ADDENTRY (0, 3, 0, 3, 1, 0, VID_R , 1, 0);
+ ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 1, 0, HBP, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 0, 0, VIDEO_COLS*2, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 1, 0, 72, 1, 1);
+
+ ADDENTRY (0, 3, 0, 3, 1, 0, 51, 1, 0);
+ ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 1, 0, HBP +(VIDEO_COLS * 2) + 72 , 1, 0);
+/*
+ * Odd field
+ */
+ ADDENTRY (0, 3, 0, 3, 1, 0, 2, 0, 0);
+ ADDENTRY (0, 0, 0, 3, 1, 0, HPW, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 0, 0);
+
+ ADDENTRY (0, 0, 0, 3, 1, 0, VPW+1, 1, 0);
+ ADDENTRY (0, 0, 0, 3, 1, 0, HPW-1, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 1, 0);
+
+ ADDENTRY (0, 3, 0, 3, 1, 0, VBP, 1, 0);
+ ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 1, 0, HBP + (VIDEO_COLS * 2) + 72, 1, 0);
+/*
+ * Active area
+ */
+ ADDENTRY (0, 3, 0, 3, 1, 0, VID_R , 1, 0);
+ ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 1, 0, HBP, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 0, 0, VIDEO_COLS*2, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 1, 0, 72, 1, 1);
+
+ ADDENTRY (0, 3, 0, 3, 1, 0, 51, 1, 0);
+ ADDENTRY (0, 3, 0, 3, 1, 0, HPW-1, 0, 0);
+ ADDENTRY (3, 3, 0, 3, 1, 0, HBP +(VIDEO_COLS * 2) + 72 , 1, 0);
+
+ debug ("done\n");
+
+#else /* !CONFIG_RRVISION */
+
+/*
+ * Hx Vx Fx Bx VDS INT LCYC LP LST
+ *
+ * vertical; blanking
+ */
+ ADDENTRY (0, 0, 0, 0, 1, 0, 22, 1, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 263, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 1440, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 24, 1, 0);
+/*
+ * active area (TOP)
+ */
+ if (Y1 > 0) {
+ ADDENTRY (0, 0, 0, 0, 1, 0, Y1, 1, 0); /* 11? */
+ ADDENTRY (3, 0, 0, 0, 1, 0, 255, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, 1448, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 24, 1, 0);
+ }
+/*
+ * field active area (CENTER)
+ */
+ ADDENTRY (0, 0, 0, 0, 1, 0, 288 - DY, 1, 0); /* 265? */
+ ADDENTRY (3, 0, 0, 0, 1, 0, 255, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, 8 + X1, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 0, 0, VIDEO_COLS * 2, 0, 0);
+
+ if (X2 > 0)
+ ADDENTRY (3, 0, 0, 1, 1, 0, X2, 0, 0);
+
+ ADDENTRY (3, 0, 0, 0, 1, 0, 24, 1, 0);
+/*
+ * field active area (BOTTOM)
+ */
+ if (Y2 > 0) {
+ ADDENTRY (0, 0, 0, 0, 1, 0, Y2, 1, 0); /* 12? */
+ ADDENTRY (3, 0, 0, 0, 1, 0, 255, 0, 0);
+ ADDENTRY (3, 0, 0, 3, 1, 0, 1448, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 24, 1, 0);
+ }
+/*
+ * field vertical; blanking
+ */
+ ADDENTRY (0, 0, 0, 0, 1, 0, 2, 1, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 263, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 1440, 0, 0);
+ ADDENTRY (3, 0, 0, 0, 1, 0, 24, 1, 0);
+/*
+ * Create the other field (like this, but whit other field selected,
+ * one more cycle loop and a last identifier)
+ */
+ video_mode_dupefield (vr, &vr[entry], entry);
+#endif /* CONFIG_RRVISION */
+
+#endif /* VIDEO_MODE_PAL */
+
+ /* See what FIFO are we using */
+ fifo = GETBIT (immap->im_vid.vid_vsr, VIDEO_VSR_CAS);
+
+ /* Set number of lines and burst (only one frame for now) */
+ if (fifo) {
+ immap->im_vid.vid_vfcr0 = VIDEO_BURST_LEN |
+ (VIDEO_BURST_LEN << 8) | ((VIDEO_ROWS / 2) << 19);
+ } else {
+ immap->im_vid.vid_vfcr1 = VIDEO_BURST_LEN |
+ (VIDEO_BURST_LEN << 8) | ((VIDEO_ROWS / 2) << 19);
+ }
+
+ SETBIT (immap->im_vid.vid_vcmr, VIDEO_VCMR_ASEL, !fifo);
+
+/*
+ * Wait until changes are applied (not done)
+ * while (GETBIT(immap->im_vid.vid_vsr, VIDEO_VSR_CAS) == fifo) ;
+ */
+
+ /* Return number of VRAM entries */
+ return entry * 2;
+}
+
+static void video_encoder_init (void)
+{
+#ifdef VIDEO_I2C
+ int rc;
+
+ /* Initialize the I2C */
+ debug ("[VIDEO ENCODER] Initializing I2C bus...\n");
+ i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+#ifdef CONFIG_FADS
+ /* Reset ADV7176 chip */
+ debug ("[VIDEO ENCODER] Resetting encoder...\n");
+ (*(int *) BCSR4) &= ~(1 << 21);
+
+ /* Wait for 5 ms inside the reset */
+ debug ("[VIDEO ENCODER] Waiting for encoder reset...\n");
+ udelay (5000);
+
+ /* Take ADV7176 out of reset */
+ (*(int *) BCSR4) |= 1 << 21;
+
+ /* Wait for 5 ms after the reset */
+ udelay (5000);
+#endif /* CONFIG_FADS */
+
+ /* Send configuration */
+#ifdef DEBUG
+ {
+ int i;
+
+ puts ("[VIDEO ENCODER] Configuring the encoder...\n");
+
+ printf ("Sending %zu bytes (@ %08lX) to I2C 0x%lX:\n ",
+ sizeof(video_encoder_data),
+ (ulong)video_encoder_data,
+ (ulong)VIDEO_I2C_ADDR);
+ for (i=0; i<sizeof(video_encoder_data); ++i) {
+ printf(" %02X", video_encoder_data[i]);
+ }
+ putc ('\n');
+ }
+#endif /* DEBUG */
+
+ if ((rc = i2c_write (VIDEO_I2C_ADDR, 0, 1,
+ video_encoder_data,
+ sizeof(video_encoder_data))) != 0) {
+ printf ("i2c_send error: rc=%d\n", rc);
+ return;
+ }
+#endif /* VIDEO_I2C */
+ return;
+}
+
+static void video_ctrl_init (void *memptr)
+{
+ immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+
+ video_fb_address = memptr;
+
+ /* Set background */
+ debug ("[VIDEO CTRL] Setting background color...\n");
+ immap->im_vid.vid_vbcb = VIDEO_BG_COL;
+
+ /* Show the background */
+ debug ("[VIDEO CTRL] Forcing background...\n");
+ SETBIT (immap->im_vid.vid_vcmr, VIDEO_VCMR_BD, 1);
+
+ /* Turn off video controller */
+ debug ("[VIDEO CTRL] Turning off video controller...\n");
+ SETBIT (immap->im_vid.vid_vccr, VIDEO_VCCR_VON, 0);
+
+#ifdef CONFIG_FADS
+ /* Turn on Video Port LED */
+ debug ("[VIDEO CTRL] Turning off video port led...\n");
+ SETBIT (*(int *) BCSR4, VIDEO_BCSR4_VIDLED_BIT, 1);
+
+ /* Disable internal clock */
+ debug ("[VIDEO CTRL] Disabling internal clock...\n");
+ SETBIT (*(int *) BCSR4, VIDEO_BCSR4_EXTCLK_BIT, 0);
+#endif
+
+ /* Generate and make active a new video mode */
+ debug ("[VIDEO CTRL] Generating video mode...\n");
+ video_mode_generate ();
+
+ /* Start of frame buffer (even and odd frame, to make it working with */
+ /* any selected active set) */
+ debug ("[VIDEO CTRL] Setting frame buffer address...\n");
+ immap->im_vid.vid_vfaa1 =
+ immap->im_vid.vid_vfaa0 = (u32) video_fb_address;
+ immap->im_vid.vid_vfba1 =
+ immap->im_vid.vid_vfba0 =
+ (u32) video_fb_address + VIDEO_LINE_LEN;
+
+ /* YUV, Big endian, SHIFT/CLK/CLK input (BEFORE ENABLING 27MHZ EXT CLOCK) */
+ debug ("[VIDEO CTRL] Setting pixel mode and clocks...\n");
+ immap->im_vid.vid_vccr = 0x2042;
+
+ /* Configure port pins */
+ debug ("[VIDEO CTRL] Configuring input/output pins...\n");
+ immap->im_ioport.iop_pdpar = 0x1fff;
+ immap->im_ioport.iop_pddir = 0x0000;
+
+#ifdef CONFIG_FADS
+ /* Turn on Video Port Clock - ONLY AFTER SET VCCR TO ENABLE EXTERNAL CLOCK */
+ debug ("[VIDEO CTRL] Turning on video clock...\n");
+ SETBIT (*(int *) BCSR4, VIDEO_BCSR4_EXTCLK_BIT, 1);
+
+ /* Turn on Video Port LED */
+ debug ("[VIDEO CTRL] Turning on video port led...\n");
+ SETBIT (*(int *) BCSR4, VIDEO_BCSR4_VIDLED_BIT, 0);
+#endif
+#ifdef CONFIG_RRVISION
+ debug ("PC5->Output(1): enable PAL clock");
+ immap->im_ioport.iop_pcpar &= ~(0x0400);
+ immap->im_ioport.iop_pcdir |= 0x0400 ;
+ immap->im_ioport.iop_pcdat |= 0x0400 ;
+ debug ("PDPAR=0x%04X PDDIR=0x%04X PDDAT=0x%04X\n",
+ immap->im_ioport.iop_pdpar,
+ immap->im_ioport.iop_pddir,
+ immap->im_ioport.iop_pddat);
+ debug ("PCPAR=0x%04X PCDIR=0x%04X PCDAT=0x%04X\n",
+ immap->im_ioport.iop_pcpar,
+ immap->im_ioport.iop_pcdir,
+ immap->im_ioport.iop_pcdat);
+#endif /* CONFIG_RRVISION */
+
+ /* Blanking the screen. */
+ debug ("[VIDEO CTRL] Blanking the screen...\n");
+ video_fill (VIDEO_BG_COL);
+
+ /*
+ * Turns on Aggressive Mode. Normally, turning on the caches
+ * will cause the screen to flicker when the caches try to
+ * fill. This gives the FIFO's for the Video Controller
+ * higher priority and prevents flickering because of
+ * underrun. This may still be an issue when using FLASH,
+ * since accessing data from Flash is so slow.
+ */
+ debug ("[VIDEO CTRL] Turning on aggressive mode...\n");
+ immap->im_siu_conf.sc_sdcr = 0x40;
+
+ /* Turn on video controller */
+ debug ("[VIDEO CTRL] Turning on video controller...\n");
+ SETBIT (immap->im_vid.vid_vccr, VIDEO_VCCR_VON, 1);
+
+ /* Show the display */
+ debug ("[VIDEO CTRL] Enabling the video...\n");
+ SETBIT (immap->im_vid.vid_vcmr, VIDEO_VCMR_BD, 0);
+}
+
+/************************************************************************/
+/* ** CONSOLE FUNCTIONS */
+/************************************************************************/
+
+static void console_scrollup (void)
+{
+ /* Copy up rows ignoring the first one */
+ memcpyl (CONSOLE_ROW_FIRST, CONSOLE_ROW_SECOND, CONSOLE_SCROLL_SIZE >> 2);
+
+ /* Clear the last one */
+ memsetl (CONSOLE_ROW_LAST, CONSOLE_ROW_SIZE >> 2, VIDEO_BG_COL);
+}
+
+static inline void console_back (void)
+{
+ console_col--;
+
+ if (console_col < 0) {
+ console_col = CONSOLE_COLS - 1;
+ console_row--;
+ if (console_row < 0)
+ console_row = 0;
+ }
+
+ video_putchar ( console_col * VIDEO_FONT_WIDTH,
+ console_row * VIDEO_FONT_HEIGHT, ' ');
+}
+
+static inline void console_newline (void)
+{
+ console_row++;
+ console_col = 0;
+
+ /* Check if we need to scroll the terminal */
+ if (console_row >= CONSOLE_ROWS) {
+ /* Scroll everything up */
+ console_scrollup ();
+
+ /* Decrement row number */
+ console_row--;
+ }
+}
+
+void video_putc (const char c)
+{
+ if (!video_enable) {
+ serial_putc (c);
+ return;
+ }
+
+ switch (c) {
+ case 13: /* Simply ignore this */
+ break;
+
+ case '\n': /* Next line, please */
+ console_newline ();
+ break;
+
+ case 9: /* Tab (8 chars alignment) */
+ console_col |= 0x0008; /* Next 8 chars boundary */
+ console_col &= ~0x0007; /* Set this bit to zero */
+
+ if (console_col >= CONSOLE_COLS)
+ console_newline ();
+ break;
+
+ case 8: /* Eat last character */
+ console_back ();
+ break;
+
+ default: /* Add to the console */
+ video_putchar ( console_col * VIDEO_FONT_WIDTH,
+ console_row * VIDEO_FONT_HEIGHT, c);
+ console_col++;
+ /* Check if we need to go to next row */
+ if (console_col >= CONSOLE_COLS)
+ console_newline ();
+ }
+}
+
+void video_puts (const char *s)
+{
+ int count = strlen (s);
+
+ if (!video_enable)
+ while (count--)
+ serial_putc (*s++);
+ else
+ while (count--)
+ video_putc (*s++);
+}
+
+/************************************************************************/
+/* ** CURSOR BLINKING FUNCTIONS */
+/************************************************************************/
+
+#ifdef VIDEO_BLINK
+
+#define BLINK_TIMER_ID 0
+#define BLINK_TIMER_HZ 2
+
+static unsigned char blink_enabled = 0;
+static timer_t blink_timer;
+
+static void blink_update (void)
+{
+ static int blink_row = -1, blink_col = -1, blink_old = 0;
+
+ /* Check if we have a new position to invert */
+ if ((console_row != blink_row) || (console_col != blink_col)) {
+ /* Check if we need to reverse last character */
+ if (blink_old)
+ video_revchar ( blink_col * VIDEO_FONT_WIDTH,
+ (blink_row
+#ifdef CONFIG_VIDEO_LOGO
+ + VIDEO_LOGO_HEIGHT
+#endif
+ ) * VIDEO_FONT_HEIGHT);
+
+ /* Update values */
+ blink_row = console_row;
+ blink_col = console_col;
+ blink_old = 0;
+ }
+
+/* Reverse this character */
+ blink_old = !blink_old;
+ video_revchar ( console_col * VIDEO_FONT_WIDTH,
+ (console_row
+#ifdef CONFIG_VIDEO_LOGO
+ + VIDEO_LOGO_HEIGHT
+#endif
+ ) * VIDEO_FONT_HEIGHT);
+
+}
+
+/*
+ * Handler for blinking cursor
+ */
+static void blink_handler (void *arg)
+{
+/* Blink */
+ blink_update ();
+/* Ack the timer */
+ timer_ack (&blink_timer);
+}
+
+int blink_set (int blink)
+{
+ int ret = blink_enabled;
+
+ if (blink)
+ timer_enable (&blink_timer);
+ else
+ timer_disable (&blink_timer);
+
+ blink_enabled = blink;
+
+ return ret;
+}
+
+static inline void blink_close (void)
+{
+ timer_close (&blink_timer);
+}
+
+static inline void blink_init (void)
+{
+ timer_init (&blink_timer,
+ BLINK_TIMER_ID, BLINK_TIMER_HZ,
+ blink_handler);
+}
+#endif
+
+/************************************************************************/
+/* ** LOGO PLOTTING FUNCTIONS */
+/************************************************************************/
+
+#ifdef CONFIG_VIDEO_LOGO
+void easylogo_plot (fastimage_t * image, void *screen, int width, int x,
+ int y)
+{
+ int skip = width - image->width, xcount, ycount = image->height;
+
+#ifdef VIDEO_MODE_YUYV
+ ushort *source = (ushort *) image->data;
+ ushort *dest = (ushort *) screen + y * width + x;
+
+ while (ycount--) {
+ xcount = image->width;
+ while (xcount--)
+ *dest++ = *source++;
+ dest += skip;
+ }
+#endif
+#ifdef VIDEO_MODE_RGB
+ unsigned char
+ *source = (unsigned short *) image->data,
+ *dest = (unsigned short *) screen + ((y * width) + x) * 3;
+
+ while (ycount--) {
+ xcount = image->width * 3;
+ memcpy (dest, source, xcount);
+ source += xcount;
+ dest += ycount;
+ }
+#endif
+}
+
+static void *video_logo (void)
+{
+ u16 *screen = video_fb_address, width = VIDEO_COLS;
+#ifdef VIDEO_INFO
+# ifndef CONFIG_FADS
+ char temp[32];
+# endif
+ char info[80];
+#endif /* VIDEO_INFO */
+
+ easylogo_plot (VIDEO_LOGO_ADDR, screen, width, 0, 0);
+
+#ifdef VIDEO_INFO
+ sprintf (info, "%s (%s - %s) ",
+ U_BOOT_VERSION, U_BOOT_DATE, U_BOOT_TIME);
+ video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y, info);
+
+ sprintf (info, "(C) 2002 DENX Software Engineering");
+ video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y + VIDEO_FONT_HEIGHT,
+ info);
+
+ sprintf (info, " Wolfgang DENK, wd@denx.de");
+ video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y + VIDEO_FONT_HEIGHT * 2,
+ info);
+#ifndef CONFIG_FADS /* all normal boards */
+ /* leave one blank line */
+
+ sprintf (info, "MPC823 CPU at %s MHz, %ld MB RAM, %ld MB Flash",
+ strmhz(temp, gd->cpu_clk),
+ gd->ram_size >> 20,
+ gd->bd->bi_flashsize >> 20 );
+ video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y + VIDEO_FONT_HEIGHT * 4,
+ info);
+#else /* FADS :-( */
+ sprintf (info, "MPC823 CPU at 50 MHz on FADS823 board");
+ video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y + VIDEO_FONT_HEIGHT,
+ info);
+
+ sprintf (info, "2MB FLASH - 8MB DRAM - 4MB SRAM");
+ video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y + VIDEO_FONT_HEIGHT * 2,
+ info);
+#endif
+#endif
+
+ return video_fb_address + VIDEO_LOGO_HEIGHT * VIDEO_LINE_LEN;
+}
+#endif
+
+/************************************************************************/
+/* ** VIDEO HIGH-LEVEL FUNCTIONS */
+/************************************************************************/
+
+static int video_init (void *videobase)
+{
+ /* Initialize the encoder */
+ debug ("[VIDEO] Initializing video encoder...\n");
+ video_encoder_init ();
+
+ /* Initialize the video controller */
+ debug ("[VIDEO] Initializing video controller at %08x...\n",
+ (int) videobase);
+ video_ctrl_init (videobase);
+
+ /* Setting the palette */
+ video_setpalette (CONSOLE_COLOR_BLACK, 0, 0, 0);
+ video_setpalette (CONSOLE_COLOR_RED, 0xFF, 0, 0);
+ video_setpalette (CONSOLE_COLOR_GREEN, 0, 0xFF, 0);
+ video_setpalette (CONSOLE_COLOR_YELLOW, 0xFF, 0xFF, 0);
+ video_setpalette (CONSOLE_COLOR_BLUE, 0, 0, 0xFF);
+ video_setpalette (CONSOLE_COLOR_MAGENTA, 0xFF, 0, 0xFF);
+ video_setpalette (CONSOLE_COLOR_CYAN, 0, 0xFF, 0xFF);
+ video_setpalette (CONSOLE_COLOR_GREY, 0xAA, 0xAA, 0xAA);
+ video_setpalette (CONSOLE_COLOR_GREY2, 0xF8, 0xF8, 0xF8);
+ video_setpalette (CONSOLE_COLOR_WHITE, 0xFF, 0xFF, 0xFF);
+
+#ifndef CONFIG_SYS_WHITE_ON_BLACK
+ video_setfgcolor (CONSOLE_COLOR_BLACK);
+ video_setbgcolor (CONSOLE_COLOR_GREY2);
+#else
+ video_setfgcolor (CONSOLE_COLOR_GREY2);
+ video_setbgcolor (CONSOLE_COLOR_BLACK);
+#endif /* CONFIG_SYS_WHITE_ON_BLACK */
+
+#ifdef CONFIG_VIDEO_LOGO
+ /* Paint the logo and retrieve tv base address */
+ debug ("[VIDEO] Drawing the logo...\n");
+ video_console_address = video_logo ();
+#else
+ video_console_address = video_fb_address;
+#endif
+
+#ifdef VIDEO_BLINK
+ /* Enable the blinking (under construction) */
+ blink_init ();
+ blink_set (0); /* To Fix! */
+#endif
+
+ /* Initialize the console */
+ console_col = 0;
+ console_row = 0;
+ video_enable = 1;
+
+#ifdef VIDEO_MODE_PAL
+# define VIDEO_MODE_TMP1 "PAL"
+#endif
+#ifdef VIDEO_MODE_NTSC
+# define VIDEO_MODE_TMP1 "NTSC"
+#endif
+#ifdef VIDEO_MODE_YUYV
+# define VIDEO_MODE_TMP2 "YCbYCr"
+#endif
+#ifdef VIDEO_MODE_RGB
+# define VIDEO_MODE_TMP2 "RGB"
+#endif
+ debug ( VIDEO_MODE_TMP1
+ " %dx%dx%d (" VIDEO_MODE_TMP2 ") on %s - console %dx%d\n",
+ VIDEO_COLS, VIDEO_ROWS, VIDEO_MODE_BPP,
+ VIDEO_ENCODER_NAME, CONSOLE_COLS, CONSOLE_ROWS);
+ return 0;
+}
+
+int drv_video_init (void)
+{
+ int error, devices = 1;
+
+ struct stdio_dev videodev;
+
+ video_init ((void *)(gd->fb_base)); /* Video initialization */
+
+/* Device initialization */
+
+ memset (&videodev, 0, sizeof (videodev));
+
+ strcpy (videodev.name, "video");
+ videodev.ext = DEV_EXT_VIDEO; /* Video extensions */
+ videodev.flags = DEV_FLAGS_OUTPUT; /* Output only */
+ videodev.putc = video_putc; /* 'putc' function */
+ videodev.puts = video_puts; /* 'puts' function */
+
+ error = stdio_register (&videodev);
+
+ return (error == 0) ? devices : error;
+}
+
+/************************************************************************/
+/* ** ROM capable initialization part - needed to reserve FB memory */
+/************************************************************************/
+
+/*
+ * This is called early in the system initialization to grab memory
+ * for the video controller.
+ * Returns new address for monitor, after reserving video buffer memory
+ *
+ * Note that this is running from ROM, so no write access to global data.
+ */
+ulong video_setmem (ulong addr)
+{
+ /* Allocate pages for the frame buffer. */
+ addr -= VIDEO_SIZE;
+
+ debug ("Reserving %dk for Video Framebuffer at: %08lx\n",
+ VIDEO_SIZE>>10, addr);
+
+ return (addr);
+}
+
+#endif
diff --git a/arch/powerpc/cpu/mpc8xx/wlkbd.c b/arch/powerpc/cpu/mpc8xx/wlkbd.c
new file mode 100644
index 0000000..13009e2
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xx/wlkbd.c
@@ -0,0 +1,36 @@
+/*
+ * (C) Copyright 2000
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+
+#ifdef CONFIG_WL_4PPM_KEYBOARD
+
+/* WIP: Wireless keyboard on SMC
+ */
+int drv_wlkbd_init (void)
+{
+ return 0 ;
+}
+
+#endif /* CONFIG_WL_4PPM_KEYBOARD */
diff --git a/arch/powerpc/cpu/mpc8xxx/Makefile b/arch/powerpc/cpu/mpc8xxx/Makefile
new file mode 100644
index 0000000..3dc8e05
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/Makefile
@@ -0,0 +1,49 @@
+#
+# Copyright 2009-2010 Freescale Semiconductor, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# Version 2 as published by the Free Software Foundation.
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib8xxx.o
+
+MINIMAL=
+
+ifdef CONFIG_SPL_BUILD
+ifdef CONFIG_SPL_INIT_MINIMAL
+MINIMAL=y
+endif
+endif
+
+ifdef MINIMAL
+
+COBJS-$(CONFIG_FSL_LAW) += law.o
+
+else
+
+ifneq ($(CPU),mpc83xx)
+COBJS-y += cpu.o
+endif
+
+COBJS-$(CONFIG_OF_LIBFDT) += fdt.o
+COBJS-$(CONFIG_FSL_IFC) += fsl_ifc.o
+COBJS-$(CONFIG_FSL_LBC) += fsl_lbc.o
+COBJS-$(CONFIG_SYS_SRIO) += srio.o
+COBJS-$(CONFIG_FSL_LAW) += law.o
+
+endif
+
+SRCS := $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
+
+all: $(obj).depend $(LIB)
+
+$(LIB): $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
diff --git a/arch/powerpc/cpu/mpc8xxx/cpu.c b/arch/powerpc/cpu/mpc8xxx/cpu.c
new file mode 100644
index 0000000..bc26855
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/cpu.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2009-2012 Freescale Semiconductor, Inc.
+ *
+ * This file is derived from arch/powerpc/cpu/mpc85xx/cpu.c and
+ * arch/powerpc/cpu/mpc86xx/cpu.c. Basically this file contains
+ * cpu specific common code for 85xx/86xx processors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <command.h>
+#include <tsec.h>
+#include <fm_eth.h>
+#include <netdev.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct cpu_type cpu_type_list[] = {
+#if defined(CONFIG_MPC85xx)
+ CPU_TYPE_ENTRY(8533, 8533, 1),
+ CPU_TYPE_ENTRY(8535, 8535, 1),
+ CPU_TYPE_ENTRY(8536, 8536, 1),
+ CPU_TYPE_ENTRY(8540, 8540, 1),
+ CPU_TYPE_ENTRY(8541, 8541, 1),
+ CPU_TYPE_ENTRY(8543, 8543, 1),
+ CPU_TYPE_ENTRY(8544, 8544, 1),
+ CPU_TYPE_ENTRY(8545, 8545, 1),
+ CPU_TYPE_ENTRY(8547, 8547, 1),
+ CPU_TYPE_ENTRY(8548, 8548, 1),
+ CPU_TYPE_ENTRY(8555, 8555, 1),
+ CPU_TYPE_ENTRY(8560, 8560, 1),
+ CPU_TYPE_ENTRY(8567, 8567, 1),
+ CPU_TYPE_ENTRY(8568, 8568, 1),
+ CPU_TYPE_ENTRY(8569, 8569, 1),
+ CPU_TYPE_ENTRY(8572, 8572, 2),
+ CPU_TYPE_ENTRY(P1010, P1010, 1),
+ CPU_TYPE_ENTRY(P1011, P1011, 1),
+ CPU_TYPE_ENTRY(P1012, P1012, 1),
+ CPU_TYPE_ENTRY(P1013, P1013, 1),
+ CPU_TYPE_ENTRY(P1014, P1014, 1),
+ CPU_TYPE_ENTRY(P1017, P1017, 1),
+ CPU_TYPE_ENTRY(P1020, P1020, 2),
+ CPU_TYPE_ENTRY(P1021, P1021, 2),
+ CPU_TYPE_ENTRY(P1022, P1022, 2),
+ CPU_TYPE_ENTRY(P1023, P1023, 2),
+ CPU_TYPE_ENTRY(P1024, P1024, 2),
+ CPU_TYPE_ENTRY(P1025, P1025, 2),
+ CPU_TYPE_ENTRY(P2010, P2010, 1),
+ CPU_TYPE_ENTRY(P2020, P2020, 2),
+ CPU_TYPE_ENTRY(P2040, P2040, 4),
+ CPU_TYPE_ENTRY(P2041, P2041, 4),
+ CPU_TYPE_ENTRY(P3041, P3041, 4),
+ CPU_TYPE_ENTRY(P4040, P4040, 4),
+ CPU_TYPE_ENTRY(P4080, P4080, 8),
+ CPU_TYPE_ENTRY(P5010, P5010, 1),
+ CPU_TYPE_ENTRY(P5020, P5020, 2),
+ CPU_TYPE_ENTRY(P5021, P5021, 2),
+ CPU_TYPE_ENTRY(P5040, P5040, 4),
+ CPU_TYPE_ENTRY(T4240, T4240, 0),
+ CPU_TYPE_ENTRY(T4120, T4120, 0),
+ CPU_TYPE_ENTRY(T4160, T4160, 0),
+ CPU_TYPE_ENTRY(B4860, B4860, 0),
+ CPU_TYPE_ENTRY(G4860, G4860, 0),
+ CPU_TYPE_ENTRY(G4060, G4060, 0),
+ CPU_TYPE_ENTRY(B4440, B4440, 0),
+ CPU_TYPE_ENTRY(G4440, G4440, 0),
+ CPU_TYPE_ENTRY(B4420, B4420, 0),
+ CPU_TYPE_ENTRY(B4220, B4220, 0),
+ CPU_TYPE_ENTRY(T1040, T1040, 0),
+ CPU_TYPE_ENTRY(T1041, T1041, 0),
+ CPU_TYPE_ENTRY(T1042, T1042, 0),
+ CPU_TYPE_ENTRY(T1020, T1020, 0),
+ CPU_TYPE_ENTRY(T1021, T1021, 0),
+ CPU_TYPE_ENTRY(T1022, T1022, 0),
+ CPU_TYPE_ENTRY(BSC9130, 9130, 1),
+ CPU_TYPE_ENTRY(BSC9131, 9131, 1),
+ CPU_TYPE_ENTRY(BSC9132, 9132, 2),
+ CPU_TYPE_ENTRY(BSC9232, 9232, 2),
+#elif defined(CONFIG_MPC86xx)
+ CPU_TYPE_ENTRY(8610, 8610, 1),
+ CPU_TYPE_ENTRY(8641, 8641, 2),
+ CPU_TYPE_ENTRY(8641D, 8641D, 2),
+#endif
+};
+
+#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2
+static inline u32 init_type(u32 cluster, int init_id)
+{
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 idx = (cluster >> (init_id * 8)) & TP_CLUSTER_INIT_MASK;
+ u32 type = in_be32(&gur->tp_ityp[idx]);
+
+ if (type & TP_ITYP_AV)
+ return type;
+
+ return 0;
+}
+
+u32 compute_ppc_cpumask(void)
+{
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ int i = 0, count = 0;
+ u32 cluster, type, mask = 0;
+
+ do {
+ int j;
+ cluster = in_be32(&gur->tp_cluster[i].lower);
+ for (j = 0; j < TP_INIT_PER_CLUSTER; j++) {
+ type = init_type(cluster, j);
+ if (type) {
+ if (TP_ITYP_TYPE(type) == TP_ITYP_TYPE_PPC)
+ mask |= 1 << count;
+ count++;
+ }
+ }
+ i++;
+ } while ((cluster & TP_CLUSTER_EOC) != TP_CLUSTER_EOC);
+
+ return mask;
+}
+
+int fsl_qoriq_core_to_cluster(unsigned int core)
+{
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ int i = 0, count = 0;
+ u32 cluster;
+
+ do {
+ int j;
+ cluster = in_be32(&gur->tp_cluster[i].lower);
+ for (j = 0; j < TP_INIT_PER_CLUSTER; j++) {
+ if (init_type(cluster, j)) {
+ if (count == core)
+ return i;
+ count++;
+ }
+ }
+ i++;
+ } while ((cluster & TP_CLUSTER_EOC) != TP_CLUSTER_EOC);
+
+ return -1; /* cannot identify the cluster */
+}
+
+#else /* CONFIG_SYS_FSL_QORIQ_CHASSIS2 */
+/*
+ * Before chassis genenration 2, the cpumask should be hard-coded.
+ * In case of cpu type unknown or cpumask unset, use 1 as fail save.
+ */
+#define compute_ppc_cpumask() 1
+#define fsl_qoriq_core_to_cluster(x) x
+#endif /* CONFIG_SYS_FSL_QORIQ_CHASSIS2 */
+
+static struct cpu_type cpu_type_unknown = CPU_TYPE_ENTRY(Unknown, Unknown, 0);
+
+struct cpu_type *identify_cpu(u32 ver)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(cpu_type_list); i++) {
+ if (cpu_type_list[i].soc_ver == ver)
+ return &cpu_type_list[i];
+ }
+ return &cpu_type_unknown;
+}
+
+#define MPC8xxx_PICFRR_NCPU_MASK 0x00001f00
+#define MPC8xxx_PICFRR_NCPU_SHIFT 8
+
+/*
+ * Return a 32-bit mask indicating which cores are present on this SOC.
+ */
+u32 cpu_mask(void)
+{
+ ccsr_pic_t __iomem *pic = (void *)CONFIG_SYS_MPC8xxx_PIC_ADDR;
+ struct cpu_type *cpu = gd->arch.cpu;
+
+ /* better to query feature reporting register than just assume 1 */
+ if (cpu == &cpu_type_unknown)
+ return ((in_be32(&pic->frr) & MPC8xxx_PICFRR_NCPU_MASK) >>
+ MPC8xxx_PICFRR_NCPU_SHIFT) + 1;
+
+ if (cpu->num_cores == 0)
+ return compute_ppc_cpumask();
+
+ return cpu->mask;
+}
+
+/*
+ * Return the number of cores on this SOC.
+ */
+int cpu_numcores(void)
+{
+ struct cpu_type *cpu = gd->arch.cpu;
+
+ /*
+ * Report # of cores in terms of the cpu_mask if we haven't
+ * figured out how many there are yet
+ */
+ if (cpu->num_cores == 0)
+ return hweight32(cpu_mask());
+
+ return cpu->num_cores;
+}
+
+/*
+ * Check if the given core ID is valid
+ *
+ * Returns zero if it isn't, 1 if it is.
+ */
+int is_core_valid(unsigned int core)
+{
+ return !!((1 << core) & cpu_mask());
+}
+
+int probecpu (void)
+{
+ uint svr;
+ uint ver;
+
+ svr = get_svr();
+ ver = SVR_SOC_VER(svr);
+
+ gd->arch.cpu = identify_cpu(ver);
+
+ return 0;
+}
+
+/* Once in memory, compute mask & # cores once and save them off */
+int fixup_cpu(void)
+{
+ struct cpu_type *cpu = gd->arch.cpu;
+
+ if (cpu->num_cores == 0) {
+ cpu->mask = cpu_mask();
+ cpu->num_cores = cpu_numcores();
+ }
+
+ return 0;
+}
+
+/*
+ * Initializes on-chip ethernet controllers.
+ * to override, implement board_eth_init()
+ */
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(CONFIG_ETHER_ON_FCC)
+ fec_initialize(bis);
+#endif
+
+#if defined(CONFIG_UEC_ETH)
+ uec_standard_init(bis);
+#endif
+
+#if defined(CONFIG_TSEC_ENET) || defined(CONFIG_MPC85XX_FEC)
+ tsec_standard_init(bis);
+#endif
+
+#ifdef CONFIG_FMAN_ENET
+ fm_standard_init(bis);
+#endif
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/Makefile b/arch/powerpc/cpu/mpc8xxx/ddr/Makefile
new file mode 100644
index 0000000..29523aa
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright 2008-2011 Freescale Semiconductor, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# Version 2 as published by the Free Software Foundation.
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)libddr.o
+
+COBJS-$(CONFIG_FSL_DDR1) += main.o util.o ctrl_regs.o options.o \
+ lc_common_dimm_params.o
+
+COBJS-$(CONFIG_FSL_DDR2) += main.o util.o ctrl_regs.o options.o \
+ lc_common_dimm_params.o
+
+COBJS-$(CONFIG_FSL_DDR3) += main.o util.o ctrl_regs.o options.o \
+ lc_common_dimm_params.o
+ifdef CONFIG_DDR_SPD
+SPD := y
+endif
+ifdef CONFIG_SPD_EEPROM
+SPD := y
+endif
+ifdef SPD
+COBJS-$(CONFIG_FSL_DDR1) += ddr1_dimm_params.o
+COBJS-$(CONFIG_FSL_DDR2) += ddr2_dimm_params.o
+COBJS-$(CONFIG_FSL_DDR3) += ddr3_dimm_params.o
+endif
+
+COBJS-$(CONFIG_FSL_DDR_INTERACTIVE) += interactive.o
+
+SRCS := $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
+
+all: $(obj).depend $(LIB)
+
+$(LIB): $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/common_timing_params.h b/arch/powerpc/cpu/mpc8xxx/ddr/common_timing_params.h
new file mode 100644
index 0000000..06706ed
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/common_timing_params.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef COMMON_TIMING_PARAMS_H
+#define COMMON_TIMING_PARAMS_H
+
+typedef struct {
+ /* parameters to constrict */
+
+ unsigned int tCKmin_X_ps;
+ unsigned int tCKmax_ps;
+ unsigned int tCKmax_max_ps;
+ unsigned int tRCD_ps;
+ unsigned int tRP_ps;
+ unsigned int tRAS_ps;
+
+ unsigned int tWR_ps; /* maximum = 63750 ps */
+ unsigned int tWTR_ps; /* maximum = 63750 ps */
+ unsigned int tRFC_ps; /* maximum = 255 ns + 256 ns + .75 ns
+ = 511750 ps */
+
+ unsigned int tRRD_ps; /* maximum = 63750 ps */
+ unsigned int tRC_ps; /* maximum = 254 ns + .75 ns = 254750 ps */
+
+ unsigned int refresh_rate_ps;
+
+ unsigned int tIS_ps; /* byte 32, spd->ca_setup */
+ unsigned int tIH_ps; /* byte 33, spd->ca_hold */
+ unsigned int tDS_ps; /* byte 34, spd->data_setup */
+ unsigned int tDH_ps; /* byte 35, spd->data_hold */
+ unsigned int tRTP_ps; /* byte 38, spd->trtp */
+ unsigned int tDQSQ_max_ps; /* byte 44, spd->tdqsq */
+ unsigned int tQHS_ps; /* byte 45, spd->tqhs */
+
+ unsigned int ndimms_present;
+ unsigned int lowest_common_SPD_caslat;
+ unsigned int highest_common_derated_caslat;
+ unsigned int additive_latency;
+ unsigned int all_DIMMs_burst_lengths_bitmask;
+ unsigned int all_DIMMs_registered;
+ unsigned int all_DIMMs_unbuffered;
+ unsigned int all_DIMMs_ECC_capable;
+
+ unsigned long long total_mem;
+ unsigned long long base_address;
+
+ /* DDR3 RDIMM */
+ unsigned char rcw[16]; /* Register Control Word 0-15 */
+} common_timing_params_t;
+
+#endif
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
new file mode 100644
index 0000000..26c42f7
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c
@@ -0,0 +1,1645 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+/*
+ * Generic driver for Freescale DDR/DDR2/DDR3 memory controller.
+ * Based on code from spd_sdram.c
+ * Author: James Yang [at freescale.com]
+ */
+
+#include <common.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#include "ddr.h"
+
+#define _DDR_ADDR CONFIG_SYS_MPC8xxx_DDR_ADDR
+
+static u32 fsl_ddr_get_version(void)
+{
+ ccsr_ddr_t *ddr;
+ u32 ver_major_minor_errata;
+
+ ddr = (void *)_DDR_ADDR;
+ ver_major_minor_errata = (in_be32(&ddr->ip_rev1) & 0xFFFF) << 8;
+ ver_major_minor_errata |= (in_be32(&ddr->ip_rev2) & 0xFF00) >> 8;
+
+ return ver_major_minor_errata;
+}
+
+unsigned int picos_to_mclk(unsigned int picos);
+
+/*
+ * Determine Rtt value.
+ *
+ * This should likely be either board or controller specific.
+ *
+ * Rtt(nominal) - DDR2:
+ * 0 = Rtt disabled
+ * 1 = 75 ohm
+ * 2 = 150 ohm
+ * 3 = 50 ohm
+ * Rtt(nominal) - DDR3:
+ * 0 = Rtt disabled
+ * 1 = 60 ohm
+ * 2 = 120 ohm
+ * 3 = 40 ohm
+ * 4 = 20 ohm
+ * 5 = 30 ohm
+ *
+ * FIXME: Apparently 8641 needs a value of 2
+ * FIXME: Old code seys if 667 MHz or higher, use 3 on 8572
+ *
+ * FIXME: There was some effort down this line earlier:
+ *
+ * unsigned int i;
+ * for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL/2; i++) {
+ * if (popts->dimmslot[i].num_valid_cs
+ * && (popts->cs_local_opts[2*i].odt_rd_cfg
+ * || popts->cs_local_opts[2*i].odt_wr_cfg)) {
+ * rtt = 2;
+ * break;
+ * }
+ * }
+ */
+static inline int fsl_ddr_get_rtt(void)
+{
+ int rtt;
+
+#if defined(CONFIG_FSL_DDR1)
+ rtt = 0;
+#elif defined(CONFIG_FSL_DDR2)
+ rtt = 3;
+#else
+ rtt = 0;
+#endif
+
+ return rtt;
+}
+
+/*
+ * compute the CAS write latency according to DDR3 spec
+ * CWL = 5 if tCK >= 2.5ns
+ * 6 if 2.5ns > tCK >= 1.875ns
+ * 7 if 1.875ns > tCK >= 1.5ns
+ * 8 if 1.5ns > tCK >= 1.25ns
+ * 9 if 1.25ns > tCK >= 1.07ns
+ * 10 if 1.07ns > tCK >= 0.935ns
+ * 11 if 0.935ns > tCK >= 0.833ns
+ * 12 if 0.833ns > tCK >= 0.75ns
+ */
+static inline unsigned int compute_cas_write_latency(void)
+{
+ unsigned int cwl;
+ const unsigned int mclk_ps = get_memory_clk_period_ps();
+
+ if (mclk_ps >= 2500)
+ cwl = 5;
+ else if (mclk_ps >= 1875)
+ cwl = 6;
+ else if (mclk_ps >= 1500)
+ cwl = 7;
+ else if (mclk_ps >= 1250)
+ cwl = 8;
+ else if (mclk_ps >= 1070)
+ cwl = 9;
+ else if (mclk_ps >= 935)
+ cwl = 10;
+ else if (mclk_ps >= 833)
+ cwl = 11;
+ else if (mclk_ps >= 750)
+ cwl = 12;
+ else {
+ cwl = 12;
+ printf("Warning: CWL is out of range\n");
+ }
+ return cwl;
+}
+
+/* Chip Select Configuration (CSn_CONFIG) */
+static void set_csn_config(int dimm_number, int i, fsl_ddr_cfg_regs_t *ddr,
+ const memctl_options_t *popts,
+ const dimm_params_t *dimm_params)
+{
+ unsigned int cs_n_en = 0; /* Chip Select enable */
+ unsigned int intlv_en = 0; /* Memory controller interleave enable */
+ unsigned int intlv_ctl = 0; /* Interleaving control */
+ unsigned int ap_n_en = 0; /* Chip select n auto-precharge enable */
+ unsigned int odt_rd_cfg = 0; /* ODT for reads configuration */
+ unsigned int odt_wr_cfg = 0; /* ODT for writes configuration */
+ unsigned int ba_bits_cs_n = 0; /* Num of bank bits for SDRAM on CSn */
+ unsigned int row_bits_cs_n = 0; /* Num of row bits for SDRAM on CSn */
+ unsigned int col_bits_cs_n = 0; /* Num of ocl bits for SDRAM on CSn */
+ int go_config = 0;
+
+ /* Compute CS_CONFIG only for existing ranks of each DIMM. */
+ switch (i) {
+ case 0:
+ if (dimm_params[dimm_number].n_ranks > 0) {
+ go_config = 1;
+ /* These fields only available in CS0_CONFIG */
+ if (!popts->memctl_interleaving)
+ break;
+ switch (popts->memctl_interleaving_mode) {
+ case FSL_DDR_CACHE_LINE_INTERLEAVING:
+ case FSL_DDR_PAGE_INTERLEAVING:
+ case FSL_DDR_BANK_INTERLEAVING:
+ case FSL_DDR_SUPERBANK_INTERLEAVING:
+ intlv_en = popts->memctl_interleaving;
+ intlv_ctl = popts->memctl_interleaving_mode;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case 1:
+ if ((dimm_number == 0 && dimm_params[0].n_ranks > 1) || \
+ (dimm_number == 1 && dimm_params[1].n_ranks > 0))
+ go_config = 1;
+ break;
+ case 2:
+ if ((dimm_number == 0 && dimm_params[0].n_ranks > 2) || \
+ (dimm_number >= 1 && dimm_params[dimm_number].n_ranks > 0))
+ go_config = 1;
+ break;
+ case 3:
+ if ((dimm_number == 0 && dimm_params[0].n_ranks > 3) || \
+ (dimm_number == 1 && dimm_params[1].n_ranks > 1) || \
+ (dimm_number == 3 && dimm_params[3].n_ranks > 0))
+ go_config = 1;
+ break;
+ default:
+ break;
+ }
+ if (go_config) {
+ unsigned int n_banks_per_sdram_device;
+ cs_n_en = 1;
+ ap_n_en = popts->cs_local_opts[i].auto_precharge;
+ odt_rd_cfg = popts->cs_local_opts[i].odt_rd_cfg;
+ odt_wr_cfg = popts->cs_local_opts[i].odt_wr_cfg;
+ n_banks_per_sdram_device
+ = dimm_params[dimm_number].n_banks_per_sdram_device;
+ ba_bits_cs_n = __ilog2(n_banks_per_sdram_device) - 2;
+ row_bits_cs_n = dimm_params[dimm_number].n_row_addr - 12;
+ col_bits_cs_n = dimm_params[dimm_number].n_col_addr - 8;
+ }
+ ddr->cs[i].config = (0
+ | ((cs_n_en & 0x1) << 31)
+ | ((intlv_en & 0x3) << 29)
+ | ((intlv_ctl & 0xf) << 24)
+ | ((ap_n_en & 0x1) << 23)
+
+ /* XXX: some implementation only have 1 bit starting at left */
+ | ((odt_rd_cfg & 0x7) << 20)
+
+ /* XXX: Some implementation only have 1 bit starting at left */
+ | ((odt_wr_cfg & 0x7) << 16)
+
+ | ((ba_bits_cs_n & 0x3) << 14)
+ | ((row_bits_cs_n & 0x7) << 8)
+ | ((col_bits_cs_n & 0x7) << 0)
+ );
+ debug("FSLDDR: cs[%d]_config = 0x%08x\n", i,ddr->cs[i].config);
+}
+
+/* Chip Select Configuration 2 (CSn_CONFIG_2) */
+/* FIXME: 8572 */
+static void set_csn_config_2(int i, fsl_ddr_cfg_regs_t *ddr)
+{
+ unsigned int pasr_cfg = 0; /* Partial array self refresh config */
+
+ ddr->cs[i].config_2 = ((pasr_cfg & 7) << 24);
+ debug("FSLDDR: cs[%d]_config_2 = 0x%08x\n", i, ddr->cs[i].config_2);
+}
+
+/* -3E = 667 CL5, -25 = CL6 800, -25E = CL5 800 */
+
+#if !defined(CONFIG_FSL_DDR1)
+static inline int avoid_odt_overlap(const dimm_params_t *dimm_params)
+{
+#if CONFIG_DIMM_SLOTS_PER_CTLR == 1
+ if (dimm_params[0].n_ranks == 4)
+ return 1;
+#endif
+
+#if CONFIG_DIMM_SLOTS_PER_CTLR == 2
+ if ((dimm_params[0].n_ranks == 2) &&
+ (dimm_params[1].n_ranks == 2))
+ return 1;
+
+#ifdef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE
+ if (dimm_params[0].n_ranks == 4)
+ return 1;
+#endif
+#endif
+ return 0;
+}
+
+/*
+ * DDR SDRAM Timing Configuration 0 (TIMING_CFG_0)
+ *
+ * Avoid writing for DDR I. The new PQ38 DDR controller
+ * dreams up non-zero default values to be backwards compatible.
+ */
+static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr,
+ const memctl_options_t *popts,
+ const dimm_params_t *dimm_params)
+{
+ unsigned char trwt_mclk = 0; /* Read-to-write turnaround */
+ unsigned char twrt_mclk = 0; /* Write-to-read turnaround */
+ /* 7.5 ns on -3E; 0 means WL - CL + BL/2 + 1 */
+ unsigned char trrt_mclk = 0; /* Read-to-read turnaround */
+ unsigned char twwt_mclk = 0; /* Write-to-write turnaround */
+
+ /* Active powerdown exit timing (tXARD and tXARDS). */
+ unsigned char act_pd_exit_mclk;
+ /* Precharge powerdown exit timing (tXP). */
+ unsigned char pre_pd_exit_mclk;
+ /* ODT powerdown exit timing (tAXPD). */
+ unsigned char taxpd_mclk;
+ /* Mode register set cycle time (tMRD). */
+ unsigned char tmrd_mclk;
+
+#ifdef CONFIG_FSL_DDR3
+ /*
+ * (tXARD and tXARDS). Empirical?
+ * The DDR3 spec has not tXARD,
+ * we use the tXP instead of it.
+ * tXP=max(3nCK, 7.5ns) for DDR3.
+ * spec has not the tAXPD, we use
+ * tAXPD=1, need design to confirm.
+ */
+ int tXP = max((get_memory_clk_period_ps() * 3), 7500); /* unit=ps */
+ unsigned int data_rate = get_ddr_freq(0);
+ tmrd_mclk = 4;
+ /* set the turnaround time */
+
+ /*
+ * for single quad-rank DIMM and two dual-rank DIMMs
+ * to avoid ODT overlap
+ */
+ if (avoid_odt_overlap(dimm_params)) {
+ twwt_mclk = 2;
+ trrt_mclk = 1;
+ }
+ /* for faster clock, need more time for data setup */
+ trwt_mclk = (data_rate/1000000 > 1800) ? 2 : 1;
+
+ if ((data_rate/1000000 > 1150) || (popts->memctl_interleaving))
+ twrt_mclk = 1;
+
+ if (popts->dynamic_power == 0) { /* powerdown is not used */
+ act_pd_exit_mclk = 1;
+ pre_pd_exit_mclk = 1;
+ taxpd_mclk = 1;
+ } else {
+ /* act_pd_exit_mclk = tXARD, see above */
+ act_pd_exit_mclk = picos_to_mclk(tXP);
+ /* Mode register MR0[A12] is '1' - fast exit */
+ pre_pd_exit_mclk = act_pd_exit_mclk;
+ taxpd_mclk = 1;
+ }
+#else /* CONFIG_FSL_DDR2 */
+ /*
+ * (tXARD and tXARDS). Empirical?
+ * tXARD = 2 for DDR2
+ * tXP=2
+ * tAXPD=8
+ */
+ act_pd_exit_mclk = 2;
+ pre_pd_exit_mclk = 2;
+ taxpd_mclk = 8;
+ tmrd_mclk = 2;
+#endif
+
+ if (popts->trwt_override)
+ trwt_mclk = popts->trwt;
+
+ ddr->timing_cfg_0 = (0
+ | ((trwt_mclk & 0x3) << 30) /* RWT */
+ | ((twrt_mclk & 0x3) << 28) /* WRT */
+ | ((trrt_mclk & 0x3) << 26) /* RRT */
+ | ((twwt_mclk & 0x3) << 24) /* WWT */
+ | ((act_pd_exit_mclk & 0x7) << 20) /* ACT_PD_EXIT */
+ | ((pre_pd_exit_mclk & 0xF) << 16) /* PRE_PD_EXIT */
+ | ((taxpd_mclk & 0xf) << 8) /* ODT_PD_EXIT */
+ | ((tmrd_mclk & 0xf) << 0) /* MRS_CYC */
+ );
+ debug("FSLDDR: timing_cfg_0 = 0x%08x\n", ddr->timing_cfg_0);
+}
+#endif /* defined(CONFIG_FSL_DDR2) */
+
+/* DDR SDRAM Timing Configuration 3 (TIMING_CFG_3) */
+static void set_timing_cfg_3(fsl_ddr_cfg_regs_t *ddr,
+ const memctl_options_t *popts,
+ const common_timing_params_t *common_dimm,
+ unsigned int cas_latency)
+{
+ /* Extended precharge to activate interval (tRP) */
+ unsigned int ext_pretoact = 0;
+ /* Extended Activate to precharge interval (tRAS) */
+ unsigned int ext_acttopre = 0;
+ /* Extended activate to read/write interval (tRCD) */
+ unsigned int ext_acttorw = 0;
+ /* Extended refresh recovery time (tRFC) */
+ unsigned int ext_refrec;
+ /* Extended MCAS latency from READ cmd */
+ unsigned int ext_caslat = 0;
+ /* Extended last data to precharge interval (tWR) */
+ unsigned int ext_wrrec = 0;
+ /* Control Adjust */
+ unsigned int cntl_adj = 0;
+
+ ext_pretoact = picos_to_mclk(common_dimm->tRP_ps) >> 4;
+ ext_acttopre = picos_to_mclk(common_dimm->tRAS_ps) >> 4;
+ ext_acttorw = picos_to_mclk(common_dimm->tRCD_ps) >> 4;
+ ext_caslat = (2 * cas_latency - 1) >> 4;
+ ext_refrec = (picos_to_mclk(common_dimm->tRFC_ps) - 8) >> 4;
+ /* ext_wrrec only deals with 16 clock and above, or 14 with OTF */
+ ext_wrrec = (picos_to_mclk(common_dimm->tWR_ps) +
+ (popts->OTF_burst_chop_en ? 2 : 0)) >> 4;
+
+ ddr->timing_cfg_3 = (0
+ | ((ext_pretoact & 0x1) << 28)
+ | ((ext_acttopre & 0x2) << 24)
+ | ((ext_acttorw & 0x1) << 22)
+ | ((ext_refrec & 0x1F) << 16)
+ | ((ext_caslat & 0x3) << 12)
+ | ((ext_wrrec & 0x1) << 8)
+ | ((cntl_adj & 0x7) << 0)
+ );
+ debug("FSLDDR: timing_cfg_3 = 0x%08x\n", ddr->timing_cfg_3);
+}
+
+/* DDR SDRAM Timing Configuration 1 (TIMING_CFG_1) */
+static void set_timing_cfg_1(fsl_ddr_cfg_regs_t *ddr,
+ const memctl_options_t *popts,
+ const common_timing_params_t *common_dimm,
+ unsigned int cas_latency)
+{
+ /* Precharge-to-activate interval (tRP) */
+ unsigned char pretoact_mclk;
+ /* Activate to precharge interval (tRAS) */
+ unsigned char acttopre_mclk;
+ /* Activate to read/write interval (tRCD) */
+ unsigned char acttorw_mclk;
+ /* CASLAT */
+ unsigned char caslat_ctrl;
+ /* Refresh recovery time (tRFC) ; trfc_low */
+ unsigned char refrec_ctrl;
+ /* Last data to precharge minimum interval (tWR) */
+ unsigned char wrrec_mclk;
+ /* Activate-to-activate interval (tRRD) */
+ unsigned char acttoact_mclk;
+ /* Last write data pair to read command issue interval (tWTR) */
+ unsigned char wrtord_mclk;
+ /* DDR_SDRAM_MODE doesn't support 9,11,13,15 */
+ static const u8 wrrec_table[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 10, 10, 12, 12, 14, 14, 0, 0};
+
+ pretoact_mclk = picos_to_mclk(common_dimm->tRP_ps);
+ acttopre_mclk = picos_to_mclk(common_dimm->tRAS_ps);
+ acttorw_mclk = picos_to_mclk(common_dimm->tRCD_ps);
+
+ /*
+ * Translate CAS Latency to a DDR controller field value:
+ *
+ * CAS Lat DDR I DDR II Ctrl
+ * Clocks SPD Bit SPD Bit Value
+ * ------- ------- ------- -----
+ * 1.0 0 0001
+ * 1.5 1 0010
+ * 2.0 2 2 0011
+ * 2.5 3 0100
+ * 3.0 4 3 0101
+ * 3.5 5 0110
+ * 4.0 4 0111
+ * 4.5 1000
+ * 5.0 5 1001
+ */
+#if defined(CONFIG_FSL_DDR1)
+ caslat_ctrl = (cas_latency + 1) & 0x07;
+#elif defined(CONFIG_FSL_DDR2)
+ caslat_ctrl = 2 * cas_latency - 1;
+#else
+ /*
+ * if the CAS latency more than 8 cycle,
+ * we need set extend bit for it at
+ * TIMING_CFG_3[EXT_CASLAT]
+ */
+ caslat_ctrl = 2 * cas_latency - 1;
+#endif
+
+ refrec_ctrl = picos_to_mclk(common_dimm->tRFC_ps) - 8;
+ wrrec_mclk = picos_to_mclk(common_dimm->tWR_ps);
+
+ if (wrrec_mclk > 16)
+ printf("Error: WRREC doesn't support more than 16 clocks\n");
+ else
+ wrrec_mclk = wrrec_table[wrrec_mclk - 1];
+ if (popts->OTF_burst_chop_en)
+ wrrec_mclk += 2;
+
+ acttoact_mclk = picos_to_mclk(common_dimm->tRRD_ps);
+ /*
+ * JEDEC has min requirement for tRRD
+ */
+#if defined(CONFIG_FSL_DDR3)
+ if (acttoact_mclk < 4)
+ acttoact_mclk = 4;
+#endif
+ wrtord_mclk = picos_to_mclk(common_dimm->tWTR_ps);
+ /*
+ * JEDEC has some min requirements for tWTR
+ */
+#if defined(CONFIG_FSL_DDR2)
+ if (wrtord_mclk < 2)
+ wrtord_mclk = 2;
+#elif defined(CONFIG_FSL_DDR3)
+ if (wrtord_mclk < 4)
+ wrtord_mclk = 4;
+#endif
+ if (popts->OTF_burst_chop_en)
+ wrtord_mclk += 2;
+
+ ddr->timing_cfg_1 = (0
+ | ((pretoact_mclk & 0x0F) << 28)
+ | ((acttopre_mclk & 0x0F) << 24)
+ | ((acttorw_mclk & 0xF) << 20)
+ | ((caslat_ctrl & 0xF) << 16)
+ | ((refrec_ctrl & 0xF) << 12)
+ | ((wrrec_mclk & 0x0F) << 8)
+ | ((acttoact_mclk & 0x0F) << 4)
+ | ((wrtord_mclk & 0x0F) << 0)
+ );
+ debug("FSLDDR: timing_cfg_1 = 0x%08x\n", ddr->timing_cfg_1);
+}
+
+/* DDR SDRAM Timing Configuration 2 (TIMING_CFG_2) */
+static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr,
+ const memctl_options_t *popts,
+ const common_timing_params_t *common_dimm,
+ unsigned int cas_latency,
+ unsigned int additive_latency)
+{
+ /* Additive latency */
+ unsigned char add_lat_mclk;
+ /* CAS-to-preamble override */
+ unsigned short cpo;
+ /* Write latency */
+ unsigned char wr_lat;
+ /* Read to precharge (tRTP) */
+ unsigned char rd_to_pre;
+ /* Write command to write data strobe timing adjustment */
+ unsigned char wr_data_delay;
+ /* Minimum CKE pulse width (tCKE) */
+ unsigned char cke_pls;
+ /* Window for four activates (tFAW) */
+ unsigned short four_act;
+
+ /* FIXME add check that this must be less than acttorw_mclk */
+ add_lat_mclk = additive_latency;
+ cpo = popts->cpo_override;
+
+#if defined(CONFIG_FSL_DDR1)
+ /*
+ * This is a lie. It should really be 1, but if it is
+ * set to 1, bits overlap into the old controller's
+ * otherwise unused ACSM field. If we leave it 0, then
+ * the HW will magically treat it as 1 for DDR 1. Oh Yea.
+ */
+ wr_lat = 0;
+#elif defined(CONFIG_FSL_DDR2)
+ wr_lat = cas_latency - 1;
+#else
+ wr_lat = compute_cas_write_latency();
+#endif
+
+ rd_to_pre = picos_to_mclk(common_dimm->tRTP_ps);
+ /*
+ * JEDEC has some min requirements for tRTP
+ */
+#if defined(CONFIG_FSL_DDR2)
+ if (rd_to_pre < 2)
+ rd_to_pre = 2;
+#elif defined(CONFIG_FSL_DDR3)
+ if (rd_to_pre < 4)
+ rd_to_pre = 4;
+#endif
+ if (additive_latency)
+ rd_to_pre += additive_latency;
+ if (popts->OTF_burst_chop_en)
+ rd_to_pre += 2; /* according to UM */
+
+ wr_data_delay = popts->write_data_delay;
+ cke_pls = picos_to_mclk(popts->tCKE_clock_pulse_width_ps);
+ four_act = picos_to_mclk(popts->tFAW_window_four_activates_ps);
+
+ ddr->timing_cfg_2 = (0
+ | ((add_lat_mclk & 0xf) << 28)
+ | ((cpo & 0x1f) << 23)
+ | ((wr_lat & 0xf) << 19)
+ | ((rd_to_pre & RD_TO_PRE_MASK) << RD_TO_PRE_SHIFT)
+ | ((wr_data_delay & WR_DATA_DELAY_MASK) << WR_DATA_DELAY_SHIFT)
+ | ((cke_pls & 0x7) << 6)
+ | ((four_act & 0x3f) << 0)
+ );
+ debug("FSLDDR: timing_cfg_2 = 0x%08x\n", ddr->timing_cfg_2);
+}
+
+/* DDR SDRAM Register Control Word */
+static void set_ddr_sdram_rcw(fsl_ddr_cfg_regs_t *ddr,
+ const memctl_options_t *popts,
+ const common_timing_params_t *common_dimm)
+{
+ if (common_dimm->all_DIMMs_registered
+ && !common_dimm->all_DIMMs_unbuffered) {
+ if (popts->rcw_override) {
+ ddr->ddr_sdram_rcw_1 = popts->rcw_1;
+ ddr->ddr_sdram_rcw_2 = popts->rcw_2;
+ } else {
+ ddr->ddr_sdram_rcw_1 =
+ common_dimm->rcw[0] << 28 | \
+ common_dimm->rcw[1] << 24 | \
+ common_dimm->rcw[2] << 20 | \
+ common_dimm->rcw[3] << 16 | \
+ common_dimm->rcw[4] << 12 | \
+ common_dimm->rcw[5] << 8 | \
+ common_dimm->rcw[6] << 4 | \
+ common_dimm->rcw[7];
+ ddr->ddr_sdram_rcw_2 =
+ common_dimm->rcw[8] << 28 | \
+ common_dimm->rcw[9] << 24 | \
+ common_dimm->rcw[10] << 20 | \
+ common_dimm->rcw[11] << 16 | \
+ common_dimm->rcw[12] << 12 | \
+ common_dimm->rcw[13] << 8 | \
+ common_dimm->rcw[14] << 4 | \
+ common_dimm->rcw[15];
+ }
+ debug("FSLDDR: ddr_sdram_rcw_1 = 0x%08x\n", ddr->ddr_sdram_rcw_1);
+ debug("FSLDDR: ddr_sdram_rcw_2 = 0x%08x\n", ddr->ddr_sdram_rcw_2);
+ }
+}
+
+/* DDR SDRAM control configuration (DDR_SDRAM_CFG) */
+static void set_ddr_sdram_cfg(fsl_ddr_cfg_regs_t *ddr,
+ const memctl_options_t *popts,
+ const common_timing_params_t *common_dimm)
+{
+ unsigned int mem_en; /* DDR SDRAM interface logic enable */
+ unsigned int sren; /* Self refresh enable (during sleep) */
+ unsigned int ecc_en; /* ECC enable. */
+ unsigned int rd_en; /* Registered DIMM enable */
+ unsigned int sdram_type; /* Type of SDRAM */
+ unsigned int dyn_pwr; /* Dynamic power management mode */
+ unsigned int dbw; /* DRAM dta bus width */
+ unsigned int eight_be = 0; /* 8-beat burst enable, DDR2 is zero */
+ unsigned int ncap = 0; /* Non-concurrent auto-precharge */
+ unsigned int threeT_en; /* Enable 3T timing */
+ unsigned int twoT_en; /* Enable 2T timing */
+ unsigned int ba_intlv_ctl; /* Bank (CS) interleaving control */
+ unsigned int x32_en = 0; /* x32 enable */
+ unsigned int pchb8 = 0; /* precharge bit 8 enable */
+ unsigned int hse; /* Global half strength override */
+ unsigned int mem_halt = 0; /* memory controller halt */
+ unsigned int bi = 0; /* Bypass initialization */
+
+ mem_en = 1;
+ sren = popts->self_refresh_in_sleep;
+ if (common_dimm->all_DIMMs_ECC_capable) {
+ /* Allow setting of ECC only if all DIMMs are ECC. */
+ ecc_en = popts->ECC_mode;
+ } else {
+ ecc_en = 0;
+ }
+
+ if (common_dimm->all_DIMMs_registered
+ && !common_dimm->all_DIMMs_unbuffered) {
+ rd_en = 1;
+ twoT_en = 0;
+ } else {
+ rd_en = 0;
+ twoT_en = popts->twoT_en;
+ }
+
+ sdram_type = CONFIG_FSL_SDRAM_TYPE;
+
+ dyn_pwr = popts->dynamic_power;
+ dbw = popts->data_bus_width;
+ /* 8-beat burst enable DDR-III case
+ * we must clear it when use the on-the-fly mode,
+ * must set it when use the 32-bits bus mode.
+ */
+ if (sdram_type == SDRAM_TYPE_DDR3) {
+ if (popts->burst_length == DDR_BL8)
+ eight_be = 1;
+ if (popts->burst_length == DDR_OTF)
+ eight_be = 0;
+ if (dbw == 0x1)
+ eight_be = 1;
+ }
+
+ threeT_en = popts->threeT_en;
+ ba_intlv_ctl = popts->ba_intlv_ctl;
+ hse = popts->half_strength_driver_enable;
+
+ ddr->ddr_sdram_cfg = (0
+ | ((mem_en & 0x1) << 31)
+ | ((sren & 0x1) << 30)
+ | ((ecc_en & 0x1) << 29)
+ | ((rd_en & 0x1) << 28)
+ | ((sdram_type & 0x7) << 24)
+ | ((dyn_pwr & 0x1) << 21)
+ | ((dbw & 0x3) << 19)
+ | ((eight_be & 0x1) << 18)
+ | ((ncap & 0x1) << 17)
+ | ((threeT_en & 0x1) << 16)
+ | ((twoT_en & 0x1) << 15)
+ | ((ba_intlv_ctl & 0x7F) << 8)
+ | ((x32_en & 0x1) << 5)
+ | ((pchb8 & 0x1) << 4)
+ | ((hse & 0x1) << 3)
+ | ((mem_halt & 0x1) << 1)
+ | ((bi & 0x1) << 0)
+ );
+ debug("FSLDDR: ddr_sdram_cfg = 0x%08x\n", ddr->ddr_sdram_cfg);
+}
+
+/* DDR SDRAM control configuration 2 (DDR_SDRAM_CFG_2) */
+static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr,
+ const memctl_options_t *popts,
+ const unsigned int unq_mrs_en)
+{
+ unsigned int frc_sr = 0; /* Force self refresh */
+ unsigned int sr_ie = 0; /* Self-refresh interrupt enable */
+ unsigned int dll_rst_dis; /* DLL reset disable */
+ unsigned int dqs_cfg; /* DQS configuration */
+ unsigned int odt_cfg = 0; /* ODT configuration */
+ unsigned int num_pr; /* Number of posted refreshes */
+ unsigned int slow = 0; /* DDR will be run less than 1250 */
+ unsigned int obc_cfg; /* On-The-Fly Burst Chop Cfg */
+ unsigned int ap_en; /* Address Parity Enable */
+ unsigned int d_init; /* DRAM data initialization */
+ unsigned int rcw_en = 0; /* Register Control Word Enable */
+ unsigned int md_en = 0; /* Mirrored DIMM Enable */
+ unsigned int qd_en = 0; /* quad-rank DIMM Enable */
+ int i;
+
+ dll_rst_dis = 1; /* Make this configurable */
+ dqs_cfg = popts->DQS_config;
+ for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+ if (popts->cs_local_opts[i].odt_rd_cfg
+ || popts->cs_local_opts[i].odt_wr_cfg) {
+ odt_cfg = SDRAM_CFG2_ODT_ONLY_READ;
+ break;
+ }
+ }
+
+ num_pr = 1; /* Make this configurable */
+
+ /*
+ * 8572 manual says
+ * {TIMING_CFG_1[PRETOACT]
+ * + [DDR_SDRAM_CFG_2[NUM_PR]
+ * * ({EXT_REFREC || REFREC} + 8 + 2)]}
+ * << DDR_SDRAM_INTERVAL[REFINT]
+ */
+#if defined(CONFIG_FSL_DDR3)
+ obc_cfg = popts->OTF_burst_chop_en;
+#else
+ obc_cfg = 0;
+#endif
+
+#if (CONFIG_SYS_FSL_DDR_VER >= FSL_DDR_VER_4_7)
+ slow = get_ddr_freq(0) < 1249000000;
+#endif
+
+ if (popts->registered_dimm_en) {
+ rcw_en = 1;
+ ap_en = popts->ap_en;
+ } else {
+ ap_en = 0;
+ }
+
+#if defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)
+ /* Use the DDR controller to auto initialize memory. */
+ d_init = popts->ECC_init_using_memctl;
+ ddr->ddr_data_init = CONFIG_MEM_INIT_VALUE;
+ debug("DDR: ddr_data_init = 0x%08x\n", ddr->ddr_data_init);
+#else
+ /* Memory will be initialized via DMA, or not at all. */
+ d_init = 0;
+#endif
+
+#if defined(CONFIG_FSL_DDR3)
+ md_en = popts->mirrored_dimm;
+#endif
+ qd_en = popts->quad_rank_present ? 1 : 0;
+ ddr->ddr_sdram_cfg_2 = (0
+ | ((frc_sr & 0x1) << 31)
+ | ((sr_ie & 0x1) << 30)
+ | ((dll_rst_dis & 0x1) << 29)
+ | ((dqs_cfg & 0x3) << 26)
+ | ((odt_cfg & 0x3) << 21)
+ | ((num_pr & 0xf) << 12)
+ | ((slow & 1) << 11)
+ | (qd_en << 9)
+ | (unq_mrs_en << 8)
+ | ((obc_cfg & 0x1) << 6)
+ | ((ap_en & 0x1) << 5)
+ | ((d_init & 0x1) << 4)
+ | ((rcw_en & 0x1) << 2)
+ | ((md_en & 0x1) << 0)
+ );
+ debug("FSLDDR: ddr_sdram_cfg_2 = 0x%08x\n", ddr->ddr_sdram_cfg_2);
+}
+
+/* DDR SDRAM Mode configuration 2 (DDR_SDRAM_MODE_2) */
+static void set_ddr_sdram_mode_2(fsl_ddr_cfg_regs_t *ddr,
+ const memctl_options_t *popts,
+ const unsigned int unq_mrs_en)
+{
+ unsigned short esdmode2 = 0; /* Extended SDRAM mode 2 */
+ unsigned short esdmode3 = 0; /* Extended SDRAM mode 3 */
+
+#if defined(CONFIG_FSL_DDR3)
+ int i;
+ unsigned int rtt_wr = 0; /* Rtt_WR - dynamic ODT off */
+ unsigned int srt = 0; /* self-refresh temerature, normal range */
+ unsigned int asr = 0; /* auto self-refresh disable */
+ unsigned int cwl = compute_cas_write_latency() - 5;
+ unsigned int pasr = 0; /* partial array self refresh disable */
+
+ if (popts->rtt_override)
+ rtt_wr = popts->rtt_wr_override_value;
+ else
+ rtt_wr = popts->cs_local_opts[0].odt_rtt_wr;
+ esdmode2 = (0
+ | ((rtt_wr & 0x3) << 9)
+ | ((srt & 0x1) << 7)
+ | ((asr & 0x1) << 6)
+ | ((cwl & 0x7) << 3)
+ | ((pasr & 0x7) << 0));
+#endif
+ ddr->ddr_sdram_mode_2 = (0
+ | ((esdmode2 & 0xFFFF) << 16)
+ | ((esdmode3 & 0xFFFF) << 0)
+ );
+ debug("FSLDDR: ddr_sdram_mode_2 = 0x%08x\n", ddr->ddr_sdram_mode_2);
+
+#ifdef CONFIG_FSL_DDR3
+ if (unq_mrs_en) { /* unique mode registers are supported */
+ for (i = 1; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+ if (popts->rtt_override)
+ rtt_wr = popts->rtt_wr_override_value;
+ else
+ rtt_wr = popts->cs_local_opts[i].odt_rtt_wr;
+
+ esdmode2 &= 0xF9FF; /* clear bit 10, 9 */
+ esdmode2 |= (rtt_wr & 0x3) << 9;
+ switch (i) {
+ case 1:
+ ddr->ddr_sdram_mode_4 = (0
+ | ((esdmode2 & 0xFFFF) << 16)
+ | ((esdmode3 & 0xFFFF) << 0)
+ );
+ break;
+ case 2:
+ ddr->ddr_sdram_mode_6 = (0
+ | ((esdmode2 & 0xFFFF) << 16)
+ | ((esdmode3 & 0xFFFF) << 0)
+ );
+ break;
+ case 3:
+ ddr->ddr_sdram_mode_8 = (0
+ | ((esdmode2 & 0xFFFF) << 16)
+ | ((esdmode3 & 0xFFFF) << 0)
+ );
+ break;
+ }
+ }
+ debug("FSLDDR: ddr_sdram_mode_4 = 0x%08x\n",
+ ddr->ddr_sdram_mode_4);
+ debug("FSLDDR: ddr_sdram_mode_6 = 0x%08x\n",
+ ddr->ddr_sdram_mode_6);
+ debug("FSLDDR: ddr_sdram_mode_8 = 0x%08x\n",
+ ddr->ddr_sdram_mode_8);
+ }
+#endif
+}
+
+/* DDR SDRAM Interval Configuration (DDR_SDRAM_INTERVAL) */
+static void set_ddr_sdram_interval(fsl_ddr_cfg_regs_t *ddr,
+ const memctl_options_t *popts,
+ const common_timing_params_t *common_dimm)
+{
+ unsigned int refint; /* Refresh interval */
+ unsigned int bstopre; /* Precharge interval */
+
+ refint = picos_to_mclk(common_dimm->refresh_rate_ps);
+
+ bstopre = popts->bstopre;
+
+ /* refint field used 0x3FFF in earlier controllers */
+ ddr->ddr_sdram_interval = (0
+ | ((refint & 0xFFFF) << 16)
+ | ((bstopre & 0x3FFF) << 0)
+ );
+ debug("FSLDDR: ddr_sdram_interval = 0x%08x\n", ddr->ddr_sdram_interval);
+}
+
+#if defined(CONFIG_FSL_DDR3)
+/* DDR SDRAM Mode configuration set (DDR_SDRAM_MODE) */
+static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
+ const memctl_options_t *popts,
+ const common_timing_params_t *common_dimm,
+ unsigned int cas_latency,
+ unsigned int additive_latency,
+ const unsigned int unq_mrs_en)
+{
+ unsigned short esdmode; /* Extended SDRAM mode */
+ unsigned short sdmode; /* SDRAM mode */
+
+ /* Mode Register - MR1 */
+ unsigned int qoff = 0; /* Output buffer enable 0=yes, 1=no */
+ unsigned int tdqs_en = 0; /* TDQS Enable: 0=no, 1=yes */
+ unsigned int rtt;
+ unsigned int wrlvl_en = 0; /* Write level enable: 0=no, 1=yes */
+ unsigned int al = 0; /* Posted CAS# additive latency (AL) */
+ unsigned int dic = 0; /* Output driver impedance, 40ohm */
+ unsigned int dll_en = 0; /* DLL Enable 0=Enable (Normal),
+ 1=Disable (Test/Debug) */
+
+ /* Mode Register - MR0 */
+ unsigned int dll_on; /* DLL control for precharge PD, 0=off, 1=on */
+ unsigned int wr = 0; /* Write Recovery */
+ unsigned int dll_rst; /* DLL Reset */
+ unsigned int mode; /* Normal=0 or Test=1 */
+ unsigned int caslat = 4;/* CAS# latency, default set as 6 cycles */
+ /* BT: Burst Type (0=Nibble Sequential, 1=Interleaved) */
+ unsigned int bt;
+ unsigned int bl; /* BL: Burst Length */
+
+ unsigned int wr_mclk;
+ /*
+ * DDR_SDRAM_MODE doesn't support 9,11,13,15
+ * Please refer JEDEC Standard No. 79-3E for Mode Register MR0
+ * for this table
+ */
+ static const u8 wr_table[] = {1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 0, 0};
+
+ const unsigned int mclk_ps = get_memory_clk_period_ps();
+ int i;
+
+ if (popts->rtt_override)
+ rtt = popts->rtt_override_value;
+ else
+ rtt = popts->cs_local_opts[0].odt_rtt_norm;
+
+ if (additive_latency == (cas_latency - 1))
+ al = 1;
+ if (additive_latency == (cas_latency - 2))
+ al = 2;
+
+ if (popts->quad_rank_present)
+ dic = 1; /* output driver impedance 240/7 ohm */
+
+ /*
+ * The esdmode value will also be used for writing
+ * MR1 during write leveling for DDR3, although the
+ * bits specifically related to the write leveling
+ * scheme will be handled automatically by the DDR
+ * controller. so we set the wrlvl_en = 0 here.
+ */
+ esdmode = (0
+ | ((qoff & 0x1) << 12)
+ | ((tdqs_en & 0x1) << 11)
+ | ((rtt & 0x4) << 7) /* rtt field is split */
+ | ((wrlvl_en & 0x1) << 7)
+ | ((rtt & 0x2) << 5) /* rtt field is split */
+ | ((dic & 0x2) << 4) /* DIC field is split */
+ | ((al & 0x3) << 3)
+ | ((rtt & 0x1) << 2) /* rtt field is split */
+ | ((dic & 0x1) << 1) /* DIC field is split */
+ | ((dll_en & 0x1) << 0)
+ );
+
+ /*
+ * DLL control for precharge PD
+ * 0=slow exit DLL off (tXPDLL)
+ * 1=fast exit DLL on (tXP)
+ */
+ dll_on = 1;
+
+ wr_mclk = (common_dimm->tWR_ps + mclk_ps - 1) / mclk_ps;
+ if (wr_mclk <= 16) {
+ wr = wr_table[wr_mclk - 5];
+ } else {
+ printf("Error: unsupported write recovery for mode register "
+ "wr_mclk = %d\n", wr_mclk);
+ }
+
+ dll_rst = 0; /* dll no reset */
+ mode = 0; /* normal mode */
+
+ /* look up table to get the cas latency bits */
+ if (cas_latency >= 5 && cas_latency <= 16) {
+ unsigned char cas_latency_table[] = {
+ 0x2, /* 5 clocks */
+ 0x4, /* 6 clocks */
+ 0x6, /* 7 clocks */
+ 0x8, /* 8 clocks */
+ 0xa, /* 9 clocks */
+ 0xc, /* 10 clocks */
+ 0xe, /* 11 clocks */
+ 0x1, /* 12 clocks */
+ 0x3, /* 13 clocks */
+ 0x5, /* 14 clocks */
+ 0x7, /* 15 clocks */
+ 0x9, /* 16 clocks */
+ };
+ caslat = cas_latency_table[cas_latency - 5];
+ } else {
+ printf("Error: unsupported cas latency for mode register\n");
+ }
+
+ bt = 0; /* Nibble sequential */
+
+ switch (popts->burst_length) {
+ case DDR_BL8:
+ bl = 0;
+ break;
+ case DDR_OTF:
+ bl = 1;
+ break;
+ case DDR_BC4:
+ bl = 2;
+ break;
+ default:
+ printf("Error: invalid burst length of %u specified. "
+ " Defaulting to on-the-fly BC4 or BL8 beats.\n",
+ popts->burst_length);
+ bl = 1;
+ break;
+ }
+
+ sdmode = (0
+ | ((dll_on & 0x1) << 12)
+ | ((wr & 0x7) << 9)
+ | ((dll_rst & 0x1) << 8)
+ | ((mode & 0x1) << 7)
+ | (((caslat >> 1) & 0x7) << 4)
+ | ((bt & 0x1) << 3)
+ | ((caslat & 1) << 2)
+ | ((bl & 0x3) << 0)
+ );
+
+ ddr->ddr_sdram_mode = (0
+ | ((esdmode & 0xFFFF) << 16)
+ | ((sdmode & 0xFFFF) << 0)
+ );
+
+ debug("FSLDDR: ddr_sdram_mode = 0x%08x\n", ddr->ddr_sdram_mode);
+
+ if (unq_mrs_en) { /* unique mode registers are supported */
+ for (i = 1; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+ if (popts->rtt_override)
+ rtt = popts->rtt_override_value;
+ else
+ rtt = popts->cs_local_opts[i].odt_rtt_norm;
+
+ esdmode &= 0xFDBB; /* clear bit 9,6,2 */
+ esdmode |= (0
+ | ((rtt & 0x4) << 7) /* rtt field is split */
+ | ((rtt & 0x2) << 5) /* rtt field is split */
+ | ((rtt & 0x1) << 2) /* rtt field is split */
+ );
+ switch (i) {
+ case 1:
+ ddr->ddr_sdram_mode_3 = (0
+ | ((esdmode & 0xFFFF) << 16)
+ | ((sdmode & 0xFFFF) << 0)
+ );
+ break;
+ case 2:
+ ddr->ddr_sdram_mode_5 = (0
+ | ((esdmode & 0xFFFF) << 16)
+ | ((sdmode & 0xFFFF) << 0)
+ );
+ break;
+ case 3:
+ ddr->ddr_sdram_mode_7 = (0
+ | ((esdmode & 0xFFFF) << 16)
+ | ((sdmode & 0xFFFF) << 0)
+ );
+ break;
+ }
+ }
+ debug("FSLDDR: ddr_sdram_mode_3 = 0x%08x\n",
+ ddr->ddr_sdram_mode_3);
+ debug("FSLDDR: ddr_sdram_mode_5 = 0x%08x\n",
+ ddr->ddr_sdram_mode_5);
+ debug("FSLDDR: ddr_sdram_mode_5 = 0x%08x\n",
+ ddr->ddr_sdram_mode_5);
+ }
+}
+
+#else /* !CONFIG_FSL_DDR3 */
+
+/* DDR SDRAM Mode configuration set (DDR_SDRAM_MODE) */
+static void set_ddr_sdram_mode(fsl_ddr_cfg_regs_t *ddr,
+ const memctl_options_t *popts,
+ const common_timing_params_t *common_dimm,
+ unsigned int cas_latency,
+ unsigned int additive_latency,
+ const unsigned int unq_mrs_en)
+{
+ unsigned short esdmode; /* Extended SDRAM mode */
+ unsigned short sdmode; /* SDRAM mode */
+
+ /*
+ * FIXME: This ought to be pre-calculated in a
+ * technology-specific routine,
+ * e.g. compute_DDR2_mode_register(), and then the
+ * sdmode and esdmode passed in as part of common_dimm.
+ */
+
+ /* Extended Mode Register */
+ unsigned int mrs = 0; /* Mode Register Set */
+ unsigned int outputs = 0; /* 0=Enabled, 1=Disabled */
+ unsigned int rdqs_en = 0; /* RDQS Enable: 0=no, 1=yes */
+ unsigned int dqs_en = 0; /* DQS# Enable: 0=enable, 1=disable */
+ unsigned int ocd = 0; /* 0x0=OCD not supported,
+ 0x7=OCD default state */
+ unsigned int rtt;
+ unsigned int al; /* Posted CAS# additive latency (AL) */
+ unsigned int ods = 0; /* Output Drive Strength:
+ 0 = Full strength (18ohm)
+ 1 = Reduced strength (4ohm) */
+ unsigned int dll_en = 0; /* DLL Enable 0=Enable (Normal),
+ 1=Disable (Test/Debug) */
+
+ /* Mode Register (MR) */
+ unsigned int mr; /* Mode Register Definition */
+ unsigned int pd; /* Power-Down Mode */
+ unsigned int wr; /* Write Recovery */
+ unsigned int dll_res; /* DLL Reset */
+ unsigned int mode; /* Normal=0 or Test=1 */
+ unsigned int caslat = 0;/* CAS# latency */
+ /* BT: Burst Type (0=Sequential, 1=Interleaved) */
+ unsigned int bt;
+ unsigned int bl; /* BL: Burst Length */
+
+#if defined(CONFIG_FSL_DDR2)
+ const unsigned int mclk_ps = get_memory_clk_period_ps();
+#endif
+ dqs_en = !popts->DQS_config;
+ rtt = fsl_ddr_get_rtt();
+
+ al = additive_latency;
+
+ esdmode = (0
+ | ((mrs & 0x3) << 14)
+ | ((outputs & 0x1) << 12)
+ | ((rdqs_en & 0x1) << 11)
+ | ((dqs_en & 0x1) << 10)
+ | ((ocd & 0x7) << 7)
+ | ((rtt & 0x2) << 5) /* rtt field is split */
+ | ((al & 0x7) << 3)
+ | ((rtt & 0x1) << 2) /* rtt field is split */
+ | ((ods & 0x1) << 1)
+ | ((dll_en & 0x1) << 0)
+ );
+
+ mr = 0; /* FIXME: CHECKME */
+
+ /*
+ * 0 = Fast Exit (Normal)
+ * 1 = Slow Exit (Low Power)
+ */
+ pd = 0;
+
+#if defined(CONFIG_FSL_DDR1)
+ wr = 0; /* Historical */
+#elif defined(CONFIG_FSL_DDR2)
+ wr = (common_dimm->tWR_ps + mclk_ps - 1) / mclk_ps - 1;
+#endif
+ dll_res = 0;
+ mode = 0;
+
+#if defined(CONFIG_FSL_DDR1)
+ if (1 <= cas_latency && cas_latency <= 4) {
+ unsigned char mode_caslat_table[4] = {
+ 0x5, /* 1.5 clocks */
+ 0x2, /* 2.0 clocks */
+ 0x6, /* 2.5 clocks */
+ 0x3 /* 3.0 clocks */
+ };
+ caslat = mode_caslat_table[cas_latency - 1];
+ } else {
+ printf("Warning: unknown cas_latency %d\n", cas_latency);
+ }
+#elif defined(CONFIG_FSL_DDR2)
+ caslat = cas_latency;
+#endif
+ bt = 0;
+
+ switch (popts->burst_length) {
+ case DDR_BL4:
+ bl = 2;
+ break;
+ case DDR_BL8:
+ bl = 3;
+ break;
+ default:
+ printf("Error: invalid burst length of %u specified. "
+ " Defaulting to 4 beats.\n",
+ popts->burst_length);
+ bl = 2;
+ break;
+ }
+
+ sdmode = (0
+ | ((mr & 0x3) << 14)
+ | ((pd & 0x1) << 12)
+ | ((wr & 0x7) << 9)
+ | ((dll_res & 0x1) << 8)
+ | ((mode & 0x1) << 7)
+ | ((caslat & 0x7) << 4)
+ | ((bt & 0x1) << 3)
+ | ((bl & 0x7) << 0)
+ );
+
+ ddr->ddr_sdram_mode = (0
+ | ((esdmode & 0xFFFF) << 16)
+ | ((sdmode & 0xFFFF) << 0)
+ );
+ debug("FSLDDR: ddr_sdram_mode = 0x%08x\n", ddr->ddr_sdram_mode);
+}
+#endif
+
+/* DDR SDRAM Data Initialization (DDR_DATA_INIT) */
+static void set_ddr_data_init(fsl_ddr_cfg_regs_t *ddr)
+{
+ unsigned int init_value; /* Initialization value */
+
+#ifdef CONFIG_MEM_INIT_VALUE
+ init_value = CONFIG_MEM_INIT_VALUE;
+#else
+ init_value = 0xDEADBEEF;
+#endif
+ ddr->ddr_data_init = init_value;
+}
+
+/*
+ * DDR SDRAM Clock Control (DDR_SDRAM_CLK_CNTL)
+ * The old controller on the 8540/60 doesn't have this register.
+ * Hope it's OK to set it (to 0) anyway.
+ */
+static void set_ddr_sdram_clk_cntl(fsl_ddr_cfg_regs_t *ddr,
+ const memctl_options_t *popts)
+{
+ unsigned int clk_adjust; /* Clock adjust */
+
+ clk_adjust = popts->clk_adjust;
+ ddr->ddr_sdram_clk_cntl = (clk_adjust & 0xF) << 23;
+ debug("FSLDDR: clk_cntl = 0x%08x\n", ddr->ddr_sdram_clk_cntl);
+}
+
+/* DDR Initialization Address (DDR_INIT_ADDR) */
+static void set_ddr_init_addr(fsl_ddr_cfg_regs_t *ddr)
+{
+ unsigned int init_addr = 0; /* Initialization address */
+
+ ddr->ddr_init_addr = init_addr;
+}
+
+/* DDR Initialization Address (DDR_INIT_EXT_ADDR) */
+static void set_ddr_init_ext_addr(fsl_ddr_cfg_regs_t *ddr)
+{
+ unsigned int uia = 0; /* Use initialization address */
+ unsigned int init_ext_addr = 0; /* Initialization address */
+
+ ddr->ddr_init_ext_addr = (0
+ | ((uia & 0x1) << 31)
+ | (init_ext_addr & 0xF)
+ );
+}
+
+/* DDR SDRAM Timing Configuration 4 (TIMING_CFG_4) */
+static void set_timing_cfg_4(fsl_ddr_cfg_regs_t *ddr,
+ const memctl_options_t *popts)
+{
+ unsigned int rwt = 0; /* Read-to-write turnaround for same CS */
+ unsigned int wrt = 0; /* Write-to-read turnaround for same CS */
+ unsigned int rrt = 0; /* Read-to-read turnaround for same CS */
+ unsigned int wwt = 0; /* Write-to-write turnaround for same CS */
+ unsigned int dll_lock = 0; /* DDR SDRAM DLL Lock Time */
+
+#if defined(CONFIG_FSL_DDR3)
+ if (popts->burst_length == DDR_BL8) {
+ /* We set BL/2 for fixed BL8 */
+ rrt = 0; /* BL/2 clocks */
+ wwt = 0; /* BL/2 clocks */
+ } else {
+ /* We need to set BL/2 + 2 to BC4 and OTF */
+ rrt = 2; /* BL/2 + 2 clocks */
+ wwt = 2; /* BL/2 + 2 clocks */
+ }
+ dll_lock = 1; /* tDLLK = 512 clocks from spec */
+#endif
+ ddr->timing_cfg_4 = (0
+ | ((rwt & 0xf) << 28)
+ | ((wrt & 0xf) << 24)
+ | ((rrt & 0xf) << 20)
+ | ((wwt & 0xf) << 16)
+ | (dll_lock & 0x3)
+ );
+ debug("FSLDDR: timing_cfg_4 = 0x%08x\n", ddr->timing_cfg_4);
+}
+
+/* DDR SDRAM Timing Configuration 5 (TIMING_CFG_5) */
+static void set_timing_cfg_5(fsl_ddr_cfg_regs_t *ddr, unsigned int cas_latency)
+{
+ unsigned int rodt_on = 0; /* Read to ODT on */
+ unsigned int rodt_off = 0; /* Read to ODT off */
+ unsigned int wodt_on = 0; /* Write to ODT on */
+ unsigned int wodt_off = 0; /* Write to ODT off */
+
+#if defined(CONFIG_FSL_DDR3)
+ /* rodt_on = timing_cfg_1[caslat] - timing_cfg_2[wrlat] + 1 */
+ rodt_on = cas_latency - ((ddr->timing_cfg_2 & 0x00780000) >> 19) + 1;
+ rodt_off = 4; /* 4 clocks */
+ wodt_on = 1; /* 1 clocks */
+ wodt_off = 4; /* 4 clocks */
+#endif
+
+ ddr->timing_cfg_5 = (0
+ | ((rodt_on & 0x1f) << 24)
+ | ((rodt_off & 0x7) << 20)
+ | ((wodt_on & 0x1f) << 12)
+ | ((wodt_off & 0x7) << 8)
+ );
+ debug("FSLDDR: timing_cfg_5 = 0x%08x\n", ddr->timing_cfg_5);
+}
+
+/* DDR ZQ Calibration Control (DDR_ZQ_CNTL) */
+static void set_ddr_zq_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int zq_en)
+{
+ unsigned int zqinit = 0;/* POR ZQ Calibration Time (tZQinit) */
+ /* Normal Operation Full Calibration Time (tZQoper) */
+ unsigned int zqoper = 0;
+ /* Normal Operation Short Calibration Time (tZQCS) */
+ unsigned int zqcs = 0;
+
+ if (zq_en) {
+ zqinit = 9; /* 512 clocks */
+ zqoper = 8; /* 256 clocks */
+ zqcs = 6; /* 64 clocks */
+ }
+
+ ddr->ddr_zq_cntl = (0
+ | ((zq_en & 0x1) << 31)
+ | ((zqinit & 0xF) << 24)
+ | ((zqoper & 0xF) << 16)
+ | ((zqcs & 0xF) << 8)
+ );
+ debug("FSLDDR: zq_cntl = 0x%08x\n", ddr->ddr_zq_cntl);
+}
+
+/* DDR Write Leveling Control (DDR_WRLVL_CNTL) */
+static void set_ddr_wrlvl_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int wrlvl_en,
+ const memctl_options_t *popts)
+{
+ /*
+ * First DQS pulse rising edge after margining mode
+ * is programmed (tWL_MRD)
+ */
+ unsigned int wrlvl_mrd = 0;
+ /* ODT delay after margining mode is programmed (tWL_ODTEN) */
+ unsigned int wrlvl_odten = 0;
+ /* DQS/DQS_ delay after margining mode is programmed (tWL_DQSEN) */
+ unsigned int wrlvl_dqsen = 0;
+ /* WRLVL_SMPL: Write leveling sample time */
+ unsigned int wrlvl_smpl = 0;
+ /* WRLVL_WLR: Write leveling repeition time */
+ unsigned int wrlvl_wlr = 0;
+ /* WRLVL_START: Write leveling start time */
+ unsigned int wrlvl_start = 0;
+
+ /* suggest enable write leveling for DDR3 due to fly-by topology */
+ if (wrlvl_en) {
+ /* tWL_MRD min = 40 nCK, we set it 64 */
+ wrlvl_mrd = 0x6;
+ /* tWL_ODTEN 128 */
+ wrlvl_odten = 0x7;
+ /* tWL_DQSEN min = 25 nCK, we set it 32 */
+ wrlvl_dqsen = 0x5;
+ /*
+ * Write leveling sample time at least need 6 clocks
+ * higher than tWLO to allow enough time for progagation
+ * delay and sampling the prime data bits.
+ */
+ wrlvl_smpl = 0xf;
+ /*
+ * Write leveling repetition time
+ * at least tWLO + 6 clocks clocks
+ * we set it 64
+ */
+ wrlvl_wlr = 0x6;
+ /*
+ * Write leveling start time
+ * The value use for the DQS_ADJUST for the first sample
+ * when write leveling is enabled. It probably needs to be
+ * overriden per platform.
+ */
+ wrlvl_start = 0x8;
+ /*
+ * Override the write leveling sample and start time
+ * according to specific board
+ */
+ if (popts->wrlvl_override) {
+ wrlvl_smpl = popts->wrlvl_sample;
+ wrlvl_start = popts->wrlvl_start;
+ }
+ }
+
+ ddr->ddr_wrlvl_cntl = (0
+ | ((wrlvl_en & 0x1) << 31)
+ | ((wrlvl_mrd & 0x7) << 24)
+ | ((wrlvl_odten & 0x7) << 20)
+ | ((wrlvl_dqsen & 0x7) << 16)
+ | ((wrlvl_smpl & 0xf) << 12)
+ | ((wrlvl_wlr & 0x7) << 8)
+ | ((wrlvl_start & 0x1F) << 0)
+ );
+ debug("FSLDDR: wrlvl_cntl = 0x%08x\n", ddr->ddr_wrlvl_cntl);
+ ddr->ddr_wrlvl_cntl_2 = popts->wrlvl_ctl_2;
+ debug("FSLDDR: wrlvl_cntl_2 = 0x%08x\n", ddr->ddr_wrlvl_cntl_2);
+ ddr->ddr_wrlvl_cntl_3 = popts->wrlvl_ctl_3;
+ debug("FSLDDR: wrlvl_cntl_3 = 0x%08x\n", ddr->ddr_wrlvl_cntl_3);
+
+}
+
+/* DDR Self Refresh Counter (DDR_SR_CNTR) */
+static void set_ddr_sr_cntr(fsl_ddr_cfg_regs_t *ddr, unsigned int sr_it)
+{
+ /* Self Refresh Idle Threshold */
+ ddr->ddr_sr_cntr = (sr_it & 0xF) << 16;
+}
+
+static void set_ddr_eor(fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts)
+{
+ if (popts->addr_hash) {
+ ddr->ddr_eor = 0x40000000; /* address hash enable */
+ puts("Address hashing enabled.\n");
+ }
+}
+
+static void set_ddr_cdr1(fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts)
+{
+ ddr->ddr_cdr1 = popts->ddr_cdr1;
+ debug("FSLDDR: ddr_cdr1 = 0x%08x\n", ddr->ddr_cdr1);
+}
+
+static void set_ddr_cdr2(fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts)
+{
+ ddr->ddr_cdr2 = popts->ddr_cdr2;
+ debug("FSLDDR: ddr_cdr2 = 0x%08x\n", ddr->ddr_cdr2);
+}
+
+unsigned int
+check_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr)
+{
+ unsigned int res = 0;
+
+ /*
+ * Check that DDR_SDRAM_CFG[RD_EN] and DDR_SDRAM_CFG[2T_EN] are
+ * not set at the same time.
+ */
+ if (ddr->ddr_sdram_cfg & 0x10000000
+ && ddr->ddr_sdram_cfg & 0x00008000) {
+ printf("Error: DDR_SDRAM_CFG[RD_EN] and DDR_SDRAM_CFG[2T_EN] "
+ " should not be set at the same time.\n");
+ res++;
+ }
+
+ return res;
+}
+
+unsigned int
+compute_fsl_memctl_config_regs(const memctl_options_t *popts,
+ fsl_ddr_cfg_regs_t *ddr,
+ const common_timing_params_t *common_dimm,
+ const dimm_params_t *dimm_params,
+ unsigned int dbw_cap_adj,
+ unsigned int size_only)
+{
+ unsigned int i;
+ unsigned int cas_latency;
+ unsigned int additive_latency;
+ unsigned int sr_it;
+ unsigned int zq_en;
+ unsigned int wrlvl_en;
+ unsigned int ip_rev = 0;
+ unsigned int unq_mrs_en = 0;
+ int cs_en = 1;
+
+ memset(ddr, 0, sizeof(fsl_ddr_cfg_regs_t));
+
+ if (common_dimm == NULL) {
+ printf("Error: subset DIMM params struct null pointer\n");
+ return 1;
+ }
+
+ /*
+ * Process overrides first.
+ *
+ * FIXME: somehow add dereated caslat to this
+ */
+ cas_latency = (popts->cas_latency_override)
+ ? popts->cas_latency_override_value
+ : common_dimm->lowest_common_SPD_caslat;
+
+ additive_latency = (popts->additive_latency_override)
+ ? popts->additive_latency_override_value
+ : common_dimm->additive_latency;
+
+ sr_it = (popts->auto_self_refresh_en)
+ ? popts->sr_it
+ : 0;
+ /* ZQ calibration */
+ zq_en = (popts->zq_en) ? 1 : 0;
+ /* write leveling */
+ wrlvl_en = (popts->wrlvl_en) ? 1 : 0;
+
+ /* Chip Select Memory Bounds (CSn_BNDS) */
+ for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+ unsigned long long ea, sa;
+ unsigned int cs_per_dimm
+ = CONFIG_CHIP_SELECTS_PER_CTRL / CONFIG_DIMM_SLOTS_PER_CTLR;
+ unsigned int dimm_number
+ = i / cs_per_dimm;
+ unsigned long long rank_density
+ = dimm_params[dimm_number].rank_density >> dbw_cap_adj;
+
+ if (dimm_params[dimm_number].n_ranks == 0) {
+ debug("Skipping setup of CS%u "
+ "because n_ranks on DIMM %u is 0\n", i, dimm_number);
+ continue;
+ }
+ if (popts->memctl_interleaving) {
+ switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) {
+ case FSL_DDR_CS0_CS1_CS2_CS3:
+ break;
+ case FSL_DDR_CS0_CS1:
+ case FSL_DDR_CS0_CS1_AND_CS2_CS3:
+ if (i > 1)
+ cs_en = 0;
+ break;
+ case FSL_DDR_CS2_CS3:
+ default:
+ if (i > 0)
+ cs_en = 0;
+ break;
+ }
+ sa = common_dimm->base_address;
+ ea = sa + common_dimm->total_mem - 1;
+ } else if (!popts->memctl_interleaving) {
+ /*
+ * If memory interleaving between controllers is NOT
+ * enabled, the starting address for each memory
+ * controller is distinct. However, because rank
+ * interleaving is enabled, the starting and ending
+ * addresses of the total memory on that memory
+ * controller needs to be programmed into its
+ * respective CS0_BNDS.
+ */
+ switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) {
+ case FSL_DDR_CS0_CS1_CS2_CS3:
+ sa = common_dimm->base_address;
+ ea = sa + common_dimm->total_mem - 1;
+ break;
+ case FSL_DDR_CS0_CS1_AND_CS2_CS3:
+ if ((i >= 2) && (dimm_number == 0)) {
+ sa = dimm_params[dimm_number].base_address +
+ 2 * rank_density;
+ ea = sa + 2 * rank_density - 1;
+ } else {
+ sa = dimm_params[dimm_number].base_address;
+ ea = sa + 2 * rank_density - 1;
+ }
+ break;
+ case FSL_DDR_CS0_CS1:
+ if (dimm_params[dimm_number].n_ranks > (i % cs_per_dimm)) {
+ sa = dimm_params[dimm_number].base_address;
+ ea = sa + rank_density - 1;
+ if (i != 1)
+ sa += (i % cs_per_dimm) * rank_density;
+ ea += (i % cs_per_dimm) * rank_density;
+ } else {
+ sa = 0;
+ ea = 0;
+ }
+ if (i == 0)
+ ea += rank_density;
+ break;
+ case FSL_DDR_CS2_CS3:
+ if (dimm_params[dimm_number].n_ranks > (i % cs_per_dimm)) {
+ sa = dimm_params[dimm_number].base_address;
+ ea = sa + rank_density - 1;
+ if (i != 3)
+ sa += (i % cs_per_dimm) * rank_density;
+ ea += (i % cs_per_dimm) * rank_density;
+ } else {
+ sa = 0;
+ ea = 0;
+ }
+ if (i == 2)
+ ea += (rank_density >> dbw_cap_adj);
+ break;
+ default: /* No bank(chip-select) interleaving */
+ sa = dimm_params[dimm_number].base_address;
+ ea = sa + rank_density - 1;
+ if (dimm_params[dimm_number].n_ranks > (i % cs_per_dimm)) {
+ sa += (i % cs_per_dimm) * rank_density;
+ ea += (i % cs_per_dimm) * rank_density;
+ } else {
+ sa = 0;
+ ea = 0;
+ }
+ break;
+ }
+ }
+
+ sa >>= 24;
+ ea >>= 24;
+
+ if (cs_en) {
+ ddr->cs[i].bnds = (0
+ | ((sa & 0xFFF) << 16)/* starting address MSB */
+ | ((ea & 0xFFF) << 0) /* ending address MSB */
+ );
+ } else {
+ debug("FSLDDR: setting bnds to 0 for inactive CS\n");
+ ddr->cs[i].bnds = 0;
+ }
+
+ debug("FSLDDR: cs[%d]_bnds = 0x%08x\n", i, ddr->cs[i].bnds);
+ set_csn_config(dimm_number, i, ddr, popts, dimm_params);
+ set_csn_config_2(i, ddr);
+ }
+
+ /*
+ * In the case we only need to compute the ddr sdram size, we only need
+ * to set csn registers, so return from here.
+ */
+ if (size_only)
+ return 0;
+
+ set_ddr_eor(ddr, popts);
+
+#if !defined(CONFIG_FSL_DDR1)
+ set_timing_cfg_0(ddr, popts, dimm_params);
+#endif
+
+ set_timing_cfg_3(ddr, popts, common_dimm, cas_latency);
+ set_timing_cfg_1(ddr, popts, common_dimm, cas_latency);
+ set_timing_cfg_2(ddr, popts, common_dimm,
+ cas_latency, additive_latency);
+
+ set_ddr_cdr1(ddr, popts);
+ set_ddr_cdr2(ddr, popts);
+ set_ddr_sdram_cfg(ddr, popts, common_dimm);
+ ip_rev = fsl_ddr_get_version();
+ if (ip_rev > 0x40400)
+ unq_mrs_en = 1;
+
+ set_ddr_sdram_cfg_2(ddr, popts, unq_mrs_en);
+ set_ddr_sdram_mode(ddr, popts, common_dimm,
+ cas_latency, additive_latency, unq_mrs_en);
+ set_ddr_sdram_mode_2(ddr, popts, unq_mrs_en);
+ set_ddr_sdram_interval(ddr, popts, common_dimm);
+ set_ddr_data_init(ddr);
+ set_ddr_sdram_clk_cntl(ddr, popts);
+ set_ddr_init_addr(ddr);
+ set_ddr_init_ext_addr(ddr);
+ set_timing_cfg_4(ddr, popts);
+ set_timing_cfg_5(ddr, cas_latency);
+
+ set_ddr_zq_cntl(ddr, zq_en);
+ set_ddr_wrlvl_cntl(ddr, wrlvl_en, popts);
+
+ set_ddr_sr_cntr(ddr, sr_it);
+
+ set_ddr_sdram_rcw(ddr, popts, common_dimm);
+
+ return check_fsl_memctl_config_regs(ddr);
+}
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ddr.h b/arch/powerpc/cpu/mpc8xxx/ddr/ddr.h
new file mode 100644
index 0000000..4dd55fc
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/ddr.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef FSL_DDR_MAIN_H
+#define FSL_DDR_MAIN_H
+
+#include <asm/fsl_ddr_sdram.h>
+#include <asm/fsl_ddr_dimm_params.h>
+
+#include "common_timing_params.h"
+
+#if defined(CONFIG_DDR_SPD) || defined(CONFIG_SPD_EEPROM)
+/*
+ * Bind the main DDR setup driver's generic names
+ * to this specific DDR technology.
+ */
+static __inline__ int
+compute_dimm_parameters(const generic_spd_eeprom_t *spd,
+ dimm_params_t *pdimm,
+ unsigned int dimm_number)
+{
+ return ddr_compute_dimm_parameters(spd, pdimm, dimm_number);
+}
+#endif
+
+/*
+ * Data Structures
+ *
+ * All data structures have to be on the stack
+ */
+#define CONFIG_SYS_NUM_DDR_CTLRS CONFIG_NUM_DDR_CONTROLLERS
+#define CONFIG_SYS_DIMM_SLOTS_PER_CTLR CONFIG_DIMM_SLOTS_PER_CTLR
+
+typedef struct {
+ generic_spd_eeprom_t
+ spd_installed_dimms[CONFIG_SYS_NUM_DDR_CTLRS][CONFIG_SYS_DIMM_SLOTS_PER_CTLR];
+ struct dimm_params_s
+ dimm_params[CONFIG_SYS_NUM_DDR_CTLRS][CONFIG_SYS_DIMM_SLOTS_PER_CTLR];
+ memctl_options_t memctl_opts[CONFIG_SYS_NUM_DDR_CTLRS];
+ common_timing_params_t common_timing_params[CONFIG_SYS_NUM_DDR_CTLRS];
+ fsl_ddr_cfg_regs_t fsl_ddr_config_reg[CONFIG_SYS_NUM_DDR_CTLRS];
+} fsl_ddr_info_t;
+
+/* Compute steps */
+#define STEP_GET_SPD (1 << 0)
+#define STEP_COMPUTE_DIMM_PARMS (1 << 1)
+#define STEP_COMPUTE_COMMON_PARMS (1 << 2)
+#define STEP_GATHER_OPTS (1 << 3)
+#define STEP_ASSIGN_ADDRESSES (1 << 4)
+#define STEP_COMPUTE_REGS (1 << 5)
+#define STEP_PROGRAM_REGS (1 << 6)
+#define STEP_ALL 0xFFF
+
+unsigned long long
+fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
+ unsigned int size_only);
+
+const char *step_to_string(unsigned int step);
+
+unsigned int compute_fsl_memctl_config_regs(const memctl_options_t *popts,
+ fsl_ddr_cfg_regs_t *ddr,
+ const common_timing_params_t *common_dimm,
+ const dimm_params_t *dimm_parameters,
+ unsigned int dbw_capacity_adjust,
+ unsigned int size_only);
+unsigned int compute_lowest_common_dimm_parameters(
+ const dimm_params_t *dimm_params,
+ common_timing_params_t *outpdimm,
+ unsigned int number_of_dimms);
+unsigned int populate_memctl_options(int all_DIMMs_registered,
+ memctl_options_t *popts,
+ dimm_params_t *pdimm,
+ unsigned int ctrl_num);
+void check_interleaving_options(fsl_ddr_info_t *pinfo);
+
+unsigned int mclk_to_picos(unsigned int mclk);
+unsigned int get_memory_clk_period_ps(void);
+unsigned int picos_to_mclk(unsigned int picos);
+void fsl_ddr_set_lawbar(
+ const common_timing_params_t *memctl_common_params,
+ unsigned int memctl_interleaved,
+ unsigned int ctrl_num);
+
+int fsl_ddr_interactive_env_var_exists(void);
+unsigned long long fsl_ddr_interactive(fsl_ddr_info_t *pinfo, int var_is_set);
+void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
+ unsigned int ctrl_num);
+
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+unsigned int check_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr);
+
+/* processor specific function */
+void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
+ unsigned int ctrl_num);
+
+/* board specific function */
+int fsl_ddr_get_dimm_params(dimm_params_t *pdimm,
+ unsigned int controller_number,
+ unsigned int dimm_number);
+#endif
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ddr1_dimm_params.c b/arch/powerpc/cpu/mpc8xxx/ddr/ddr1_dimm_params.c
new file mode 100644
index 0000000..376be2f
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/ddr1_dimm_params.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#include "ddr.h"
+
+/*
+ * Calculate the Density of each Physical Rank.
+ * Returned size is in bytes.
+ *
+ * Study these table from Byte 31 of JEDEC SPD Spec.
+ *
+ * DDR I DDR II
+ * Bit Size Size
+ * --- ----- ------
+ * 7 high 512MB 512MB
+ * 6 256MB 256MB
+ * 5 128MB 128MB
+ * 4 64MB 16GB
+ * 3 32MB 8GB
+ * 2 16MB 4GB
+ * 1 2GB 2GB
+ * 0 low 1GB 1GB
+ *
+ * Reorder Table to be linear by stripping the bottom
+ * 2 or 5 bits off and shifting them up to the top.
+ */
+
+static unsigned long long
+compute_ranksize(unsigned int mem_type, unsigned char row_dens)
+{
+ unsigned long long bsize;
+
+ /* Bottom 2 bits up to the top. */
+ bsize = ((row_dens >> 2) | ((row_dens & 3) << 6));
+ bsize <<= 24ULL;
+ debug("DDR: DDR I rank density = 0x%16llx\n", bsize);
+
+ return bsize;
+}
+
+/*
+ * Convert a two-nibble BCD value into a cycle time.
+ * While the spec calls for nano-seconds, picos are returned.
+ *
+ * This implements the tables for bytes 9, 23 and 25 for both
+ * DDR I and II. No allowance for distinguishing the invalid
+ * fields absent for DDR I yet present in DDR II is made.
+ * (That is, cycle times of .25, .33, .66 and .75 ns are
+ * allowed for both DDR II and I.)
+ */
+static unsigned int
+convert_bcd_tenths_to_cycle_time_ps(unsigned int spd_val)
+{
+ /* Table look up the lower nibble, allow DDR I & II. */
+ unsigned int tenths_ps[16] = {
+ 0,
+ 100,
+ 200,
+ 300,
+ 400,
+ 500,
+ 600,
+ 700,
+ 800,
+ 900,
+ 250, /* This and the next 3 entries valid ... */
+ 330, /* ... only for tCK calculations. */
+ 660,
+ 750,
+ 0, /* undefined */
+ 0 /* undefined */
+ };
+
+ unsigned int whole_ns = (spd_val & 0xF0) >> 4;
+ unsigned int tenth_ns = spd_val & 0x0F;
+ unsigned int ps = whole_ns * 1000 + tenths_ps[tenth_ns];
+
+ return ps;
+}
+
+static unsigned int
+convert_bcd_hundredths_to_cycle_time_ps(unsigned int spd_val)
+{
+ unsigned int tenth_ns = (spd_val & 0xF0) >> 4;
+ unsigned int hundredth_ns = spd_val & 0x0F;
+ unsigned int ps = tenth_ns * 100 + hundredth_ns * 10;
+
+ return ps;
+}
+
+static unsigned int byte40_table_ps[8] = {
+ 0,
+ 250,
+ 330,
+ 500,
+ 660,
+ 750,
+ 0, /* supposed to be RFC, but not sure what that means */
+ 0 /* Undefined */
+};
+
+static unsigned int
+compute_trfc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trfc)
+{
+ unsigned int trfc_ps;
+
+ trfc_ps = (((trctrfc_ext & 0x1) * 256) + trfc) * 1000
+ + byte40_table_ps[(trctrfc_ext >> 1) & 0x7];
+
+ return trfc_ps;
+}
+
+static unsigned int
+compute_trc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trc)
+{
+ unsigned int trc_ps;
+
+ trc_ps = trc * 1000 + byte40_table_ps[(trctrfc_ext >> 4) & 0x7];
+
+ return trc_ps;
+}
+
+/*
+ * tCKmax from DDR I SPD Byte 43
+ *
+ * Bits 7:2 == whole ns
+ * Bits 1:0 == quarter ns
+ * 00 == 0.00 ns
+ * 01 == 0.25 ns
+ * 10 == 0.50 ns
+ * 11 == 0.75 ns
+ *
+ * Returns picoseconds.
+ */
+static unsigned int
+compute_tckmax_from_spd_ps(unsigned int byte43)
+{
+ return (byte43 >> 2) * 1000 + (byte43 & 0x3) * 250;
+}
+
+/*
+ * Determine Refresh Rate. Ignore self refresh bit on DDR I.
+ * Table from SPD Spec, Byte 12, converted to picoseconds and
+ * filled in with "default" normal values.
+ */
+static unsigned int
+determine_refresh_rate_ps(const unsigned int spd_refresh)
+{
+ unsigned int refresh_time_ps[8] = {
+ 15625000, /* 0 Normal 1.00x */
+ 3900000, /* 1 Reduced .25x */
+ 7800000, /* 2 Extended .50x */
+ 31300000, /* 3 Extended 2.00x */
+ 62500000, /* 4 Extended 4.00x */
+ 125000000, /* 5 Extended 8.00x */
+ 15625000, /* 6 Normal 1.00x filler */
+ 15625000, /* 7 Normal 1.00x filler */
+ };
+
+ return refresh_time_ps[spd_refresh & 0x7];
+}
+
+/*
+ * The purpose of this function is to compute a suitable
+ * CAS latency given the DRAM clock period. The SPD only
+ * defines at most 3 CAS latencies. Typically the slower in
+ * frequency the DIMM runs at, the shorter its CAS latency can be.
+ * If the DIMM is operating at a sufficiently low frequency,
+ * it may be able to run at a CAS latency shorter than the
+ * shortest SPD-defined CAS latency.
+ *
+ * If a CAS latency is not found, 0 is returned.
+ *
+ * Do this by finding in the standard speed bin table the longest
+ * tCKmin that doesn't exceed the value of mclk_ps (tCK).
+ *
+ * An assumption made is that the SDRAM device allows the
+ * CL to be programmed for a value that is lower than those
+ * advertised by the SPD. This is not always the case,
+ * as those modes not defined in the SPD are optional.
+ *
+ * CAS latency de-rating based upon values JEDEC Standard No. 79-E
+ * Table 11.
+ *
+ * ordinal 2, ddr1_speed_bins[1] contains tCK for CL=2
+ */
+ /* CL2.0 CL2.5 CL3.0 */
+unsigned short ddr1_speed_bins[] = {0, 7500, 6000, 5000 };
+
+unsigned int
+compute_derated_DDR1_CAS_latency(unsigned int mclk_ps)
+{
+ const unsigned int num_speed_bins = ARRAY_SIZE(ddr1_speed_bins);
+ unsigned int lowest_tCKmin_found = 0;
+ unsigned int lowest_tCKmin_CL = 0;
+ unsigned int i;
+
+ debug("mclk_ps = %u\n", mclk_ps);
+
+ for (i = 0; i < num_speed_bins; i++) {
+ unsigned int x = ddr1_speed_bins[i];
+ debug("i=%u, x = %u, lowest_tCKmin_found = %u\n",
+ i, x, lowest_tCKmin_found);
+ if (x && lowest_tCKmin_found <= x && x <= mclk_ps) {
+ lowest_tCKmin_found = x;
+ lowest_tCKmin_CL = i + 1;
+ }
+ }
+
+ debug("lowest_tCKmin_CL = %u\n", lowest_tCKmin_CL);
+
+ return lowest_tCKmin_CL;
+}
+
+/*
+ * ddr_compute_dimm_parameters for DDR1 SPD
+ *
+ * Compute DIMM parameters based upon the SPD information in spd.
+ * Writes the results to the dimm_params_t structure pointed by pdimm.
+ *
+ * FIXME: use #define for the retvals
+ */
+unsigned int
+ddr_compute_dimm_parameters(const ddr1_spd_eeprom_t *spd,
+ dimm_params_t *pdimm,
+ unsigned int dimm_number)
+{
+ unsigned int retval;
+
+ if (spd->mem_type) {
+ if (spd->mem_type != SPD_MEMTYPE_DDR) {
+ printf("DIMM %u: is not a DDR1 SPD.\n", dimm_number);
+ return 1;
+ }
+ } else {
+ memset(pdimm, 0, sizeof(dimm_params_t));
+ return 1;
+ }
+
+ retval = ddr1_spd_check(spd);
+ if (retval) {
+ printf("DIMM %u: failed checksum\n", dimm_number);
+ return 2;
+ }
+
+ /*
+ * The part name in ASCII in the SPD EEPROM is not null terminated.
+ * Guarantee null termination here by presetting all bytes to 0
+ * and copying the part name in ASCII from the SPD onto it
+ */
+ memset(pdimm->mpart, 0, sizeof(pdimm->mpart));
+ memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1);
+
+ /* DIMM organization parameters */
+ pdimm->n_ranks = spd->nrows;
+ pdimm->rank_density = compute_ranksize(spd->mem_type, spd->bank_dens);
+ pdimm->capacity = pdimm->n_ranks * pdimm->rank_density;
+ pdimm->data_width = spd->dataw_lsb;
+ pdimm->primary_sdram_width = spd->primw;
+ pdimm->ec_sdram_width = spd->ecw;
+
+ /*
+ * FIXME: Need to determine registered_dimm status.
+ * 1 == register buffered
+ * 0 == unbuffered
+ */
+ pdimm->registered_dimm = 0; /* unbuffered */
+
+ /* SDRAM device parameters */
+ pdimm->n_row_addr = spd->nrow_addr;
+ pdimm->n_col_addr = spd->ncol_addr;
+ pdimm->n_banks_per_sdram_device = spd->nbanks;
+ pdimm->edc_config = spd->config;
+ pdimm->burst_lengths_bitmask = spd->burstl;
+ pdimm->row_density = spd->bank_dens;
+
+ /*
+ * Calculate the Maximum Data Rate based on the Minimum Cycle time.
+ * The SPD clk_cycle field (tCKmin) is measured in tenths of
+ * nanoseconds and represented as BCD.
+ */
+ pdimm->tCKmin_X_ps
+ = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle);
+ pdimm->tCKmin_X_minus_1_ps
+ = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle2);
+ pdimm->tCKmin_X_minus_2_ps
+ = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle3);
+
+ pdimm->tCKmax_ps = compute_tckmax_from_spd_ps(spd->tckmax);
+
+ /*
+ * Compute CAS latencies defined by SPD
+ * The SPD caslat_X should have at least 1 and at most 3 bits set.
+ *
+ * If cas_lat after masking is 0, the __ilog2 function returns
+ * 255 into the variable. This behavior is abused once.
+ */
+ pdimm->caslat_X = __ilog2(spd->cas_lat);
+ pdimm->caslat_X_minus_1 = __ilog2(spd->cas_lat
+ & ~(1 << pdimm->caslat_X));
+ pdimm->caslat_X_minus_2 = __ilog2(spd->cas_lat
+ & ~(1 << pdimm->caslat_X)
+ & ~(1 << pdimm->caslat_X_minus_1));
+
+ /* Compute CAS latencies below that defined by SPD */
+ pdimm->caslat_lowest_derated
+ = compute_derated_DDR1_CAS_latency(get_memory_clk_period_ps());
+
+ /* Compute timing parameters */
+ pdimm->tRCD_ps = spd->trcd * 250;
+ pdimm->tRP_ps = spd->trp * 250;
+ pdimm->tRAS_ps = spd->tras * 1000;
+
+ pdimm->tWR_ps = mclk_to_picos(3);
+ pdimm->tWTR_ps = mclk_to_picos(1);
+ pdimm->tRFC_ps = compute_trfc_ps_from_spd(0, spd->trfc);
+
+ pdimm->tRRD_ps = spd->trrd * 250;
+ pdimm->tRC_ps = compute_trc_ps_from_spd(0, spd->trc);
+
+ pdimm->refresh_rate_ps = determine_refresh_rate_ps(spd->refresh);
+
+ pdimm->tIS_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_setup);
+ pdimm->tIH_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_hold);
+ pdimm->tDS_ps
+ = convert_bcd_hundredths_to_cycle_time_ps(spd->data_setup);
+ pdimm->tDH_ps
+ = convert_bcd_hundredths_to_cycle_time_ps(spd->data_hold);
+
+ pdimm->tRTP_ps = mclk_to_picos(2); /* By the book. */
+ pdimm->tDQSQ_max_ps = spd->tdqsq * 10;
+ pdimm->tQHS_ps = spd->tqhs * 10;
+
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ddr2_dimm_params.c b/arch/powerpc/cpu/mpc8xxx/ddr/ddr2_dimm_params.c
new file mode 100644
index 0000000..f637f3d
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/ddr2_dimm_params.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#include "ddr.h"
+/*
+ * Calculate the Density of each Physical Rank.
+ * Returned size is in bytes.
+ *
+ * Study these table from Byte 31 of JEDEC SPD Spec.
+ *
+ * DDR I DDR II
+ * Bit Size Size
+ * --- ----- ------
+ * 7 high 512MB 512MB
+ * 6 256MB 256MB
+ * 5 128MB 128MB
+ * 4 64MB 16GB
+ * 3 32MB 8GB
+ * 2 16MB 4GB
+ * 1 2GB 2GB
+ * 0 low 1GB 1GB
+ *
+ * Reorder Table to be linear by stripping the bottom
+ * 2 or 5 bits off and shifting them up to the top.
+ *
+ */
+static unsigned long long
+compute_ranksize(unsigned int mem_type, unsigned char row_dens)
+{
+ unsigned long long bsize;
+
+ /* Bottom 5 bits up to the top. */
+ bsize = ((row_dens >> 5) | ((row_dens & 31) << 3));
+ bsize <<= 27ULL;
+ debug("DDR: DDR II rank density = 0x%16llx\n", bsize);
+
+ return bsize;
+}
+
+/*
+ * Convert a two-nibble BCD value into a cycle time.
+ * While the spec calls for nano-seconds, picos are returned.
+ *
+ * This implements the tables for bytes 9, 23 and 25 for both
+ * DDR I and II. No allowance for distinguishing the invalid
+ * fields absent for DDR I yet present in DDR II is made.
+ * (That is, cycle times of .25, .33, .66 and .75 ns are
+ * allowed for both DDR II and I.)
+ */
+static unsigned int
+convert_bcd_tenths_to_cycle_time_ps(unsigned int spd_val)
+{
+ /* Table look up the lower nibble, allow DDR I & II. */
+ unsigned int tenths_ps[16] = {
+ 0,
+ 100,
+ 200,
+ 300,
+ 400,
+ 500,
+ 600,
+ 700,
+ 800,
+ 900,
+ 250, /* This and the next 3 entries valid ... */
+ 330, /* ... only for tCK calculations. */
+ 660,
+ 750,
+ 0, /* undefined */
+ 0 /* undefined */
+ };
+
+ unsigned int whole_ns = (spd_val & 0xF0) >> 4;
+ unsigned int tenth_ns = spd_val & 0x0F;
+ unsigned int ps = whole_ns * 1000 + tenths_ps[tenth_ns];
+
+ return ps;
+}
+
+static unsigned int
+convert_bcd_hundredths_to_cycle_time_ps(unsigned int spd_val)
+{
+ unsigned int tenth_ns = (spd_val & 0xF0) >> 4;
+ unsigned int hundredth_ns = spd_val & 0x0F;
+ unsigned int ps = tenth_ns * 100 + hundredth_ns * 10;
+
+ return ps;
+}
+
+static unsigned int byte40_table_ps[8] = {
+ 0,
+ 250,
+ 330,
+ 500,
+ 660,
+ 750,
+ 0, /* supposed to be RFC, but not sure what that means */
+ 0 /* Undefined */
+};
+
+static unsigned int
+compute_trfc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trfc)
+{
+ unsigned int trfc_ps;
+
+ trfc_ps = (((trctrfc_ext & 0x1) * 256) + trfc) * 1000
+ + byte40_table_ps[(trctrfc_ext >> 1) & 0x7];
+
+ return trfc_ps;
+}
+
+static unsigned int
+compute_trc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trc)
+{
+ unsigned int trc_ps;
+
+ trc_ps = trc * 1000 + byte40_table_ps[(trctrfc_ext >> 4) & 0x7];
+
+ return trc_ps;
+}
+
+/*
+ * Determine Refresh Rate. Ignore self refresh bit on DDR I.
+ * Table from SPD Spec, Byte 12, converted to picoseconds and
+ * filled in with "default" normal values.
+ */
+static unsigned int
+determine_refresh_rate_ps(const unsigned int spd_refresh)
+{
+ unsigned int refresh_time_ps[8] = {
+ 15625000, /* 0 Normal 1.00x */
+ 3900000, /* 1 Reduced .25x */
+ 7800000, /* 2 Extended .50x */
+ 31300000, /* 3 Extended 2.00x */
+ 62500000, /* 4 Extended 4.00x */
+ 125000000, /* 5 Extended 8.00x */
+ 15625000, /* 6 Normal 1.00x filler */
+ 15625000, /* 7 Normal 1.00x filler */
+ };
+
+ return refresh_time_ps[spd_refresh & 0x7];
+}
+
+/*
+ * The purpose of this function is to compute a suitable
+ * CAS latency given the DRAM clock period. The SPD only
+ * defines at most 3 CAS latencies. Typically the slower in
+ * frequency the DIMM runs at, the shorter its CAS latency can.
+ * be. If the DIMM is operating at a sufficiently low frequency,
+ * it may be able to run at a CAS latency shorter than the
+ * shortest SPD-defined CAS latency.
+ *
+ * If a CAS latency is not found, 0 is returned.
+ *
+ * Do this by finding in the standard speed bin table the longest
+ * tCKmin that doesn't exceed the value of mclk_ps (tCK).
+ *
+ * An assumption made is that the SDRAM device allows the
+ * CL to be programmed for a value that is lower than those
+ * advertised by the SPD. This is not always the case,
+ * as those modes not defined in the SPD are optional.
+ *
+ * CAS latency de-rating based upon values JEDEC Standard No. 79-2C
+ * Table 40, "DDR2 SDRAM stanadard speed bins and tCK, tRCD, tRP, tRAS,
+ * and tRC for corresponding bin"
+ *
+ * ordinal 2, ddr2_speed_bins[1] contains tCK for CL=3
+ * Not certain if any good value exists for CL=2
+ */
+ /* CL2 CL3 CL4 CL5 CL6 CL7*/
+unsigned short ddr2_speed_bins[] = { 0, 5000, 3750, 3000, 2500, 1875 };
+
+unsigned int
+compute_derated_DDR2_CAS_latency(unsigned int mclk_ps)
+{
+ const unsigned int num_speed_bins = ARRAY_SIZE(ddr2_speed_bins);
+ unsigned int lowest_tCKmin_found = 0;
+ unsigned int lowest_tCKmin_CL = 0;
+ unsigned int i;
+
+ debug("mclk_ps = %u\n", mclk_ps);
+
+ for (i = 0; i < num_speed_bins; i++) {
+ unsigned int x = ddr2_speed_bins[i];
+ debug("i=%u, x = %u, lowest_tCKmin_found = %u\n",
+ i, x, lowest_tCKmin_found);
+ if (x && x <= mclk_ps && x >= lowest_tCKmin_found ) {
+ lowest_tCKmin_found = x;
+ lowest_tCKmin_CL = i + 2;
+ }
+ }
+
+ debug("lowest_tCKmin_CL = %u\n", lowest_tCKmin_CL);
+
+ return lowest_tCKmin_CL;
+}
+
+/*
+ * ddr_compute_dimm_parameters for DDR2 SPD
+ *
+ * Compute DIMM parameters based upon the SPD information in spd.
+ * Writes the results to the dimm_params_t structure pointed by pdimm.
+ *
+ * FIXME: use #define for the retvals
+ */
+unsigned int
+ddr_compute_dimm_parameters(const ddr2_spd_eeprom_t *spd,
+ dimm_params_t *pdimm,
+ unsigned int dimm_number)
+{
+ unsigned int retval;
+
+ if (spd->mem_type) {
+ if (spd->mem_type != SPD_MEMTYPE_DDR2) {
+ printf("DIMM %u: is not a DDR2 SPD.\n", dimm_number);
+ return 1;
+ }
+ } else {
+ memset(pdimm, 0, sizeof(dimm_params_t));
+ return 1;
+ }
+
+ retval = ddr2_spd_check(spd);
+ if (retval) {
+ printf("DIMM %u: failed checksum\n", dimm_number);
+ return 2;
+ }
+
+ /*
+ * The part name in ASCII in the SPD EEPROM is not null terminated.
+ * Guarantee null termination here by presetting all bytes to 0
+ * and copying the part name in ASCII from the SPD onto it
+ */
+ memset(pdimm->mpart, 0, sizeof(pdimm->mpart));
+ memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1);
+
+ /* DIMM organization parameters */
+ pdimm->n_ranks = (spd->mod_ranks & 0x7) + 1;
+ pdimm->rank_density = compute_ranksize(spd->mem_type, spd->rank_dens);
+ pdimm->capacity = pdimm->n_ranks * pdimm->rank_density;
+ pdimm->data_width = spd->dataw;
+ pdimm->primary_sdram_width = spd->primw;
+ pdimm->ec_sdram_width = spd->ecw;
+
+ /* These are all the types defined by the JEDEC DDR2 SPD 1.3 spec */
+ switch (spd->dimm_type) {
+ case DDR2_SPD_DIMMTYPE_RDIMM:
+ case DDR2_SPD_DIMMTYPE_72B_SO_RDIMM:
+ case DDR2_SPD_DIMMTYPE_MINI_RDIMM:
+ /* Registered/buffered DIMMs */
+ pdimm->registered_dimm = 1;
+ break;
+
+ case DDR2_SPD_DIMMTYPE_UDIMM:
+ case DDR2_SPD_DIMMTYPE_SO_DIMM:
+ case DDR2_SPD_DIMMTYPE_MICRO_DIMM:
+ case DDR2_SPD_DIMMTYPE_MINI_UDIMM:
+ /* Unbuffered DIMMs */
+ pdimm->registered_dimm = 0;
+ break;
+
+ case DDR2_SPD_DIMMTYPE_72B_SO_CDIMM:
+ default:
+ printf("unknown dimm_type 0x%02X\n", spd->dimm_type);
+ return 1;
+ }
+
+ /* SDRAM device parameters */
+ pdimm->n_row_addr = spd->nrow_addr;
+ pdimm->n_col_addr = spd->ncol_addr;
+ pdimm->n_banks_per_sdram_device = spd->nbanks;
+ pdimm->edc_config = spd->config;
+ pdimm->burst_lengths_bitmask = spd->burstl;
+ pdimm->row_density = spd->rank_dens;
+
+ /*
+ * Calculate the Maximum Data Rate based on the Minimum Cycle time.
+ * The SPD clk_cycle field (tCKmin) is measured in tenths of
+ * nanoseconds and represented as BCD.
+ */
+ pdimm->tCKmin_X_ps
+ = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle);
+ pdimm->tCKmin_X_minus_1_ps
+ = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle2);
+ pdimm->tCKmin_X_minus_2_ps
+ = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle3);
+
+ pdimm->tCKmax_ps = convert_bcd_tenths_to_cycle_time_ps(spd->tckmax);
+
+ /*
+ * Compute CAS latencies defined by SPD
+ * The SPD caslat_X should have at least 1 and at most 3 bits set.
+ *
+ * If cas_lat after masking is 0, the __ilog2 function returns
+ * 255 into the variable. This behavior is abused once.
+ */
+ pdimm->caslat_X = __ilog2(spd->cas_lat);
+ pdimm->caslat_X_minus_1 = __ilog2(spd->cas_lat
+ & ~(1 << pdimm->caslat_X));
+ pdimm->caslat_X_minus_2 = __ilog2(spd->cas_lat
+ & ~(1 << pdimm->caslat_X)
+ & ~(1 << pdimm->caslat_X_minus_1));
+
+ /* Compute CAS latencies below that defined by SPD */
+ pdimm->caslat_lowest_derated
+ = compute_derated_DDR2_CAS_latency(get_memory_clk_period_ps());
+
+ /* Compute timing parameters */
+ pdimm->tRCD_ps = spd->trcd * 250;
+ pdimm->tRP_ps = spd->trp * 250;
+ pdimm->tRAS_ps = spd->tras * 1000;
+
+ pdimm->tWR_ps = spd->twr * 250;
+ pdimm->tWTR_ps = spd->twtr * 250;
+ pdimm->tRFC_ps = compute_trfc_ps_from_spd(spd->trctrfc_ext, spd->trfc);
+
+ pdimm->tRRD_ps = spd->trrd * 250;
+ pdimm->tRC_ps = compute_trc_ps_from_spd(spd->trctrfc_ext, spd->trc);
+
+ pdimm->refresh_rate_ps = determine_refresh_rate_ps(spd->refresh);
+
+ pdimm->tIS_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_setup);
+ pdimm->tIH_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_hold);
+ pdimm->tDS_ps
+ = convert_bcd_hundredths_to_cycle_time_ps(spd->data_setup);
+ pdimm->tDH_ps
+ = convert_bcd_hundredths_to_cycle_time_ps(spd->data_hold);
+
+ pdimm->tRTP_ps = spd->trtp * 250;
+ pdimm->tDQSQ_max_ps = spd->tdqsq * 10;
+ pdimm->tQHS_ps = spd->tqhs * 10;
+
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c b/arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c
new file mode 100644
index 0000000..3e7c269
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor, Inc.
+ * Dave Liu <daveliu@freescale.com>
+ *
+ * calculate the organization and timing parameter
+ * from ddr3 spd, please refer to the spec
+ * JEDEC standard No.21-C 4_01_02_11R18.pdf
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#include "ddr.h"
+
+/*
+ * Calculate the Density of each Physical Rank.
+ * Returned size is in bytes.
+ *
+ * each rank size =
+ * sdram capacity(bit) / 8 * primary bus width / sdram width
+ *
+ * where: sdram capacity = spd byte4[3:0]
+ * primary bus width = spd byte8[2:0]
+ * sdram width = spd byte7[2:0]
+ *
+ * SPD byte4 - sdram density and banks
+ * bit[3:0] size(bit) size(byte)
+ * 0000 256Mb 32MB
+ * 0001 512Mb 64MB
+ * 0010 1Gb 128MB
+ * 0011 2Gb 256MB
+ * 0100 4Gb 512MB
+ * 0101 8Gb 1GB
+ * 0110 16Gb 2GB
+ *
+ * SPD byte8 - module memory bus width
+ * bit[2:0] primary bus width
+ * 000 8bits
+ * 001 16bits
+ * 010 32bits
+ * 011 64bits
+ *
+ * SPD byte7 - module organiztion
+ * bit[2:0] sdram device width
+ * 000 4bits
+ * 001 8bits
+ * 010 16bits
+ * 011 32bits
+ *
+ */
+static unsigned long long
+compute_ranksize(const ddr3_spd_eeprom_t *spd)
+{
+ unsigned long long bsize;
+
+ int nbit_sdram_cap_bsize = 0;
+ int nbit_primary_bus_width = 0;
+ int nbit_sdram_width = 0;
+
+ if ((spd->density_banks & 0xf) < 7)
+ nbit_sdram_cap_bsize = (spd->density_banks & 0xf) + 28;
+ if ((spd->bus_width & 0x7) < 4)
+ nbit_primary_bus_width = (spd->bus_width & 0x7) + 3;
+ if ((spd->organization & 0x7) < 4)
+ nbit_sdram_width = (spd->organization & 0x7) + 2;
+
+ bsize = 1ULL << (nbit_sdram_cap_bsize - 3
+ + nbit_primary_bus_width - nbit_sdram_width);
+
+ debug("DDR: DDR III rank density = 0x%16llx\n", bsize);
+
+ return bsize;
+}
+
+/*
+ * ddr_compute_dimm_parameters for DDR3 SPD
+ *
+ * Compute DIMM parameters based upon the SPD information in spd.
+ * Writes the results to the dimm_params_t structure pointed by pdimm.
+ *
+ */
+unsigned int
+ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd,
+ dimm_params_t *pdimm,
+ unsigned int dimm_number)
+{
+ unsigned int retval;
+ unsigned int mtb_ps;
+ int ftb_10th_ps;
+ int i;
+
+ if (spd->mem_type) {
+ if (spd->mem_type != SPD_MEMTYPE_DDR3) {
+ printf("DIMM %u: is not a DDR3 SPD.\n", dimm_number);
+ return 1;
+ }
+ } else {
+ memset(pdimm, 0, sizeof(dimm_params_t));
+ return 1;
+ }
+
+ retval = ddr3_spd_check(spd);
+ if (retval) {
+ printf("DIMM %u: failed checksum\n", dimm_number);
+ return 2;
+ }
+
+ /*
+ * The part name in ASCII in the SPD EEPROM is not null terminated.
+ * Guarantee null termination here by presetting all bytes to 0
+ * and copying the part name in ASCII from the SPD onto it
+ */
+ memset(pdimm->mpart, 0, sizeof(pdimm->mpart));
+ if ((spd->info_size_crc & 0xF) > 1)
+ memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1);
+
+ /* DIMM organization parameters */
+ pdimm->n_ranks = ((spd->organization >> 3) & 0x7) + 1;
+ pdimm->rank_density = compute_ranksize(spd);
+ pdimm->capacity = pdimm->n_ranks * pdimm->rank_density;
+ pdimm->primary_sdram_width = 1 << (3 + (spd->bus_width & 0x7));
+ if ((spd->bus_width >> 3) & 0x3)
+ pdimm->ec_sdram_width = 8;
+ else
+ pdimm->ec_sdram_width = 0;
+ pdimm->data_width = pdimm->primary_sdram_width
+ + pdimm->ec_sdram_width;
+
+ /* These are the types defined by the JEDEC DDR3 SPD spec */
+ pdimm->mirrored_dimm = 0;
+ pdimm->registered_dimm = 0;
+ switch (spd->module_type & DDR3_SPD_MODULETYPE_MASK) {
+ case DDR3_SPD_MODULETYPE_RDIMM:
+ case DDR3_SPD_MODULETYPE_MINI_RDIMM:
+ case DDR3_SPD_MODULETYPE_72B_SO_RDIMM:
+ /* Registered/buffered DIMMs */
+ pdimm->registered_dimm = 1;
+ for (i = 0; i < 16; i += 2) {
+ u8 rcw = spd->mod_section.registered.rcw[i/2];
+ pdimm->rcw[i] = (rcw >> 0) & 0x0F;
+ pdimm->rcw[i+1] = (rcw >> 4) & 0x0F;
+ }
+ break;
+
+ case DDR3_SPD_MODULETYPE_UDIMM:
+ case DDR3_SPD_MODULETYPE_SO_DIMM:
+ case DDR3_SPD_MODULETYPE_MICRO_DIMM:
+ case DDR3_SPD_MODULETYPE_MINI_UDIMM:
+ case DDR3_SPD_MODULETYPE_MINI_CDIMM:
+ case DDR3_SPD_MODULETYPE_72B_SO_UDIMM:
+ case DDR3_SPD_MODULETYPE_72B_SO_CDIMM:
+ case DDR3_SPD_MODULETYPE_LRDIMM:
+ case DDR3_SPD_MODULETYPE_16B_SO_DIMM:
+ case DDR3_SPD_MODULETYPE_32B_SO_DIMM:
+ /* Unbuffered DIMMs */
+ if (spd->mod_section.unbuffered.addr_mapping & 0x1)
+ pdimm->mirrored_dimm = 1;
+ break;
+
+ default:
+ printf("unknown module_type 0x%02X\n", spd->module_type);
+ return 1;
+ }
+
+ /* SDRAM device parameters */
+ pdimm->n_row_addr = ((spd->addressing >> 3) & 0x7) + 12;
+ pdimm->n_col_addr = (spd->addressing & 0x7) + 9;
+ pdimm->n_banks_per_sdram_device = 8 << ((spd->density_banks >> 4) & 0x7);
+
+ /*
+ * The SPD spec has not the ECC bit,
+ * We consider the DIMM as ECC capability
+ * when the extension bus exist
+ */
+ if (pdimm->ec_sdram_width)
+ pdimm->edc_config = 0x02;
+ else
+ pdimm->edc_config = 0x00;
+
+ /*
+ * The SPD spec has not the burst length byte
+ * but DDR3 spec has nature BL8 and BC4,
+ * BL8 -bit3, BC4 -bit2
+ */
+ pdimm->burst_lengths_bitmask = 0x0c;
+ pdimm->row_density = __ilog2(pdimm->rank_density);
+
+ /* MTB - medium timebase
+ * The unit in the SPD spec is ns,
+ * We convert it to ps.
+ * eg: MTB = 0.125ns (125ps)
+ */
+ mtb_ps = (spd->mtb_dividend * 1000) /spd->mtb_divisor;
+ pdimm->mtb_ps = mtb_ps;
+
+ /*
+ * FTB - fine timebase
+ * use 1/10th of ps as our unit to avoid floating point
+ * eg, 10 for 1ps, 25 for 2.5ps, 50 for 5ps
+ */
+ ftb_10th_ps =
+ ((spd->ftb_div & 0xf0) >> 4) * 10 / (spd->ftb_div & 0x0f);
+ pdimm->ftb_10th_ps = ftb_10th_ps;
+ /*
+ * sdram minimum cycle time
+ * we assume the MTB is 0.125ns
+ * eg:
+ * tCK_min=15 MTB (1.875ns) ->DDR3-1066
+ * =12 MTB (1.5ns) ->DDR3-1333
+ * =10 MTB (1.25ns) ->DDR3-1600
+ */
+ pdimm->tCKmin_X_ps = spd->tCK_min * mtb_ps +
+ (spd->fine_tCK_min * ftb_10th_ps) / 10;
+
+ /*
+ * CAS latency supported
+ * bit4 - CL4
+ * bit5 - CL5
+ * bit18 - CL18
+ */
+ pdimm->caslat_X = ((spd->caslat_msb << 8) | spd->caslat_lsb) << 4;
+
+ /*
+ * min CAS latency time
+ * eg: tAA_min =
+ * DDR3-800D 100 MTB (12.5ns)
+ * DDR3-1066F 105 MTB (13.125ns)
+ * DDR3-1333H 108 MTB (13.5ns)
+ * DDR3-1600H 90 MTB (11.25ns)
+ */
+ pdimm->tAA_ps = spd->tAA_min * mtb_ps +
+ (spd->fine_tAA_min * ftb_10th_ps) / 10;
+
+ /*
+ * min write recovery time
+ * eg:
+ * tWR_min = 120 MTB (15ns) -> all speed grades.
+ */
+ pdimm->tWR_ps = spd->tWR_min * mtb_ps;
+
+ /*
+ * min RAS to CAS delay time
+ * eg: tRCD_min =
+ * DDR3-800 100 MTB (12.5ns)
+ * DDR3-1066F 105 MTB (13.125ns)
+ * DDR3-1333H 108 MTB (13.5ns)
+ * DDR3-1600H 90 MTB (11.25)
+ */
+ pdimm->tRCD_ps = spd->tRCD_min * mtb_ps +
+ (spd->fine_tRCD_min * ftb_10th_ps) / 10;
+
+ /*
+ * min row active to row active delay time
+ * eg: tRRD_min =
+ * DDR3-800(1KB page) 80 MTB (10ns)
+ * DDR3-1333(1KB page) 48 MTB (6ns)
+ */
+ pdimm->tRRD_ps = spd->tRRD_min * mtb_ps;
+
+ /*
+ * min row precharge delay time
+ * eg: tRP_min =
+ * DDR3-800D 100 MTB (12.5ns)
+ * DDR3-1066F 105 MTB (13.125ns)
+ * DDR3-1333H 108 MTB (13.5ns)
+ * DDR3-1600H 90 MTB (11.25ns)
+ */
+ pdimm->tRP_ps = spd->tRP_min * mtb_ps +
+ (spd->fine_tRP_min * ftb_10th_ps) / 10;
+
+ /* min active to precharge delay time
+ * eg: tRAS_min =
+ * DDR3-800D 300 MTB (37.5ns)
+ * DDR3-1066F 300 MTB (37.5ns)
+ * DDR3-1333H 288 MTB (36ns)
+ * DDR3-1600H 280 MTB (35ns)
+ */
+ pdimm->tRAS_ps = (((spd->tRAS_tRC_ext & 0xf) << 8) | spd->tRAS_min_lsb)
+ * mtb_ps;
+ /*
+ * min active to actice/refresh delay time
+ * eg: tRC_min =
+ * DDR3-800D 400 MTB (50ns)
+ * DDR3-1066F 405 MTB (50.625ns)
+ * DDR3-1333H 396 MTB (49.5ns)
+ * DDR3-1600H 370 MTB (46.25ns)
+ */
+ pdimm->tRC_ps = (((spd->tRAS_tRC_ext & 0xf0) << 4) | spd->tRC_min_lsb)
+ * mtb_ps + (spd->fine_tRC_min * ftb_10th_ps) / 10;
+ /*
+ * min refresh recovery delay time
+ * eg: tRFC_min =
+ * 512Mb 720 MTB (90ns)
+ * 1Gb 880 MTB (110ns)
+ * 2Gb 1280 MTB (160ns)
+ */
+ pdimm->tRFC_ps = ((spd->tRFC_min_msb << 8) | spd->tRFC_min_lsb)
+ * mtb_ps;
+ /*
+ * min internal write to read command delay time
+ * eg: tWTR_min = 40 MTB (7.5ns) - all speed bins.
+ * tWRT is at least 4 mclk independent of operating freq.
+ */
+ pdimm->tWTR_ps = spd->tWTR_min * mtb_ps;
+
+ /*
+ * min internal read to precharge command delay time
+ * eg: tRTP_min = 40 MTB (7.5ns) - all speed bins.
+ * tRTP is at least 4 mclk independent of operating freq.
+ */
+ pdimm->tRTP_ps = spd->tRTP_min * mtb_ps;
+
+ /*
+ * Average periodic refresh interval
+ * tREFI = 7.8 us at normal temperature range
+ * = 3.9 us at ext temperature range
+ */
+ pdimm->refresh_rate_ps = 7800000;
+
+ /*
+ * min four active window delay time
+ * eg: tFAW_min =
+ * DDR3-800(1KB page) 320 MTB (40ns)
+ * DDR3-1066(1KB page) 300 MTB (37.5ns)
+ * DDR3-1333(1KB page) 240 MTB (30ns)
+ * DDR3-1600(1KB page) 240 MTB (30ns)
+ */
+ pdimm->tFAW_ps = (((spd->tFAW_msb & 0xf) << 8) | spd->tFAW_min)
+ * mtb_ps;
+
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
new file mode 100644
index 0000000..46257c9
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
@@ -0,0 +1,1868 @@
+/*
+ * Copyright 2010-2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 or any later versionas published by the Free Software Foundation.
+ */
+
+/*
+ * Generic driver for Freescale DDR/DDR2/DDR3 memory controller.
+ * Based on code from spd_sdram.c
+ * Author: James Yang [at freescale.com]
+ * York Sun [at freescale.com]
+ */
+
+#include <common.h>
+#include <linux/ctype.h>
+#include <asm/types.h>
+
+#include <asm/fsl_ddr_sdram.h>
+#include "ddr.h"
+
+/* Option parameter Structures */
+struct options_string {
+ const char *option_name;
+ size_t offset;
+ unsigned int size;
+ const char printhex;
+};
+
+static unsigned int picos_to_mhz(unsigned int picos)
+{
+ return 1000000 / picos;
+}
+
+static void print_option_table(const struct options_string *table,
+ int table_size,
+ const void *base)
+{
+ unsigned int i;
+ unsigned int *ptr;
+ unsigned long long *ptr_l;
+
+ for (i = 0; i < table_size; i++) {
+ switch (table[i].size) {
+ case 4:
+ ptr = (unsigned int *) (base + table[i].offset);
+ if (table[i].printhex) {
+ printf("%s = 0x%08X\n",
+ table[i].option_name, *ptr);
+ } else {
+ printf("%s = %u\n",
+ table[i].option_name, *ptr);
+ }
+ break;
+ case 8:
+ ptr_l = (unsigned long long *) (base + table[i].offset);
+ printf("%s = %llu\n",
+ table[i].option_name, *ptr_l);
+ break;
+ default:
+ printf("Unrecognized size!\n");
+ break;
+ }
+ }
+}
+
+static int handle_option_table(const struct options_string *table,
+ int table_size,
+ void *base,
+ const char *opt,
+ const char *val)
+{
+ unsigned int i;
+ unsigned int value, *ptr;
+ unsigned long long value_l, *ptr_l;
+
+ for (i = 0; i < table_size; i++) {
+ if (strcmp(table[i].option_name, opt) != 0)
+ continue;
+ switch (table[i].size) {
+ case 4:
+ value = simple_strtoul(val, NULL, 0);
+ ptr = base + table[i].offset;
+ *ptr = value;
+ break;
+ case 8:
+ value_l = simple_strtoull(val, NULL, 0);
+ ptr_l = base + table[i].offset;
+ *ptr_l = value_l;
+ break;
+ default:
+ printf("Unrecognized size!\n");
+ break;
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+static void fsl_ddr_generic_edit(void *pdata,
+ void *pend,
+ unsigned int element_size,
+ unsigned int element_num,
+ unsigned int value)
+{
+ char *pcdata = (char *)pdata; /* BIG ENDIAN ONLY */
+
+ pcdata += element_num * element_size;
+ if ((pcdata + element_size) > (char *) pend) {
+ printf("trying to write past end of data\n");
+ return;
+ }
+
+ switch (element_size) {
+ case 1:
+ __raw_writeb(value, pcdata);
+ break;
+ case 2:
+ __raw_writew(value, pcdata);
+ break;
+ case 4:
+ __raw_writel(value, pcdata);
+ break;
+ default:
+ printf("unexpected element size %u\n", element_size);
+ break;
+ }
+}
+
+static void fsl_ddr_spd_edit(fsl_ddr_info_t *pinfo,
+ unsigned int ctrl_num,
+ unsigned int dimm_num,
+ unsigned int element_num,
+ unsigned int value)
+{
+ generic_spd_eeprom_t *pspd;
+
+ pspd = &(pinfo->spd_installed_dimms[ctrl_num][dimm_num]);
+ fsl_ddr_generic_edit(pspd, pspd + 1, 1, element_num, value);
+}
+
+#define COMMON_TIMING(x) {#x, offsetof(common_timing_params_t, x), \
+ sizeof((common_timing_params_t *)0)->x, 0}
+
+static void lowest_common_dimm_parameters_edit(fsl_ddr_info_t *pinfo,
+ unsigned int ctrl_num,
+ const char *optname_str,
+ const char *value_str)
+{
+ common_timing_params_t *p = &pinfo->common_timing_params[ctrl_num];
+
+ static const struct options_string options[] = {
+ COMMON_TIMING(tCKmin_X_ps),
+ COMMON_TIMING(tCKmax_ps),
+ COMMON_TIMING(tCKmax_max_ps),
+ COMMON_TIMING(tRCD_ps),
+ COMMON_TIMING(tRP_ps),
+ COMMON_TIMING(tRAS_ps),
+ COMMON_TIMING(tWR_ps),
+ COMMON_TIMING(tWTR_ps),
+ COMMON_TIMING(tRFC_ps),
+ COMMON_TIMING(tRRD_ps),
+ COMMON_TIMING(tRC_ps),
+ COMMON_TIMING(refresh_rate_ps),
+ COMMON_TIMING(tIS_ps),
+ COMMON_TIMING(tIH_ps),
+ COMMON_TIMING(tDS_ps),
+ COMMON_TIMING(tDH_ps),
+ COMMON_TIMING(tRTP_ps),
+ COMMON_TIMING(tDQSQ_max_ps),
+ COMMON_TIMING(tQHS_ps),
+ COMMON_TIMING(ndimms_present),
+ COMMON_TIMING(lowest_common_SPD_caslat),
+ COMMON_TIMING(highest_common_derated_caslat),
+ COMMON_TIMING(additive_latency),
+ COMMON_TIMING(all_DIMMs_burst_lengths_bitmask),
+ COMMON_TIMING(all_DIMMs_registered),
+ COMMON_TIMING(all_DIMMs_unbuffered),
+ COMMON_TIMING(all_DIMMs_ECC_capable),
+ COMMON_TIMING(total_mem),
+ COMMON_TIMING(base_address),
+ };
+ static const unsigned int n_opts = ARRAY_SIZE(options);
+
+ if (handle_option_table(options, n_opts, p, optname_str, value_str))
+ return;
+
+ printf("Error: couldn't find option string %s\n", optname_str);
+}
+
+#define DIMM_PARM(x) {#x, offsetof(dimm_params_t, x), \
+ sizeof((dimm_params_t *)0)->x, 0}
+
+static void fsl_ddr_dimm_parameters_edit(fsl_ddr_info_t *pinfo,
+ unsigned int ctrl_num,
+ unsigned int dimm_num,
+ const char *optname_str,
+ const char *value_str)
+{
+ dimm_params_t *p = &(pinfo->dimm_params[ctrl_num][dimm_num]);
+
+ static const struct options_string options[] = {
+ DIMM_PARM(n_ranks),
+ DIMM_PARM(data_width),
+ DIMM_PARM(primary_sdram_width),
+ DIMM_PARM(ec_sdram_width),
+ DIMM_PARM(registered_dimm),
+
+ DIMM_PARM(n_row_addr),
+ DIMM_PARM(n_col_addr),
+ DIMM_PARM(edc_config),
+ DIMM_PARM(n_banks_per_sdram_device),
+ DIMM_PARM(burst_lengths_bitmask),
+ DIMM_PARM(row_density),
+
+ DIMM_PARM(tCKmin_X_ps),
+ DIMM_PARM(tCKmin_X_minus_1_ps),
+ DIMM_PARM(tCKmin_X_minus_2_ps),
+ DIMM_PARM(tCKmax_ps),
+
+ DIMM_PARM(caslat_X),
+ DIMM_PARM(caslat_X_minus_1),
+ DIMM_PARM(caslat_X_minus_2),
+
+ DIMM_PARM(caslat_lowest_derated),
+
+ DIMM_PARM(tRCD_ps),
+ DIMM_PARM(tRP_ps),
+ DIMM_PARM(tRAS_ps),
+ DIMM_PARM(tWR_ps),
+ DIMM_PARM(tWTR_ps),
+ DIMM_PARM(tRFC_ps),
+ DIMM_PARM(tRRD_ps),
+ DIMM_PARM(tRC_ps),
+ DIMM_PARM(refresh_rate_ps),
+
+ DIMM_PARM(tIS_ps),
+ DIMM_PARM(tIH_ps),
+ DIMM_PARM(tDS_ps),
+ DIMM_PARM(tDH_ps),
+ DIMM_PARM(tRTP_ps),
+ DIMM_PARM(tDQSQ_max_ps),
+ DIMM_PARM(tQHS_ps),
+
+ DIMM_PARM(rank_density),
+ DIMM_PARM(capacity),
+ DIMM_PARM(base_address),
+ };
+
+ static const unsigned int n_opts = ARRAY_SIZE(options);
+
+ if (handle_option_table(options, n_opts, p, optname_str, value_str))
+ return;
+
+ printf("couldn't find option string %s\n", optname_str);
+}
+
+static void print_dimm_parameters(const dimm_params_t *pdimm)
+{
+ static const struct options_string options[] = {
+ DIMM_PARM(n_ranks),
+ DIMM_PARM(data_width),
+ DIMM_PARM(primary_sdram_width),
+ DIMM_PARM(ec_sdram_width),
+ DIMM_PARM(registered_dimm),
+
+ DIMM_PARM(n_row_addr),
+ DIMM_PARM(n_col_addr),
+ DIMM_PARM(edc_config),
+ DIMM_PARM(n_banks_per_sdram_device),
+
+ DIMM_PARM(tCKmin_X_ps),
+ DIMM_PARM(tCKmin_X_minus_1_ps),
+ DIMM_PARM(tCKmin_X_minus_2_ps),
+ DIMM_PARM(tCKmax_ps),
+
+ DIMM_PARM(caslat_X),
+ DIMM_PARM(tAA_ps),
+ DIMM_PARM(caslat_X_minus_1),
+ DIMM_PARM(caslat_X_minus_2),
+ DIMM_PARM(caslat_lowest_derated),
+
+ DIMM_PARM(tRCD_ps),
+ DIMM_PARM(tRP_ps),
+ DIMM_PARM(tRAS_ps),
+ DIMM_PARM(tWR_ps),
+ DIMM_PARM(tWTR_ps),
+ DIMM_PARM(tRFC_ps),
+ DIMM_PARM(tRRD_ps),
+ DIMM_PARM(tRC_ps),
+ DIMM_PARM(refresh_rate_ps),
+
+ DIMM_PARM(tIS_ps),
+ DIMM_PARM(tIH_ps),
+ DIMM_PARM(tDS_ps),
+ DIMM_PARM(tDH_ps),
+ DIMM_PARM(tRTP_ps),
+ DIMM_PARM(tDQSQ_max_ps),
+ DIMM_PARM(tQHS_ps),
+ };
+ static const unsigned int n_opts = ARRAY_SIZE(options);
+
+ if (pdimm->n_ranks == 0) {
+ printf("DIMM not present\n");
+ return;
+ }
+ printf("DIMM organization parameters:\n");
+ printf("module part name = %s\n", pdimm->mpart);
+ printf("rank_density = %llu bytes (%llu megabytes)\n",
+ pdimm->rank_density, pdimm->rank_density / 0x100000);
+ printf("capacity = %llu bytes (%llu megabytes)\n",
+ pdimm->capacity, pdimm->capacity / 0x100000);
+ printf("burst_lengths_bitmask = %02X\n",
+ pdimm->burst_lengths_bitmask);
+ printf("base_addresss = %llu (%08llX %08llX)\n",
+ pdimm->base_address,
+ (pdimm->base_address >> 32),
+ pdimm->base_address & 0xFFFFFFFF);
+ print_option_table(options, n_opts, pdimm);
+}
+
+static void print_lowest_common_dimm_parameters(
+ const common_timing_params_t *plcd_dimm_params)
+{
+ static const struct options_string options[] = {
+ COMMON_TIMING(tCKmax_max_ps),
+ COMMON_TIMING(tRCD_ps),
+ COMMON_TIMING(tRP_ps),
+ COMMON_TIMING(tRAS_ps),
+ COMMON_TIMING(tWR_ps),
+ COMMON_TIMING(tWTR_ps),
+ COMMON_TIMING(tRFC_ps),
+ COMMON_TIMING(tRRD_ps),
+ COMMON_TIMING(tRC_ps),
+ COMMON_TIMING(refresh_rate_ps),
+ COMMON_TIMING(tIS_ps),
+ COMMON_TIMING(tDS_ps),
+ COMMON_TIMING(tDH_ps),
+ COMMON_TIMING(tRTP_ps),
+ COMMON_TIMING(tDQSQ_max_ps),
+ COMMON_TIMING(tQHS_ps),
+ COMMON_TIMING(lowest_common_SPD_caslat),
+ COMMON_TIMING(highest_common_derated_caslat),
+ COMMON_TIMING(additive_latency),
+ COMMON_TIMING(ndimms_present),
+ COMMON_TIMING(all_DIMMs_registered),
+ COMMON_TIMING(all_DIMMs_unbuffered),
+ COMMON_TIMING(all_DIMMs_ECC_capable),
+ };
+ static const unsigned int n_opts = ARRAY_SIZE(options);
+
+ /* Clock frequencies */
+ printf("tCKmin_X_ps = %u (%u MHz)\n",
+ plcd_dimm_params->tCKmin_X_ps,
+ picos_to_mhz(plcd_dimm_params->tCKmin_X_ps));
+ printf("tCKmax_ps = %u (%u MHz)\n",
+ plcd_dimm_params->tCKmax_ps,
+ picos_to_mhz(plcd_dimm_params->tCKmax_ps));
+ printf("all_DIMMs_burst_lengths_bitmask = %02X\n",
+ plcd_dimm_params->all_DIMMs_burst_lengths_bitmask);
+
+ print_option_table(options, n_opts, plcd_dimm_params);
+
+ printf("total_mem = %llu (%llu megabytes)\n",
+ plcd_dimm_params->total_mem,
+ plcd_dimm_params->total_mem / 0x100000);
+ printf("base_address = %llu (%llu megabytes)\n",
+ plcd_dimm_params->base_address,
+ plcd_dimm_params->base_address / 0x100000);
+}
+
+#define CTRL_OPTIONS(x) {#x, offsetof(memctl_options_t, x), \
+ sizeof((memctl_options_t *)0)->x, 0}
+#define CTRL_OPTIONS_CS(x, y) {"cs" #x "_" #y, \
+ offsetof(memctl_options_t, cs_local_opts[x].y), \
+ sizeof((memctl_options_t *)0)->cs_local_opts[x].y, 0}
+
+static void fsl_ddr_options_edit(fsl_ddr_info_t *pinfo,
+ unsigned int ctl_num,
+ const char *optname_str,
+ const char *value_str)
+{
+ memctl_options_t *p = &(pinfo->memctl_opts[ctl_num]);
+ /*
+ * This array all on the stack and *computed* each time this
+ * function is rung.
+ */
+ static const struct options_string options[] = {
+ CTRL_OPTIONS_CS(0, odt_rd_cfg),
+ CTRL_OPTIONS_CS(0, odt_wr_cfg),
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 1)
+ CTRL_OPTIONS_CS(1, odt_rd_cfg),
+ CTRL_OPTIONS_CS(1, odt_wr_cfg),
+#endif
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2)
+ CTRL_OPTIONS_CS(2, odt_rd_cfg),
+ CTRL_OPTIONS_CS(2, odt_wr_cfg),
+#endif
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2)
+ CTRL_OPTIONS_CS(3, odt_rd_cfg),
+ CTRL_OPTIONS_CS(3, odt_wr_cfg),
+#endif
+#if defined(CONFIG_FSL_DDR3)
+ CTRL_OPTIONS_CS(0, odt_rtt_norm),
+ CTRL_OPTIONS_CS(0, odt_rtt_wr),
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 1)
+ CTRL_OPTIONS_CS(1, odt_rtt_norm),
+ CTRL_OPTIONS_CS(1, odt_rtt_wr),
+#endif
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2)
+ CTRL_OPTIONS_CS(2, odt_rtt_norm),
+ CTRL_OPTIONS_CS(2, odt_rtt_wr),
+#endif
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2)
+ CTRL_OPTIONS_CS(3, odt_rtt_norm),
+ CTRL_OPTIONS_CS(3, odt_rtt_wr),
+#endif
+#endif
+ CTRL_OPTIONS(memctl_interleaving),
+ CTRL_OPTIONS(memctl_interleaving_mode),
+ CTRL_OPTIONS(ba_intlv_ctl),
+ CTRL_OPTIONS(ECC_mode),
+ CTRL_OPTIONS(ECC_init_using_memctl),
+ CTRL_OPTIONS(DQS_config),
+ CTRL_OPTIONS(self_refresh_in_sleep),
+ CTRL_OPTIONS(dynamic_power),
+ CTRL_OPTIONS(data_bus_width),
+ CTRL_OPTIONS(burst_length),
+ CTRL_OPTIONS(cas_latency_override),
+ CTRL_OPTIONS(cas_latency_override_value),
+ CTRL_OPTIONS(use_derated_caslat),
+ CTRL_OPTIONS(additive_latency_override),
+ CTRL_OPTIONS(additive_latency_override_value),
+ CTRL_OPTIONS(clk_adjust),
+ CTRL_OPTIONS(cpo_override),
+ CTRL_OPTIONS(write_data_delay),
+ CTRL_OPTIONS(half_strength_driver_enable),
+
+ /*
+ * These can probably be changed to 2T_EN and 3T_EN
+ * (using a leading numerical character) without problem
+ */
+ CTRL_OPTIONS(twoT_en),
+ CTRL_OPTIONS(threeT_en),
+ CTRL_OPTIONS(ap_en),
+ CTRL_OPTIONS(bstopre),
+ CTRL_OPTIONS(wrlvl_override),
+ CTRL_OPTIONS(wrlvl_sample),
+ CTRL_OPTIONS(wrlvl_start),
+ CTRL_OPTIONS(rcw_override),
+ CTRL_OPTIONS(rcw_1),
+ CTRL_OPTIONS(rcw_2),
+ CTRL_OPTIONS(ddr_cdr1),
+ CTRL_OPTIONS(ddr_cdr2),
+ CTRL_OPTIONS(tCKE_clock_pulse_width_ps),
+ CTRL_OPTIONS(tFAW_window_four_activates_ps),
+ CTRL_OPTIONS(trwt_override),
+ CTRL_OPTIONS(trwt),
+ };
+
+ static const unsigned int n_opts = ARRAY_SIZE(options);
+
+ if (handle_option_table(options, n_opts, p,
+ optname_str, value_str))
+ return;
+
+ printf("couldn't find option string %s\n", optname_str);
+}
+
+#define CFG_REGS(x) {#x, offsetof(fsl_ddr_cfg_regs_t, x), \
+ sizeof((fsl_ddr_cfg_regs_t *)0)->x, 1}
+#define CFG_REGS_CS(x, y) {"cs" #x "_" #y, \
+ offsetof(fsl_ddr_cfg_regs_t, cs[x].y), \
+ sizeof((fsl_ddr_cfg_regs_t *)0)->cs[x].y, 1}
+
+static void print_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr)
+{
+ unsigned int i;
+ static const struct options_string options[] = {
+ CFG_REGS_CS(0, bnds),
+ CFG_REGS_CS(0, config),
+ CFG_REGS_CS(0, config_2),
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 1)
+ CFG_REGS_CS(1, bnds),
+ CFG_REGS_CS(1, config),
+ CFG_REGS_CS(1, config_2),
+#endif
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2)
+ CFG_REGS_CS(2, bnds),
+ CFG_REGS_CS(2, config),
+ CFG_REGS_CS(2, config_2),
+#endif
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2)
+ CFG_REGS_CS(3, bnds),
+ CFG_REGS_CS(3, config),
+ CFG_REGS_CS(3, config_2),
+#endif
+ CFG_REGS(timing_cfg_3),
+ CFG_REGS(timing_cfg_0),
+ CFG_REGS(timing_cfg_1),
+ CFG_REGS(timing_cfg_2),
+ CFG_REGS(ddr_sdram_cfg),
+ CFG_REGS(ddr_sdram_cfg_2),
+ CFG_REGS(ddr_sdram_mode),
+ CFG_REGS(ddr_sdram_mode_2),
+ CFG_REGS(ddr_sdram_mode_3),
+ CFG_REGS(ddr_sdram_mode_4),
+ CFG_REGS(ddr_sdram_mode_5),
+ CFG_REGS(ddr_sdram_mode_6),
+ CFG_REGS(ddr_sdram_mode_7),
+ CFG_REGS(ddr_sdram_mode_8),
+ CFG_REGS(ddr_sdram_interval),
+ CFG_REGS(ddr_data_init),
+ CFG_REGS(ddr_sdram_clk_cntl),
+ CFG_REGS(ddr_init_addr),
+ CFG_REGS(ddr_init_ext_addr),
+ CFG_REGS(timing_cfg_4),
+ CFG_REGS(timing_cfg_5),
+ CFG_REGS(ddr_zq_cntl),
+ CFG_REGS(ddr_wrlvl_cntl),
+ CFG_REGS(ddr_wrlvl_cntl_2),
+ CFG_REGS(ddr_wrlvl_cntl_3),
+ CFG_REGS(ddr_sr_cntr),
+ CFG_REGS(ddr_sdram_rcw_1),
+ CFG_REGS(ddr_sdram_rcw_2),
+ CFG_REGS(ddr_cdr1),
+ CFG_REGS(ddr_cdr2),
+ CFG_REGS(err_disable),
+ CFG_REGS(err_int_en),
+ CFG_REGS(ddr_eor),
+ };
+ static const unsigned int n_opts = ARRAY_SIZE(options);
+
+ print_option_table(options, n_opts, ddr);
+
+ for (i = 0; i < 32; i++)
+ printf("debug_%02d = 0x%08X\n", i+1, ddr->debug[i]);
+}
+
+static void fsl_ddr_regs_edit(fsl_ddr_info_t *pinfo,
+ unsigned int ctrl_num,
+ const char *regname,
+ const char *value_str)
+{
+ unsigned int i;
+ fsl_ddr_cfg_regs_t *ddr;
+ char buf[20];
+ static const struct options_string options[] = {
+ CFG_REGS_CS(0, bnds),
+ CFG_REGS_CS(0, config),
+ CFG_REGS_CS(0, config_2),
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 1)
+ CFG_REGS_CS(1, bnds),
+ CFG_REGS_CS(1, config),
+ CFG_REGS_CS(1, config_2),
+#endif
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2)
+ CFG_REGS_CS(2, bnds),
+ CFG_REGS_CS(2, config),
+ CFG_REGS_CS(2, config_2),
+#endif
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 3)
+ CFG_REGS_CS(3, bnds),
+ CFG_REGS_CS(3, config),
+ CFG_REGS_CS(3, config_2),
+#endif
+ CFG_REGS(timing_cfg_3),
+ CFG_REGS(timing_cfg_0),
+ CFG_REGS(timing_cfg_1),
+ CFG_REGS(timing_cfg_2),
+ CFG_REGS(ddr_sdram_cfg),
+ CFG_REGS(ddr_sdram_cfg_2),
+ CFG_REGS(ddr_sdram_mode),
+ CFG_REGS(ddr_sdram_mode_2),
+ CFG_REGS(ddr_sdram_mode_3),
+ CFG_REGS(ddr_sdram_mode_4),
+ CFG_REGS(ddr_sdram_mode_5),
+ CFG_REGS(ddr_sdram_mode_6),
+ CFG_REGS(ddr_sdram_mode_7),
+ CFG_REGS(ddr_sdram_mode_8),
+ CFG_REGS(ddr_sdram_interval),
+ CFG_REGS(ddr_data_init),
+ CFG_REGS(ddr_sdram_clk_cntl),
+ CFG_REGS(ddr_init_addr),
+ CFG_REGS(ddr_init_ext_addr),
+ CFG_REGS(timing_cfg_4),
+ CFG_REGS(timing_cfg_5),
+ CFG_REGS(ddr_zq_cntl),
+ CFG_REGS(ddr_wrlvl_cntl),
+ CFG_REGS(ddr_wrlvl_cntl_2),
+ CFG_REGS(ddr_wrlvl_cntl_3),
+ CFG_REGS(ddr_sr_cntr),
+ CFG_REGS(ddr_sdram_rcw_1),
+ CFG_REGS(ddr_sdram_rcw_2),
+ CFG_REGS(ddr_cdr1),
+ CFG_REGS(ddr_cdr2),
+ CFG_REGS(err_disable),
+ CFG_REGS(err_int_en),
+ CFG_REGS(ddr_sdram_rcw_2),
+ CFG_REGS(ddr_sdram_rcw_2),
+ CFG_REGS(ddr_eor),
+ };
+ static const unsigned int n_opts = ARRAY_SIZE(options);
+
+ debug("fsl_ddr_regs_edit: ctrl_num = %u, "
+ "regname = %s, value = %s\n",
+ ctrl_num, regname, value_str);
+ if (ctrl_num > CONFIG_NUM_DDR_CONTROLLERS)
+ return;
+
+ ddr = &(pinfo->fsl_ddr_config_reg[ctrl_num]);
+
+ if (handle_option_table(options, n_opts, ddr, regname, value_str))
+ return;
+
+ for (i = 0; i < 32; i++) {
+ unsigned int value = simple_strtoul(value_str, NULL, 0);
+ sprintf(buf, "debug_%u", i + 1);
+ if (strcmp(buf, regname) == 0) {
+ ddr->debug[i] = value;
+ return;
+ }
+ }
+ printf("Error: couldn't find register string %s\n", regname);
+}
+
+#define CTRL_OPTIONS_HEX(x) {#x, offsetof(memctl_options_t, x), \
+ sizeof((memctl_options_t *)0)->x, 1}
+
+static void print_memctl_options(const memctl_options_t *popts)
+{
+ static const struct options_string options[] = {
+ CTRL_OPTIONS_CS(0, odt_rd_cfg),
+ CTRL_OPTIONS_CS(0, odt_wr_cfg),
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 1)
+ CTRL_OPTIONS_CS(1, odt_rd_cfg),
+ CTRL_OPTIONS_CS(1, odt_wr_cfg),
+#endif
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2)
+ CTRL_OPTIONS_CS(2, odt_rd_cfg),
+ CTRL_OPTIONS_CS(2, odt_wr_cfg),
+#endif
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 3)
+ CTRL_OPTIONS_CS(3, odt_rd_cfg),
+ CTRL_OPTIONS_CS(3, odt_wr_cfg),
+#endif
+#if defined(CONFIG_FSL_DDR3)
+ CTRL_OPTIONS_CS(0, odt_rtt_norm),
+ CTRL_OPTIONS_CS(0, odt_rtt_wr),
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 1)
+ CTRL_OPTIONS_CS(1, odt_rtt_norm),
+ CTRL_OPTIONS_CS(1, odt_rtt_wr),
+#endif
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 2)
+ CTRL_OPTIONS_CS(2, odt_rtt_norm),
+ CTRL_OPTIONS_CS(2, odt_rtt_wr),
+#endif
+#if (CONFIG_CHIP_SELECTS_PER_CTRL > 3)
+ CTRL_OPTIONS_CS(3, odt_rtt_norm),
+ CTRL_OPTIONS_CS(3, odt_rtt_wr),
+#endif
+#endif
+ CTRL_OPTIONS(memctl_interleaving),
+ CTRL_OPTIONS(memctl_interleaving_mode),
+ CTRL_OPTIONS_HEX(ba_intlv_ctl),
+ CTRL_OPTIONS(ECC_mode),
+ CTRL_OPTIONS(ECC_init_using_memctl),
+ CTRL_OPTIONS(DQS_config),
+ CTRL_OPTIONS(self_refresh_in_sleep),
+ CTRL_OPTIONS(dynamic_power),
+ CTRL_OPTIONS(data_bus_width),
+ CTRL_OPTIONS(burst_length),
+ CTRL_OPTIONS(cas_latency_override),
+ CTRL_OPTIONS(cas_latency_override_value),
+ CTRL_OPTIONS(use_derated_caslat),
+ CTRL_OPTIONS(additive_latency_override),
+ CTRL_OPTIONS(additive_latency_override_value),
+ CTRL_OPTIONS(clk_adjust),
+ CTRL_OPTIONS(cpo_override),
+ CTRL_OPTIONS(write_data_delay),
+ CTRL_OPTIONS(half_strength_driver_enable),
+ /*
+ * These can probably be changed to 2T_EN and 3T_EN
+ * (using a leading numerical character) without problem
+ */
+ CTRL_OPTIONS(twoT_en),
+ CTRL_OPTIONS(threeT_en),
+ CTRL_OPTIONS(registered_dimm_en),
+ CTRL_OPTIONS(ap_en),
+ CTRL_OPTIONS(bstopre),
+ CTRL_OPTIONS(wrlvl_override),
+ CTRL_OPTIONS(wrlvl_sample),
+ CTRL_OPTIONS(wrlvl_start),
+ CTRL_OPTIONS(rcw_override),
+ CTRL_OPTIONS(rcw_1),
+ CTRL_OPTIONS(rcw_2),
+ CTRL_OPTIONS_HEX(ddr_cdr1),
+ CTRL_OPTIONS_HEX(ddr_cdr2),
+ CTRL_OPTIONS(tCKE_clock_pulse_width_ps),
+ CTRL_OPTIONS(tFAW_window_four_activates_ps),
+ CTRL_OPTIONS(trwt_override),
+ CTRL_OPTIONS(trwt),
+ };
+ static const unsigned int n_opts = ARRAY_SIZE(options);
+
+ print_option_table(options, n_opts, popts);
+}
+
+#ifdef CONFIG_FSL_DDR1
+void ddr1_spd_dump(const ddr1_spd_eeprom_t *spd)
+{
+ unsigned int i;
+
+ printf("%-3d : %02x %s\n", 0, spd->info_size,
+ " spd->info_size, * 0 # bytes written into serial memory *");
+ printf("%-3d : %02x %s\n", 1, spd->chip_size,
+ " spd->chip_size, * 1 Total # bytes of SPD memory device *");
+ printf("%-3d : %02x %s\n", 2, spd->mem_type,
+ " spd->mem_type, * 2 Fundamental memory type *");
+ printf("%-3d : %02x %s\n", 3, spd->nrow_addr,
+ " spd->nrow_addr, * 3 # of Row Addresses on this assembly *");
+ printf("%-3d : %02x %s\n", 4, spd->ncol_addr,
+ " spd->ncol_addr, * 4 # of Column Addrs on this assembly *");
+ printf("%-3d : %02x %s\n", 5, spd->nrows,
+ " spd->nrows * 5 # of DIMM Banks *");
+ printf("%-3d : %02x %s\n", 6, spd->dataw_lsb,
+ " spd->dataw_lsb, * 6 Data Width lsb of this assembly *");
+ printf("%-3d : %02x %s\n", 7, spd->dataw_msb,
+ " spd->dataw_msb, * 7 Data Width msb of this assembly *");
+ printf("%-3d : %02x %s\n", 8, spd->voltage,
+ " spd->voltage, * 8 Voltage intf std of this assembly *");
+ printf("%-3d : %02x %s\n", 9, spd->clk_cycle,
+ " spd->clk_cycle, * 9 SDRAM Cycle time at CL=X *");
+ printf("%-3d : %02x %s\n", 10, spd->clk_access,
+ " spd->clk_access, * 10 SDRAM Access from Clock at CL=X *");
+ printf("%-3d : %02x %s\n", 11, spd->config,
+ " spd->config, * 11 DIMM Configuration type *");
+ printf("%-3d : %02x %s\n", 12, spd->refresh,
+ " spd->refresh, * 12 Refresh Rate/Type *");
+ printf("%-3d : %02x %s\n", 13, spd->primw,
+ " spd->primw, * 13 Primary SDRAM Width *");
+ printf("%-3d : %02x %s\n", 14, spd->ecw,
+ " spd->ecw, * 14 Error Checking SDRAM width *");
+ printf("%-3d : %02x %s\n", 15, spd->min_delay,
+ " spd->min_delay, * 15 Back to Back Random Access *");
+ printf("%-3d : %02x %s\n", 16, spd->burstl,
+ " spd->burstl, * 16 Burst Lengths Supported *");
+ printf("%-3d : %02x %s\n", 17, spd->nbanks,
+ " spd->nbanks, * 17 # of Banks on Each SDRAM Device *");
+ printf("%-3d : %02x %s\n", 18, spd->cas_lat,
+ " spd->cas_lat, * 18 CAS# Latencies Supported *");
+ printf("%-3d : %02x %s\n", 19, spd->cs_lat,
+ " spd->cs_lat, * 19 Chip Select Latency *");
+ printf("%-3d : %02x %s\n", 20, spd->write_lat,
+ " spd->write_lat, * 20 Write Latency/Recovery *");
+ printf("%-3d : %02x %s\n", 21, spd->mod_attr,
+ " spd->mod_attr, * 21 SDRAM Module Attributes *");
+ printf("%-3d : %02x %s\n", 22, spd->dev_attr,
+ " spd->dev_attr, * 22 SDRAM Device Attributes *");
+ printf("%-3d : %02x %s\n", 23, spd->clk_cycle2,
+ " spd->clk_cycle2, * 23 Min SDRAM Cycle time at CL=X-1 *");
+ printf("%-3d : %02x %s\n", 24, spd->clk_access2,
+ " spd->clk_access2, * 24 SDRAM Access from Clock at CL=X-1 *");
+ printf("%-3d : %02x %s\n", 25, spd->clk_cycle3,
+ " spd->clk_cycle3, * 25 Min SDRAM Cycle time at CL=X-2 *");
+ printf("%-3d : %02x %s\n", 26, spd->clk_access3,
+ " spd->clk_access3, * 26 Max Access from Clock at CL=X-2 *");
+ printf("%-3d : %02x %s\n", 27, spd->trp,
+ " spd->trp, * 27 Min Row Precharge Time (tRP)*");
+ printf("%-3d : %02x %s\n", 28, spd->trrd,
+ " spd->trrd, * 28 Min Row Active to Row Active (tRRD) *");
+ printf("%-3d : %02x %s\n", 29, spd->trcd,
+ " spd->trcd, * 29 Min RAS to CAS Delay (tRCD) *");
+ printf("%-3d : %02x %s\n", 30, spd->tras,
+ " spd->tras, * 30 Minimum RAS Pulse Width (tRAS) *");
+ printf("%-3d : %02x %s\n", 31, spd->bank_dens,
+ " spd->bank_dens, * 31 Density of each bank on module *");
+ printf("%-3d : %02x %s\n", 32, spd->ca_setup,
+ " spd->ca_setup, * 32 Cmd + Addr signal input setup time *");
+ printf("%-3d : %02x %s\n", 33, spd->ca_hold,
+ " spd->ca_hold, * 33 Cmd and Addr signal input hold time *");
+ printf("%-3d : %02x %s\n", 34, spd->data_setup,
+ " spd->data_setup, * 34 Data signal input setup time *");
+ printf("%-3d : %02x %s\n", 35, spd->data_hold,
+ " spd->data_hold, * 35 Data signal input hold time *");
+ printf("%-3d : %02x %s\n", 36, spd->res_36_40[0],
+ " spd->res_36_40[0], * 36 Reserved / tWR *");
+ printf("%-3d : %02x %s\n", 37, spd->res_36_40[1],
+ " spd->res_36_40[1], * 37 Reserved / tWTR *");
+ printf("%-3d : %02x %s\n", 38, spd->res_36_40[2],
+ " spd->res_36_40[2], * 38 Reserved / tRTP *");
+ printf("%-3d : %02x %s\n", 39, spd->res_36_40[3],
+ " spd->res_36_40[3], * 39 Reserved / mem_probe *");
+ printf("%-3d : %02x %s\n", 40, spd->res_36_40[4],
+ " spd->res_36_40[4], * 40 Reserved / trc,trfc extensions *");
+ printf("%-3d : %02x %s\n", 41, spd->trc,
+ " spd->trc, * 41 Min Active to Auto refresh time tRC *");
+ printf("%-3d : %02x %s\n", 42, spd->trfc,
+ " spd->trfc, * 42 Min Auto to Active period tRFC *");
+ printf("%-3d : %02x %s\n", 43, spd->tckmax,
+ " spd->tckmax, * 43 Max device cycle time tCKmax *");
+ printf("%-3d : %02x %s\n", 44, spd->tdqsq,
+ " spd->tdqsq, * 44 Max DQS to DQ skew *");
+ printf("%-3d : %02x %s\n", 45, spd->tqhs,
+ " spd->tqhs, * 45 Max Read DataHold skew tQHS *");
+ printf("%-3d : %02x %s\n", 46, spd->res_46,
+ " spd->res_46, * 46 Reserved/ PLL Relock time *");
+ printf("%-3d : %02x %s\n", 47, spd->dimm_height,
+ " spd->dimm_height * 47 SDRAM DIMM Height *");
+
+ printf("%-3d-%3d: ", 48, 61);
+
+ for (i = 0; i < 14; i++)
+ printf("%02x", spd->res_48_61[i]);
+
+ printf(" * 48-61 IDD in SPD and Reserved space *\n");
+
+ printf("%-3d : %02x %s\n", 62, spd->spd_rev,
+ " spd->spd_rev, * 62 SPD Data Revision Code *");
+ printf("%-3d : %02x %s\n", 63, spd->cksum,
+ " spd->cksum, * 63 Checksum for bytes 0-62 *");
+ printf("%-3d-%3d: ", 64, 71);
+
+ for (i = 0; i < 8; i++)
+ printf("%02x", spd->mid[i]);
+
+ printf("* 64 Mfr's JEDEC ID code per JEP-108E *\n");
+ printf("%-3d : %02x %s\n", 72, spd->mloc,
+ " spd->mloc, * 72 Manufacturing Location *");
+
+ printf("%-3d-%3d: >>", 73, 90);
+
+ for (i = 0; i < 18; i++)
+ printf("%c", spd->mpart[i]);
+
+ printf("<<* 73 Manufacturer's Part Number *\n");
+
+ printf("%-3d-%3d: %02x %02x %s\n", 91, 92, spd->rev[0], spd->rev[1],
+ "* 91 Revision Code *");
+ printf("%-3d-%3d: %02x %02x %s\n", 93, 94, spd->mdate[0], spd->mdate[1],
+ "* 93 Manufacturing Date *");
+ printf("%-3d-%3d: ", 95, 98);
+
+ for (i = 0; i < 4; i++)
+ printf("%02x", spd->sernum[i]);
+
+ printf("* 95 Assembly Serial Number *\n");
+
+ printf("%-3d-%3d: ", 99, 127);
+
+ for (i = 0; i < 27; i++)
+ printf("%02x", spd->mspec[i]);
+
+ printf("* 99 Manufacturer Specific Data *\n");
+}
+#endif
+
+#ifdef CONFIG_FSL_DDR2
+void ddr2_spd_dump(const ddr2_spd_eeprom_t *spd)
+{
+ unsigned int i;
+
+ printf("%-3d : %02x %s\n", 0, spd->info_size,
+ " spd->info_size, * 0 # bytes written into serial memory *");
+ printf("%-3d : %02x %s\n", 1, spd->chip_size,
+ " spd->chip_size, * 1 Total # bytes of SPD memory device *");
+ printf("%-3d : %02x %s\n", 2, spd->mem_type,
+ " spd->mem_type, * 2 Fundamental memory type *");
+ printf("%-3d : %02x %s\n", 3, spd->nrow_addr,
+ " spd->nrow_addr, * 3 # of Row Addresses on this assembly *");
+ printf("%-3d : %02x %s\n", 4, spd->ncol_addr,
+ " spd->ncol_addr, * 4 # of Column Addrs on this assembly *");
+ printf("%-3d : %02x %s\n", 5, spd->mod_ranks,
+ " spd->mod_ranks * 5 # of Module Rows on this assembly *");
+ printf("%-3d : %02x %s\n", 6, spd->dataw,
+ " spd->dataw, * 6 Data Width of this assembly *");
+ printf("%-3d : %02x %s\n", 7, spd->res_7,
+ " spd->res_7, * 7 Reserved *");
+ printf("%-3d : %02x %s\n", 8, spd->voltage,
+ " spd->voltage, * 8 Voltage intf std of this assembly *");
+ printf("%-3d : %02x %s\n", 9, spd->clk_cycle,
+ " spd->clk_cycle, * 9 SDRAM Cycle time at CL=X *");
+ printf("%-3d : %02x %s\n", 10, spd->clk_access,
+ " spd->clk_access, * 10 SDRAM Access from Clock at CL=X *");
+ printf("%-3d : %02x %s\n", 11, spd->config,
+ " spd->config, * 11 DIMM Configuration type *");
+ printf("%-3d : %02x %s\n", 12, spd->refresh,
+ " spd->refresh, * 12 Refresh Rate/Type *");
+ printf("%-3d : %02x %s\n", 13, spd->primw,
+ " spd->primw, * 13 Primary SDRAM Width *");
+ printf("%-3d : %02x %s\n", 14, spd->ecw,
+ " spd->ecw, * 14 Error Checking SDRAM width *");
+ printf("%-3d : %02x %s\n", 15, spd->res_15,
+ " spd->res_15, * 15 Reserved *");
+ printf("%-3d : %02x %s\n", 16, spd->burstl,
+ " spd->burstl, * 16 Burst Lengths Supported *");
+ printf("%-3d : %02x %s\n", 17, spd->nbanks,
+ " spd->nbanks, * 17 # of Banks on Each SDRAM Device *");
+ printf("%-3d : %02x %s\n", 18, spd->cas_lat,
+ " spd->cas_lat, * 18 CAS# Latencies Supported *");
+ printf("%-3d : %02x %s\n", 19, spd->mech_char,
+ " spd->mech_char, * 19 Mechanical Characteristics *");
+ printf("%-3d : %02x %s\n", 20, spd->dimm_type,
+ " spd->dimm_type, * 20 DIMM type *");
+ printf("%-3d : %02x %s\n", 21, spd->mod_attr,
+ " spd->mod_attr, * 21 SDRAM Module Attributes *");
+ printf("%-3d : %02x %s\n", 22, spd->dev_attr,
+ " spd->dev_attr, * 22 SDRAM Device Attributes *");
+ printf("%-3d : %02x %s\n", 23, spd->clk_cycle2,
+ " spd->clk_cycle2, * 23 Min SDRAM Cycle time at CL=X-1 *");
+ printf("%-3d : %02x %s\n", 24, spd->clk_access2,
+ " spd->clk_access2, * 24 SDRAM Access from Clock at CL=X-1 *");
+ printf("%-3d : %02x %s\n", 25, spd->clk_cycle3,
+ " spd->clk_cycle3, * 25 Min SDRAM Cycle time at CL=X-2 *");
+ printf("%-3d : %02x %s\n", 26, spd->clk_access3,
+ " spd->clk_access3, * 26 Max Access from Clock at CL=X-2 *");
+ printf("%-3d : %02x %s\n", 27, spd->trp,
+ " spd->trp, * 27 Min Row Precharge Time (tRP)*");
+ printf("%-3d : %02x %s\n", 28, spd->trrd,
+ " spd->trrd, * 28 Min Row Active to Row Active (tRRD) *");
+ printf("%-3d : %02x %s\n", 29, spd->trcd,
+ " spd->trcd, * 29 Min RAS to CAS Delay (tRCD) *");
+ printf("%-3d : %02x %s\n", 30, spd->tras,
+ " spd->tras, * 30 Minimum RAS Pulse Width (tRAS) *");
+ printf("%-3d : %02x %s\n", 31, spd->rank_dens,
+ " spd->rank_dens, * 31 Density of each rank on module *");
+ printf("%-3d : %02x %s\n", 32, spd->ca_setup,
+ " spd->ca_setup, * 32 Cmd + Addr signal input setup time *");
+ printf("%-3d : %02x %s\n", 33, spd->ca_hold,
+ " spd->ca_hold, * 33 Cmd and Addr signal input hold time *");
+ printf("%-3d : %02x %s\n", 34, spd->data_setup,
+ " spd->data_setup, * 34 Data signal input setup time *");
+ printf("%-3d : %02x %s\n", 35, spd->data_hold,
+ " spd->data_hold, * 35 Data signal input hold time *");
+ printf("%-3d : %02x %s\n", 36, spd->twr,
+ " spd->twr, * 36 Write Recovery time tWR *");
+ printf("%-3d : %02x %s\n", 37, spd->twtr,
+ " spd->twtr, * 37 Int write to read delay tWTR *");
+ printf("%-3d : %02x %s\n", 38, spd->trtp,
+ " spd->trtp, * 38 Int read to precharge delay tRTP *");
+ printf("%-3d : %02x %s\n", 39, spd->mem_probe,
+ " spd->mem_probe, * 39 Mem analysis probe characteristics *");
+ printf("%-3d : %02x %s\n", 40, spd->trctrfc_ext,
+ " spd->trctrfc_ext, * 40 Extensions to trc and trfc *");
+ printf("%-3d : %02x %s\n", 41, spd->trc,
+ " spd->trc, * 41 Min Active to Auto refresh time tRC *");
+ printf("%-3d : %02x %s\n", 42, spd->trfc,
+ " spd->trfc, * 42 Min Auto to Active period tRFC *");
+ printf("%-3d : %02x %s\n", 43, spd->tckmax,
+ " spd->tckmax, * 43 Max device cycle time tCKmax *");
+ printf("%-3d : %02x %s\n", 44, spd->tdqsq,
+ " spd->tdqsq, * 44 Max DQS to DQ skew *");
+ printf("%-3d : %02x %s\n", 45, spd->tqhs,
+ " spd->tqhs, * 45 Max Read DataHold skew tQHS *");
+ printf("%-3d : %02x %s\n", 46, spd->pll_relock,
+ " spd->pll_relock, * 46 PLL Relock time *");
+ printf("%-3d : %02x %s\n", 47, spd->Tcasemax,
+ " spd->Tcasemax, * 47 Tcasemax *");
+ printf("%-3d : %02x %s\n", 48, spd->psiTAdram,
+ " spd->psiTAdram, * 48 Thermal Resistance of DRAM Package "
+ "from Top (Case) to Ambient (Psi T-A DRAM) *");
+ printf("%-3d : %02x %s\n", 49, spd->dt0_mode,
+ " spd->dt0_mode, * 49 DRAM Case Temperature Rise from "
+ "Ambient due to Activate-Precharge/Mode Bits "
+ "(DT0/Mode Bits) *)");
+ printf("%-3d : %02x %s\n", 50, spd->dt2n_dt2q,
+ " spd->dt2n_dt2q, * 50 DRAM Case Temperature Rise from "
+ "Ambient due to Precharge/Quiet Standby "
+ "(DT2N/DT2Q) *");
+ printf("%-3d : %02x %s\n", 51, spd->dt2p,
+ " spd->dt2p, * 51 DRAM Case Temperature Rise from "
+ "Ambient due to Precharge Power-Down (DT2P) *");
+ printf("%-3d : %02x %s\n", 52, spd->dt3n,
+ " spd->dt3n, * 52 DRAM Case Temperature Rise from "
+ "Ambient due to Active Standby (DT3N) *");
+ printf("%-3d : %02x %s\n", 53, spd->dt3pfast,
+ " spd->dt3pfast, * 53 DRAM Case Temperature Rise from "
+ "Ambient due to Active Power-Down with Fast PDN Exit "
+ "(DT3Pfast) *");
+ printf("%-3d : %02x %s\n", 54, spd->dt3pslow,
+ " spd->dt3pslow, * 54 DRAM Case Temperature Rise from "
+ "Ambient due to Active Power-Down with Slow PDN Exit "
+ "(DT3Pslow) *");
+ printf("%-3d : %02x %s\n", 55, spd->dt4r_dt4r4w,
+ " spd->dt4r_dt4r4w, * 55 DRAM Case Temperature Rise from "
+ "Ambient due to Page Open Burst Read/DT4R4W Mode Bit "
+ "(DT4R/DT4R4W Mode Bit) *");
+ printf("%-3d : %02x %s\n", 56, spd->dt5b,
+ " spd->dt5b, * 56 DRAM Case Temperature Rise from "
+ "Ambient due to Burst Refresh (DT5B) *");
+ printf("%-3d : %02x %s\n", 57, spd->dt7,
+ " spd->dt7, * 57 DRAM Case Temperature Rise from "
+ "Ambient due to Bank Interleave Reads with "
+ "Auto-Precharge (DT7) *");
+ printf("%-3d : %02x %s\n", 58, spd->psiTApll,
+ " spd->psiTApll, * 58 Thermal Resistance of PLL Package form"
+ " Top (Case) to Ambient (Psi T-A PLL) *");
+ printf("%-3d : %02x %s\n", 59, spd->psiTAreg,
+ " spd->psiTAreg, * 59 Thermal Reisitance of Register Package"
+ " from Top (Case) to Ambient (Psi T-A Register) *");
+ printf("%-3d : %02x %s\n", 60, spd->dtpllactive,
+ " spd->dtpllactive, * 60 PLL Case Temperature Rise from "
+ "Ambient due to PLL Active (DT PLL Active) *");
+ printf("%-3d : %02x %s\n", 61, spd->dtregact,
+ " spd->dtregact, "
+ "* 61 Register Case Temperature Rise from Ambient due to "
+ "Register Active/Mode Bit (DT Register Active/Mode Bit) *");
+ printf("%-3d : %02x %s\n", 62, spd->spd_rev,
+ " spd->spd_rev, * 62 SPD Data Revision Code *");
+ printf("%-3d : %02x %s\n", 63, spd->cksum,
+ " spd->cksum, * 63 Checksum for bytes 0-62 *");
+
+ printf("%-3d-%3d: ", 64, 71);
+
+ for (i = 0; i < 8; i++)
+ printf("%02x", spd->mid[i]);
+
+ printf("* 64 Mfr's JEDEC ID code per JEP-108E *\n");
+
+ printf("%-3d : %02x %s\n", 72, spd->mloc,
+ " spd->mloc, * 72 Manufacturing Location *");
+
+ printf("%-3d-%3d: >>", 73, 90);
+ for (i = 0; i < 18; i++)
+ printf("%c", spd->mpart[i]);
+
+
+ printf("<<* 73 Manufacturer's Part Number *\n");
+
+ printf("%-3d-%3d: %02x %02x %s\n", 91, 92, spd->rev[0], spd->rev[1],
+ "* 91 Revision Code *");
+ printf("%-3d-%3d: %02x %02x %s\n", 93, 94, spd->mdate[0], spd->mdate[1],
+ "* 93 Manufacturing Date *");
+ printf("%-3d-%3d: ", 95, 98);
+
+ for (i = 0; i < 4; i++)
+ printf("%02x", spd->sernum[i]);
+
+ printf("* 95 Assembly Serial Number *\n");
+
+ printf("%-3d-%3d: ", 99, 127);
+ for (i = 0; i < 27; i++)
+ printf("%02x", spd->mspec[i]);
+
+
+ printf("* 99 Manufacturer Specific Data *\n");
+}
+#endif
+
+#ifdef CONFIG_FSL_DDR3
+void ddr3_spd_dump(const ddr3_spd_eeprom_t *spd)
+{
+ unsigned int i;
+
+ /* General Section: Bytes 0-59 */
+
+#define PRINT_NXS(x, y, z...) printf("%-3d : %02x " z "\n", x, (u8)y);
+#define PRINT_NNXXS(n0, n1, x0, x1, s) \
+ printf("%-3d-%3d: %02x %02x " s "\n", n0, n1, x0, x1);
+
+ PRINT_NXS(0, spd->info_size_crc,
+ "info_size_crc bytes written into serial memory, "
+ "CRC coverage");
+ PRINT_NXS(1, spd->spd_rev,
+ "spd_rev SPD Revision");
+ PRINT_NXS(2, spd->mem_type,
+ "mem_type Key Byte / DRAM Device Type");
+ PRINT_NXS(3, spd->module_type,
+ "module_type Key Byte / Module Type");
+ PRINT_NXS(4, spd->density_banks,
+ "density_banks SDRAM Density and Banks");
+ PRINT_NXS(5, spd->addressing,
+ "addressing SDRAM Addressing");
+ PRINT_NXS(6, spd->module_vdd,
+ "module_vdd Module Nominal Voltage, VDD");
+ PRINT_NXS(7, spd->organization,
+ "organization Module Organization");
+ PRINT_NXS(8, spd->bus_width,
+ "bus_width Module Memory Bus Width");
+ PRINT_NXS(9, spd->ftb_div,
+ "ftb_div Fine Timebase (FTB) Dividend / Divisor");
+ PRINT_NXS(10, spd->mtb_dividend,
+ "mtb_dividend Medium Timebase (MTB) Dividend");
+ PRINT_NXS(11, spd->mtb_divisor,
+ "mtb_divisor Medium Timebase (MTB) Divisor");
+ PRINT_NXS(12, spd->tCK_min,
+ "tCK_min SDRAM Minimum Cycle Time");
+ PRINT_NXS(13, spd->res_13,
+ "res_13 Reserved");
+ PRINT_NXS(14, spd->caslat_lsb,
+ "caslat_lsb CAS Latencies Supported, LSB");
+ PRINT_NXS(15, spd->caslat_msb,
+ "caslat_msb CAS Latencies Supported, MSB");
+ PRINT_NXS(16, spd->tAA_min,
+ "tAA_min Min CAS Latency Time");
+ PRINT_NXS(17, spd->tWR_min,
+ "tWR_min Min Write REcovery Time");
+ PRINT_NXS(18, spd->tRCD_min,
+ "tRCD_min Min RAS# to CAS# Delay Time");
+ PRINT_NXS(19, spd->tRRD_min,
+ "tRRD_min Min Row Active to Row Active Delay Time");
+ PRINT_NXS(20, spd->tRP_min,
+ "tRP_min Min Row Precharge Delay Time");
+ PRINT_NXS(21, spd->tRAS_tRC_ext,
+ "tRAS_tRC_ext Upper Nibbles for tRAS and tRC");
+ PRINT_NXS(22, spd->tRAS_min_lsb,
+ "tRAS_min_lsb Min Active to Precharge Delay Time, LSB");
+ PRINT_NXS(23, spd->tRC_min_lsb,
+ "tRC_min_lsb Min Active to Active/Refresh Delay Time, LSB");
+ PRINT_NXS(24, spd->tRFC_min_lsb,
+ "tRFC_min_lsb Min Refresh Recovery Delay Time LSB");
+ PRINT_NXS(25, spd->tRFC_min_msb,
+ "tRFC_min_msb Min Refresh Recovery Delay Time MSB");
+ PRINT_NXS(26, spd->tWTR_min,
+ "tWTR_min Min Internal Write to Read Command Delay Time");
+ PRINT_NXS(27, spd->tRTP_min,
+ "tRTP_min "
+ "Min Internal Read to Precharge Command Delay Time");
+ PRINT_NXS(28, spd->tFAW_msb,
+ "tFAW_msb Upper Nibble for tFAW");
+ PRINT_NXS(29, spd->tFAW_min,
+ "tFAW_min Min Four Activate Window Delay Time");
+ PRINT_NXS(30, spd->opt_features,
+ "opt_features SDRAM Optional Features");
+ PRINT_NXS(31, spd->therm_ref_opt,
+ "therm_ref_opt SDRAM Thermal and Refresh Opts");
+ PRINT_NXS(32, spd->therm_sensor,
+ "therm_sensor SDRAM Thermal Sensor");
+ PRINT_NXS(33, spd->device_type,
+ "device_type SDRAM Device Type");
+ PRINT_NXS(34, spd->fine_tCK_min,
+ "fine_tCK_min Fine offset for tCKmin");
+ PRINT_NXS(35, spd->fine_tAA_min,
+ "fine_tAA_min Fine offset for tAAmin");
+ PRINT_NXS(36, spd->fine_tRCD_min,
+ "fine_tRCD_min Fine offset for tRCDmin");
+ PRINT_NXS(37, spd->fine_tRP_min,
+ "fine_tRP_min Fine offset for tRPmin");
+ PRINT_NXS(38, spd->fine_tRC_min,
+ "fine_tRC_min Fine offset for tRCmin");
+
+ printf("%-3d-%3d: ", 39, 59); /* Reserved, General Section */
+
+ for (i = 39; i <= 59; i++)
+ printf("%02x ", spd->res_39_59[i - 39]);
+
+ puts("\n");
+
+ switch (spd->module_type) {
+ case 0x02: /* UDIMM */
+ case 0x03: /* SO-DIMM */
+ case 0x04: /* Micro-DIMM */
+ case 0x06: /* Mini-UDIMM */
+ PRINT_NXS(60, spd->mod_section.unbuffered.mod_height,
+ "mod_height (Unbuffered) Module Nominal Height");
+ PRINT_NXS(61, spd->mod_section.unbuffered.mod_thickness,
+ "mod_thickness (Unbuffered) Module Maximum Thickness");
+ PRINT_NXS(62, spd->mod_section.unbuffered.ref_raw_card,
+ "ref_raw_card (Unbuffered) Reference Raw Card Used");
+ PRINT_NXS(63, spd->mod_section.unbuffered.addr_mapping,
+ "addr_mapping (Unbuffered) Address mapping from "
+ "Edge Connector to DRAM");
+ break;
+ case 0x01: /* RDIMM */
+ case 0x05: /* Mini-RDIMM */
+ PRINT_NXS(60, spd->mod_section.registered.mod_height,
+ "mod_height (Registered) Module Nominal Height");
+ PRINT_NXS(61, spd->mod_section.registered.mod_thickness,
+ "mod_thickness (Registered) Module Maximum Thickness");
+ PRINT_NXS(62, spd->mod_section.registered.ref_raw_card,
+ "ref_raw_card (Registered) Reference Raw Card Used");
+ PRINT_NXS(63, spd->mod_section.registered.modu_attr,
+ "modu_attr (Registered) DIMM Module Attributes");
+ PRINT_NXS(64, spd->mod_section.registered.thermal,
+ "thermal (Registered) Thermal Heat "
+ "Spreader Solution");
+ PRINT_NXS(65, spd->mod_section.registered.reg_id_lo,
+ "reg_id_lo (Registered) Register Manufacturer ID "
+ "Code, LSB");
+ PRINT_NXS(66, spd->mod_section.registered.reg_id_hi,
+ "reg_id_hi (Registered) Register Manufacturer ID "
+ "Code, MSB");
+ PRINT_NXS(67, spd->mod_section.registered.reg_rev,
+ "reg_rev (Registered) Register "
+ "Revision Number");
+ PRINT_NXS(68, spd->mod_section.registered.reg_type,
+ "reg_type (Registered) Register Type");
+ for (i = 69; i <= 76; i++) {
+ printf("%-3d : %02x rcw[%d]\n", i,
+ spd->mod_section.registered.rcw[i-69], i-69);
+ }
+ break;
+ default:
+ /* Module-specific Section, Unsupported Module Type */
+ printf("%-3d-%3d: ", 60, 116);
+
+ for (i = 60; i <= 116; i++)
+ printf("%02x", spd->mod_section.uc[i - 60]);
+
+ break;
+ }
+
+ /* Unique Module ID: Bytes 117-125 */
+ PRINT_NXS(117, spd->mmid_lsb, "Module MfgID Code LSB - JEP-106");
+ PRINT_NXS(118, spd->mmid_msb, "Module MfgID Code MSB - JEP-106");
+ PRINT_NXS(119, spd->mloc, "Mfg Location");
+ PRINT_NNXXS(120, 121, spd->mdate[0], spd->mdate[1], "Mfg Date");
+
+ printf("%-3d-%3d: ", 122, 125);
+
+ for (i = 122; i <= 125; i++)
+ printf("%02x ", spd->sernum[i - 122]);
+ printf(" Module Serial Number\n");
+
+ /* CRC: Bytes 126-127 */
+ PRINT_NNXXS(126, 127, spd->crc[0], spd->crc[1], " SPD CRC");
+
+ /* Other Manufacturer Fields and User Space: Bytes 128-255 */
+ printf("%-3d-%3d: ", 128, 145);
+ for (i = 128; i <= 145; i++)
+ printf("%02x ", spd->mpart[i - 128]);
+ printf(" Mfg's Module Part Number\n");
+
+ PRINT_NNXXS(146, 147, spd->mrev[0], spd->mrev[1],
+ "Module Revision code");
+
+ PRINT_NXS(148, spd->dmid_lsb, "DRAM MfgID Code LSB - JEP-106");
+ PRINT_NXS(149, spd->dmid_msb, "DRAM MfgID Code MSB - JEP-106");
+
+ printf("%-3d-%3d: ", 150, 175);
+ for (i = 150; i <= 175; i++)
+ printf("%02x ", spd->msd[i - 150]);
+ printf(" Mfg's Specific Data\n");
+
+ printf("%-3d-%3d: ", 176, 255);
+ for (i = 176; i <= 255; i++)
+ printf("%02x", spd->cust[i - 176]);
+ printf(" Mfg's Specific Data\n");
+
+}
+#endif
+
+static inline void generic_spd_dump(const generic_spd_eeprom_t *spd)
+{
+#if defined(CONFIG_FSL_DDR1)
+ ddr1_spd_dump(spd);
+#elif defined(CONFIG_FSL_DDR2)
+ ddr2_spd_dump(spd);
+#elif defined(CONFIG_FSL_DDR3)
+ ddr3_spd_dump(spd);
+#endif
+}
+
+static void fsl_ddr_printinfo(const fsl_ddr_info_t *pinfo,
+ unsigned int ctrl_mask,
+ unsigned int dimm_mask,
+ unsigned int do_mask)
+{
+ unsigned int i, j, retval;
+
+ /* STEP 1: DIMM SPD data */
+ if (do_mask & STEP_GET_SPD) {
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ if (!(ctrl_mask & (1 << i)))
+ continue;
+
+ for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+ if (!(dimm_mask & (1 << j)))
+ continue;
+
+ printf("SPD info: Controller=%u "
+ "DIMM=%u\n", i, j);
+ generic_spd_dump(
+ &(pinfo->spd_installed_dimms[i][j]));
+ printf("\n");
+ }
+ printf("\n");
+ }
+ printf("\n");
+ }
+
+ /* STEP 2: DIMM Parameters */
+ if (do_mask & STEP_COMPUTE_DIMM_PARMS) {
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ if (!(ctrl_mask & (1 << i)))
+ continue;
+ for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+ if (!(dimm_mask & (1 << j)))
+ continue;
+ printf("DIMM parameters: Controller=%u "
+ "DIMM=%u\n", i, j);
+ print_dimm_parameters(
+ &(pinfo->dimm_params[i][j]));
+ printf("\n");
+ }
+ printf("\n");
+ }
+ printf("\n");
+ }
+
+ /* STEP 3: Common Parameters */
+ if (do_mask & STEP_COMPUTE_COMMON_PARMS) {
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ if (!(ctrl_mask & (1 << i)))
+ continue;
+ printf("\"lowest common\" DIMM parameters: "
+ "Controller=%u\n", i);
+ print_lowest_common_dimm_parameters(
+ &pinfo->common_timing_params[i]);
+ printf("\n");
+ }
+ printf("\n");
+ }
+
+ /* STEP 4: User Configuration Options */
+ if (do_mask & STEP_GATHER_OPTS) {
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ if (!(ctrl_mask & (1 << i)))
+ continue;
+ printf("User Config Options: Controller=%u\n", i);
+ print_memctl_options(&pinfo->memctl_opts[i]);
+ printf("\n");
+ }
+ printf("\n");
+ }
+
+ /* STEP 5: Address assignment */
+ if (do_mask & STEP_ASSIGN_ADDRESSES) {
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ if (!(ctrl_mask & (1 << i)))
+ continue;
+ for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+ printf("Address Assignment: Controller=%u "
+ "DIMM=%u\n", i, j);
+ printf("Don't have this functionality yet\n");
+ }
+ printf("\n");
+ }
+ printf("\n");
+ }
+
+ /* STEP 6: computed controller register values */
+ if (do_mask & STEP_COMPUTE_REGS) {
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ if (!(ctrl_mask & (1 << i)))
+ continue;
+ printf("Computed Register Values: Controller=%u\n", i);
+ print_fsl_memctl_config_regs(
+ &pinfo->fsl_ddr_config_reg[i]);
+ retval = check_fsl_memctl_config_regs(
+ &pinfo->fsl_ddr_config_reg[i]);
+ if (retval) {
+ printf("check_fsl_memctl_config_regs "
+ "result = %u\n", retval);
+ }
+ printf("\n");
+ }
+ printf("\n");
+ }
+}
+
+struct data_strings {
+ const char *data_name;
+ unsigned int step_mask;
+ unsigned int dimm_number_required;
+};
+
+#define DATA_OPTIONS(name, step, dimm) {#name, step, dimm}
+
+static unsigned int fsl_ddr_parse_interactive_cmd(
+ char **argv,
+ int argc,
+ unsigned int *pstep_mask,
+ unsigned int *pctlr_mask,
+ unsigned int *pdimm_mask,
+ unsigned int *pdimm_number_required
+ ) {
+
+ static const struct data_strings options[] = {
+ DATA_OPTIONS(spd, STEP_GET_SPD, 1),
+ DATA_OPTIONS(dimmparms, STEP_COMPUTE_DIMM_PARMS, 1),
+ DATA_OPTIONS(commonparms, STEP_COMPUTE_COMMON_PARMS, 0),
+ DATA_OPTIONS(opts, STEP_GATHER_OPTS, 0),
+ DATA_OPTIONS(addresses, STEP_ASSIGN_ADDRESSES, 0),
+ DATA_OPTIONS(regs, STEP_COMPUTE_REGS, 0),
+ };
+ static const unsigned int n_opts = ARRAY_SIZE(options);
+
+ unsigned int i, j;
+ unsigned int error = 0;
+
+ for (i = 1; i < argc; i++) {
+ unsigned int matched = 0;
+
+ for (j = 0; j < n_opts; j++) {
+ if (strcmp(options[j].data_name, argv[i]) != 0)
+ continue;
+ *pstep_mask |= options[j].step_mask;
+ *pdimm_number_required =
+ options[j].dimm_number_required;
+ matched = 1;
+ break;
+ }
+
+ if (matched)
+ continue;
+
+ if (argv[i][0] == 'c') {
+ char c = argv[i][1];
+ if (isdigit(c))
+ *pctlr_mask |= 1 << (c - '0');
+ continue;
+ }
+
+ if (argv[i][0] == 'd') {
+ char c = argv[i][1];
+ if (isdigit(c))
+ *pdimm_mask |= 1 << (c - '0');
+ continue;
+ }
+
+ printf("unknown arg %s\n", argv[i]);
+ *pstep_mask = 0;
+ error = 1;
+ break;
+ }
+
+ return error;
+}
+
+int fsl_ddr_interactive_env_var_exists(void)
+{
+ char buffer[CONFIG_SYS_CBSIZE];
+
+ if (getenv_f("ddr_interactive", buffer, CONFIG_SYS_CBSIZE) >= 0)
+ return 1;
+
+ return 0;
+}
+
+unsigned long long fsl_ddr_interactive(fsl_ddr_info_t *pinfo, int var_is_set)
+{
+ unsigned long long ddrsize;
+ const char *prompt = "FSL DDR>";
+ char buffer[CONFIG_SYS_CBSIZE];
+ char buffer2[CONFIG_SYS_CBSIZE];
+ char *p = NULL;
+ char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
+ int argc;
+ unsigned int next_step = STEP_GET_SPD;
+ const char *usage = {
+ "commands:\n"
+ "print print SPD and intermediate computed data\n"
+ "reset reboot machine\n"
+ "recompute reload SPD and options to default and recompute regs\n"
+ "edit modify spd, parameter, or option\n"
+ "compute recompute registers from current next_step to end\n"
+ "copy copy parameters\n"
+ "next_step shows current next_step\n"
+ "help this message\n"
+ "go program the memory controller and continue with u-boot\n"
+ };
+
+ if (var_is_set) {
+ if (getenv_f("ddr_interactive", buffer2, CONFIG_SYS_CBSIZE) > 0) {
+ p = buffer2;
+ } else {
+ var_is_set = 0;
+ }
+ }
+
+ /*
+ * The strategy for next_step is that it points to the next
+ * step in the computation process that needs to be done.
+ */
+ while (1) {
+ if (var_is_set) {
+ char *pend = strchr(p, ';');
+ if (pend) {
+ /* found command separator, copy sub-command */
+ *pend = '\0';
+ strcpy(buffer, p);
+ p = pend + 1;
+ } else {
+ /* separator not found, copy whole string */
+ strcpy(buffer, p);
+ p = NULL;
+ var_is_set = 0;
+ }
+ } else {
+ /*
+ * No need to worry for buffer overflow here in
+ * this function; readline() maxes out at CFG_CBSIZE
+ */
+ readline_into_buffer(prompt, buffer, 0);
+ }
+ argc = parse_line(buffer, argv);
+ if (argc == 0)
+ continue;
+
+
+ if (strcmp(argv[0], "help") == 0) {
+ puts(usage);
+ continue;
+ }
+
+ if (strcmp(argv[0], "next_step") == 0) {
+ printf("next_step = 0x%02X (%s)\n",
+ next_step,
+ step_to_string(next_step));
+ continue;
+ }
+
+ if (strcmp(argv[0], "copy") == 0) {
+ unsigned int error = 0;
+ unsigned int step_mask = 0;
+ unsigned int src_ctlr_mask = 0;
+ unsigned int src_dimm_mask = 0;
+ unsigned int dimm_number_required = 0;
+ unsigned int src_ctlr_num = 0;
+ unsigned int src_dimm_num = 0;
+ unsigned int dst_ctlr_num = -1;
+ unsigned int dst_dimm_num = -1;
+ unsigned int i, num_dest_parms;
+
+ if (argc == 1) {
+ printf("copy <src c#> <src d#> <spd|dimmparms|commonparms|opts|addresses|regs> <dst c#> <dst d#>\n");
+ continue;
+ }
+
+ error = fsl_ddr_parse_interactive_cmd(
+ argv, argc,
+ &step_mask,
+ &src_ctlr_mask,
+ &src_dimm_mask,
+ &dimm_number_required
+ );
+
+ /* XXX: only dimm_number_required and step_mask will
+ be used by this function. Parse the controller and
+ DIMM number separately because it is easier. */
+
+ if (error)
+ continue;
+
+ /* parse source destination controller / DIMM */
+
+ num_dest_parms = dimm_number_required ? 2 : 1;
+
+ for (i = 0; i < argc; i++) {
+ if (argv[i][0] == 'c') {
+ char c = argv[i][1];
+ if (isdigit(c)) {
+ src_ctlr_num = (c - '0');
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < argc; i++) {
+ if (argv[i][0] == 'd') {
+ char c = argv[i][1];
+ if (isdigit(c)) {
+ src_dimm_num = (c - '0');
+ break;
+ }
+ }
+ }
+
+ /* parse destination controller / DIMM */
+
+ for (i = argc - 1; i >= argc - num_dest_parms; i--) {
+ if (argv[i][0] == 'c') {
+ char c = argv[i][1];
+ if (isdigit(c)) {
+ dst_ctlr_num = (c - '0');
+ break;
+ }
+ }
+ }
+
+ for (i = argc - 1; i >= argc - num_dest_parms; i--) {
+ if (argv[i][0] == 'd') {
+ char c = argv[i][1];
+ if (isdigit(c)) {
+ dst_dimm_num = (c - '0');
+ break;
+ }
+ }
+ }
+
+ /* TODO: validate inputs */
+
+ debug("src_ctlr_num = %u, src_dimm_num = %u, dst_ctlr_num = %u, dst_dimm_num = %u, step_mask = %x\n",
+ src_ctlr_num, src_dimm_num, dst_ctlr_num, dst_dimm_num, step_mask);
+
+
+ switch (step_mask) {
+
+ case STEP_GET_SPD:
+ memcpy(&(pinfo->spd_installed_dimms[dst_ctlr_num][dst_dimm_num]),
+ &(pinfo->spd_installed_dimms[src_ctlr_num][src_dimm_num]),
+ sizeof(pinfo->spd_installed_dimms[0][0]));
+ break;
+
+ case STEP_COMPUTE_DIMM_PARMS:
+ memcpy(&(pinfo->dimm_params[dst_ctlr_num][dst_dimm_num]),
+ &(pinfo->dimm_params[src_ctlr_num][src_dimm_num]),
+ sizeof(pinfo->dimm_params[0][0]));
+ break;
+
+ case STEP_COMPUTE_COMMON_PARMS:
+ memcpy(&(pinfo->common_timing_params[dst_ctlr_num]),
+ &(pinfo->common_timing_params[src_ctlr_num]),
+ sizeof(pinfo->common_timing_params[0]));
+ break;
+
+ case STEP_GATHER_OPTS:
+ memcpy(&(pinfo->memctl_opts[dst_ctlr_num]),
+ &(pinfo->memctl_opts[src_ctlr_num]),
+ sizeof(pinfo->memctl_opts[0]));
+ break;
+
+ /* someday be able to have addresses to copy addresses... */
+
+ case STEP_COMPUTE_REGS:
+ memcpy(&(pinfo->fsl_ddr_config_reg[dst_ctlr_num]),
+ &(pinfo->fsl_ddr_config_reg[src_ctlr_num]),
+ sizeof(pinfo->memctl_opts[0]));
+ break;
+
+ default:
+ printf("unexpected step_mask value\n");
+ }
+
+ continue;
+
+ }
+
+ if (strcmp(argv[0], "edit") == 0) {
+ unsigned int error = 0;
+ unsigned int step_mask = 0;
+ unsigned int ctlr_mask = 0;
+ unsigned int dimm_mask = 0;
+ char *p_element = NULL;
+ char *p_value = NULL;
+ unsigned int dimm_number_required = 0;
+ unsigned int ctrl_num;
+ unsigned int dimm_num;
+
+ if (argc == 1) {
+ /* Only the element and value must be last */
+ printf("edit <c#> <d#> "
+ "<spd|dimmparms|commonparms|opts|"
+ "addresses|regs> <element> <value>\n");
+ printf("for spd, specify byte number for "
+ "element\n");
+ continue;
+ }
+
+ error = fsl_ddr_parse_interactive_cmd(
+ argv, argc - 2,
+ &step_mask,
+ &ctlr_mask,
+ &dimm_mask,
+ &dimm_number_required
+ );
+
+ if (error)
+ continue;
+
+
+ /* Check arguments */
+
+ /* ERROR: If no steps were found */
+ if (step_mask == 0) {
+ printf("Error: No valid steps were specified "
+ "in argument.\n");
+ continue;
+ }
+
+ /* ERROR: If multiple steps were found */
+ if (step_mask & (step_mask - 1)) {
+ printf("Error: Multiple steps specified in "
+ "argument.\n");
+ continue;
+ }
+
+ /* ERROR: Controller not specified */
+ if (ctlr_mask == 0) {
+ printf("Error: controller number not "
+ "specified or no element and "
+ "value specified\n");
+ continue;
+ }
+
+ if (ctlr_mask & (ctlr_mask - 1)) {
+ printf("Error: multiple controllers "
+ "specified, %X\n", ctlr_mask);
+ continue;
+ }
+
+ /* ERROR: DIMM number not specified */
+ if (dimm_number_required && dimm_mask == 0) {
+ printf("Error: DIMM number number not "
+ "specified or no element and "
+ "value specified\n");
+ continue;
+ }
+
+ if (dimm_mask & (dimm_mask - 1)) {
+ printf("Error: multipled DIMMs specified\n");
+ continue;
+ }
+
+ p_element = argv[argc - 2];
+ p_value = argv[argc - 1];
+
+ ctrl_num = __ilog2(ctlr_mask);
+ dimm_num = __ilog2(dimm_mask);
+
+ switch (step_mask) {
+ case STEP_GET_SPD:
+ {
+ unsigned int element_num;
+ unsigned int value;
+
+ element_num = simple_strtoul(p_element,
+ NULL, 0);
+ value = simple_strtoul(p_value,
+ NULL, 0);
+ fsl_ddr_spd_edit(pinfo,
+ ctrl_num,
+ dimm_num,
+ element_num,
+ value);
+ next_step = STEP_COMPUTE_DIMM_PARMS;
+ }
+ break;
+
+ case STEP_COMPUTE_DIMM_PARMS:
+ fsl_ddr_dimm_parameters_edit(
+ pinfo, ctrl_num, dimm_num,
+ p_element, p_value);
+ next_step = STEP_COMPUTE_COMMON_PARMS;
+ break;
+
+ case STEP_COMPUTE_COMMON_PARMS:
+ lowest_common_dimm_parameters_edit(pinfo,
+ ctrl_num, p_element, p_value);
+ next_step = STEP_GATHER_OPTS;
+ break;
+
+ case STEP_GATHER_OPTS:
+ fsl_ddr_options_edit(pinfo, ctrl_num,
+ p_element, p_value);
+ next_step = STEP_ASSIGN_ADDRESSES;
+ break;
+
+ case STEP_ASSIGN_ADDRESSES:
+ printf("editing of address assignment "
+ "not yet implemented\n");
+ break;
+
+ case STEP_COMPUTE_REGS:
+ {
+ fsl_ddr_regs_edit(pinfo,
+ ctrl_num,
+ p_element,
+ p_value);
+ next_step = STEP_PROGRAM_REGS;
+ }
+ break;
+
+ default:
+ printf("programming error\n");
+ while (1)
+ ;
+ break;
+ }
+ continue;
+ }
+
+ if (strcmp(argv[0], "reset") == 0) {
+ /*
+ * Reboot machine.
+ * Args don't seem to matter because this
+ * doesn't return
+ */
+ do_reset(NULL, 0, 0, NULL);
+ printf("Reset didn't work\n");
+ }
+
+ if (strcmp(argv[0], "recompute") == 0) {
+ /*
+ * Recalculate everything, starting with
+ * loading SPD EEPROM from DIMMs
+ */
+ next_step = STEP_GET_SPD;
+ ddrsize = fsl_ddr_compute(pinfo, next_step, 0);
+ continue;
+ }
+
+ if (strcmp(argv[0], "compute") == 0) {
+ /*
+ * Compute rest of steps starting at
+ * the current next_step/
+ */
+ ddrsize = fsl_ddr_compute(pinfo, next_step, 0);
+ continue;
+ }
+
+ if (strcmp(argv[0], "print") == 0) {
+ unsigned int error = 0;
+ unsigned int step_mask = 0;
+ unsigned int ctlr_mask = 0;
+ unsigned int dimm_mask = 0;
+ unsigned int dimm_number_required = 0;
+
+ if (argc == 1) {
+ printf("print [c<n>] [d<n>] [spd] [dimmparms] "
+ "[commonparms] [opts] [addresses] [regs]\n");
+ continue;
+ }
+
+ error = fsl_ddr_parse_interactive_cmd(
+ argv, argc,
+ &step_mask,
+ &ctlr_mask,
+ &dimm_mask,
+ &dimm_number_required
+ );
+
+ if (error)
+ continue;
+
+ /* If no particular controller was found, print all */
+ if (ctlr_mask == 0)
+ ctlr_mask = 0xFF;
+
+ /* If no particular dimm was found, print all dimms. */
+ if (dimm_mask == 0)
+ dimm_mask = 0xFF;
+
+ /* If no steps were found, print all steps. */
+ if (step_mask == 0)
+ step_mask = STEP_ALL;
+
+ fsl_ddr_printinfo(pinfo, ctlr_mask,
+ dimm_mask, step_mask);
+ continue;
+ }
+
+ if (strcmp(argv[0], "go") == 0) {
+ if (next_step)
+ ddrsize = fsl_ddr_compute(pinfo, next_step, 0);
+ break;
+ }
+
+ printf("unknown command %s\n", argv[0]);
+ }
+
+ debug("end of memory = %llu\n", (u64)ddrsize);
+
+ return ddrsize;
+}
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c b/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c
new file mode 100644
index 0000000..e958e13
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c
@@ -0,0 +1,517 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#include "ddr.h"
+
+#if defined(CONFIG_FSL_DDR3)
+static unsigned int
+compute_cas_latency_ddr3(const dimm_params_t *dimm_params,
+ common_timing_params_t *outpdimm,
+ unsigned int number_of_dimms)
+{
+ unsigned int i;
+ unsigned int tAAmin_ps = 0;
+ unsigned int tCKmin_X_ps = 0;
+ unsigned int common_caslat;
+ unsigned int caslat_actual;
+ unsigned int retry = 16;
+ unsigned int tmp;
+ const unsigned int mclk_ps = get_memory_clk_period_ps();
+
+ /* compute the common CAS latency supported between slots */
+ tmp = dimm_params[0].caslat_X;
+ for (i = 1; i < number_of_dimms; i++) {
+ if (dimm_params[i].n_ranks)
+ tmp &= dimm_params[i].caslat_X;
+ }
+ common_caslat = tmp;
+
+ /* compute the max tAAmin tCKmin between slots */
+ for (i = 0; i < number_of_dimms; i++) {
+ tAAmin_ps = max(tAAmin_ps, dimm_params[i].tAA_ps);
+ tCKmin_X_ps = max(tCKmin_X_ps, dimm_params[i].tCKmin_X_ps);
+ }
+ /* validate if the memory clk is in the range of dimms */
+ if (mclk_ps < tCKmin_X_ps) {
+ printf("DDR clock (MCLK cycle %u ps) is faster than "
+ "the slowest DIMM(s) (tCKmin %u ps) can support.\n",
+ mclk_ps, tCKmin_X_ps);
+ }
+ /* determine the acutal cas latency */
+ caslat_actual = (tAAmin_ps + mclk_ps - 1) / mclk_ps;
+ /* check if the dimms support the CAS latency */
+ while (!(common_caslat & (1 << caslat_actual)) && retry > 0) {
+ caslat_actual++;
+ retry--;
+ }
+ /* once the caculation of caslat_actual is completed
+ * we must verify that this CAS latency value does not
+ * exceed tAAmax, which is 20 ns for all DDR3 speed grades
+ */
+ if (caslat_actual * mclk_ps > 20000) {
+ printf("The choosen cas latency %d is too large\n",
+ caslat_actual);
+ }
+ outpdimm->lowest_common_SPD_caslat = caslat_actual;
+
+ return 0;
+}
+#endif
+
+/*
+ * compute_lowest_common_dimm_parameters()
+ *
+ * Determine the worst-case DIMM timing parameters from the set of DIMMs
+ * whose parameters have been computed into the array pointed to
+ * by dimm_params.
+ */
+unsigned int
+compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params,
+ common_timing_params_t *outpdimm,
+ const unsigned int number_of_dimms)
+{
+ unsigned int i, j;
+
+ unsigned int tCKmin_X_ps = 0;
+ unsigned int tCKmax_ps = 0xFFFFFFFF;
+ unsigned int tCKmax_max_ps = 0;
+ unsigned int tRCD_ps = 0;
+ unsigned int tRP_ps = 0;
+ unsigned int tRAS_ps = 0;
+ unsigned int tWR_ps = 0;
+ unsigned int tWTR_ps = 0;
+ unsigned int tRFC_ps = 0;
+ unsigned int tRRD_ps = 0;
+ unsigned int tRC_ps = 0;
+ unsigned int refresh_rate_ps = 0;
+ unsigned int tIS_ps = 0;
+ unsigned int tIH_ps = 0;
+ unsigned int tDS_ps = 0;
+ unsigned int tDH_ps = 0;
+ unsigned int tRTP_ps = 0;
+ unsigned int tDQSQ_max_ps = 0;
+ unsigned int tQHS_ps = 0;
+
+ unsigned int temp1, temp2;
+ unsigned int additive_latency = 0;
+#if !defined(CONFIG_FSL_DDR3)
+ const unsigned int mclk_ps = get_memory_clk_period_ps();
+ unsigned int lowest_good_caslat;
+ unsigned int not_ok;
+
+ debug("using mclk_ps = %u\n", mclk_ps);
+#endif
+
+ temp1 = 0;
+ for (i = 0; i < number_of_dimms; i++) {
+ /*
+ * If there are no ranks on this DIMM,
+ * it probably doesn't exist, so skip it.
+ */
+ if (dimm_params[i].n_ranks == 0) {
+ temp1++;
+ continue;
+ }
+ if (dimm_params[i].n_ranks == 4 && i != 0) {
+ printf("Found Quad-rank DIMM in wrong bank, ignored."
+ " Software may not run as expected.\n");
+ temp1++;
+ continue;
+ }
+
+ /*
+ * check if quad-rank DIMM is plugged if
+ * CONFIG_CHIP_SELECT_QUAD_CAPABLE is not defined
+ * Only the board with proper design is capable
+ */
+#ifndef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE
+ if (dimm_params[i].n_ranks == 4 && \
+ CONFIG_CHIP_SELECTS_PER_CTRL/CONFIG_DIMM_SLOTS_PER_CTLR < 4) {
+ printf("Found Quad-rank DIMM, not able to support.");
+ temp1++;
+ continue;
+ }
+#endif
+ /*
+ * Find minimum tCKmax_ps to find fastest slow speed,
+ * i.e., this is the slowest the whole system can go.
+ */
+ tCKmax_ps = min(tCKmax_ps, dimm_params[i].tCKmax_ps);
+
+ /* Either find maximum value to determine slowest
+ * speed, delay, time, period, etc */
+ tCKmin_X_ps = max(tCKmin_X_ps, dimm_params[i].tCKmin_X_ps);
+ tCKmax_max_ps = max(tCKmax_max_ps, dimm_params[i].tCKmax_ps);
+ tRCD_ps = max(tRCD_ps, dimm_params[i].tRCD_ps);
+ tRP_ps = max(tRP_ps, dimm_params[i].tRP_ps);
+ tRAS_ps = max(tRAS_ps, dimm_params[i].tRAS_ps);
+ tWR_ps = max(tWR_ps, dimm_params[i].tWR_ps);
+ tWTR_ps = max(tWTR_ps, dimm_params[i].tWTR_ps);
+ tRFC_ps = max(tRFC_ps, dimm_params[i].tRFC_ps);
+ tRRD_ps = max(tRRD_ps, dimm_params[i].tRRD_ps);
+ tRC_ps = max(tRC_ps, dimm_params[i].tRC_ps);
+ tIS_ps = max(tIS_ps, dimm_params[i].tIS_ps);
+ tIH_ps = max(tIH_ps, dimm_params[i].tIH_ps);
+ tDS_ps = max(tDS_ps, dimm_params[i].tDS_ps);
+ tDH_ps = max(tDH_ps, dimm_params[i].tDH_ps);
+ tRTP_ps = max(tRTP_ps, dimm_params[i].tRTP_ps);
+ tQHS_ps = max(tQHS_ps, dimm_params[i].tQHS_ps);
+ refresh_rate_ps = max(refresh_rate_ps,
+ dimm_params[i].refresh_rate_ps);
+
+ /*
+ * Find maximum tDQSQ_max_ps to find slowest.
+ *
+ * FIXME: is finding the slowest value the correct
+ * strategy for this parameter?
+ */
+ tDQSQ_max_ps = max(tDQSQ_max_ps, dimm_params[i].tDQSQ_max_ps);
+ }
+
+ outpdimm->ndimms_present = number_of_dimms - temp1;
+
+ if (temp1 == number_of_dimms) {
+ debug("no dimms this memory controller\n");
+ return 0;
+ }
+
+ outpdimm->tCKmin_X_ps = tCKmin_X_ps;
+ outpdimm->tCKmax_ps = tCKmax_ps;
+ outpdimm->tCKmax_max_ps = tCKmax_max_ps;
+ outpdimm->tRCD_ps = tRCD_ps;
+ outpdimm->tRP_ps = tRP_ps;
+ outpdimm->tRAS_ps = tRAS_ps;
+ outpdimm->tWR_ps = tWR_ps;
+ outpdimm->tWTR_ps = tWTR_ps;
+ outpdimm->tRFC_ps = tRFC_ps;
+ outpdimm->tRRD_ps = tRRD_ps;
+ outpdimm->tRC_ps = tRC_ps;
+ outpdimm->refresh_rate_ps = refresh_rate_ps;
+ outpdimm->tIS_ps = tIS_ps;
+ outpdimm->tIH_ps = tIH_ps;
+ outpdimm->tDS_ps = tDS_ps;
+ outpdimm->tDH_ps = tDH_ps;
+ outpdimm->tRTP_ps = tRTP_ps;
+ outpdimm->tDQSQ_max_ps = tDQSQ_max_ps;
+ outpdimm->tQHS_ps = tQHS_ps;
+
+ /* Determine common burst length for all DIMMs. */
+ temp1 = 0xff;
+ for (i = 0; i < number_of_dimms; i++) {
+ if (dimm_params[i].n_ranks) {
+ temp1 &= dimm_params[i].burst_lengths_bitmask;
+ }
+ }
+ outpdimm->all_DIMMs_burst_lengths_bitmask = temp1;
+
+ /* Determine if all DIMMs registered buffered. */
+ temp1 = temp2 = 0;
+ for (i = 0; i < number_of_dimms; i++) {
+ if (dimm_params[i].n_ranks) {
+ if (dimm_params[i].registered_dimm) {
+ temp1 = 1;
+ printf("Detected RDIMM %s\n",
+ dimm_params[i].mpart);
+ } else {
+ temp2 = 1;
+ printf("Detected UDIMM %s\n",
+ dimm_params[i].mpart);
+ }
+ }
+ }
+
+ outpdimm->all_DIMMs_registered = 0;
+ outpdimm->all_DIMMs_unbuffered = 0;
+ if (temp1 && !temp2) {
+ outpdimm->all_DIMMs_registered = 1;
+ } else if (!temp1 && temp2) {
+ outpdimm->all_DIMMs_unbuffered = 1;
+ } else {
+ printf("ERROR: Mix of registered buffered and unbuffered "
+ "DIMMs detected!\n");
+ }
+
+ temp1 = 0;
+ if (outpdimm->all_DIMMs_registered)
+ for (j = 0; j < 16; j++) {
+ outpdimm->rcw[j] = dimm_params[0].rcw[j];
+ for (i = 1; i < number_of_dimms; i++) {
+ if (!dimm_params[i].n_ranks)
+ continue;
+ if (dimm_params[i].rcw[j] != dimm_params[0].rcw[j]) {
+ temp1 = 1;
+ break;
+ }
+ }
+ }
+
+ if (temp1 != 0)
+ printf("ERROR: Mix different RDIMM detected!\n");
+
+#if defined(CONFIG_FSL_DDR3)
+ if (compute_cas_latency_ddr3(dimm_params, outpdimm, number_of_dimms))
+ return 1;
+#else
+ /*
+ * Compute a CAS latency suitable for all DIMMs
+ *
+ * Strategy for SPD-defined latencies: compute only
+ * CAS latency defined by all DIMMs.
+ */
+
+ /*
+ * Step 1: find CAS latency common to all DIMMs using bitwise
+ * operation.
+ */
+ temp1 = 0xFF;
+ for (i = 0; i < number_of_dimms; i++) {
+ if (dimm_params[i].n_ranks) {
+ temp2 = 0;
+ temp2 |= 1 << dimm_params[i].caslat_X;
+ temp2 |= 1 << dimm_params[i].caslat_X_minus_1;
+ temp2 |= 1 << dimm_params[i].caslat_X_minus_2;
+ /*
+ * FIXME: If there was no entry for X-2 (X-1) in
+ * the SPD, then caslat_X_minus_2
+ * (caslat_X_minus_1) contains either 255 or
+ * 0xFFFFFFFF because that's what the glorious
+ * __ilog2 function returns for an input of 0.
+ * On 32-bit PowerPC, left shift counts with bit
+ * 26 set (that the value of 255 or 0xFFFFFFFF
+ * will have), cause the destination register to
+ * be 0. That is why this works.
+ */
+ temp1 &= temp2;
+ }
+ }
+
+ /*
+ * Step 2: check each common CAS latency against tCK of each
+ * DIMM's SPD.
+ */
+ lowest_good_caslat = 0;
+ temp2 = 0;
+ while (temp1) {
+ not_ok = 0;
+ temp2 = __ilog2(temp1);
+ debug("checking common caslat = %u\n", temp2);
+
+ /* Check if this CAS latency will work on all DIMMs at tCK. */
+ for (i = 0; i < number_of_dimms; i++) {
+ if (!dimm_params[i].n_ranks) {
+ continue;
+ }
+ if (dimm_params[i].caslat_X == temp2) {
+ if (mclk_ps >= dimm_params[i].tCKmin_X_ps) {
+ debug("CL = %u ok on DIMM %u at tCK=%u"
+ " ps with its tCKmin_X_ps of %u\n",
+ temp2, i, mclk_ps,
+ dimm_params[i].tCKmin_X_ps);
+ continue;
+ } else {
+ not_ok++;
+ }
+ }
+
+ if (dimm_params[i].caslat_X_minus_1 == temp2) {
+ unsigned int tCKmin_X_minus_1_ps
+ = dimm_params[i].tCKmin_X_minus_1_ps;
+ if (mclk_ps >= tCKmin_X_minus_1_ps) {
+ debug("CL = %u ok on DIMM %u at "
+ "tCK=%u ps with its "
+ "tCKmin_X_minus_1_ps of %u\n",
+ temp2, i, mclk_ps,
+ tCKmin_X_minus_1_ps);
+ continue;
+ } else {
+ not_ok++;
+ }
+ }
+
+ if (dimm_params[i].caslat_X_minus_2 == temp2) {
+ unsigned int tCKmin_X_minus_2_ps
+ = dimm_params[i].tCKmin_X_minus_2_ps;
+ if (mclk_ps >= tCKmin_X_minus_2_ps) {
+ debug("CL = %u ok on DIMM %u at "
+ "tCK=%u ps with its "
+ "tCKmin_X_minus_2_ps of %u\n",
+ temp2, i, mclk_ps,
+ tCKmin_X_minus_2_ps);
+ continue;
+ } else {
+ not_ok++;
+ }
+ }
+ }
+
+ if (!not_ok) {
+ lowest_good_caslat = temp2;
+ }
+
+ temp1 &= ~(1 << temp2);
+ }
+
+ debug("lowest common SPD-defined CAS latency = %u\n",
+ lowest_good_caslat);
+ outpdimm->lowest_common_SPD_caslat = lowest_good_caslat;
+
+
+ /*
+ * Compute a common 'de-rated' CAS latency.
+ *
+ * The strategy here is to find the *highest* dereated cas latency
+ * with the assumption that all of the DIMMs will support a dereated
+ * CAS latency higher than or equal to their lowest dereated value.
+ */
+ temp1 = 0;
+ for (i = 0; i < number_of_dimms; i++) {
+ temp1 = max(temp1, dimm_params[i].caslat_lowest_derated);
+ }
+ outpdimm->highest_common_derated_caslat = temp1;
+ debug("highest common dereated CAS latency = %u\n", temp1);
+#endif /* #if defined(CONFIG_FSL_DDR3) */
+
+ /* Determine if all DIMMs ECC capable. */
+ temp1 = 1;
+ for (i = 0; i < number_of_dimms; i++) {
+ if (dimm_params[i].n_ranks &&
+ !(dimm_params[i].edc_config & EDC_ECC)) {
+ temp1 = 0;
+ break;
+ }
+ }
+ if (temp1) {
+ debug("all DIMMs ECC capable\n");
+ } else {
+ debug("Warning: not all DIMMs ECC capable, cant enable ECC\n");
+ }
+ outpdimm->all_DIMMs_ECC_capable = temp1;
+
+#ifndef CONFIG_FSL_DDR3
+ /* FIXME: move to somewhere else to validate. */
+ if (mclk_ps > tCKmax_max_ps) {
+ printf("Warning: some of the installed DIMMs "
+ "can not operate this slowly.\n");
+ return 1;
+ }
+#endif
+ /*
+ * Compute additive latency.
+ *
+ * For DDR1, additive latency should be 0.
+ *
+ * For DDR2, with ODT enabled, use "a value" less than ACTTORW,
+ * which comes from Trcd, and also note that:
+ * add_lat + caslat must be >= 4
+ *
+ * For DDR3, we use the AL=0
+ *
+ * When to use additive latency for DDR2:
+ *
+ * I. Because you are using CL=3 and need to do ODT on writes and
+ * want functionality.
+ * 1. Are you going to use ODT? (Does your board not have
+ * additional termination circuitry for DQ, DQS, DQS_,
+ * DM, RDQS, RDQS_ for x4/x8 configs?)
+ * 2. If so, is your lowest supported CL going to be 3?
+ * 3. If so, then you must set AL=1 because
+ *
+ * WL >= 3 for ODT on writes
+ * RL = AL + CL
+ * WL = RL - 1
+ * ->
+ * WL = AL + CL - 1
+ * AL + CL - 1 >= 3
+ * AL + CL >= 4
+ * QED
+ *
+ * RL >= 3 for ODT on reads
+ * RL = AL + CL
+ *
+ * Since CL aren't usually less than 2, AL=0 is a minimum,
+ * so the WL-derived AL should be the -- FIXME?
+ *
+ * II. Because you are using auto-precharge globally and want to
+ * use additive latency (posted CAS) to get more bandwidth.
+ * 1. Are you going to use auto-precharge mode globally?
+ *
+ * Use addtivie latency and compute AL to be 1 cycle less than
+ * tRCD, i.e. the READ or WRITE command is in the cycle
+ * immediately following the ACTIVATE command..
+ *
+ * III. Because you feel like it or want to do some sort of
+ * degraded-performance experiment.
+ * 1. Do you just want to use additive latency because you feel
+ * like it?
+ *
+ * Validation: AL is less than tRCD, and within the other
+ * read-to-precharge constraints.
+ */
+
+ additive_latency = 0;
+
+#if defined(CONFIG_FSL_DDR2)
+ if (lowest_good_caslat < 4) {
+ additive_latency = (picos_to_mclk(tRCD_ps) > lowest_good_caslat)
+ ? picos_to_mclk(tRCD_ps) - lowest_good_caslat : 0;
+ if (mclk_to_picos(additive_latency) > tRCD_ps) {
+ additive_latency = picos_to_mclk(tRCD_ps);
+ debug("setting additive_latency to %u because it was "
+ " greater than tRCD_ps\n", additive_latency);
+ }
+ }
+
+#elif defined(CONFIG_FSL_DDR3)
+ /*
+ * The system will not use the global auto-precharge mode.
+ * However, it uses the page mode, so we set AL=0
+ */
+ additive_latency = 0;
+#endif
+
+ /*
+ * Validate additive latency
+ * FIXME: move to somewhere else to validate
+ *
+ * AL <= tRCD(min)
+ */
+ if (mclk_to_picos(additive_latency) > tRCD_ps) {
+ printf("Error: invalid additive latency exceeds tRCD(min).\n");
+ return 1;
+ }
+
+ /*
+ * RL = CL + AL; RL >= 3 for ODT_RD_CFG to be enabled
+ * WL = RL - 1; WL >= 3 for ODT_WL_CFG to be enabled
+ * ADD_LAT (the register) must be set to a value less
+ * than ACTTORW if WL = 1, then AL must be set to 1
+ * RD_TO_PRE (the register) must be set to a minimum
+ * tRTP + AL if AL is nonzero
+ */
+
+ /*
+ * Additive latency will be applied only if the memctl option to
+ * use it.
+ */
+ outpdimm->additive_latency = additive_latency;
+
+ debug("tCKmin_ps = %u\n", outpdimm->tCKmin_X_ps);
+ debug("tRCD_ps = %u\n", outpdimm->tRCD_ps);
+ debug("tRP_ps = %u\n", outpdimm->tRP_ps);
+ debug("tRAS_ps = %u\n", outpdimm->tRAS_ps);
+ debug("tWR_ps = %u\n", outpdimm->tWR_ps);
+ debug("tWTR_ps = %u\n", outpdimm->tWTR_ps);
+ debug("tRFC_ps = %u\n", outpdimm->tRFC_ps);
+ debug("tRRD_ps = %u\n", outpdimm->tRRD_ps);
+ debug("tRC_ps = %u\n", outpdimm->tRC_ps);
+
+ return 0;
+}
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/main.c b/arch/powerpc/cpu/mpc8xxx/ddr/main.c
new file mode 100644
index 0000000..7a8636d
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/main.c
@@ -0,0 +1,667 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+/*
+ * Generic driver for Freescale DDR/DDR2/DDR3 memory controller.
+ * Based on code from spd_sdram.c
+ * Author: James Yang [at freescale.com]
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <asm/fsl_ddr_sdram.h>
+#include <asm/fsl_law.h>
+
+#include "ddr.h"
+
+void fsl_ddr_set_lawbar(
+ const common_timing_params_t *memctl_common_params,
+ unsigned int memctl_interleaved,
+ unsigned int ctrl_num);
+void fsl_ddr_set_intl3r(const unsigned int granule_size);
+
+/* processor specific function */
+extern void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
+ unsigned int ctrl_num);
+
+#if defined(SPD_EEPROM_ADDRESS) || \
+ defined(SPD_EEPROM_ADDRESS1) || defined(SPD_EEPROM_ADDRESS2) || \
+ defined(SPD_EEPROM_ADDRESS3) || defined(SPD_EEPROM_ADDRESS4)
+#if (CONFIG_NUM_DDR_CONTROLLERS == 1) && (CONFIG_DIMM_SLOTS_PER_CTLR == 1)
+u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
+ [0][0] = SPD_EEPROM_ADDRESS,
+};
+#elif (CONFIG_NUM_DDR_CONTROLLERS == 1) && (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
+u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
+ [0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */
+ [0][1] = SPD_EEPROM_ADDRESS2, /* controller 1 */
+};
+#elif (CONFIG_NUM_DDR_CONTROLLERS == 2) && (CONFIG_DIMM_SLOTS_PER_CTLR == 1)
+u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
+ [0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */
+ [1][0] = SPD_EEPROM_ADDRESS2, /* controller 2 */
+};
+#elif (CONFIG_NUM_DDR_CONTROLLERS == 2) && (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
+u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
+ [0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */
+ [0][1] = SPD_EEPROM_ADDRESS2, /* controller 1 */
+ [1][0] = SPD_EEPROM_ADDRESS3, /* controller 2 */
+ [1][1] = SPD_EEPROM_ADDRESS4, /* controller 2 */
+};
+#elif (CONFIG_NUM_DDR_CONTROLLERS == 3) && (CONFIG_DIMM_SLOTS_PER_CTLR == 1)
+u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
+ [0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */
+ [1][0] = SPD_EEPROM_ADDRESS2, /* controller 2 */
+ [2][0] = SPD_EEPROM_ADDRESS3, /* controller 3 */
+};
+#elif (CONFIG_NUM_DDR_CONTROLLERS == 3) && (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
+u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
+ [0][0] = SPD_EEPROM_ADDRESS1, /* controller 1 */
+ [0][1] = SPD_EEPROM_ADDRESS2, /* controller 1 */
+ [1][0] = SPD_EEPROM_ADDRESS3, /* controller 2 */
+ [1][1] = SPD_EEPROM_ADDRESS4, /* controller 2 */
+ [2][0] = SPD_EEPROM_ADDRESS5, /* controller 3 */
+ [2][1] = SPD_EEPROM_ADDRESS6, /* controller 3 */
+};
+
+#endif
+
+static void __get_spd(generic_spd_eeprom_t *spd, u8 i2c_address)
+{
+ int ret = i2c_read(i2c_address, 0, 1, (uchar *)spd,
+ sizeof(generic_spd_eeprom_t));
+
+ if (ret) {
+ if (i2c_address ==
+#ifdef SPD_EEPROM_ADDRESS
+ SPD_EEPROM_ADDRESS
+#elif defined(SPD_EEPROM_ADDRESS1)
+ SPD_EEPROM_ADDRESS1
+#endif
+ ) {
+ printf("DDR: failed to read SPD from address %u\n",
+ i2c_address);
+ } else {
+ debug("DDR: failed to read SPD from address %u\n",
+ i2c_address);
+ }
+ memset(spd, 0, sizeof(generic_spd_eeprom_t));
+ }
+}
+
+__attribute__((weak, alias("__get_spd")))
+void get_spd(generic_spd_eeprom_t *spd, u8 i2c_address);
+
+void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
+ unsigned int ctrl_num)
+{
+ unsigned int i;
+ unsigned int i2c_address = 0;
+
+ if (ctrl_num >= CONFIG_NUM_DDR_CONTROLLERS) {
+ printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num);
+ return;
+ }
+
+ for (i = 0; i < CONFIG_DIMM_SLOTS_PER_CTLR; i++) {
+ i2c_address = spd_i2c_addr[ctrl_num][i];
+ get_spd(&(ctrl_dimms_spd[i]), i2c_address);
+ }
+}
+#else
+void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
+ unsigned int ctrl_num)
+{
+}
+#endif /* SPD_EEPROM_ADDRESSx */
+
+/*
+ * ASSUMPTIONS:
+ * - Same number of CONFIG_DIMM_SLOTS_PER_CTLR on each controller
+ * - Same memory data bus width on all controllers
+ *
+ * NOTES:
+ *
+ * The memory controller and associated documentation use confusing
+ * terminology when referring to the orgranization of DRAM.
+ *
+ * Here is a terminology translation table:
+ *
+ * memory controller/documention |industry |this code |signals
+ * -------------------------------|-----------|-----------|-----------------
+ * physical bank/bank |rank |rank |chip select (CS)
+ * logical bank/sub-bank |bank |bank |bank address (BA)
+ * page/row |row |page |row address
+ * ??? |column |column |column address
+ *
+ * The naming confusion is further exacerbated by the descriptions of the
+ * memory controller interleaving feature, where accesses are interleaved
+ * _BETWEEN_ two seperate memory controllers. This is configured only in
+ * CS0_CONFIG[INTLV_CTL] of each memory controller.
+ *
+ * memory controller documentation | number of chip selects
+ * | per memory controller supported
+ * --------------------------------|-----------------------------------------
+ * cache line interleaving | 1 (CS0 only)
+ * page interleaving | 1 (CS0 only)
+ * bank interleaving | 1 (CS0 only)
+ * superbank interleraving | depends on bank (chip select)
+ * | interleraving [rank interleaving]
+ * | mode used on every memory controller
+ *
+ * Even further confusing is the existence of the interleaving feature
+ * _WITHIN_ each memory controller. The feature is referred to in
+ * documentation as chip select interleaving or bank interleaving,
+ * although it is configured in the DDR_SDRAM_CFG field.
+ *
+ * Name of field | documentation name | this code
+ * -----------------------------|-----------------------|------------------
+ * DDR_SDRAM_CFG[BA_INTLV_CTL] | Bank (chip select) | rank interleaving
+ * | interleaving
+ */
+
+const char *step_string_tbl[] = {
+ "STEP_GET_SPD",
+ "STEP_COMPUTE_DIMM_PARMS",
+ "STEP_COMPUTE_COMMON_PARMS",
+ "STEP_GATHER_OPTS",
+ "STEP_ASSIGN_ADDRESSES",
+ "STEP_COMPUTE_REGS",
+ "STEP_PROGRAM_REGS",
+ "STEP_ALL"
+};
+
+const char * step_to_string(unsigned int step) {
+
+ unsigned int s = __ilog2(step);
+
+ if ((1 << s) != step)
+ return step_string_tbl[7];
+
+ return step_string_tbl[s];
+}
+
+static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
+ unsigned int dbw_cap_adj[])
+{
+ int i, j;
+ unsigned long long total_mem, current_mem_base, total_ctlr_mem;
+ unsigned long long rank_density, ctlr_density = 0;
+
+ /*
+ * If a reduced data width is requested, but the SPD
+ * specifies a physically wider device, adjust the
+ * computed dimm capacities accordingly before
+ * assigning addresses.
+ */
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ unsigned int found = 0;
+
+ switch (pinfo->memctl_opts[i].data_bus_width) {
+ case 2:
+ /* 16-bit */
+ for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+ unsigned int dw;
+ if (!pinfo->dimm_params[i][j].n_ranks)
+ continue;
+ dw = pinfo->dimm_params[i][j].primary_sdram_width;
+ if ((dw == 72 || dw == 64)) {
+ dbw_cap_adj[i] = 2;
+ break;
+ } else if ((dw == 40 || dw == 32)) {
+ dbw_cap_adj[i] = 1;
+ break;
+ }
+ }
+ break;
+
+ case 1:
+ /* 32-bit */
+ for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+ unsigned int dw;
+ dw = pinfo->dimm_params[i][j].data_width;
+ if (pinfo->dimm_params[i][j].n_ranks
+ && (dw == 72 || dw == 64)) {
+ /*
+ * FIXME: can't really do it
+ * like this because this just
+ * further reduces the memory
+ */
+ found = 1;
+ break;
+ }
+ }
+ if (found) {
+ dbw_cap_adj[i] = 1;
+ }
+ break;
+
+ case 0:
+ /* 64-bit */
+ break;
+
+ default:
+ printf("unexpected data bus width "
+ "specified controller %u\n", i);
+ return 1;
+ }
+ debug("dbw_cap_adj[%d]=%d\n", i, dbw_cap_adj[i]);
+ }
+
+ current_mem_base = 0ull;
+ total_mem = 0;
+ if (pinfo->memctl_opts[0].memctl_interleaving) {
+ rank_density = pinfo->dimm_params[0][0].rank_density >>
+ dbw_cap_adj[0];
+ switch (pinfo->memctl_opts[0].ba_intlv_ctl &
+ FSL_DDR_CS0_CS1_CS2_CS3) {
+ case FSL_DDR_CS0_CS1_CS2_CS3:
+ ctlr_density = 4 * rank_density;
+ break;
+ case FSL_DDR_CS0_CS1:
+ case FSL_DDR_CS0_CS1_AND_CS2_CS3:
+ ctlr_density = 2 * rank_density;
+ break;
+ case FSL_DDR_CS2_CS3:
+ default:
+ ctlr_density = rank_density;
+ break;
+ }
+ debug("rank density is 0x%llx, ctlr density is 0x%llx\n",
+ rank_density, ctlr_density);
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ if (pinfo->memctl_opts[i].memctl_interleaving) {
+ switch (pinfo->memctl_opts[i].memctl_interleaving_mode) {
+ case FSL_DDR_CACHE_LINE_INTERLEAVING:
+ case FSL_DDR_PAGE_INTERLEAVING:
+ case FSL_DDR_BANK_INTERLEAVING:
+ case FSL_DDR_SUPERBANK_INTERLEAVING:
+ total_ctlr_mem = 2 * ctlr_density;
+ break;
+ case FSL_DDR_3WAY_1KB_INTERLEAVING:
+ case FSL_DDR_3WAY_4KB_INTERLEAVING:
+ case FSL_DDR_3WAY_8KB_INTERLEAVING:
+ total_ctlr_mem = 3 * ctlr_density;
+ break;
+ case FSL_DDR_4WAY_1KB_INTERLEAVING:
+ case FSL_DDR_4WAY_4KB_INTERLEAVING:
+ case FSL_DDR_4WAY_8KB_INTERLEAVING:
+ total_ctlr_mem = 4 * ctlr_density;
+ break;
+ default:
+ panic("Unknown interleaving mode");
+ }
+ pinfo->common_timing_params[i].base_address =
+ current_mem_base;
+ pinfo->common_timing_params[i].total_mem =
+ total_ctlr_mem;
+ total_mem = current_mem_base + total_ctlr_mem;
+ debug("ctrl %d base 0x%llx\n", i, current_mem_base);
+ debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem);
+ } else {
+ /* when 3rd controller not interleaved */
+ current_mem_base = total_mem;
+ total_ctlr_mem = 0;
+ pinfo->common_timing_params[i].base_address =
+ current_mem_base;
+ for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+ unsigned long long cap =
+ pinfo->dimm_params[i][j].capacity >> dbw_cap_adj[i];
+ pinfo->dimm_params[i][j].base_address =
+ current_mem_base;
+ debug("ctrl %d dimm %d base 0x%llx\n", i, j, current_mem_base);
+ current_mem_base += cap;
+ total_ctlr_mem += cap;
+ }
+ debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem);
+ pinfo->common_timing_params[i].total_mem =
+ total_ctlr_mem;
+ total_mem += total_ctlr_mem;
+ }
+ }
+ } else {
+ /*
+ * Simple linear assignment if memory
+ * controllers are not interleaved.
+ */
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ total_ctlr_mem = 0;
+ pinfo->common_timing_params[i].base_address =
+ current_mem_base;
+ for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+ /* Compute DIMM base addresses. */
+ unsigned long long cap =
+ pinfo->dimm_params[i][j].capacity >> dbw_cap_adj[i];
+ pinfo->dimm_params[i][j].base_address =
+ current_mem_base;
+ debug("ctrl %d dimm %d base 0x%llx\n", i, j, current_mem_base);
+ current_mem_base += cap;
+ total_ctlr_mem += cap;
+ }
+ debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem);
+ pinfo->common_timing_params[i].total_mem =
+ total_ctlr_mem;
+ total_mem += total_ctlr_mem;
+ }
+ }
+ debug("Total mem by %s is 0x%llx\n", __func__, total_mem);
+
+ return total_mem;
+}
+
+/* Use weak function to allow board file to override the address assignment */
+__attribute__((weak, alias("__step_assign_addresses")))
+unsigned long long step_assign_addresses(fsl_ddr_info_t *pinfo,
+ unsigned int dbw_cap_adj[]);
+
+unsigned long long
+fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
+ unsigned int size_only)
+{
+ unsigned int i, j;
+ unsigned long long total_mem = 0;
+
+ fsl_ddr_cfg_regs_t *ddr_reg = pinfo->fsl_ddr_config_reg;
+ common_timing_params_t *timing_params = pinfo->common_timing_params;
+
+ /* data bus width capacity adjust shift amount */
+ unsigned int dbw_capacity_adjust[CONFIG_NUM_DDR_CONTROLLERS];
+
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ dbw_capacity_adjust[i] = 0;
+ }
+
+ debug("starting at step %u (%s)\n",
+ start_step, step_to_string(start_step));
+
+ switch (start_step) {
+ case STEP_GET_SPD:
+#if defined(CONFIG_DDR_SPD) || defined(CONFIG_SPD_EEPROM)
+ /* STEP 1: Gather all DIMM SPD data */
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ fsl_ddr_get_spd(pinfo->spd_installed_dimms[i], i);
+ }
+
+ case STEP_COMPUTE_DIMM_PARMS:
+ /* STEP 2: Compute DIMM parameters from SPD data */
+
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+ unsigned int retval;
+ generic_spd_eeprom_t *spd =
+ &(pinfo->spd_installed_dimms[i][j]);
+ dimm_params_t *pdimm =
+ &(pinfo->dimm_params[i][j]);
+
+ retval = compute_dimm_parameters(spd, pdimm, i);
+#ifdef CONFIG_SYS_DDR_RAW_TIMING
+ if (!i && !j && retval) {
+ printf("SPD error on controller %d! "
+ "Trying fallback to raw timing "
+ "calculation\n", i);
+ fsl_ddr_get_dimm_params(pdimm, i, j);
+ }
+#else
+ if (retval == 2) {
+ printf("Error: compute_dimm_parameters"
+ " non-zero returned FATAL value "
+ "for memctl=%u dimm=%u\n", i, j);
+ return 0;
+ }
+#endif
+ if (retval) {
+ debug("Warning: compute_dimm_parameters"
+ " non-zero return value for memctl=%u "
+ "dimm=%u\n", i, j);
+ }
+ }
+ }
+
+#elif defined(CONFIG_SYS_DDR_RAW_TIMING)
+ case STEP_COMPUTE_DIMM_PARMS:
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+ dimm_params_t *pdimm =
+ &(pinfo->dimm_params[i][j]);
+ fsl_ddr_get_dimm_params(pdimm, i, j);
+ }
+ }
+ debug("Filling dimm parameters from board specific file\n");
+#endif
+ case STEP_COMPUTE_COMMON_PARMS:
+ /*
+ * STEP 3: Compute a common set of timing parameters
+ * suitable for all of the DIMMs on each memory controller
+ */
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ debug("Computing lowest common DIMM"
+ " parameters for memctl=%u\n", i);
+ compute_lowest_common_dimm_parameters(
+ pinfo->dimm_params[i],
+ &timing_params[i],
+ CONFIG_DIMM_SLOTS_PER_CTLR);
+ }
+
+ case STEP_GATHER_OPTS:
+ /* STEP 4: Gather configuration requirements from user */
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ debug("Reloading memory controller "
+ "configuration options for memctl=%u\n", i);
+ /*
+ * This "reloads" the memory controller options
+ * to defaults. If the user "edits" an option,
+ * next_step points to the step after this,
+ * which is currently STEP_ASSIGN_ADDRESSES.
+ */
+ populate_memctl_options(
+ timing_params[i].all_DIMMs_registered,
+ &pinfo->memctl_opts[i],
+ pinfo->dimm_params[i], i);
+ }
+ case STEP_ASSIGN_ADDRESSES:
+ /* STEP 5: Assign addresses to chip selects */
+ check_interleaving_options(pinfo);
+ total_mem = step_assign_addresses(pinfo, dbw_capacity_adjust);
+
+ case STEP_COMPUTE_REGS:
+ /* STEP 6: compute controller register values */
+ debug("FSL Memory ctrl register computation\n");
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ if (timing_params[i].ndimms_present == 0) {
+ memset(&ddr_reg[i], 0,
+ sizeof(fsl_ddr_cfg_regs_t));
+ continue;
+ }
+
+ compute_fsl_memctl_config_regs(
+ &pinfo->memctl_opts[i],
+ &ddr_reg[i], &timing_params[i],
+ pinfo->dimm_params[i],
+ dbw_capacity_adjust[i],
+ size_only);
+ }
+
+ default:
+ break;
+ }
+
+ {
+ /*
+ * Compute the amount of memory available just by
+ * looking for the highest valid CSn_BNDS value.
+ * This allows us to also experiment with using
+ * only CS0 when using dual-rank DIMMs.
+ */
+ unsigned int max_end = 0;
+
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ for (j = 0; j < CONFIG_CHIP_SELECTS_PER_CTRL; j++) {
+ fsl_ddr_cfg_regs_t *reg = &ddr_reg[i];
+ if (reg->cs[j].config & 0x80000000) {
+ unsigned int end;
+ end = reg->cs[j].bnds & 0xFFF;
+ if (end > max_end) {
+ max_end = end;
+ }
+ }
+ }
+ }
+
+ total_mem = 1 + (((unsigned long long)max_end << 24ULL)
+ | 0xFFFFFFULL);
+ }
+
+ return total_mem;
+}
+
+/*
+ * fsl_ddr_sdram() -- this is the main function to be called by
+ * initdram() in the board file.
+ *
+ * It returns amount of memory configured in bytes.
+ */
+phys_size_t fsl_ddr_sdram(void)
+{
+ unsigned int i;
+ unsigned int law_memctl = LAW_TRGT_IF_DDR_1;
+ unsigned long long total_memory;
+ fsl_ddr_info_t info;
+
+ /* Reset info structure. */
+ memset(&info, 0, sizeof(fsl_ddr_info_t));
+
+ /* Compute it once normally. */
+#ifdef CONFIG_FSL_DDR_INTERACTIVE
+ if (tstc() && (getc() == 'd')) { /* we got a key press of 'd' */
+ total_memory = fsl_ddr_interactive(&info, 0);
+ } else if (fsl_ddr_interactive_env_var_exists()) {
+ total_memory = fsl_ddr_interactive(&info, 1);
+ } else
+#endif
+ total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 0);
+
+ /* setup 3-way interleaving before enabling DDRC */
+ if (info.memctl_opts[0].memctl_interleaving) {
+ switch (info.memctl_opts[0].memctl_interleaving_mode) {
+ case FSL_DDR_3WAY_1KB_INTERLEAVING:
+ case FSL_DDR_3WAY_4KB_INTERLEAVING:
+ case FSL_DDR_3WAY_8KB_INTERLEAVING:
+ fsl_ddr_set_intl3r(
+ info.memctl_opts[0].memctl_interleaving_mode);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Program configuration registers. */
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ debug("Programming controller %u\n", i);
+ if (info.common_timing_params[i].ndimms_present == 0) {
+ debug("No dimms present on controller %u; "
+ "skipping programming\n", i);
+ continue;
+ }
+
+ fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]), i);
+ }
+
+ /* program LAWs */
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ if (info.memctl_opts[i].memctl_interleaving) {
+ switch (info.memctl_opts[i].memctl_interleaving_mode) {
+ case FSL_DDR_CACHE_LINE_INTERLEAVING:
+ case FSL_DDR_PAGE_INTERLEAVING:
+ case FSL_DDR_BANK_INTERLEAVING:
+ case FSL_DDR_SUPERBANK_INTERLEAVING:
+ if (i == 0) {
+ law_memctl = LAW_TRGT_IF_DDR_INTRLV;
+ fsl_ddr_set_lawbar(&info.common_timing_params[i],
+ law_memctl, i);
+ } else if (i == 2) {
+ law_memctl = LAW_TRGT_IF_DDR_INTLV_34;
+ fsl_ddr_set_lawbar(&info.common_timing_params[i],
+ law_memctl, i);
+ }
+ break;
+ case FSL_DDR_3WAY_1KB_INTERLEAVING:
+ case FSL_DDR_3WAY_4KB_INTERLEAVING:
+ case FSL_DDR_3WAY_8KB_INTERLEAVING:
+ law_memctl = LAW_TRGT_IF_DDR_INTLV_123;
+ if (i == 0) {
+ fsl_ddr_set_lawbar(&info.common_timing_params[i],
+ law_memctl, i);
+ }
+ break;
+ case FSL_DDR_4WAY_1KB_INTERLEAVING:
+ case FSL_DDR_4WAY_4KB_INTERLEAVING:
+ case FSL_DDR_4WAY_8KB_INTERLEAVING:
+ law_memctl = LAW_TRGT_IF_DDR_INTLV_1234;
+ if (i == 0)
+ fsl_ddr_set_lawbar(&info.common_timing_params[i],
+ law_memctl, i);
+ /* place holder for future 4-way interleaving */
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (i) {
+ case 0:
+ law_memctl = LAW_TRGT_IF_DDR_1;
+ break;
+ case 1:
+ law_memctl = LAW_TRGT_IF_DDR_2;
+ break;
+ case 2:
+ law_memctl = LAW_TRGT_IF_DDR_3;
+ break;
+ case 3:
+ law_memctl = LAW_TRGT_IF_DDR_4;
+ break;
+ default:
+ break;
+ }
+ fsl_ddr_set_lawbar(&info.common_timing_params[i],
+ law_memctl, i);
+ }
+ }
+
+ debug("total_memory by %s = %llu\n", __func__, total_memory);
+
+#if !defined(CONFIG_PHYS_64BIT)
+ /* Check for 4G or more. Bad. */
+ if (total_memory >= (1ull << 32)) {
+ printf("Detected %lld MB of memory\n", total_memory >> 20);
+ printf(" This U-Boot only supports < 4G of DDR\n");
+ printf(" You could rebuild it with CONFIG_PHYS_64BIT\n");
+ printf(" "); /* re-align to match init_func_ram print */
+ total_memory = CONFIG_MAX_MEM_MAPPED;
+ }
+#endif
+
+ return total_memory;
+}
+
+/*
+ * fsl_ddr_sdram_size() - This function only returns the size of the total
+ * memory without setting ddr control registers.
+ */
+phys_size_t
+fsl_ddr_sdram_size(void)
+{
+ fsl_ddr_info_t info;
+ unsigned long long total_memory = 0;
+
+ memset(&info, 0 , sizeof(fsl_ddr_info_t));
+
+ /* Compute it once normally. */
+ total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 1);
+
+ return total_memory;
+}
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/options.c b/arch/powerpc/cpu/mpc8xxx/ddr/options.c
new file mode 100644
index 0000000..2f13b8f
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c
@@ -0,0 +1,1148 @@
+/*
+ * Copyright 2008, 2010-2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <common.h>
+#include <hwconfig.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#include "ddr.h"
+
+/*
+ * Use our own stack based buffer before relocation to allow accessing longer
+ * hwconfig strings that might be in the environment before we've relocated.
+ * This is pretty fragile on both the use of stack and if the buffer is big
+ * enough. However we will get a warning from getenv_f for the later.
+ */
+
+/* Board-specific functions defined in each board's ddr.c */
+extern void fsl_ddr_board_options(memctl_options_t *popts,
+ dimm_params_t *pdimm,
+ unsigned int ctrl_num);
+
+struct dynamic_odt {
+ unsigned int odt_rd_cfg;
+ unsigned int odt_wr_cfg;
+ unsigned int odt_rtt_norm;
+ unsigned int odt_rtt_wr;
+};
+
+#ifdef CONFIG_FSL_DDR3
+static const struct dynamic_odt single_Q[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS_AND_OTHER_DIMM,
+ DDR3_RTT_20_OHM,
+ DDR3_RTT_120_OHM
+ },
+ { /* cs1 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER, /* tied high */
+ DDR3_RTT_OFF,
+ DDR3_RTT_120_OHM
+ },
+ { /* cs2 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS_AND_OTHER_DIMM,
+ DDR3_RTT_20_OHM,
+ DDR3_RTT_120_OHM
+ },
+ { /* cs3 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER, /* tied high */
+ DDR3_RTT_OFF,
+ DDR3_RTT_120_OHM
+ }
+};
+
+static const struct dynamic_odt single_D[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_ALL,
+ DDR3_RTT_40_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs1 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER,
+ DDR3_RTT_OFF,
+ DDR3_RTT_OFF
+ },
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}
+};
+
+static const struct dynamic_odt single_S[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_ALL,
+ DDR3_RTT_40_OHM,
+ DDR3_RTT_OFF
+ },
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+};
+
+static const struct dynamic_odt dual_DD[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_SAME_DIMM,
+ DDR3_RTT_120_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs1 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_OTHER_DIMM,
+ DDR3_RTT_30_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs2 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_SAME_DIMM,
+ DDR3_RTT_120_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs3 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_OTHER_DIMM,
+ DDR3_RTT_30_OHM,
+ DDR3_RTT_OFF
+ }
+};
+
+static const struct dynamic_odt dual_DS[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_SAME_DIMM,
+ DDR3_RTT_120_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs1 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_OTHER_DIMM,
+ DDR3_RTT_30_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs2 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_ALL,
+ DDR3_RTT_20_OHM,
+ DDR3_RTT_120_OHM
+ },
+ {0, 0, 0, 0}
+};
+static const struct dynamic_odt dual_SD[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_ALL,
+ DDR3_RTT_20_OHM,
+ DDR3_RTT_120_OHM
+ },
+ {0, 0, 0, 0},
+ { /* cs2 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_SAME_DIMM,
+ DDR3_RTT_120_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs3 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_OTHER_DIMM,
+ DDR3_RTT_20_OHM,
+ DDR3_RTT_OFF
+ }
+};
+
+static const struct dynamic_odt dual_SS[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_ALL,
+ DDR3_RTT_30_OHM,
+ DDR3_RTT_120_OHM
+ },
+ {0, 0, 0, 0},
+ { /* cs2 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_ALL,
+ DDR3_RTT_30_OHM,
+ DDR3_RTT_120_OHM
+ },
+ {0, 0, 0, 0}
+};
+
+static const struct dynamic_odt dual_D0[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_SAME_DIMM,
+ DDR3_RTT_40_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs1 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER,
+ DDR3_RTT_OFF,
+ DDR3_RTT_OFF
+ },
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}
+};
+
+static const struct dynamic_odt dual_0D[4] = {
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ { /* cs2 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_SAME_DIMM,
+ DDR3_RTT_40_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs3 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER,
+ DDR3_RTT_OFF,
+ DDR3_RTT_OFF
+ }
+};
+
+static const struct dynamic_odt dual_S0[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS,
+ DDR3_RTT_40_OHM,
+ DDR3_RTT_OFF
+ },
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}
+
+};
+
+static const struct dynamic_odt dual_0S[4] = {
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ { /* cs2 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS,
+ DDR3_RTT_40_OHM,
+ DDR3_RTT_OFF
+ },
+ {0, 0, 0, 0}
+
+};
+
+static const struct dynamic_odt odt_unknown[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS,
+ DDR3_RTT_120_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs1 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS,
+ DDR3_RTT_120_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs2 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS,
+ DDR3_RTT_120_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs3 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS,
+ DDR3_RTT_120_OHM,
+ DDR3_RTT_OFF
+ }
+};
+#else /* CONFIG_FSL_DDR3 */
+static const struct dynamic_odt single_Q[4] = {
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}
+};
+
+static const struct dynamic_odt single_D[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_ALL,
+ DDR2_RTT_150_OHM,
+ DDR2_RTT_OFF
+ },
+ { /* cs1 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER,
+ DDR2_RTT_OFF,
+ DDR2_RTT_OFF
+ },
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}
+};
+
+static const struct dynamic_odt single_S[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_ALL,
+ DDR2_RTT_150_OHM,
+ DDR2_RTT_OFF
+ },
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+};
+
+static const struct dynamic_odt dual_DD[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_OTHER_DIMM,
+ DDR2_RTT_75_OHM,
+ DDR2_RTT_OFF
+ },
+ { /* cs1 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER,
+ DDR2_RTT_OFF,
+ DDR2_RTT_OFF
+ },
+ { /* cs2 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_OTHER_DIMM,
+ DDR2_RTT_75_OHM,
+ DDR2_RTT_OFF
+ },
+ { /* cs3 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER,
+ DDR2_RTT_OFF,
+ DDR2_RTT_OFF
+ }
+};
+
+static const struct dynamic_odt dual_DS[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_OTHER_DIMM,
+ DDR2_RTT_75_OHM,
+ DDR2_RTT_OFF
+ },
+ { /* cs1 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER,
+ DDR2_RTT_OFF,
+ DDR2_RTT_OFF
+ },
+ { /* cs2 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_OTHER_DIMM,
+ DDR2_RTT_75_OHM,
+ DDR2_RTT_OFF
+ },
+ {0, 0, 0, 0}
+};
+
+static const struct dynamic_odt dual_SD[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_OTHER_DIMM,
+ DDR2_RTT_75_OHM,
+ DDR2_RTT_OFF
+ },
+ {0, 0, 0, 0},
+ { /* cs2 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_OTHER_DIMM,
+ DDR2_RTT_75_OHM,
+ DDR2_RTT_OFF
+ },
+ { /* cs3 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER,
+ DDR2_RTT_OFF,
+ DDR2_RTT_OFF
+ }
+};
+
+static const struct dynamic_odt dual_SS[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_OTHER_DIMM,
+ DDR2_RTT_75_OHM,
+ DDR2_RTT_OFF
+ },
+ {0, 0, 0, 0},
+ { /* cs2 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_OTHER_DIMM,
+ DDR2_RTT_75_OHM,
+ DDR2_RTT_OFF
+ },
+ {0, 0, 0, 0}
+};
+
+static const struct dynamic_odt dual_D0[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_ALL,
+ DDR2_RTT_150_OHM,
+ DDR2_RTT_OFF
+ },
+ { /* cs1 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER,
+ DDR2_RTT_OFF,
+ DDR2_RTT_OFF
+ },
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}
+};
+
+static const struct dynamic_odt dual_0D[4] = {
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ { /* cs2 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_ALL,
+ DDR2_RTT_150_OHM,
+ DDR2_RTT_OFF
+ },
+ { /* cs3 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER,
+ DDR2_RTT_OFF,
+ DDR2_RTT_OFF
+ }
+};
+
+static const struct dynamic_odt dual_S0[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS,
+ DDR2_RTT_150_OHM,
+ DDR2_RTT_OFF
+ },
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}
+
+};
+
+static const struct dynamic_odt dual_0S[4] = {
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ { /* cs2 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS,
+ DDR2_RTT_150_OHM,
+ DDR2_RTT_OFF
+ },
+ {0, 0, 0, 0}
+
+};
+
+static const struct dynamic_odt odt_unknown[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS,
+ DDR2_RTT_75_OHM,
+ DDR2_RTT_OFF
+ },
+ { /* cs1 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER,
+ DDR2_RTT_OFF,
+ DDR2_RTT_OFF
+ },
+ { /* cs2 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS,
+ DDR2_RTT_75_OHM,
+ DDR2_RTT_OFF
+ },
+ { /* cs3 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER,
+ DDR2_RTT_OFF,
+ DDR2_RTT_OFF
+ }
+};
+#endif
+
+/*
+ * Automatically seleect bank interleaving mode based on DIMMs
+ * in this order: cs0_cs1_cs2_cs3, cs0_cs1, null.
+ * This function only deal with one or two slots per controller.
+ */
+static inline unsigned int auto_bank_intlv(dimm_params_t *pdimm)
+{
+#if (CONFIG_DIMM_SLOTS_PER_CTLR == 1)
+ if (pdimm[0].n_ranks == 4)
+ return FSL_DDR_CS0_CS1_CS2_CS3;
+ else if (pdimm[0].n_ranks == 2)
+ return FSL_DDR_CS0_CS1;
+#elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
+#ifdef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE
+ if (pdimm[0].n_ranks == 4)
+ return FSL_DDR_CS0_CS1_CS2_CS3;
+#endif
+ if (pdimm[0].n_ranks == 2) {
+ if (pdimm[1].n_ranks == 2)
+ return FSL_DDR_CS0_CS1_CS2_CS3;
+ else
+ return FSL_DDR_CS0_CS1;
+ }
+#endif
+ return 0;
+}
+
+unsigned int populate_memctl_options(int all_DIMMs_registered,
+ memctl_options_t *popts,
+ dimm_params_t *pdimm,
+ unsigned int ctrl_num)
+{
+ unsigned int i;
+ char buffer[HWCONFIG_BUFFER_SIZE];
+ char *buf = NULL;
+#if defined(CONFIG_FSL_DDR3) || defined(CONFIG_FSL_DDR2)
+ const struct dynamic_odt *pdodt = odt_unknown;
+#endif
+ ulong ddr_freq;
+
+ /*
+ * Extract hwconfig from environment since we have not properly setup
+ * the environment but need it for ddr config params
+ */
+ if (getenv_f("hwconfig", buffer, sizeof(buffer)) > 0)
+ buf = buffer;
+
+#if defined(CONFIG_FSL_DDR3) || defined(CONFIG_FSL_DDR2)
+ /* Chip select options. */
+ if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) {
+ switch (pdimm[0].n_ranks) {
+ case 1:
+ pdodt = single_S;
+ break;
+ case 2:
+ pdodt = single_D;
+ break;
+ case 4:
+ pdodt = single_Q;
+ break;
+ }
+ } else if (CONFIG_DIMM_SLOTS_PER_CTLR == 2) {
+ switch (pdimm[0].n_ranks) {
+#ifdef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE
+ case 4:
+ pdodt = single_Q;
+ if (pdimm[1].n_ranks)
+ printf("Error: Quad- and Dual-rank DIMMs "
+ "cannot be used together\n");
+ break;
+#endif
+ case 2:
+ switch (pdimm[1].n_ranks) {
+ case 2:
+ pdodt = dual_DD;
+ break;
+ case 1:
+ pdodt = dual_DS;
+ break;
+ case 0:
+ pdodt = dual_D0;
+ break;
+ }
+ break;
+ case 1:
+ switch (pdimm[1].n_ranks) {
+ case 2:
+ pdodt = dual_SD;
+ break;
+ case 1:
+ pdodt = dual_SS;
+ break;
+ case 0:
+ pdodt = dual_S0;
+ break;
+ }
+ break;
+ case 0:
+ switch (pdimm[1].n_ranks) {
+ case 2:
+ pdodt = dual_0D;
+ break;
+ case 1:
+ pdodt = dual_0S;
+ break;
+ }
+ break;
+ }
+ }
+#endif
+
+ /* Pick chip-select local options. */
+ for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+#if defined(CONFIG_FSL_DDR3) || defined(CONFIG_FSL_DDR2)
+ popts->cs_local_opts[i].odt_rd_cfg = pdodt[i].odt_rd_cfg;
+ popts->cs_local_opts[i].odt_wr_cfg = pdodt[i].odt_wr_cfg;
+ popts->cs_local_opts[i].odt_rtt_norm = pdodt[i].odt_rtt_norm;
+ popts->cs_local_opts[i].odt_rtt_wr = pdodt[i].odt_rtt_wr;
+#else
+ popts->cs_local_opts[i].odt_rd_cfg = FSL_DDR_ODT_NEVER;
+ popts->cs_local_opts[i].odt_wr_cfg = FSL_DDR_ODT_CS;
+#endif
+ popts->cs_local_opts[i].auto_precharge = 0;
+ }
+
+ /* Pick interleaving mode. */
+
+ /*
+ * 0 = no interleaving
+ * 1 = interleaving between 2 controllers
+ */
+ popts->memctl_interleaving = 0;
+
+ /*
+ * 0 = cacheline
+ * 1 = page
+ * 2 = (logical) bank
+ * 3 = superbank (only if CS interleaving is enabled)
+ */
+ popts->memctl_interleaving_mode = 0;
+
+ /*
+ * 0: cacheline: bit 30 of the 36-bit physical addr selects the memctl
+ * 1: page: bit to the left of the column bits selects the memctl
+ * 2: bank: bit to the left of the bank bits selects the memctl
+ * 3: superbank: bit to the left of the chip select selects the memctl
+ *
+ * NOTE: ba_intlv (rank interleaving) is independent of memory
+ * controller interleaving; it is only within a memory controller.
+ * Must use superbank interleaving if rank interleaving is used and
+ * memory controller interleaving is enabled.
+ */
+
+ /*
+ * 0 = no
+ * 0x40 = CS0,CS1
+ * 0x20 = CS2,CS3
+ * 0x60 = CS0,CS1 + CS2,CS3
+ * 0x04 = CS0,CS1,CS2,CS3
+ */
+ popts->ba_intlv_ctl = 0;
+
+ /* Memory Organization Parameters */
+ popts->registered_dimm_en = all_DIMMs_registered;
+
+ /* Operational Mode Paramters */
+
+ /* Pick ECC modes */
+ popts->ECC_mode = 0; /* 0 = disabled, 1 = enabled */
+#ifdef CONFIG_DDR_ECC
+ if (hwconfig_sub_f("fsl_ddr", "ecc", buf)) {
+ if (hwconfig_subarg_cmp_f("fsl_ddr", "ecc", "on", buf))
+ popts->ECC_mode = 1;
+ } else
+ popts->ECC_mode = 1;
+#endif
+ popts->ECC_init_using_memctl = 1; /* 0 = use DMA, 1 = use memctl */
+
+ /*
+ * Choose DQS config
+ * 0 for DDR1
+ * 1 for DDR2
+ */
+#if defined(CONFIG_FSL_DDR1)
+ popts->DQS_config = 0;
+#elif defined(CONFIG_FSL_DDR2) || defined(CONFIG_FSL_DDR3)
+ popts->DQS_config = 1;
+#endif
+
+ /* Choose self-refresh during sleep. */
+ popts->self_refresh_in_sleep = 1;
+
+ /* Choose dynamic power management mode. */
+ popts->dynamic_power = 0;
+
+ /*
+ * check first dimm for primary sdram width
+ * presuming all dimms are similar
+ * 0 = 64-bit, 1 = 32-bit, 2 = 16-bit
+ */
+#if defined(CONFIG_FSL_DDR1) || defined(CONFIG_FSL_DDR2)
+ if (pdimm[0].n_ranks != 0) {
+ if ((pdimm[0].data_width >= 64) && \
+ (pdimm[0].data_width <= 72))
+ popts->data_bus_width = 0;
+ else if ((pdimm[0].data_width >= 32) || \
+ (pdimm[0].data_width <= 40))
+ popts->data_bus_width = 1;
+ else {
+ panic("Error: data width %u is invalid!\n",
+ pdimm[0].data_width);
+ }
+ }
+#else
+ if (pdimm[0].n_ranks != 0) {
+ if (pdimm[0].primary_sdram_width == 64)
+ popts->data_bus_width = 0;
+ else if (pdimm[0].primary_sdram_width == 32)
+ popts->data_bus_width = 1;
+ else if (pdimm[0].primary_sdram_width == 16)
+ popts->data_bus_width = 2;
+ else {
+ panic("Error: primary sdram width %u is invalid!\n",
+ pdimm[0].primary_sdram_width);
+ }
+ }
+#endif
+
+ /* Choose burst length. */
+#if defined(CONFIG_FSL_DDR3)
+#if defined(CONFIG_E500MC)
+ popts->OTF_burst_chop_en = 0; /* on-the-fly burst chop disable */
+ popts->burst_length = DDR_BL8; /* Fixed 8-beat burst len */
+#else
+ if ((popts->data_bus_width == 1) || (popts->data_bus_width == 2)) {
+ /* 32-bit or 16-bit bus */
+ popts->OTF_burst_chop_en = 0;
+ popts->burst_length = DDR_BL8;
+ } else {
+ popts->OTF_burst_chop_en = 1; /* on-the-fly burst chop */
+ popts->burst_length = DDR_OTF; /* on-the-fly BC4 and BL8 */
+ }
+#endif
+#else
+ popts->burst_length = DDR_BL4; /* has to be 4 for DDR2 */
+#endif
+
+ /* Choose ddr controller address mirror mode */
+#if defined(CONFIG_FSL_DDR3)
+ popts->mirrored_dimm = pdimm[0].mirrored_dimm;
+#endif
+
+ /* Global Timing Parameters. */
+ debug("mclk_ps = %u ps\n", get_memory_clk_period_ps());
+
+ /* Pick a caslat override. */
+ popts->cas_latency_override = 0;
+ popts->cas_latency_override_value = 3;
+ if (popts->cas_latency_override) {
+ debug("using caslat override value = %u\n",
+ popts->cas_latency_override_value);
+ }
+
+ /* Decide whether to use the computed derated latency */
+ popts->use_derated_caslat = 0;
+
+ /* Choose an additive latency. */
+ popts->additive_latency_override = 0;
+ popts->additive_latency_override_value = 3;
+ if (popts->additive_latency_override) {
+ debug("using additive latency override value = %u\n",
+ popts->additive_latency_override_value);
+ }
+
+ /*
+ * 2T_EN setting
+ *
+ * Factors to consider for 2T_EN:
+ * - number of DIMMs installed
+ * - number of components, number of active ranks
+ * - how much time you want to spend playing around
+ */
+ popts->twoT_en = 0;
+ popts->threeT_en = 0;
+
+ /* for RDIMM, address parity enable */
+ popts->ap_en = 1;
+
+ /*
+ * BSTTOPRE precharge interval
+ *
+ * Set this to 0 for global auto precharge
+ *
+ * FIXME: Should this be configured in picoseconds?
+ * Why it should be in ps: better understanding of this
+ * relative to actual DRAM timing parameters such as tRAS.
+ * e.g. tRAS(min) = 40 ns
+ */
+ popts->bstopre = 0x100;
+
+ /* Minimum CKE pulse width -- tCKE(MIN) */
+ popts->tCKE_clock_pulse_width_ps
+ = mclk_to_picos(FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR);
+
+ /*
+ * Window for four activates -- tFAW
+ *
+ * FIXME: UM: applies only to DDR2/DDR3 with eight logical banks only
+ * FIXME: varies depending upon number of column addresses or data
+ * FIXME: width, was considering looking at pdimm->primary_sdram_width
+ */
+#if defined(CONFIG_FSL_DDR1)
+ popts->tFAW_window_four_activates_ps = mclk_to_picos(1);
+
+#elif defined(CONFIG_FSL_DDR2)
+ /*
+ * x4/x8; some datasheets have 35000
+ * x16 wide columns only? Use 50000?
+ */
+ popts->tFAW_window_four_activates_ps = 37500;
+
+#elif defined(CONFIG_FSL_DDR3)
+ popts->tFAW_window_four_activates_ps = pdimm[0].tFAW_ps;
+#endif
+ popts->zq_en = 0;
+ popts->wrlvl_en = 0;
+#if defined(CONFIG_FSL_DDR3)
+ /*
+ * due to ddr3 dimm is fly-by topology
+ * we suggest to enable write leveling to
+ * meet the tQDSS under different loading.
+ */
+ popts->wrlvl_en = 1;
+ popts->zq_en = 1;
+ popts->wrlvl_override = 0;
+#endif
+
+ /*
+ * Check interleaving configuration from environment.
+ * Please refer to doc/README.fsl-ddr for the detail.
+ *
+ * If memory controller interleaving is enabled, then the data
+ * bus widths must be programmed identically for all memory controllers.
+ *
+ * XXX: Attempt to set all controllers to the same chip select
+ * interleaving mode. It will do a best effort to get the
+ * requested ranks interleaved together such that the result
+ * should be a subset of the requested configuration.
+ */
+#if (CONFIG_NUM_DDR_CONTROLLERS > 1)
+ if (!hwconfig_sub_f("fsl_ddr", "ctlr_intlv", buf))
+ goto done;
+
+ if (pdimm[0].n_ranks == 0) {
+ printf("There is no rank on CS0 for controller %d.\n", ctrl_num);
+ popts->memctl_interleaving = 0;
+ goto done;
+ }
+ popts->memctl_interleaving = 1;
+ /*
+ * test null first. if CONFIG_HWCONFIG is not defined
+ * hwconfig_arg_cmp returns non-zero
+ */
+ if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv",
+ "null", buf)) {
+ popts->memctl_interleaving = 0;
+ debug("memory controller interleaving disabled.\n");
+ } else if (hwconfig_subarg_cmp_f("fsl_ddr",
+ "ctlr_intlv",
+ "cacheline", buf)) {
+ popts->memctl_interleaving_mode =
+ ((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ?
+ 0 : FSL_DDR_CACHE_LINE_INTERLEAVING;
+ popts->memctl_interleaving =
+ ((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ?
+ 0 : 1;
+ } else if (hwconfig_subarg_cmp_f("fsl_ddr",
+ "ctlr_intlv",
+ "page", buf)) {
+ popts->memctl_interleaving_mode =
+ ((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ?
+ 0 : FSL_DDR_PAGE_INTERLEAVING;
+ popts->memctl_interleaving =
+ ((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ?
+ 0 : 1;
+ } else if (hwconfig_subarg_cmp_f("fsl_ddr",
+ "ctlr_intlv",
+ "bank", buf)) {
+ popts->memctl_interleaving_mode =
+ ((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ?
+ 0 : FSL_DDR_BANK_INTERLEAVING;
+ popts->memctl_interleaving =
+ ((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ?
+ 0 : 1;
+ } else if (hwconfig_subarg_cmp_f("fsl_ddr",
+ "ctlr_intlv",
+ "superbank", buf)) {
+ popts->memctl_interleaving_mode =
+ ((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ?
+ 0 : FSL_DDR_SUPERBANK_INTERLEAVING;
+ popts->memctl_interleaving =
+ ((CONFIG_NUM_DDR_CONTROLLERS == 3) && ctrl_num == 2) ?
+ 0 : 1;
+#if (CONFIG_NUM_DDR_CONTROLLERS == 3)
+ } else if (hwconfig_subarg_cmp_f("fsl_ddr",
+ "ctlr_intlv",
+ "3way_1KB", buf)) {
+ popts->memctl_interleaving_mode =
+ FSL_DDR_3WAY_1KB_INTERLEAVING;
+ } else if (hwconfig_subarg_cmp_f("fsl_ddr",
+ "ctlr_intlv",
+ "3way_4KB", buf)) {
+ popts->memctl_interleaving_mode =
+ FSL_DDR_3WAY_4KB_INTERLEAVING;
+ } else if (hwconfig_subarg_cmp_f("fsl_ddr",
+ "ctlr_intlv",
+ "3way_8KB", buf)) {
+ popts->memctl_interleaving_mode =
+ FSL_DDR_3WAY_8KB_INTERLEAVING;
+#elif (CONFIG_NUM_DDR_CONTROLLERS == 4)
+ } else if (hwconfig_subarg_cmp_f("fsl_ddr",
+ "ctlr_intlv",
+ "4way_1KB", buf)) {
+ popts->memctl_interleaving_mode =
+ FSL_DDR_4WAY_1KB_INTERLEAVING;
+ } else if (hwconfig_subarg_cmp_f("fsl_ddr",
+ "ctlr_intlv",
+ "4way_4KB", buf)) {
+ popts->memctl_interleaving_mode =
+ FSL_DDR_4WAY_4KB_INTERLEAVING;
+ } else if (hwconfig_subarg_cmp_f("fsl_ddr",
+ "ctlr_intlv",
+ "4way_8KB", buf)) {
+ popts->memctl_interleaving_mode =
+ FSL_DDR_4WAY_8KB_INTERLEAVING;
+#endif
+ } else {
+ popts->memctl_interleaving = 0;
+ printf("hwconfig has unrecognized parameter for ctlr_intlv.\n");
+ }
+done:
+#endif
+ if ((hwconfig_sub_f("fsl_ddr", "bank_intlv", buf)) &&
+ (CONFIG_CHIP_SELECTS_PER_CTRL > 1)) {
+ /* test null first. if CONFIG_HWCONFIG is not defined,
+ * hwconfig_subarg_cmp_f returns non-zero */
+ if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv",
+ "null", buf))
+ debug("bank interleaving disabled.\n");
+ else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv",
+ "cs0_cs1", buf))
+ popts->ba_intlv_ctl = FSL_DDR_CS0_CS1;
+ else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv",
+ "cs2_cs3", buf))
+ popts->ba_intlv_ctl = FSL_DDR_CS2_CS3;
+ else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv",
+ "cs0_cs1_and_cs2_cs3", buf))
+ popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_AND_CS2_CS3;
+ else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv",
+ "cs0_cs1_cs2_cs3", buf))
+ popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_CS2_CS3;
+ else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv",
+ "auto", buf))
+ popts->ba_intlv_ctl = auto_bank_intlv(pdimm);
+ else
+ printf("hwconfig has unrecognized parameter for bank_intlv.\n");
+ switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) {
+ case FSL_DDR_CS0_CS1_CS2_CS3:
+#if (CONFIG_DIMM_SLOTS_PER_CTLR == 1)
+ if (pdimm[0].n_ranks < 4) {
+ popts->ba_intlv_ctl = 0;
+ printf("Not enough bank(chip-select) for "
+ "CS0+CS1+CS2+CS3 on controller %d, "
+ "interleaving disabled!\n", ctrl_num);
+ }
+#elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
+#ifdef CONFIG_FSL_DDR_FIRST_SLOT_QUAD_CAPABLE
+ if (pdimm[0].n_ranks == 4)
+ break;
+#endif
+ if ((pdimm[0].n_ranks < 2) && (pdimm[1].n_ranks < 2)) {
+ popts->ba_intlv_ctl = 0;
+ printf("Not enough bank(chip-select) for "
+ "CS0+CS1+CS2+CS3 on controller %d, "
+ "interleaving disabled!\n", ctrl_num);
+ }
+ if (pdimm[0].capacity != pdimm[1].capacity) {
+ popts->ba_intlv_ctl = 0;
+ printf("Not identical DIMM size for "
+ "CS0+CS1+CS2+CS3 on controller %d, "
+ "interleaving disabled!\n", ctrl_num);
+ }
+#endif
+ break;
+ case FSL_DDR_CS0_CS1:
+ if (pdimm[0].n_ranks < 2) {
+ popts->ba_intlv_ctl = 0;
+ printf("Not enough bank(chip-select) for "
+ "CS0+CS1 on controller %d, "
+ "interleaving disabled!\n", ctrl_num);
+ }
+ break;
+ case FSL_DDR_CS2_CS3:
+#if (CONFIG_DIMM_SLOTS_PER_CTLR == 1)
+ if (pdimm[0].n_ranks < 4) {
+ popts->ba_intlv_ctl = 0;
+ printf("Not enough bank(chip-select) for CS2+CS3 "
+ "on controller %d, interleaving disabled!\n", ctrl_num);
+ }
+#elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
+ if (pdimm[1].n_ranks < 2) {
+ popts->ba_intlv_ctl = 0;
+ printf("Not enough bank(chip-select) for CS2+CS3 "
+ "on controller %d, interleaving disabled!\n", ctrl_num);
+ }
+#endif
+ break;
+ case FSL_DDR_CS0_CS1_AND_CS2_CS3:
+#if (CONFIG_DIMM_SLOTS_PER_CTLR == 1)
+ if (pdimm[0].n_ranks < 4) {
+ popts->ba_intlv_ctl = 0;
+ printf("Not enough bank(CS) for CS0+CS1 and "
+ "CS2+CS3 on controller %d, "
+ "interleaving disabled!\n", ctrl_num);
+ }
+#elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
+ if ((pdimm[0].n_ranks < 2) || (pdimm[1].n_ranks < 2)) {
+ popts->ba_intlv_ctl = 0;
+ printf("Not enough bank(CS) for CS0+CS1 and "
+ "CS2+CS3 on controller %d, "
+ "interleaving disabled!\n", ctrl_num);
+ }
+#endif
+ break;
+ default:
+ popts->ba_intlv_ctl = 0;
+ break;
+ }
+ }
+
+ if (hwconfig_sub_f("fsl_ddr", "addr_hash", buf)) {
+ if (hwconfig_subarg_cmp_f("fsl_ddr", "addr_hash", "null", buf))
+ popts->addr_hash = 0;
+ else if (hwconfig_subarg_cmp_f("fsl_ddr", "addr_hash",
+ "true", buf))
+ popts->addr_hash = 1;
+ }
+
+ if (pdimm[0].n_ranks == 4)
+ popts->quad_rank_present = 1;
+
+ ddr_freq = get_ddr_freq(0) / 1000000;
+ if (popts->registered_dimm_en) {
+ popts->rcw_override = 1;
+ popts->rcw_1 = 0x000a5a00;
+ if (ddr_freq <= 800)
+ popts->rcw_2 = 0x00000000;
+ else if (ddr_freq <= 1066)
+ popts->rcw_2 = 0x00100000;
+ else if (ddr_freq <= 1333)
+ popts->rcw_2 = 0x00200000;
+ else
+ popts->rcw_2 = 0x00300000;
+ }
+
+ fsl_ddr_board_options(popts, pdimm, ctrl_num);
+
+ return 0;
+}
+
+void check_interleaving_options(fsl_ddr_info_t *pinfo)
+{
+ int i, j, k, check_n_ranks, intlv_invalid = 0;
+ unsigned int check_intlv, check_n_row_addr, check_n_col_addr;
+ unsigned long long check_rank_density;
+ struct dimm_params_s *dimm;
+ /*
+ * Check if all controllers are configured for memory
+ * controller interleaving. Identical dimms are recommended. At least
+ * the size, row and col address should be checked.
+ */
+ j = 0;
+ check_n_ranks = pinfo->dimm_params[0][0].n_ranks;
+ check_rank_density = pinfo->dimm_params[0][0].rank_density;
+ check_n_row_addr = pinfo->dimm_params[0][0].n_row_addr;
+ check_n_col_addr = pinfo->dimm_params[0][0].n_col_addr;
+ check_intlv = pinfo->memctl_opts[0].memctl_interleaving_mode;
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ dimm = &pinfo->dimm_params[i][0];
+ if (!pinfo->memctl_opts[i].memctl_interleaving) {
+ continue;
+ } else if (((check_rank_density != dimm->rank_density) ||
+ (check_n_ranks != dimm->n_ranks) ||
+ (check_n_row_addr != dimm->n_row_addr) ||
+ (check_n_col_addr != dimm->n_col_addr) ||
+ (check_intlv !=
+ pinfo->memctl_opts[i].memctl_interleaving_mode))){
+ intlv_invalid = 1;
+ break;
+ } else {
+ j++;
+ }
+
+ }
+ if (intlv_invalid) {
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
+ pinfo->memctl_opts[i].memctl_interleaving = 0;
+ printf("Not all DIMMs are identical. "
+ "Memory controller interleaving disabled.\n");
+ } else {
+ switch (check_intlv) {
+ case FSL_DDR_CACHE_LINE_INTERLEAVING:
+ case FSL_DDR_PAGE_INTERLEAVING:
+ case FSL_DDR_BANK_INTERLEAVING:
+ case FSL_DDR_SUPERBANK_INTERLEAVING:
+ if (3 == CONFIG_NUM_DDR_CONTROLLERS)
+ k = 2;
+ else
+ k = CONFIG_NUM_DDR_CONTROLLERS;
+ break;
+ case FSL_DDR_3WAY_1KB_INTERLEAVING:
+ case FSL_DDR_3WAY_4KB_INTERLEAVING:
+ case FSL_DDR_3WAY_8KB_INTERLEAVING:
+ case FSL_DDR_4WAY_1KB_INTERLEAVING:
+ case FSL_DDR_4WAY_4KB_INTERLEAVING:
+ case FSL_DDR_4WAY_8KB_INTERLEAVING:
+ default:
+ k = CONFIG_NUM_DDR_CONTROLLERS;
+ break;
+ }
+ debug("%d of %d controllers are interleaving.\n", j, k);
+ if (j && (j != k)) {
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
+ pinfo->memctl_opts[i].memctl_interleaving = 0;
+ printf("Not all controllers have compatible "
+ "interleaving mode. All disabled.\n");
+ }
+ }
+ debug("Checking interleaving options completed\n");
+}
+
+int fsl_use_spd(void)
+{
+ int use_spd = 0;
+
+#ifdef CONFIG_DDR_SPD
+ char buffer[HWCONFIG_BUFFER_SIZE];
+ char *buf = NULL;
+
+ /*
+ * Extract hwconfig from environment since we have not properly setup
+ * the environment but need it for ddr config params
+ */
+ if (getenv_f("hwconfig", buffer, sizeof(buffer)) > 0)
+ buf = buffer;
+
+ /* if hwconfig is not enabled, or "sdram" is not defined, use spd */
+ if (hwconfig_sub_f("fsl_ddr", "sdram", buf)) {
+ if (hwconfig_subarg_cmp_f("fsl_ddr", "sdram", "spd", buf))
+ use_spd = 1;
+ else if (hwconfig_subarg_cmp_f("fsl_ddr", "sdram",
+ "fixed", buf))
+ use_spd = 0;
+ else
+ use_spd = 1;
+ } else
+ use_spd = 1;
+#endif
+
+ return use_spd;
+}
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/util.c b/arch/powerpc/cpu/mpc8xxx/ddr/util.c
new file mode 100644
index 0000000..acfe1f0
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/util.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/fsl_law.h>
+#include <div64.h>
+
+#include "ddr.h"
+
+/* To avoid 64-bit full-divides, we factor this here */
+#define ULL_2E12 2000000000000ULL
+#define UL_5POW12 244140625UL
+#define UL_2POW13 (1UL << 13)
+
+#define ULL_8FS 0xFFFFFFFFULL
+
+/*
+ * Round up mclk_ps to nearest 1 ps in memory controller code
+ * if the error is 0.5ps or more.
+ *
+ * If an imprecise data rate is too high due to rounding error
+ * propagation, compute a suitably rounded mclk_ps to compute
+ * a working memory controller configuration.
+ */
+unsigned int get_memory_clk_period_ps(void)
+{
+ unsigned int data_rate = get_ddr_freq(0);
+ unsigned int result;
+
+ /* Round to nearest 10ps, being careful about 64-bit multiply/divide */
+ unsigned long long rem, mclk_ps = ULL_2E12;
+
+ /* Now perform the big divide, the result fits in 32-bits */
+ rem = do_div(mclk_ps, data_rate);
+ result = (rem >= (data_rate >> 1)) ? mclk_ps + 1 : mclk_ps;
+
+ return result;
+}
+
+/* Convert picoseconds into DRAM clock cycles (rounding up if needed). */
+unsigned int picos_to_mclk(unsigned int picos)
+{
+ unsigned long long clks, clks_rem;
+ unsigned long data_rate = get_ddr_freq(0);
+
+ /* Short circuit for zero picos */
+ if (!picos)
+ return 0;
+
+ /* First multiply the time by the data rate (32x32 => 64) */
+ clks = picos * (unsigned long long)data_rate;
+ /*
+ * Now divide by 5^12 and track the 32-bit remainder, then divide
+ * by 2*(2^12) using shifts (and updating the remainder).
+ */
+ clks_rem = do_div(clks, UL_5POW12);
+ clks_rem += (clks & (UL_2POW13-1)) * UL_5POW12;
+ clks >>= 13;
+
+ /* If we had a remainder greater than the 1ps error, then round up */
+ if (clks_rem > data_rate)
+ clks++;
+
+ /* Clamp to the maximum representable value */
+ if (clks > ULL_8FS)
+ clks = ULL_8FS;
+ return (unsigned int) clks;
+}
+
+unsigned int mclk_to_picos(unsigned int mclk)
+{
+ return get_memory_clk_period_ps() * mclk;
+}
+
+void
+__fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params,
+ unsigned int law_memctl,
+ unsigned int ctrl_num)
+{
+ unsigned long long base = memctl_common_params->base_address;
+ unsigned long long size = memctl_common_params->total_mem;
+
+ /*
+ * If no DIMMs on this controller, do not proceed any further.
+ */
+ if (!memctl_common_params->ndimms_present) {
+ return;
+ }
+
+#if !defined(CONFIG_PHYS_64BIT)
+ if (base >= CONFIG_MAX_MEM_MAPPED)
+ return;
+ if ((base + size) >= CONFIG_MAX_MEM_MAPPED)
+ size = CONFIG_MAX_MEM_MAPPED - base;
+#endif
+ if (set_ddr_laws(base, size, law_memctl) < 0) {
+ printf("%s: ERROR (ctrl #%d, TRGT ID=%x)\n", __func__, ctrl_num,
+ law_memctl);
+ return ;
+ }
+ debug("setup ddr law base = 0x%llx, size 0x%llx, TRGT_ID 0x%x\n",
+ base, size, law_memctl);
+}
+
+__attribute__((weak, alias("__fsl_ddr_set_lawbar"))) void
+fsl_ddr_set_lawbar(const common_timing_params_t *memctl_common_params,
+ unsigned int memctl_interleaved,
+ unsigned int ctrl_num);
+
+void fsl_ddr_set_intl3r(const unsigned int granule_size)
+{
+#ifdef CONFIG_E6500
+ u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004);
+ *mcintl3r = 0x80000000 | (granule_size & 0x1f);
+ debug("Enable MCINTL3R with granule size 0x%x\n", granule_size);
+#endif
+}
+
+u32 fsl_ddr_get_intl3r(void)
+{
+ u32 val = 0;
+#ifdef CONFIG_E6500
+ u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004);
+ val = *mcintl3r;
+#endif
+ return val;
+}
+
+void board_add_ram_info(int use_default)
+{
+ ccsr_ddr_t *ddr = (void *)(CONFIG_SYS_MPC8xxx_DDR_ADDR);
+
+#if defined(CONFIG_E6500) && (CONFIG_NUM_DDR_CONTROLLERS == 3)
+ u32 *mcintl3r = (void *) (CONFIG_SYS_IMMR + 0x18004);
+#endif
+#if (CONFIG_NUM_DDR_CONTROLLERS > 1)
+ uint32_t cs0_config = in_be32(&ddr->cs0_config);
+#endif
+ uint32_t sdram_cfg = in_be32(&ddr->sdram_cfg);
+ int cas_lat;
+
+#if CONFIG_NUM_DDR_CONTROLLERS >= 2
+ if (!(sdram_cfg & SDRAM_CFG_MEM_EN)) {
+ ddr = (void __iomem *)CONFIG_SYS_MPC8xxx_DDR2_ADDR;
+ sdram_cfg = in_be32(&ddr->sdram_cfg);
+ }
+#endif
+#if CONFIG_NUM_DDR_CONTROLLERS >= 3
+ if (!(sdram_cfg & SDRAM_CFG_MEM_EN)) {
+ ddr = (void __iomem *)CONFIG_SYS_MPC8xxx_DDR3_ADDR;
+ sdram_cfg = in_be32(&ddr->sdram_cfg);
+ }
+#endif
+ puts(" (DDR");
+ switch ((sdram_cfg & SDRAM_CFG_SDRAM_TYPE_MASK) >>
+ SDRAM_CFG_SDRAM_TYPE_SHIFT) {
+ case SDRAM_TYPE_DDR1:
+ puts("1");
+ break;
+ case SDRAM_TYPE_DDR2:
+ puts("2");
+ break;
+ case SDRAM_TYPE_DDR3:
+ puts("3");
+ break;
+ default:
+ puts("?");
+ break;
+ }
+
+ if (sdram_cfg & SDRAM_CFG_32_BE)
+ puts(", 32-bit");
+ else if (sdram_cfg & SDRAM_CFG_16_BE)
+ puts(", 16-bit");
+ else
+ puts(", 64-bit");
+
+ /* Calculate CAS latency based on timing cfg values */
+ cas_lat = ((in_be32(&ddr->timing_cfg_1) >> 16) & 0xf) + 1;
+ if ((in_be32(&ddr->timing_cfg_3) >> 12) & 1)
+ cas_lat += (8 << 1);
+ printf(", CL=%d", cas_lat >> 1);
+ if (cas_lat & 0x1)
+ puts(".5");
+
+ if (sdram_cfg & SDRAM_CFG_ECC_EN)
+ puts(", ECC on)");
+ else
+ puts(", ECC off)");
+
+#if (CONFIG_NUM_DDR_CONTROLLERS == 3)
+#ifdef CONFIG_E6500
+ if (*mcintl3r & 0x80000000) {
+ puts("\n");
+ puts(" DDR Controller Interleaving Mode: ");
+ switch (*mcintl3r & 0x1f) {
+ case FSL_DDR_3WAY_1KB_INTERLEAVING:
+ puts("3-way 1KB");
+ break;
+ case FSL_DDR_3WAY_4KB_INTERLEAVING:
+ puts("3-way 4KB");
+ break;
+ case FSL_DDR_3WAY_8KB_INTERLEAVING:
+ puts("3-way 8KB");
+ break;
+ default:
+ puts("3-way UNKNOWN");
+ break;
+ }
+ }
+#endif
+#endif
+#if (CONFIG_NUM_DDR_CONTROLLERS >= 2)
+ if (cs0_config & 0x20000000) {
+ puts("\n");
+ puts(" DDR Controller Interleaving Mode: ");
+
+ switch ((cs0_config >> 24) & 0xf) {
+ case FSL_DDR_CACHE_LINE_INTERLEAVING:
+ puts("cache line");
+ break;
+ case FSL_DDR_PAGE_INTERLEAVING:
+ puts("page");
+ break;
+ case FSL_DDR_BANK_INTERLEAVING:
+ puts("bank");
+ break;
+ case FSL_DDR_SUPERBANK_INTERLEAVING:
+ puts("super-bank");
+ break;
+ default:
+ puts("invalid");
+ break;
+ }
+ }
+#endif
+
+ if ((sdram_cfg >> 8) & 0x7f) {
+ puts("\n");
+ puts(" DDR Chip-Select Interleaving Mode: ");
+ switch(sdram_cfg >> 8 & 0x7f) {
+ case FSL_DDR_CS0_CS1_CS2_CS3:
+ puts("CS0+CS1+CS2+CS3");
+ break;
+ case FSL_DDR_CS0_CS1:
+ puts("CS0+CS1");
+ break;
+ case FSL_DDR_CS2_CS3:
+ puts("CS2+CS3");
+ break;
+ case FSL_DDR_CS0_CS1_AND_CS2_CS3:
+ puts("CS0+CS1 and CS2+CS3");
+ break;
+ default:
+ puts("invalid");
+ break;
+ }
+ }
+}
diff --git a/arch/powerpc/cpu/mpc8xxx/fdt.c b/arch/powerpc/cpu/mpc8xxx/fdt.c
new file mode 100644
index 0000000..2db9045
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/fdt.c
@@ -0,0 +1,464 @@
+/*
+ * Copyright 2009-2012 Freescale Semiconductor, Inc.
+ *
+ * This file is derived from arch/powerpc/cpu/mpc85xx/cpu.c and
+ * arch/powerpc/cpu/mpc86xx/cpu.c. Basically this file contains
+ * cpu specific common code for 85xx/86xx processors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+#include <asm/mp.h>
+#include <asm/fsl_serdes.h>
+#include <phy.h>
+#include <hwconfig.h>
+
+#define FSL_MAX_NUM_USB_CTRLS 2
+
+#if defined(CONFIG_MP) && (defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx))
+static int ft_del_cpuhandle(void *blob, int cpuhandle)
+{
+ int off, ret = -FDT_ERR_NOTFOUND;
+
+ /* if we find a match, we'll delete at it which point the offsets are
+ * invalid so we start over from the beginning
+ */
+ off = fdt_node_offset_by_prop_value(blob, -1, "cpu-handle",
+ &cpuhandle, 4);
+ while (off != -FDT_ERR_NOTFOUND) {
+ fdt_delprop(blob, off, "cpu-handle");
+ ret = 1;
+ off = fdt_node_offset_by_prop_value(blob, -1, "cpu-handle",
+ &cpuhandle, 4);
+ }
+
+ return ret;
+}
+
+void ft_fixup_num_cores(void *blob) {
+ int off, num_cores, del_cores;
+
+ del_cores = 0;
+ num_cores = cpu_numcores();
+
+ off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
+ while (off != -FDT_ERR_NOTFOUND) {
+ u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", 0);
+ u32 phys_cpu_id = thread_to_core(*reg);
+
+ if (!is_core_valid(phys_cpu_id) || is_core_disabled(phys_cpu_id)) {
+ int ph = fdt_get_phandle(blob, off);
+
+ /* Delete the cpu node once there are no cpu handles */
+ if (-FDT_ERR_NOTFOUND == ft_del_cpuhandle(blob, ph)) {
+ fdt_del_node(blob, off);
+ del_cores++;
+ }
+ /* either we deleted some cpu handles or the cpu node
+ * so we reset the offset back to the start since we
+ * can't trust the offsets anymore
+ */
+ off = -1;
+ }
+ off = fdt_node_offset_by_prop_value(blob, off,
+ "device_type", "cpu", 4);
+ }
+ debug ("%x core system found\n", num_cores);
+ debug ("deleted %d extra core entry entries from device tree\n",
+ del_cores);
+}
+#endif /* defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx) */
+
+#if defined(CONFIG_HAS_FSL_DR_USB) || defined(CONFIG_HAS_FSL_MPH_USB)
+static int fdt_fixup_usb_mode_phy_type(void *blob, const char *mode,
+ const char *phy_type, int start_offset)
+{
+ const char *compat_dr = "fsl-usb2-dr";
+ const char *compat_mph = "fsl-usb2-mph";
+ const char *prop_mode = "dr_mode";
+ const char *prop_type = "phy_type";
+ const char *node_type = NULL;
+ int node_offset;
+ int err;
+
+ node_offset = fdt_node_offset_by_compatible(blob,
+ start_offset, compat_mph);
+ if (node_offset < 0) {
+ node_offset = fdt_node_offset_by_compatible(blob,
+ start_offset, compat_dr);
+ if (node_offset < 0) {
+ printf("WARNING: could not find compatible"
+ " node %s or %s: %s.\n", compat_mph,
+ compat_dr, fdt_strerror(node_offset));
+ return -1;
+ } else
+ node_type = compat_dr;
+ } else
+ node_type = compat_mph;
+
+ if (mode) {
+ err = fdt_setprop(blob, node_offset, prop_mode, mode,
+ strlen(mode) + 1);
+ if (err < 0)
+ printf("WARNING: could not set %s for %s: %s.\n",
+ prop_mode, node_type, fdt_strerror(err));
+ }
+
+ if (phy_type) {
+ err = fdt_setprop(blob, node_offset, prop_type, phy_type,
+ strlen(phy_type) + 1);
+ if (err < 0)
+ printf("WARNING: could not set %s for %s: %s.\n",
+ prop_type, node_type, fdt_strerror(err));
+ }
+
+ return node_offset;
+}
+
+void fdt_fixup_dr_usb(void *blob, bd_t *bd)
+{
+ const char *modes[] = { "host", "peripheral", "otg" };
+ const char *phys[] = { "ulpi", "utmi" };
+ const char *mode = NULL;
+ const char *phy_type = NULL;
+ const char *dr_mode_type = NULL;
+ const char *dr_phy_type = NULL;
+ char usb1_defined = 0;
+ int usb_mode_off = -1;
+ int usb_phy_off = -1;
+ char str[5];
+ int i, j;
+
+ for (i = 1; i <= FSL_MAX_NUM_USB_CTRLS; i++) {
+ int mode_idx = -1, phy_idx = -1;
+ snprintf(str, 5, "%s%d", "usb", i);
+ if (hwconfig(str)) {
+ for (j = 0; j < ARRAY_SIZE(modes); j++) {
+ if (hwconfig_subarg_cmp(str, "dr_mode",
+ modes[j])) {
+ mode_idx = j;
+ break;
+ }
+ }
+
+ for (j = 0; j < ARRAY_SIZE(phys); j++) {
+ if (hwconfig_subarg_cmp(str, "phy_type",
+ phys[j])) {
+ phy_idx = j;
+ break;
+ }
+ }
+
+ if (mode_idx < 0 || phy_idx < 0) {
+ puts("ERROR: wrong usb mode/phy defined!!\n");
+ return;
+ }
+
+ dr_mode_type = modes[mode_idx];
+ dr_phy_type = phys[phy_idx];
+
+ /* use usb_dr_mode and usb_phy_type if
+ usb1_defined = 0; these variables are to
+ be deprecated */
+ if (!strcmp(str, "usb1"))
+ usb1_defined = 1;
+
+ if (mode_idx < 0 && phy_idx < 0) {
+ printf("WARNING: invalid phy or mode\n");
+ return;
+ }
+ }
+
+ usb_mode_off = fdt_fixup_usb_mode_phy_type(blob,
+ dr_mode_type, NULL, usb_mode_off);
+
+ if (usb_mode_off < 0)
+ return;
+
+ usb_phy_off = fdt_fixup_usb_mode_phy_type(blob,
+ NULL, dr_phy_type, usb_phy_off);
+
+ if (usb_phy_off < 0)
+ return;
+ }
+
+ if (!usb1_defined) {
+ int usb_off = -1;
+ mode = getenv("usb_dr_mode");
+ phy_type = getenv("usb_phy_type");
+ if (mode || phy_type) {
+ printf("WARNING: usb_dr_mode and usb_phy_type "
+ "are to be deprecated soon. Use "
+ "hwconfig to set these values instead!!\n");
+ fdt_fixup_usb_mode_phy_type(blob, mode,
+ phy_type, usb_off);
+ }
+ }
+}
+#endif /* defined(CONFIG_HAS_FSL_DR_USB) || defined(CONFIG_HAS_FSL_MPH_USB) */
+
+/*
+ * update crypto node properties to a specified revision of the SEC
+ * called with sec_rev == 0 if not on an E processor
+ */
+#if CONFIG_SYS_FSL_SEC_COMPAT == 2 /* SEC 2.x/3.x */
+void fdt_fixup_crypto_node(void *blob, int sec_rev)
+{
+ static const struct sec_rev_prop {
+ u32 sec_rev;
+ u32 num_channels;
+ u32 channel_fifo_len;
+ u32 exec_units_mask;
+ u32 descriptor_types_mask;
+ } sec_rev_prop_list [] = {
+ { 0x0200, 4, 24, 0x07e, 0x01010ebf }, /* SEC 2.0 */
+ { 0x0201, 4, 24, 0x0fe, 0x012b0ebf }, /* SEC 2.1 */
+ { 0x0202, 1, 24, 0x04c, 0x0122003f }, /* SEC 2.2 */
+ { 0x0204, 4, 24, 0x07e, 0x012b0ebf }, /* SEC 2.4 */
+ { 0x0300, 4, 24, 0x9fe, 0x03ab0ebf }, /* SEC 3.0 */
+ { 0x0301, 4, 24, 0xbfe, 0x03ab0ebf }, /* SEC 3.1 */
+ { 0x0303, 4, 24, 0x97c, 0x03a30abf }, /* SEC 3.3 */
+ };
+ static char compat_strlist[ARRAY_SIZE(sec_rev_prop_list) *
+ sizeof("fsl,secX.Y")];
+ int crypto_node, sec_idx, err;
+ char *p;
+ u32 val;
+
+ /* locate crypto node based on lowest common compatible */
+ crypto_node = fdt_node_offset_by_compatible(blob, -1, "fsl,sec2.0");
+ if (crypto_node == -FDT_ERR_NOTFOUND)
+ return;
+
+ /* delete it if not on an E-processor */
+ if (crypto_node > 0 && !sec_rev) {
+ fdt_del_node(blob, crypto_node);
+ return;
+ }
+
+ /* else we got called for possible uprev */
+ for (sec_idx = 0; sec_idx < ARRAY_SIZE(sec_rev_prop_list); sec_idx++)
+ if (sec_rev_prop_list[sec_idx].sec_rev == sec_rev)
+ break;
+
+ if (sec_idx == ARRAY_SIZE(sec_rev_prop_list)) {
+ puts("warning: unknown SEC revision number\n");
+ return;
+ }
+
+ val = cpu_to_fdt32(sec_rev_prop_list[sec_idx].num_channels);
+ err = fdt_setprop(blob, crypto_node, "fsl,num-channels", &val, 4);
+ if (err < 0)
+ printf("WARNING: could not set crypto property: %s\n",
+ fdt_strerror(err));
+
+ val = cpu_to_fdt32(sec_rev_prop_list[sec_idx].descriptor_types_mask);
+ err = fdt_setprop(blob, crypto_node, "fsl,descriptor-types-mask", &val, 4);
+ if (err < 0)
+ printf("WARNING: could not set crypto property: %s\n",
+ fdt_strerror(err));
+
+ val = cpu_to_fdt32(sec_rev_prop_list[sec_idx].exec_units_mask);
+ err = fdt_setprop(blob, crypto_node, "fsl,exec-units-mask", &val, 4);
+ if (err < 0)
+ printf("WARNING: could not set crypto property: %s\n",
+ fdt_strerror(err));
+
+ val = cpu_to_fdt32(sec_rev_prop_list[sec_idx].channel_fifo_len);
+ err = fdt_setprop(blob, crypto_node, "fsl,channel-fifo-len", &val, 4);
+ if (err < 0)
+ printf("WARNING: could not set crypto property: %s\n",
+ fdt_strerror(err));
+
+ val = 0;
+ while (sec_idx >= 0) {
+ p = compat_strlist + val;
+ val += sprintf(p, "fsl,sec%d.%d",
+ (sec_rev_prop_list[sec_idx].sec_rev & 0xff00) >> 8,
+ sec_rev_prop_list[sec_idx].sec_rev & 0x00ff) + 1;
+ sec_idx--;
+ }
+ err = fdt_setprop(blob, crypto_node, "compatible", &compat_strlist, val);
+ if (err < 0)
+ printf("WARNING: could not set crypto property: %s\n",
+ fdt_strerror(err));
+}
+#elif CONFIG_SYS_FSL_SEC_COMPAT >= 4 /* SEC4 */
+static u8 caam_get_era(void)
+{
+ static const struct {
+ u16 ip_id;
+ u8 maj_rev;
+ u8 era;
+ } caam_eras[] = {
+ {0x0A10, 1, 1},
+ {0x0A10, 2, 2},
+ {0x0A12, 1, 3},
+ {0x0A14, 1, 3},
+ {0x0A14, 2, 4},
+ {0x0A16, 1, 4},
+ {0x0A10, 3, 4},
+ {0x0A11, 1, 4},
+ {0x0A18, 1, 4},
+ {0x0A11, 2, 5},
+ {0x0A12, 2, 5},
+ {0x0A13, 1, 5},
+ {0x0A1C, 1, 5}
+ };
+
+ ccsr_sec_t __iomem *sec = (void __iomem *)CONFIG_SYS_FSL_SEC_ADDR;
+ u32 secvid_ms = in_be32(&sec->secvid_ms);
+ u32 ccbvid = in_be32(&sec->ccbvid);
+ u16 ip_id = (secvid_ms & SEC_SECVID_MS_IPID_MASK) >>
+ SEC_SECVID_MS_IPID_SHIFT;
+ u8 maj_rev = (secvid_ms & SEC_SECVID_MS_MAJ_REV_MASK) >>
+ SEC_SECVID_MS_MAJ_REV_SHIFT;
+ u8 era = (ccbvid & SEC_CCBVID_ERA_MASK) >> SEC_CCBVID_ERA_SHIFT;
+
+ int i;
+
+ if (era) /* This is '0' prior to CAAM ERA-6 */
+ return era;
+
+ for (i = 0; i < ARRAY_SIZE(caam_eras); i++)
+ if (caam_eras[i].ip_id == ip_id &&
+ caam_eras[i].maj_rev == maj_rev)
+ return caam_eras[i].era;
+
+ return 0;
+}
+
+static void fdt_fixup_crypto_era(void *blob, u32 era)
+{
+ int err;
+ int crypto_node;
+
+ crypto_node = fdt_path_offset(blob, "crypto");
+ if (crypto_node < 0) {
+ printf("WARNING: Missing crypto node\n");
+ return;
+ }
+
+ err = fdt_setprop(blob, crypto_node, "fsl,sec-era", &era,
+ sizeof(era));
+ if (err < 0) {
+ printf("ERROR: could not set fsl,sec-era property: %s\n",
+ fdt_strerror(err));
+ }
+}
+
+void fdt_fixup_crypto_node(void *blob, int sec_rev)
+{
+ u8 era;
+
+ if (!sec_rev) {
+ fdt_del_node_and_alias(blob, "crypto");
+ return;
+ }
+
+ /* Add SEC ERA information in compatible */
+ era = caam_get_era();
+ if (era) {
+ fdt_fixup_crypto_era(blob, era);
+ } else {
+ printf("WARNING: Unable to get ERA for CAAM rev: %d\n",
+ sec_rev);
+ }
+}
+#endif
+
+int fdt_fixup_phy_connection(void *blob, int offset, phy_interface_t phyc)
+{
+ return fdt_setprop_string(blob, offset, "phy-connection-type",
+ phy_string_for_interface(phyc));
+}
+
+#ifdef CONFIG_SYS_SRIO
+static inline void ft_disable_srio_port(void *blob, int srio_off, int port)
+{
+ int off = fdt_node_offset_by_prop_value(blob, srio_off,
+ "cell-index", &port, 4);
+ if (off >= 0) {
+ off = fdt_setprop_string(blob, off, "status", "disabled");
+ if (off > 0)
+ printf("WARNING unable to set status for fsl,srio "
+ "port %d: %s\n", port, fdt_strerror(off));
+ }
+}
+
+static inline void ft_disable_rman(void *blob)
+{
+ int off = fdt_node_offset_by_compatible(blob, -1, "fsl,rman");
+ if (off >= 0) {
+ off = fdt_setprop_string(blob, off, "status", "disabled");
+ if (off > 0)
+ printf("WARNING unable to set status for fsl,rman %s\n",
+ fdt_strerror(off));
+ }
+}
+
+static inline void ft_disable_rmu(void *blob)
+{
+ int off = fdt_node_offset_by_compatible(blob, -1, "fsl,srio-rmu");
+ if (off >= 0) {
+ off = fdt_setprop_string(blob, off, "status", "disabled");
+ if (off > 0)
+ printf("WARNING unable to set status for "
+ "fsl,srio-rmu %s\n", fdt_strerror(off));
+ }
+}
+
+void ft_srio_setup(void *blob)
+{
+ int srio1_used = 0, srio2_used = 0;
+ int srio_off;
+
+ /* search for srio node, if doesn't exist just return - nothing todo */
+ srio_off = fdt_node_offset_by_compatible(blob, -1, "fsl,srio");
+ if (srio_off < 0)
+ return ;
+
+#ifdef CONFIG_SRIO1
+ if (is_serdes_configured(SRIO1))
+ srio1_used = 1;
+#endif
+#ifdef CONFIG_SRIO2
+ if (is_serdes_configured(SRIO2))
+ srio2_used = 1;
+#endif
+
+ /* mark port1 disabled */
+ if (!srio1_used)
+ ft_disable_srio_port(blob, srio_off, 1);
+
+ /* mark port2 disabled */
+ if (!srio2_used)
+ ft_disable_srio_port(blob, srio_off, 2);
+
+ /* if both ports not used, disable controller, rmu and rman */
+ if (!srio1_used && !srio2_used) {
+ fdt_setprop_string(blob, srio_off, "status", "disabled");
+
+ ft_disable_rman(blob);
+ ft_disable_rmu(blob);
+ }
+}
+#endif
diff --git a/arch/powerpc/cpu/mpc8xxx/fsl_ifc.c b/arch/powerpc/cpu/mpc8xxx/fsl_ifc.c
new file mode 100644
index 0000000..4e8a441
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/fsl_ifc.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ * Author: Dipen Dudhat <dipen.dudhat@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/fsl_ifc.h>
+
+void print_ifc_regs(void)
+{
+ int i, j;
+
+ printf("IFC Controller Registers\n");
+ for (i = 0; i < CONFIG_SYS_FSL_IFC_BANK_COUNT; i++) {
+ printf("CSPR%d:0x%08X\tAMASK%d:0x%08X\tCSOR%d:0x%08X\n",
+ i, get_ifc_cspr(i), i, get_ifc_amask(i),
+ i, get_ifc_csor(i));
+ for (j = 0; j < 4; j++)
+ printf("IFC_FTIM%d:0x%08X\n", j, get_ifc_ftim(i, j));
+ }
+}
+
+void init_early_memctl_regs(void)
+{
+#if defined(CONFIG_SYS_CSPR0) && defined(CONFIG_SYS_CSOR0)
+ set_ifc_ftim(IFC_CS0, IFC_FTIM0, CONFIG_SYS_CS0_FTIM0);
+ set_ifc_ftim(IFC_CS0, IFC_FTIM1, CONFIG_SYS_CS0_FTIM1);
+ set_ifc_ftim(IFC_CS0, IFC_FTIM2, CONFIG_SYS_CS0_FTIM2);
+ set_ifc_ftim(IFC_CS0, IFC_FTIM3, CONFIG_SYS_CS0_FTIM3);
+
+#ifndef CONFIG_A003399_NOR_WORKAROUND
+#ifdef CONFIG_SYS_CSPR0_EXT
+ set_ifc_cspr_ext(IFC_CS0, CONFIG_SYS_CSPR0_EXT);
+#endif
+ set_ifc_cspr(IFC_CS0, CONFIG_SYS_CSPR0);
+ set_ifc_amask(IFC_CS0, CONFIG_SYS_AMASK0);
+ set_ifc_csor(IFC_CS0, CONFIG_SYS_CSOR0);
+#endif
+#endif
+
+#ifdef CONFIG_SYS_CSPR1_EXT
+ set_ifc_cspr_ext(IFC_CS1, CONFIG_SYS_CSPR1_EXT);
+#endif
+#if defined(CONFIG_SYS_CSPR1) && defined(CONFIG_SYS_CSOR1)
+ set_ifc_ftim(IFC_CS1, IFC_FTIM0, CONFIG_SYS_CS1_FTIM0);
+ set_ifc_ftim(IFC_CS1, IFC_FTIM1, CONFIG_SYS_CS1_FTIM1);
+ set_ifc_ftim(IFC_CS1, IFC_FTIM2, CONFIG_SYS_CS1_FTIM2);
+ set_ifc_ftim(IFC_CS1, IFC_FTIM3, CONFIG_SYS_CS1_FTIM3);
+
+ set_ifc_csor(IFC_CS1, CONFIG_SYS_CSOR1);
+ set_ifc_amask(IFC_CS1, CONFIG_SYS_AMASK1);
+ set_ifc_cspr(IFC_CS1, CONFIG_SYS_CSPR1);
+#endif
+
+#ifdef CONFIG_SYS_CSPR2_EXT
+ set_ifc_cspr_ext(IFC_CS2, CONFIG_SYS_CSPR2_EXT);
+#endif
+#if defined(CONFIG_SYS_CSPR2) && defined(CONFIG_SYS_CSOR2)
+ set_ifc_ftim(IFC_CS2, IFC_FTIM0, CONFIG_SYS_CS2_FTIM0);
+ set_ifc_ftim(IFC_CS2, IFC_FTIM1, CONFIG_SYS_CS2_FTIM1);
+ set_ifc_ftim(IFC_CS2, IFC_FTIM2, CONFIG_SYS_CS2_FTIM2);
+ set_ifc_ftim(IFC_CS2, IFC_FTIM3, CONFIG_SYS_CS2_FTIM3);
+
+ set_ifc_csor(IFC_CS2, CONFIG_SYS_CSOR2);
+ set_ifc_amask(IFC_CS2, CONFIG_SYS_AMASK2);
+ set_ifc_cspr(IFC_CS2, CONFIG_SYS_CSPR2);
+#endif
+
+#ifdef CONFIG_SYS_CSPR3_EXT
+ set_ifc_cspr_ext(IFC_CS3, CONFIG_SYS_CSPR3_EXT);
+#endif
+#if defined(CONFIG_SYS_CSPR3) && defined(CONFIG_SYS_CSOR3)
+ set_ifc_ftim(IFC_CS3, IFC_FTIM0, CONFIG_SYS_CS3_FTIM0);
+ set_ifc_ftim(IFC_CS3, IFC_FTIM1, CONFIG_SYS_CS3_FTIM1);
+ set_ifc_ftim(IFC_CS3, IFC_FTIM2, CONFIG_SYS_CS3_FTIM2);
+ set_ifc_ftim(IFC_CS3, IFC_FTIM3, CONFIG_SYS_CS3_FTIM3);
+
+ set_ifc_cspr(IFC_CS3, CONFIG_SYS_CSPR3);
+ set_ifc_amask(IFC_CS3, CONFIG_SYS_AMASK3);
+ set_ifc_csor(IFC_CS3, CONFIG_SYS_CSOR3);
+#endif
+
+#ifdef CONFIG_SYS_CSPR4_EXT
+ set_ifc_cspr_ext(IFC_CS4, CONFIG_SYS_CSPR4_EXT);
+#endif
+#if defined(CONFIG_SYS_CSPR4) && defined(CONFIG_SYS_CSOR4)
+ set_ifc_ftim(IFC_CS4, IFC_FTIM0, CONFIG_SYS_CS4_FTIM0);
+ set_ifc_ftim(IFC_CS4, IFC_FTIM1, CONFIG_SYS_CS4_FTIM1);
+ set_ifc_ftim(IFC_CS4, IFC_FTIM2, CONFIG_SYS_CS4_FTIM2);
+ set_ifc_ftim(IFC_CS4, IFC_FTIM3, CONFIG_SYS_CS4_FTIM3);
+
+ set_ifc_cspr(IFC_CS4, CONFIG_SYS_CSPR4);
+ set_ifc_amask(IFC_CS4, CONFIG_SYS_AMASK4);
+ set_ifc_csor(IFC_CS4, CONFIG_SYS_CSOR4);
+#endif
+
+#ifdef CONFIG_SYS_CSPR5_EXT
+ set_ifc_cspr_ext(IFC_CS5, CONFIG_SYS_CSPR5_EXT);
+#endif
+#if defined(CONFIG_SYS_CSPR5) && defined(CONFIG_SYS_CSOR5)
+ set_ifc_ftim(IFC_CS5, IFC_FTIM0, CONFIG_SYS_CS5_FTIM0);
+ set_ifc_ftim(IFC_CS5, IFC_FTIM1, CONFIG_SYS_CS5_FTIM1);
+ set_ifc_ftim(IFC_CS5, IFC_FTIM2, CONFIG_SYS_CS5_FTIM2);
+ set_ifc_ftim(IFC_CS5, IFC_FTIM3, CONFIG_SYS_CS5_FTIM3);
+
+ set_ifc_cspr(IFC_CS5, CONFIG_SYS_CSPR5);
+ set_ifc_amask(IFC_CS5, CONFIG_SYS_AMASK5);
+ set_ifc_csor(IFC_CS5, CONFIG_SYS_CSOR5);
+#endif
+
+#ifdef CONFIG_SYS_CSPR6_EXT
+ set_ifc_cspr_ext(IFC_CS6, CONFIG_SYS_CSPR6_EXT);
+#endif
+#if defined(CONFIG_SYS_CSPR6) && defined(CONFIG_SYS_CSOR6)
+ set_ifc_ftim(IFC_CS6, IFC_FTIM0, CONFIG_SYS_CS6_FTIM0);
+ set_ifc_ftim(IFC_CS6, IFC_FTIM1, CONFIG_SYS_CS6_FTIM1);
+ set_ifc_ftim(IFC_CS6, IFC_FTIM2, CONFIG_SYS_CS6_FTIM2);
+ set_ifc_ftim(IFC_CS6, IFC_FTIM3, CONFIG_SYS_CS6_FTIM3);
+
+ set_ifc_cspr(IFC_CS6, CONFIG_SYS_CSPR6);
+ set_ifc_amask(IFC_CS6, CONFIG_SYS_AMASK6);
+ set_ifc_csor(IFC_CS6, CONFIG_SYS_CSOR6);
+#endif
+
+#ifdef CONFIG_SYS_CSPR7_EXT
+ set_ifc_cspr_ext(IFC_CS7, CONFIG_SYS_CSPR7_EXT);
+#endif
+#if defined(CONFIG_SYS_CSPR7) && defined(CONFIG_SYS_CSOR7)
+ set_ifc_ftim(IFC_CS7, IFC_FTIM0, CONFIG_SYS_CS7_FTIM0);
+ set_ifc_ftim(IFC_CS7, IFC_FTIM1, CONFIG_SYS_CS7_FTIM1);
+ set_ifc_ftim(IFC_CS7, IFC_FTIM2, CONFIG_SYS_CS7_FTIM2);
+ set_ifc_ftim(IFC_CS7, IFC_FTIM3, CONFIG_SYS_CS7_FTIM3);
+
+ set_ifc_cspr(IFC_CS7, CONFIG_SYS_CSPR7);
+ set_ifc_amask(IFC_CS7, CONFIG_SYS_AMASK7);
+ set_ifc_csor(IFC_CS7, CONFIG_SYS_CSOR7);
+#endif
+}
diff --git a/arch/powerpc/cpu/mpc8xxx/fsl_lbc.c b/arch/powerpc/cpu/mpc8xxx/fsl_lbc.c
new file mode 100644
index 0000000..c1fe579
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/fsl_lbc.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/fsl_lbc.h>
+
+#ifdef CONFIG_MPC85xx
+/* Boards should provide their own version of this if they use lbc sdram */
+static void __lbc_sdram_init(void)
+{
+ /* Do nothing */
+}
+void lbc_sdram_init(void) __attribute__((weak, alias("__lbc_sdram_init")));
+#endif
+
+
+void print_lbc_regs(void)
+{
+ int i;
+
+ printf("\nLocal Bus Controller Registers\n");
+ for (i = 0; i < 8; i++) {
+ printf("BR%d\t0x%08X\tOR%d\t0x%08X\n",
+ i, get_lbc_br(i), i, get_lbc_or(i));
+ }
+ printf("LBCR\t0x%08X\tLCRR\t0x%08X\n",
+ get_lbc_lbcr(), get_lbc_lcrr());
+}
+
+void init_early_memctl_regs(void)
+{
+ uint init_br1 = 1;
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_ELBC_A001
+ /* Set the local bus monitor timeout value to the maximum */
+ clrsetbits_be32(&(LBC_BASE_ADDR)->lbcr, LBCR_BMT|LBCR_BMTPS, 0xf);
+#endif
+
+#ifdef CONFIG_MPC85xx
+ /* if cs1 is already set via debugger, leave cs0/cs1 alone */
+ if (get_lbc_br(1) & BR_V)
+ init_br1 = 0;
+#endif
+
+ /*
+ * Map banks 0 (and maybe 1) to the FLASH banks 0 (and 1) at
+ * preliminary addresses - these have to be modified later
+ * when FLASH size has been determined
+ */
+#if defined(CONFIG_SYS_OR0_REMAP)
+ set_lbc_or(0, CONFIG_SYS_OR0_REMAP);
+#endif
+#if defined(CONFIG_SYS_OR1_REMAP)
+ set_lbc_or(1, CONFIG_SYS_OR1_REMAP);
+#endif
+ /* now restrict to preliminary range */
+ if (init_br1) {
+#if defined(CONFIG_SYS_BR0_PRELIM) && defined(CONFIG_SYS_OR0_PRELIM)
+ set_lbc_br(0, CONFIG_SYS_BR0_PRELIM);
+ set_lbc_or(0, CONFIG_SYS_OR0_PRELIM);
+#endif
+
+#if defined(CONFIG_SYS_BR1_PRELIM) && defined(CONFIG_SYS_OR1_PRELIM)
+ set_lbc_or(1, CONFIG_SYS_OR1_PRELIM);
+ set_lbc_br(1, CONFIG_SYS_BR1_PRELIM);
+#endif
+ }
+
+#if defined(CONFIG_SYS_BR2_PRELIM) && defined(CONFIG_SYS_OR2_PRELIM)
+ set_lbc_or(2, CONFIG_SYS_OR2_PRELIM);
+ set_lbc_br(2, CONFIG_SYS_BR2_PRELIM);
+#endif
+
+#if defined(CONFIG_SYS_BR3_PRELIM) && defined(CONFIG_SYS_OR3_PRELIM)
+ set_lbc_or(3, CONFIG_SYS_OR3_PRELIM);
+ set_lbc_br(3, CONFIG_SYS_BR3_PRELIM);
+#endif
+
+#if defined(CONFIG_SYS_BR4_PRELIM) && defined(CONFIG_SYS_OR4_PRELIM)
+ set_lbc_or(4, CONFIG_SYS_OR4_PRELIM);
+ set_lbc_br(4, CONFIG_SYS_BR4_PRELIM);
+#endif
+
+#if defined(CONFIG_SYS_BR5_PRELIM) && defined(CONFIG_SYS_OR5_PRELIM)
+ set_lbc_or(5, CONFIG_SYS_OR5_PRELIM);
+ set_lbc_br(5, CONFIG_SYS_BR5_PRELIM);
+#endif
+
+#if defined(CONFIG_SYS_BR6_PRELIM) && defined(CONFIG_SYS_OR6_PRELIM)
+ set_lbc_or(6, CONFIG_SYS_OR6_PRELIM);
+ set_lbc_br(6, CONFIG_SYS_BR6_PRELIM);
+#endif
+
+#if defined(CONFIG_SYS_BR7_PRELIM) && defined(CONFIG_SYS_OR7_PRELIM)
+ set_lbc_or(7, CONFIG_SYS_OR7_PRELIM);
+ set_lbc_br(7, CONFIG_SYS_BR7_PRELIM);
+#endif
+}
+
+/*
+ * Configures a UPM. The function requires the respective MxMR to be set
+ * before calling this function. "size" is the number or entries, not a sizeof.
+ */
+void upmconfig(uint upm, uint *table, uint size)
+{
+ fsl_lbc_t *lbc = LBC_BASE_ADDR;
+ int i, mad, old_mad = 0;
+ u32 mask = (~MxMR_OP_MSK & ~MxMR_MAD_MSK);
+ u32 msel = BR_UPMx_TO_MSEL(upm);
+ u32 *mxmr = &lbc->mamr + upm;
+ volatile u8 *dummy = NULL;
+
+ if (upm < UPMA || upm > UPMC) {
+ printf("Error: %s() Bad UPM index %d\n", __func__, upm);
+ hang();
+ }
+
+ /*
+ * Find the address for the dummy write - scan all of the BRs until we
+ * find one matching the UPM and extract the base address bits from it.
+ */
+ for (i = 0; i < 8; i++) {
+ if ((get_lbc_br(i) & (BR_V | BR_MSEL)) == (BR_V | msel)) {
+ dummy = (volatile u8 *)(get_lbc_br(i) & BR_BA);
+ break;
+ }
+ }
+
+ if (!dummy) {
+ printf("Error: %s() No matching BR\n", __func__);
+ hang();
+ }
+
+ /* Program UPM using steps outlined by the reference manual */
+ for (i = 0; i < size; i++) {
+ out_be32(mxmr, (in_be32(mxmr) & mask) | MxMR_OP_WARR | i);
+ out_be32(&lbc->mdr, table[i]);
+ (void)in_be32(&lbc->mdr);
+ *dummy = 0;
+ do {
+ mad = in_be32(mxmr) & MxMR_MAD_MSK;
+ } while (mad <= old_mad && !(!mad && i == (size-1)));
+ old_mad = mad;
+ }
+
+ /* Return to normal operation */
+ out_be32(mxmr, (in_be32(mxmr) & mask) | MxMR_OP_NORM);
+}
diff --git a/arch/powerpc/cpu/mpc8xxx/law.c b/arch/powerpc/cpu/mpc8xxx/law.c
new file mode 100644
index 0000000..6f9d568
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/law.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <linux/compiler.h>
+#include <asm/fsl_law.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define FSL_HW_NUM_LAWS CONFIG_SYS_FSL_NUM_LAWS
+
+#ifdef CONFIG_FSL_CORENET
+#define LAW_BASE (CONFIG_SYS_FSL_CORENET_CCM_ADDR)
+#define LAWAR_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawar)
+#define LAWBARH_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawbarh)
+#define LAWBARL_ADDR(x) (&((ccsr_local_t *)LAW_BASE)->law[x].lawbarl)
+#define LAWBAR_SHIFT 0
+#else
+#define LAW_BASE (CONFIG_SYS_IMMR + 0xc08)
+#define LAWAR_ADDR(x) ((u32 *)LAW_BASE + 8 * x + 2)
+#define LAWBAR_ADDR(x) ((u32 *)LAW_BASE + 8 * x)
+#define LAWBAR_SHIFT 12
+#endif
+
+
+static inline phys_addr_t get_law_base_addr(int idx)
+{
+#ifdef CONFIG_FSL_CORENET
+ return (phys_addr_t)
+ ((u64)in_be32(LAWBARH_ADDR(idx)) << 32) |
+ in_be32(LAWBARL_ADDR(idx));
+#else
+ return (phys_addr_t)in_be32(LAWBAR_ADDR(idx)) << LAWBAR_SHIFT;
+#endif
+}
+
+static inline void set_law_base_addr(int idx, phys_addr_t addr)
+{
+#ifdef CONFIG_FSL_CORENET
+ out_be32(LAWBARL_ADDR(idx), addr & 0xffffffff);
+ out_be32(LAWBARH_ADDR(idx), (u64)addr >> 32);
+#else
+ out_be32(LAWBAR_ADDR(idx), addr >> LAWBAR_SHIFT);
+#endif
+}
+
+void set_law(u8 idx, phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
+{
+ gd->arch.used_laws |= (1 << idx);
+
+ out_be32(LAWAR_ADDR(idx), 0);
+ set_law_base_addr(idx, addr);
+ out_be32(LAWAR_ADDR(idx), LAW_EN | ((u32)id << 20) | (u32)sz);
+
+ /* Read back so that we sync the writes */
+ in_be32(LAWAR_ADDR(idx));
+}
+
+void disable_law(u8 idx)
+{
+ gd->arch.used_laws &= ~(1 << idx);
+
+ out_be32(LAWAR_ADDR(idx), 0);
+ set_law_base_addr(idx, 0);
+
+ /* Read back so that we sync the writes */
+ in_be32(LAWAR_ADDR(idx));
+
+ return;
+}
+
+#if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_SPL_BUILD)
+static int get_law_entry(u8 i, struct law_entry *e)
+{
+ u32 lawar;
+
+ lawar = in_be32(LAWAR_ADDR(i));
+
+ if (!(lawar & LAW_EN))
+ return 0;
+
+ e->addr = get_law_base_addr(i);
+ e->size = lawar & 0x3f;
+ e->trgt_id = (lawar >> 20) & 0xff;
+
+ return 1;
+}
+#endif
+
+int set_next_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
+{
+ u32 idx = ffz(gd->arch.used_laws);
+
+ if (idx >= FSL_HW_NUM_LAWS)
+ return -1;
+
+ set_law(idx, addr, sz, id);
+
+ return idx;
+}
+
+#if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_SPL_BUILD)
+int set_last_law(phys_addr_t addr, enum law_size sz, enum law_trgt_if id)
+{
+ u32 idx;
+
+ /* we have no LAWs free */
+ if (gd->arch.used_laws == -1)
+ return -1;
+
+ /* grab the last free law */
+ idx = __ilog2(~(gd->arch.used_laws));
+
+ if (idx >= FSL_HW_NUM_LAWS)
+ return -1;
+
+ set_law(idx, addr, sz, id);
+
+ return idx;
+}
+
+struct law_entry find_law(phys_addr_t addr)
+{
+ struct law_entry entry;
+ int i;
+
+ entry.index = -1;
+ entry.addr = 0;
+ entry.size = 0;
+ entry.trgt_id = 0;
+
+ for (i = 0; i < FSL_HW_NUM_LAWS; i++) {
+ u64 upper;
+
+ if (!get_law_entry(i, &entry))
+ continue;
+
+ upper = entry.addr + (2ull << entry.size);
+ if ((addr >= entry.addr) && (addr < upper)) {
+ entry.index = i;
+ break;
+ }
+ }
+
+ return entry;
+}
+
+void print_laws(void)
+{
+ int i;
+ u32 lawar;
+
+ printf("\nLocal Access Window Configuration\n");
+ for (i = 0; i < FSL_HW_NUM_LAWS; i++) {
+ lawar = in_be32(LAWAR_ADDR(i));
+#ifdef CONFIG_FSL_CORENET
+ printf("LAWBARH%02d: 0x%08x LAWBARL%02d: 0x%08x",
+ i, in_be32(LAWBARH_ADDR(i)),
+ i, in_be32(LAWBARL_ADDR(i)));
+#else
+ printf("LAWBAR%02d: 0x%08x", i, in_be32(LAWBAR_ADDR(i)));
+#endif
+ printf(" LAWAR%02d: 0x%08x\n", i, lawar);
+ printf("\t(EN: %d TGT: 0x%02x SIZE: ",
+ (lawar & LAW_EN) ? 1 : 0, (lawar >> 20) & 0xff);
+ print_size(lawar_size(lawar), ")\n");
+ }
+
+ return;
+}
+
+/* use up to 2 LAWs for DDR, used the last available LAWs */
+int set_ddr_laws(u64 start, u64 sz, enum law_trgt_if id)
+{
+ u64 start_align, law_sz;
+ int law_sz_enc;
+
+ if (start == 0)
+ start_align = 1ull << (LAW_SIZE_32G + 1);
+ else
+ start_align = 1ull << (ffs64(start) - 1);
+ law_sz = min(start_align, sz);
+ law_sz_enc = __ilog2_u64(law_sz) - 1;
+
+ if (set_last_law(start, law_sz_enc, id) < 0)
+ return -1;
+
+ /* recalculate size based on what was actually covered by the law */
+ law_sz = 1ull << __ilog2_u64(law_sz);
+
+ /* do we still have anything to map */
+ sz = sz - law_sz;
+ if (sz) {
+ start += law_sz;
+
+ start_align = 1ull << (ffs64(start) - 1);
+ law_sz = min(start_align, sz);
+ law_sz_enc = __ilog2_u64(law_sz) - 1;
+
+ if (set_last_law(start, law_sz_enc, id) < 0)
+ return -1;
+ } else {
+ return 0;
+ }
+
+ /* do we still have anything to map */
+ sz = sz - law_sz;
+ if (sz)
+ return 1;
+
+ return 0;
+}
+#endif /* not SPL */
+
+void init_laws(void)
+{
+ int i;
+
+#if FSL_HW_NUM_LAWS < 32
+ gd->arch.used_laws = ~((1 << FSL_HW_NUM_LAWS) - 1);
+#elif FSL_HW_NUM_LAWS == 32
+ gd->arch.used_laws = 0;
+#else
+#error FSL_HW_NUM_LAWS can not be greater than 32 w/o code changes
+#endif
+
+ /*
+ * Any LAWs that were set up before we booted assume they are meant to
+ * be around and mark them used.
+ */
+ for (i = 0; i < FSL_HW_NUM_LAWS; i++) {
+ u32 lawar = in_be32(LAWAR_ADDR(i));
+
+ if (lawar & LAW_EN)
+ gd->arch.used_laws |= (1 << i);
+ }
+
+#if (defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL)) || \
+ (defined(CONFIG_SPL) && !defined(CONFIG_SPL_BUILD))
+ /*
+ * in SPL boot we've already parsed the law_table and setup those LAWs
+ * so don't do it again.
+ */
+ return;
+#endif
+
+ for (i = 0; i < num_law_entries; i++) {
+ if (law_table[i].index == -1)
+ set_next_law(law_table[i].addr, law_table[i].size,
+ law_table[i].trgt_id);
+ else
+ set_law(law_table[i].index, law_table[i].addr,
+ law_table[i].size, law_table[i].trgt_id);
+ }
+
+#ifdef CONFIG_SRIO_PCIE_BOOT_SLAVE
+ /* check RCW to get which port is used for boot */
+ ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
+ u32 bootloc = in_be32(&gur->rcwsr[6]);
+ /*
+ * in SRIO or PCIE boot we need to set specail LAWs for
+ * SRIO or PCIE interfaces.
+ */
+ switch ((bootloc & FSL_CORENET_RCWSR6_BOOT_LOC) >> 23) {
+ case 0x0: /* boot from PCIE1 */
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_PCIE_1);
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_PCIE_1);
+ break;
+ case 0x1: /* boot from PCIE2 */
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_PCIE_2);
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_PCIE_2);
+ break;
+ case 0x2: /* boot from PCIE3 */
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_PCIE_3);
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_PCIE_3);
+ break;
+ case 0x8: /* boot from SRIO1 */
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_RIO_1);
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_RIO_1);
+ break;
+ case 0x9: /* boot from SRIO2 */
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_RIO_2);
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_RIO_2);
+ break;
+ default:
+ break;
+ }
+#endif
+
+ return ;
+}
diff --git a/arch/powerpc/cpu/mpc8xxx/srio.c b/arch/powerpc/cpu/mpc8xxx/srio.c
new file mode 100644
index 0000000..90d1065
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/srio.c
@@ -0,0 +1,459 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+#include <asm/fsl_law.h>
+#include <asm/fsl_serdes.h>
+#include <asm/fsl_srio.h>
+#include <asm/errno.h>
+
+#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER
+#define SRIO_PORT_ACCEPT_ALL 0x10000001
+#define SRIO_IB_ATMU_AR 0x80f55000
+#define SRIO_OB_ATMU_AR_MAINT 0x80077000
+#define SRIO_OB_ATMU_AR_RW 0x80045000
+#define SRIO_LCSBA1CSR_OFFSET 0x5c
+#define SRIO_MAINT_WIN_SIZE 0x1000000 /* 16M */
+#define SRIO_RW_WIN_SIZE 0x100000 /* 1M */
+#define SRIO_LCSBA1CSR 0x60000000
+#endif
+
+#if defined(CONFIG_FSL_CORENET)
+#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2
+ #define _DEVDISR_SRIO1 FSL_CORENET_DEVDISR3_SRIO1
+ #define _DEVDISR_SRIO2 FSL_CORENET_DEVDISR3_SRIO2
+#else
+ #define _DEVDISR_SRIO1 FSL_CORENET_DEVDISR_SRIO1
+ #define _DEVDISR_SRIO2 FSL_CORENET_DEVDISR_SRIO2
+#endif
+ #define _DEVDISR_RMU FSL_CORENET_DEVDISR_RMU
+ #define CONFIG_SYS_MPC8xxx_GUTS_ADDR CONFIG_SYS_MPC85xx_GUTS_ADDR
+#elif defined(CONFIG_MPC85xx)
+ #define _DEVDISR_SRIO1 MPC85xx_DEVDISR_SRIO
+ #define _DEVDISR_SRIO2 MPC85xx_DEVDISR_SRIO
+ #define _DEVDISR_RMU MPC85xx_DEVDISR_RMSG
+ #define CONFIG_SYS_MPC8xxx_GUTS_ADDR CONFIG_SYS_MPC85xx_GUTS_ADDR
+#elif defined(CONFIG_MPC86xx)
+ #define _DEVDISR_SRIO1 MPC86xx_DEVDISR_SRIO
+ #define _DEVDISR_SRIO2 MPC86xx_DEVDISR_SRIO
+ #define _DEVDISR_RMU MPC86xx_DEVDISR_RMSG
+ #define CONFIG_SYS_MPC8xxx_GUTS_ADDR \
+ (&((immap_t *)CONFIG_SYS_IMMR)->im_gur)
+#else
+#error "No defines for DEVDISR_SRIO"
+#endif
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_SRIO_A004034
+/*
+ * Erratum A-004034
+ * Affects: SRIO
+ * Description: During port initialization, the SRIO port performs
+ * lane synchronization (detecting valid symbols on a lane) and
+ * lane alignment (coordinating multiple lanes to receive valid data
+ * across lanes). Internal errors in lane synchronization and lane
+ * alignment may cause failure to achieve link initialization at
+ * the configured port width.
+ * An SRIO port configured as a 4x port may see one of these scenarios:
+ * 1. One or more lanes fails to achieve lane synchronization. Depending
+ * on which lanes fail, this may result in downtraining from 4x to 1x
+ * on lane 0, 4x to 1x on lane R (redundant lane).
+ * 2. The link may fail to achieve lane alignment as a 4x, even though
+ * all 4 lanes achieve lane synchronization, and downtrain to a 1x.
+ * An SRIO port configured as a 1x port may fail to complete port
+ * initialization (PnESCSR[PU] never deasserts) because of scenario 1.
+ * Impact: SRIO port may downtrain to 1x, or may fail to complete
+ * link initialization. Once a port completes link initialization
+ * successfully, it will operate normally.
+ */
+static int srio_erratum_a004034(u8 port)
+{
+ serdes_corenet_t *srds_regs;
+ u32 conf_lane;
+ u32 init_lane;
+ int idx, first, last;
+ u32 i;
+ unsigned long long end_tick;
+ struct ccsr_rio *srio_regs = (void *)CONFIG_SYS_FSL_SRIO_ADDR;
+
+ srds_regs = (void *)(CONFIG_SYS_FSL_CORENET_SERDES_ADDR);
+ conf_lane = (in_be32((void *)&srds_regs->srdspccr0)
+ >> (12 - port * 4)) & 0x3;
+ init_lane = (in_be32((void *)&srio_regs->lp_serial
+ .port[port].pccsr) >> 27) & 0x7;
+
+ /*
+ * Start a counter set to ~2 ms after the SERDES reset is
+ * complete (SERDES SRDSBnRSTCTL[RST_DONE]=1 for n
+ * corresponding to the SERDES bank/PLL for the SRIO port).
+ */
+ if (in_be32((void *)&srds_regs->bank[0].rstctl)
+ & SRDS_RSTCTL_RSTDONE) {
+ /*
+ * Poll the port uninitialized status (SRIO PnESCSR[PO]) until
+ * PO=1 or the counter expires. If the counter expires, the
+ * port has failed initialization: go to recover steps. If PO=1
+ * and the desired port width is 1x, go to normal steps. If
+ * PO = 1 and the desired port width is 4x, go to recover steps.
+ */
+ end_tick = usec2ticks(2000) + get_ticks();
+ do {
+ if (in_be32((void *)&srio_regs->lp_serial
+ .port[port].pescsr) & 0x2) {
+ if (conf_lane == 0x1)
+ goto host_ok;
+ else {
+ if (init_lane == 0x2)
+ goto host_ok;
+ else
+ break;
+ }
+ }
+ } while (end_tick > get_ticks());
+
+ /* recover at most 3 times */
+ for (i = 0; i < 3; i++) {
+ /* Set SRIO PnCCSR[PD]=1 */
+ setbits_be32((void *)&srio_regs->lp_serial
+ .port[port].pccsr,
+ 0x800000);
+ /*
+ * Set SRIO PnPCR[OBDEN] on the host to
+ * enable the discarding of any pending packets.
+ */
+ setbits_be32((void *)&srio_regs->impl.port[port].pcr,
+ 0x04);
+ /* Wait 50 us */
+ udelay(50);
+ /* Run sync command */
+ isync();
+
+ if (port)
+ first = serdes_get_first_lane(SRIO2);
+ else
+ first = serdes_get_first_lane(SRIO1);
+ if (unlikely(first < 0))
+ return -ENODEV;
+ if (conf_lane == 0x1)
+ last = first;
+ else
+ last = first + 3;
+ /*
+ * Set SERDES BnGCRm0[RRST]=0 for each SRIO
+ * bank n and lane m.
+ */
+ for (idx = first; idx <= last; idx++)
+ clrbits_be32(&srds_regs->lane[idx].gcr0,
+ SRDS_GCR0_RRST);
+ /*
+ * Read SERDES BnGCRm0 for each SRIO
+ * bank n and lane m
+ */
+ for (idx = first; idx <= last; idx++)
+ in_be32(&srds_regs->lane[idx].gcr0);
+ /* Run sync command */
+ isync();
+ /* Wait >= 100 ns */
+ udelay(1);
+ /*
+ * Set SERDES BnGCRm0[RRST]=1 for each SRIO
+ * bank n and lane m.
+ */
+ for (idx = first; idx <= last; idx++)
+ setbits_be32(&srds_regs->lane[idx].gcr0,
+ SRDS_GCR0_RRST);
+ /*
+ * Read SERDES BnGCRm0 for each SRIO
+ * bank n and lane m
+ */
+ for (idx = first; idx <= last; idx++)
+ in_be32(&srds_regs->lane[idx].gcr0);
+ /* Run sync command */
+ isync();
+ /* Wait >= 300 ns */
+ udelay(1);
+
+ /* Write 1 to clear all bits in SRIO PnSLCSR */
+ out_be32((void *)&srio_regs->impl.port[port].slcsr,
+ 0xffffffff);
+ /* Clear SRIO PnPCR[OBDEN] on the host */
+ clrbits_be32((void *)&srio_regs->impl.port[port].pcr,
+ 0x04);
+ /* Set SRIO PnCCSR[PD]=0 */
+ clrbits_be32((void *)&srio_regs->lp_serial
+ .port[port].pccsr,
+ 0x800000);
+ /* Wait >= 24 ms */
+ udelay(24000);
+ /* Poll the state of the port again */
+ init_lane =
+ (in_be32((void *)&srio_regs->lp_serial
+ .port[port].pccsr) >> 27) & 0x7;
+ if (in_be32((void *)&srio_regs->lp_serial
+ .port[port].pescsr) & 0x2) {
+ if (conf_lane == 0x1)
+ goto host_ok;
+ else {
+ if (init_lane == 0x2)
+ goto host_ok;
+ }
+ }
+ if (i == 2)
+ return -ENODEV;
+ }
+ } else
+ return -ENODEV;
+
+host_ok:
+ /* Poll PnESCSR[OES] on the host until it is clear */
+ end_tick = usec2ticks(1000000) + get_ticks();
+ do {
+ if (!(in_be32((void *)&srio_regs->lp_serial.port[port].pescsr)
+ & 0x10000)) {
+ out_be32(((void *)&srio_regs->lp_serial
+ .port[port].pescsr), 0xffffffff);
+ out_be32(((void *)&srio_regs->phys_err
+ .port[port].edcsr), 0);
+ out_be32(((void *)&srio_regs->logical_err.ltledcsr), 0);
+ return 0;
+ }
+ } while (end_tick > get_ticks());
+
+ return -ENODEV;
+}
+#endif
+
+void srio_init(void)
+{
+ ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC8xxx_GUTS_ADDR;
+ int srio1_used = 0, srio2_used = 0;
+ u32 *devdisr;
+
+#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2
+ devdisr = &gur->devdisr3;
+#else
+ devdisr = &gur->devdisr;
+#endif
+ if (is_serdes_configured(SRIO1)) {
+ set_next_law(CONFIG_SYS_SRIO1_MEM_PHYS,
+ law_size_bits(CONFIG_SYS_SRIO1_MEM_SIZE),
+ LAW_TRGT_IF_RIO_1);
+ srio1_used = 1;
+#ifdef CONFIG_SYS_FSL_ERRATUM_SRIO_A004034
+ if (srio_erratum_a004034(0) < 0)
+ printf("SRIO1: enabled but port error\n");
+ else
+#endif
+ printf("SRIO1: enabled\n");
+ } else {
+ printf("SRIO1: disabled\n");
+ }
+
+#ifdef CONFIG_SRIO2
+ if (is_serdes_configured(SRIO2)) {
+ set_next_law(CONFIG_SYS_SRIO2_MEM_PHYS,
+ law_size_bits(CONFIG_SYS_SRIO2_MEM_SIZE),
+ LAW_TRGT_IF_RIO_2);
+ srio2_used = 1;
+#ifdef CONFIG_SYS_FSL_ERRATUM_SRIO_A004034
+ if (srio_erratum_a004034(1) < 0)
+ printf("SRIO2: enabled but port error\n");
+ else
+#endif
+ printf("SRIO2: enabled\n");
+
+ } else {
+ printf("SRIO2: disabled\n");
+ }
+#endif
+
+#ifdef CONFIG_FSL_CORENET
+ /* On FSL_CORENET devices we can disable individual ports */
+ if (!srio1_used)
+ setbits_be32(devdisr, _DEVDISR_SRIO1);
+ if (!srio2_used)
+ setbits_be32(devdisr, _DEVDISR_SRIO2);
+#endif
+
+ /* neither port is used - disable everything */
+ if (!srio1_used && !srio2_used) {
+ setbits_be32(devdisr, _DEVDISR_SRIO1);
+ setbits_be32(devdisr, _DEVDISR_SRIO2);
+ setbits_be32(devdisr, _DEVDISR_RMU);
+ }
+}
+
+#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER
+void srio_boot_master(int port)
+{
+ struct ccsr_rio *srio = (void *)CONFIG_SYS_FSL_SRIO_ADDR;
+
+ /* set port accept-all */
+ out_be32((void *)&srio->impl.port[port - 1].ptaacr,
+ SRIO_PORT_ACCEPT_ALL);
+
+ debug("SRIOBOOT - MASTER: Master port [ %d ] for srio boot.\n", port);
+ /* configure inbound window for slave's u-boot image */
+ debug("SRIOBOOT - MASTER: Inbound window for slave's image; "
+ "Local = 0x%llx, Srio = 0x%llx, Size = 0x%x\n",
+ (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
+ (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS1,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
+ out_be32((void *)&srio->atmu.port[port - 1].inbw[0].riwtar,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS >> 12);
+ out_be32((void *)&srio->atmu.port[port - 1].inbw[0].riwbar,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS1 >> 12);
+ out_be32((void *)&srio->atmu.port[port - 1].inbw[0].riwar,
+ SRIO_IB_ATMU_AR
+ | atmu_size_mask(CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE));
+
+ /* configure inbound window for slave's u-boot image */
+ debug("SRIOBOOT - MASTER: Inbound window for slave's image; "
+ "Local = 0x%llx, Srio = 0x%llx, Size = 0x%x\n",
+ (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
+ (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS2,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
+ out_be32((void *)&srio->atmu.port[port - 1].inbw[1].riwtar,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS >> 12);
+ out_be32((void *)&srio->atmu.port[port - 1].inbw[1].riwbar,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS2 >> 12);
+ out_be32((void *)&srio->atmu.port[port - 1].inbw[1].riwar,
+ SRIO_IB_ATMU_AR
+ | atmu_size_mask(CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE));
+
+ /* configure inbound window for slave's ucode and ENV */
+ debug("SRIOBOOT - MASTER: Inbound window for slave's ucode and ENV; "
+ "Local = 0x%llx, Srio = 0x%llx, Size = 0x%x\n",
+ (u64)CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_PHYS,
+ (u64)CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_BUS,
+ CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE);
+ out_be32((void *)&srio->atmu.port[port - 1].inbw[2].riwtar,
+ CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_PHYS >> 12);
+ out_be32((void *)&srio->atmu.port[port - 1].inbw[2].riwbar,
+ CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_BUS >> 12);
+ out_be32((void *)&srio->atmu.port[port - 1].inbw[2].riwar,
+ SRIO_IB_ATMU_AR
+ | atmu_size_mask(CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE));
+}
+
+void srio_boot_master_release_slave(int port)
+{
+ struct ccsr_rio *srio = (void *)CONFIG_SYS_FSL_SRIO_ADDR;
+ u32 escsr;
+ debug("SRIOBOOT - MASTER: "
+ "Check the port status and release slave core ...\n");
+
+ escsr = in_be32((void *)&srio->lp_serial.port[port - 1].pescsr);
+ if (escsr & 0x2) {
+ if (escsr & 0x10100) {
+ debug("SRIOBOOT - MASTER: Port [ %d ] is error.\n",
+ port);
+ } else {
+ debug("SRIOBOOT - MASTER: "
+ "Port [ %d ] is ready, now release slave's core ...\n",
+ port);
+ /*
+ * configure outbound window
+ * with maintenance attribute to set slave's LCSBA1CSR
+ */
+ out_be32((void *)&srio->atmu.port[port - 1]
+ .outbw[1].rowtar, 0);
+ out_be32((void *)&srio->atmu.port[port - 1]
+ .outbw[1].rowtear, 0);
+ if (port - 1)
+ out_be32((void *)&srio->atmu.port[port - 1]
+ .outbw[1].rowbar,
+ CONFIG_SYS_SRIO2_MEM_PHYS >> 12);
+ else
+ out_be32((void *)&srio->atmu.port[port - 1]
+ .outbw[1].rowbar,
+ CONFIG_SYS_SRIO1_MEM_PHYS >> 12);
+ out_be32((void *)&srio->atmu.port[port - 1]
+ .outbw[1].rowar,
+ SRIO_OB_ATMU_AR_MAINT
+ | atmu_size_mask(SRIO_MAINT_WIN_SIZE));
+
+ /*
+ * configure outbound window
+ * with R/W attribute to set slave's BRR
+ */
+ out_be32((void *)&srio->atmu.port[port - 1]
+ .outbw[2].rowtar,
+ SRIO_LCSBA1CSR >> 9);
+ out_be32((void *)&srio->atmu.port[port - 1]
+ .outbw[2].rowtear, 0);
+ if (port - 1)
+ out_be32((void *)&srio->atmu.port[port - 1]
+ .outbw[2].rowbar,
+ (CONFIG_SYS_SRIO2_MEM_PHYS
+ + SRIO_MAINT_WIN_SIZE) >> 12);
+ else
+ out_be32((void *)&srio->atmu.port[port - 1]
+ .outbw[2].rowbar,
+ (CONFIG_SYS_SRIO1_MEM_PHYS
+ + SRIO_MAINT_WIN_SIZE) >> 12);
+ out_be32((void *)&srio->atmu.port[port - 1]
+ .outbw[2].rowar,
+ SRIO_OB_ATMU_AR_RW
+ | atmu_size_mask(SRIO_RW_WIN_SIZE));
+
+ /*
+ * Set the LCSBA1CSR register in slave
+ * by the maint-outbound window
+ */
+ if (port - 1) {
+ out_be32((void *)CONFIG_SYS_SRIO2_MEM_VIRT
+ + SRIO_LCSBA1CSR_OFFSET,
+ SRIO_LCSBA1CSR);
+ while (in_be32((void *)CONFIG_SYS_SRIO2_MEM_VIRT
+ + SRIO_LCSBA1CSR_OFFSET)
+ != SRIO_LCSBA1CSR)
+ ;
+ /*
+ * And then set the BRR register
+ * to release slave core
+ */
+ out_be32((void *)CONFIG_SYS_SRIO2_MEM_VIRT
+ + SRIO_MAINT_WIN_SIZE
+ + CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET,
+ CONFIG_SRIO_PCIE_BOOT_RELEASE_MASK);
+ } else {
+ out_be32((void *)CONFIG_SYS_SRIO1_MEM_VIRT
+ + SRIO_LCSBA1CSR_OFFSET,
+ SRIO_LCSBA1CSR);
+ while (in_be32((void *)CONFIG_SYS_SRIO1_MEM_VIRT
+ + SRIO_LCSBA1CSR_OFFSET)
+ != SRIO_LCSBA1CSR)
+ ;
+ /*
+ * And then set the BRR register
+ * to release slave core
+ */
+ out_be32((void *)CONFIG_SYS_SRIO1_MEM_VIRT
+ + SRIO_MAINT_WIN_SIZE
+ + CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET,
+ CONFIG_SRIO_PCIE_BOOT_RELEASE_MASK);
+ }
+ debug("SRIOBOOT - MASTER: "
+ "Release slave successfully! Now the slave should start up!\n");
+ }
+ } else
+ debug("SRIOBOOT - MASTER: Port [ %d ] is not ready.\n", port);
+}
+#endif
diff --git a/arch/powerpc/cpu/ppc4xx/40x_spd_sdram.c b/arch/powerpc/cpu/ppc4xx/40x_spd_sdram.c
new file mode 100644
index 0000000..48aa753
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/40x_spd_sdram.c
@@ -0,0 +1,464 @@
+/*
+ * arch/powerpc/cpu/ppc4xx/40x_spd_sdram.c
+ * This SPD SDRAM detection code supports IBM/AMCC PPC44x cpu with a
+ * SDRAM controller. Those are all current 405 PPC's.
+ *
+ * (C) Copyright 2001
+ * Bill Hunter, Wave 7 Optics, williamhunter@attbi.com
+ *
+ * Based on code by:
+ *
+ * Kenneth Johansson ,Ericsson AB.
+ * kenneth.johansson@etx.ericsson.se
+ *
+ * hacked up by bill hunter. fixed so we could run before
+ * serial_init and console_init. previous version avoided this by
+ * running out of cache memory during serial/console init, then running
+ * this code later.
+ *
+ * (C) Copyright 2002
+ * Jun Gu, Artesyn Technology, jung@artesyncp.com
+ * Support for AMCC 440 based on OpenBIOS draminit.c from IBM.
+ *
+ * (C) Copyright 2005
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <i2c.h>
+#include <asm/ppc4xx.h>
+
+#if defined(CONFIG_SPD_EEPROM) && !defined(CONFIG_440)
+
+/*
+ * Set default values
+ */
+#ifndef CONFIG_SYS_I2C_SPEED
+#define CONFIG_SYS_I2C_SPEED 50000
+#endif
+
+#define ONE_BILLION 1000000000
+
+#define SDRAM0_CFG_DCE 0x80000000
+#define SDRAM0_CFG_SRE 0x40000000
+#define SDRAM0_CFG_PME 0x20000000
+#define SDRAM0_CFG_MEMCHK 0x10000000
+#define SDRAM0_CFG_REGEN 0x08000000
+#define SDRAM0_CFG_ECCDD 0x00400000
+#define SDRAM0_CFG_EMDULR 0x00200000
+#define SDRAM0_CFG_DRW_SHIFT (31-6)
+#define SDRAM0_CFG_BRPF_SHIFT (31-8)
+
+#define SDRAM0_TR_CASL_SHIFT (31-8)
+#define SDRAM0_TR_PTA_SHIFT (31-13)
+#define SDRAM0_TR_CTP_SHIFT (31-15)
+#define SDRAM0_TR_LDF_SHIFT (31-17)
+#define SDRAM0_TR_RFTA_SHIFT (31-29)
+#define SDRAM0_TR_RCD_SHIFT (31-31)
+
+#define SDRAM0_RTR_SHIFT (31-15)
+#define SDRAM0_ECCCFG_SHIFT (31-11)
+
+/* SDRAM0_CFG enable macro */
+#define SDRAM0_CFG_BRPF(x) ( ( x & 0x3)<< SDRAM0_CFG_BRPF_SHIFT )
+
+#define SDRAM0_BXCR_SZ_MASK 0x000e0000
+#define SDRAM0_BXCR_AM_MASK 0x0000e000
+
+#define SDRAM0_BXCR_SZ_SHIFT (31-14)
+#define SDRAM0_BXCR_AM_SHIFT (31-18)
+
+#define SDRAM0_BXCR_SZ(x) ( (( x << SDRAM0_BXCR_SZ_SHIFT) & SDRAM0_BXCR_SZ_MASK) )
+#define SDRAM0_BXCR_AM(x) ( (( x << SDRAM0_BXCR_AM_SHIFT) & SDRAM0_BXCR_AM_MASK) )
+
+#ifdef CONFIG_SPDDRAM_SILENT
+# define SPD_ERR(x) do { return 0; } while (0)
+#else
+# define SPD_ERR(x) do { printf(x); return(0); } while (0)
+#endif
+
+#define sdram_HZ_to_ns(hertz) (1000000000/(hertz))
+
+/* function prototypes */
+int spd_read(uint addr);
+
+
+/*
+ * This function is reading data from the DIMM module EEPROM over the SPD bus
+ * and uses that to program the sdram controller.
+ *
+ * This works on boards that has the same schematics that the AMCC walnut has.
+ *
+ * Input: null for default I2C spd functions or a pointer to a custom function
+ * returning spd_data.
+ */
+
+long int spd_sdram(int(read_spd)(uint addr))
+{
+ int tmp,row,col;
+ int total_size,bank_size,bank_code;
+ int mode;
+ int bank_cnt;
+
+ int sdram0_pmit=0x07c00000;
+ int sdram0_b0cr;
+ int sdram0_b1cr = 0;
+#ifndef CONFIG_405EP /* not on PPC405EP */
+ int sdram0_b2cr = 0;
+ int sdram0_b3cr = 0;
+ int sdram0_besr0 = -1;
+ int sdram0_besr1 = -1;
+ int sdram0_eccesr = -1;
+ int sdram0_ecccfg;
+ int ecc_on;
+#endif
+
+ int sdram0_rtr=0;
+ int sdram0_tr=0;
+
+ int sdram0_cfg=0;
+
+ int t_rp;
+ int t_rcd;
+ int t_ras;
+ int t_rc;
+ int min_cas;
+
+ PPC4xx_SYS_INFO sys_info;
+ unsigned long bus_period_x_10;
+
+ /*
+ * get the board info
+ */
+ get_sys_info(&sys_info);
+ bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10);
+
+ if (read_spd == 0){
+ read_spd=spd_read;
+ /*
+ * Make sure I2C controller is initialized
+ * before continuing.
+ */
+ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+ }
+
+ /* Make shure we are using SDRAM */
+ if (read_spd(2) != 0x04) {
+ SPD_ERR("SDRAM - non SDRAM memory module found\n");
+ }
+
+ /* ------------------------------------------------------------------
+ * configure memory timing register
+ *
+ * data from DIMM:
+ * 27 IN Row Precharge Time ( t RP)
+ * 29 MIN RAS to CAS Delay ( t RCD)
+ * 127 Component and Clock Detail ,clk0-clk3, junction temp, CAS
+ * -------------------------------------------------------------------*/
+
+ /*
+ * first figure out which cas latency mode to use
+ * use the min supported mode
+ */
+
+ tmp = read_spd(127) & 0x6;
+ if (tmp == 0x02) { /* only cas = 2 supported */
+ min_cas = 2;
+/* t_ck = read_spd(9); */
+/* t_ac = read_spd(10); */
+ } else if (tmp == 0x04) { /* only cas = 3 supported */
+ min_cas = 3;
+/* t_ck = read_spd(9); */
+/* t_ac = read_spd(10); */
+ } else if (tmp == 0x06) { /* 2,3 supported, so use 2 */
+ min_cas = 2;
+/* t_ck = read_spd(23); */
+/* t_ac = read_spd(24); */
+ } else {
+ SPD_ERR("SDRAM - unsupported CAS latency \n");
+ }
+
+ /* get some timing values, t_rp,t_rcd,t_ras,t_rc
+ */
+ t_rp = read_spd(27);
+ t_rcd = read_spd(29);
+ t_ras = read_spd(30);
+ t_rc = t_ras + t_rp;
+
+ /* The following timing calcs subtract 1 before deviding.
+ * this has effect of using ceiling instead of floor rounding,
+ * and also subtracting 1 to convert number to reg value
+ */
+ /* set up CASL */
+ sdram0_tr = (min_cas - 1) << SDRAM0_TR_CASL_SHIFT;
+ /* set up PTA */
+ sdram0_tr |= ((((t_rp - 1) * 10)/bus_period_x_10) & 0x3) << SDRAM0_TR_PTA_SHIFT;
+ /* set up CTP */
+ tmp = (((t_rc - t_rcd - t_rp -1) * 10) / bus_period_x_10) & 0x3;
+ if (tmp < 1)
+ tmp = 1;
+ sdram0_tr |= tmp << SDRAM0_TR_CTP_SHIFT;
+ /* set LDF = 2 cycles, reg value = 1 */
+ sdram0_tr |= 1 << SDRAM0_TR_LDF_SHIFT;
+ /* set RFTA = t_rfc/bus_period, use t_rfc = t_rc */
+ tmp = (((t_rc - 1) * 10) / bus_period_x_10) - 3;
+ if (tmp < 0)
+ tmp = 0;
+ if (tmp > 6)
+ tmp = 6;
+ sdram0_tr |= tmp << SDRAM0_TR_RFTA_SHIFT;
+ /* set RCD = t_rcd/bus_period*/
+ sdram0_tr |= ((((t_rcd - 1) * 10) / bus_period_x_10) &0x3) << SDRAM0_TR_RCD_SHIFT ;
+
+
+ /*------------------------------------------------------------------
+ * configure RTR register
+ * -------------------------------------------------------------------*/
+ row = read_spd(3);
+ col = read_spd(4);
+ tmp = read_spd(12) & 0x7f ; /* refresh type less self refresh bit */
+ switch (tmp) {
+ case 0x00:
+ tmp = 15625;
+ break;
+ case 0x01:
+ tmp = 15625 / 4;
+ break;
+ case 0x02:
+ tmp = 15625 / 2;
+ break;
+ case 0x03:
+ tmp = 15625 * 2;
+ break;
+ case 0x04:
+ tmp = 15625 * 4;
+ break;
+ case 0x05:
+ tmp = 15625 * 8;
+ break;
+ default:
+ SPD_ERR("SDRAM - Bad refresh period \n");
+ }
+ /* convert from nsec to bus cycles */
+ tmp = (tmp * 10) / bus_period_x_10;
+ sdram0_rtr = (tmp & 0x3ff8) << SDRAM0_RTR_SHIFT;
+
+ /*------------------------------------------------------------------
+ * determine the number of banks used
+ * -------------------------------------------------------------------*/
+ /* byte 7:6 is module data width */
+ if (read_spd(7) != 0)
+ SPD_ERR("SDRAM - unsupported module width\n");
+ tmp = read_spd(6);
+ if (tmp < 32)
+ SPD_ERR("SDRAM - unsupported module width\n");
+ else if (tmp < 64)
+ bank_cnt = 1; /* one bank per sdram side */
+ else if (tmp < 73)
+ bank_cnt = 2; /* need two banks per side */
+ else if (tmp < 161)
+ bank_cnt = 4; /* need four banks per side */
+ else
+ SPD_ERR("SDRAM - unsupported module width\n");
+
+ /* byte 5 is the module row count (refered to as dimm "sides") */
+ tmp = read_spd(5);
+ if (tmp == 1)
+ ;
+ else if (tmp==2)
+ bank_cnt *= 2;
+ else if (tmp==4)
+ bank_cnt *= 4;
+ else
+ bank_cnt = 8; /* 8 is an error code */
+
+ if (bank_cnt > 4) /* we only have 4 banks to work with */
+ SPD_ERR("SDRAM - unsupported module rows for this width\n");
+
+#ifndef CONFIG_405EP /* not on PPC405EP */
+ /* now check for ECC ability of module. We only support ECC
+ * on 32 bit wide devices with 8 bit ECC.
+ */
+ if ((read_spd(11)==2) && (read_spd(6)==40) && (read_spd(14)==8)) {
+ sdram0_ecccfg = 0xf << SDRAM0_ECCCFG_SHIFT;
+ ecc_on = 1;
+ } else {
+ sdram0_ecccfg = 0;
+ ecc_on = 0;
+ }
+#endif
+
+ /*------------------------------------------------------------------
+ * calculate total size
+ * -------------------------------------------------------------------*/
+ /* calculate total size and do sanity check */
+ tmp = read_spd(31);
+ total_size = 1 << 22; /* total_size = 4MB */
+ /* now multiply 4M by the smallest device row density */
+ /* note that we don't support asymetric rows */
+ while (((tmp & 0x0001) == 0) && (tmp != 0)) {
+ total_size = total_size << 1;
+ tmp = tmp >> 1;
+ }
+ total_size *= read_spd(5); /* mult by module rows (dimm sides) */
+
+ /*------------------------------------------------------------------
+ * map rows * cols * banks to a mode
+ * -------------------------------------------------------------------*/
+
+ switch (row) {
+ case 11:
+ switch (col) {
+ case 8:
+ mode=4; /* mode 5 */
+ break;
+ case 9:
+ case 10:
+ mode=0; /* mode 1 */
+ break;
+ default:
+ SPD_ERR("SDRAM - unsupported mode\n");
+ }
+ break;
+ case 12:
+ switch (col) {
+ case 8:
+ mode=3; /* mode 4 */
+ break;
+ case 9:
+ case 10:
+ mode=1; /* mode 2 */
+ break;
+ default:
+ SPD_ERR("SDRAM - unsupported mode\n");
+ }
+ break;
+ case 13:
+ switch (col) {
+ case 8:
+ mode=5; /* mode 6 */
+ break;
+ case 9:
+ case 10:
+ if (read_spd(17) == 2)
+ mode = 6; /* mode 7 */
+ else
+ mode = 2; /* mode 3 */
+ break;
+ case 11:
+ mode = 2; /* mode 3 */
+ break;
+ default:
+ SPD_ERR("SDRAM - unsupported mode\n");
+ }
+ break;
+ default:
+ SPD_ERR("SDRAM - unsupported mode\n");
+ }
+
+ /*------------------------------------------------------------------
+ * using the calculated values, compute the bank
+ * config register values.
+ * -------------------------------------------------------------------*/
+
+ /* compute the size of each bank */
+ bank_size = total_size / bank_cnt;
+ /* convert bank size to bank size code for ppc4xx
+ by takeing log2(bank_size) - 22 */
+ tmp = bank_size; /* start with tmp = bank_size */
+ bank_code = 0; /* and bank_code = 0 */
+ while (tmp > 1) { /* this takes log2 of tmp */
+ bank_code++; /* and stores result in bank_code */
+ tmp = tmp >> 1;
+ } /* bank_code is now log2(bank_size) */
+ bank_code -= 22; /* subtract 22 to get the code */
+
+ tmp = SDRAM0_BXCR_SZ(bank_code) | SDRAM0_BXCR_AM(mode) | 1;
+ sdram0_b0cr = (bank_size * 0) | tmp;
+#ifndef CONFIG_405EP /* not on PPC405EP */
+ if (bank_cnt > 1)
+ sdram0_b2cr = (bank_size * 1) | tmp;
+ if (bank_cnt > 2)
+ sdram0_b1cr = (bank_size * 2) | tmp;
+ if (bank_cnt > 3)
+ sdram0_b3cr = (bank_size * 3) | tmp;
+#else
+ /* PPC405EP chip only supports two SDRAM banks */
+ if (bank_cnt > 1)
+ sdram0_b1cr = (bank_size * 1) | tmp;
+ if (bank_cnt > 2)
+ total_size = 2 * bank_size;
+#endif
+
+ /*
+ * enable sdram controller DCE=1
+ * enable burst read prefetch to 32 bytes BRPF=2
+ * leave other functions off
+ */
+
+ /*------------------------------------------------------------------
+ * now that we've done our calculations, we are ready to
+ * program all the registers.
+ * -------------------------------------------------------------------*/
+
+ /* disable memcontroller so updates work */
+ mtsdram(SDRAM0_CFG, 0);
+
+#ifndef CONFIG_405EP /* not on PPC405EP */
+ mtsdram(SDRAM0_BESR0, sdram0_besr0);
+ mtsdram(SDRAM0_BESR1, sdram0_besr1);
+ mtsdram(SDRAM0_ECCCFG, sdram0_ecccfg);
+ mtsdram(SDRAM0_ECCESR, sdram0_eccesr);
+#endif
+ mtsdram(SDRAM0_RTR, sdram0_rtr);
+ mtsdram(SDRAM0_PMIT, sdram0_pmit);
+ mtsdram(SDRAM0_B0CR, sdram0_b0cr);
+ mtsdram(SDRAM0_B1CR, sdram0_b1cr);
+#ifndef CONFIG_405EP /* not on PPC405EP */
+ mtsdram(SDRAM0_B2CR, sdram0_b2cr);
+ mtsdram(SDRAM0_B3CR, sdram0_b3cr);
+#endif
+ mtsdram(SDRAM0_TR, sdram0_tr);
+
+ /* SDRAM have a power on delay, 500 micro should do */
+ udelay(500);
+ sdram0_cfg = SDRAM0_CFG_DCE | SDRAM0_CFG_BRPF(1) | SDRAM0_CFG_ECCDD | SDRAM0_CFG_EMDULR;
+#ifndef CONFIG_405EP /* not on PPC405EP */
+ if (ecc_on)
+ sdram0_cfg |= SDRAM0_CFG_MEMCHK;
+#endif
+ mtsdram(SDRAM0_CFG, sdram0_cfg);
+
+ return (total_size);
+}
+
+int spd_read(uint addr)
+{
+ uchar data[2];
+
+ if (i2c_read(SPD_EEPROM_ADDRESS, addr, 1, data, 1) == 0)
+ return (int)data[0];
+ else
+ return 0;
+}
+
+#endif /* CONFIG_SPD_EEPROM */
diff --git a/arch/powerpc/cpu/ppc4xx/44x_spd_ddr.c b/arch/powerpc/cpu/ppc4xx/44x_spd_ddr.c
new file mode 100644
index 0000000..161d274
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/44x_spd_ddr.c
@@ -0,0 +1,1244 @@
+/*
+ * arch/powerpc/cpu/ppc4xx/44x_spd_ddr.c
+ * This SPD DDR detection code supports IBM/AMCC PPC44x cpu with a
+ * DDR controller. Those are 440GP/GX/EP/GR.
+ *
+ * (C) Copyright 2001
+ * Bill Hunter, Wave 7 Optics, williamhunter@attbi.com
+ *
+ * Based on code by:
+ *
+ * Kenneth Johansson ,Ericsson AB.
+ * kenneth.johansson@etx.ericsson.se
+ *
+ * hacked up by bill hunter. fixed so we could run before
+ * serial_init and console_init. previous version avoided this by
+ * running out of cache memory during serial/console init, then running
+ * this code later.
+ *
+ * (C) Copyright 2002
+ * Jun Gu, Artesyn Technology, jung@artesyncp.com
+ * Support for AMCC 440 based on OpenBIOS draminit.c from IBM.
+ *
+ * (C) Copyright 2005-2007
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* define DEBUG for debugging output (obviously ;-)) */
+#if 0
+#define DEBUG
+#endif
+
+#include <common.h>
+#include <asm/processor.h>
+#include <i2c.h>
+#include <asm/ppc4xx.h>
+#include <asm/mmu.h>
+
+#include "ecc.h"
+
+#if defined(CONFIG_SPD_EEPROM) && \
+ (defined(CONFIG_440GP) || defined(CONFIG_440GX) || \
+ defined(CONFIG_440EP) || defined(CONFIG_440GR))
+
+/*
+ * Set default values
+ */
+#ifndef CONFIG_SYS_I2C_SPEED
+#define CONFIG_SYS_I2C_SPEED 50000
+#endif
+
+#define ONE_BILLION 1000000000
+
+/*
+ * Board-specific Platform code can reimplement spd_ddr_init_hang () if needed
+ */
+void __spd_ddr_init_hang (void)
+{
+ hang ();
+}
+void spd_ddr_init_hang (void) __attribute__((weak, alias("__spd_ddr_init_hang")));
+
+/*-----------------------------------------------------------------------------+
+ | General Definition
+ +-----------------------------------------------------------------------------*/
+#define DEFAULT_SPD_ADDR1 0x53
+#define DEFAULT_SPD_ADDR2 0x52
+#define MAXBANKS 4 /* at most 4 dimm banks */
+#define MAX_SPD_BYTES 256
+#define NUMHALFCYCLES 4
+#define NUMMEMTESTS 8
+#define NUMMEMWORDS 8
+#define MAXBXCR 4
+
+/*
+ * This DDR2 setup code can dynamically setup the TLB entries for the DDR2 memory
+ * region. Right now the cache should still be disabled in U-Boot because of the
+ * EMAC driver, that need it's buffer descriptor to be located in non cached
+ * memory.
+ *
+ * If at some time this restriction doesn't apply anymore, just define
+ * CONFIG_4xx_DCACHE in the board config file and this code should setup
+ * everything correctly.
+ */
+#ifdef CONFIG_4xx_DCACHE
+#define MY_TLB_WORD2_I_ENABLE 0 /* enable caching on SDRAM */
+#else
+#define MY_TLB_WORD2_I_ENABLE TLB_WORD2_I_ENABLE /* disable caching on SDRAM */
+#endif
+
+/* bank_parms is used to sort the bank sizes by descending order */
+struct bank_param {
+ unsigned long cr;
+ unsigned long bank_size_bytes;
+};
+
+typedef struct bank_param BANKPARMS;
+
+#ifdef CONFIG_SYS_SIMULATE_SPD_EEPROM
+extern const unsigned char cfg_simulate_spd_eeprom[128];
+#endif
+
+static unsigned char spd_read(uchar chip, uint addr);
+static void get_spd_info(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void check_mem_type(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void check_volt_type(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_cfg0(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_cfg1(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_rtr(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_tr0(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_tr1(void);
+
+static unsigned long program_bxcr(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+
+/*
+ * This function is reading data from the DIMM module EEPROM over the SPD bus
+ * and uses that to program the sdram controller.
+ *
+ * This works on boards that has the same schematics that the AMCC walnut has.
+ *
+ * BUG: Don't handle ECC memory
+ * BUG: A few values in the TR register is currently hardcoded
+ */
+long int spd_sdram(void) {
+ unsigned char iic0_dimm_addr[] = SPD_EEPROM_ADDRESS;
+ unsigned long dimm_populated[sizeof(iic0_dimm_addr)];
+ unsigned long total_size;
+ unsigned long cfg0;
+ unsigned long mcsts;
+ unsigned long num_dimm_banks; /* on board dimm banks */
+
+ num_dimm_banks = sizeof(iic0_dimm_addr);
+
+ /*
+ * Make sure I2C controller is initialized
+ * before continuing.
+ */
+ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+ /*
+ * Read the SPD information using I2C interface. Check to see if the
+ * DIMM slots are populated.
+ */
+ get_spd_info(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*
+ * Check the memory type for the dimms plugged.
+ */
+ check_mem_type(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*
+ * Check the voltage type for the dimms plugged.
+ */
+ check_volt_type(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+#if defined(CONFIG_440GX) || defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ /*
+ * Soft-reset SDRAM controller.
+ */
+ mtsdr(SDR0_SRST, SDR0_SRST_DMC);
+ mtsdr(SDR0_SRST, 0x00000000);
+#endif
+
+ /*
+ * program 440GP SDRAM controller options (SDRAM0_CFG0)
+ */
+ program_cfg0(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*
+ * program 440GP SDRAM controller options (SDRAM0_CFG1)
+ */
+ program_cfg1(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*
+ * program SDRAM refresh register (SDRAM0_RTR)
+ */
+ program_rtr(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*
+ * program SDRAM Timing Register 0 (SDRAM0_TR0)
+ */
+ program_tr0(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*
+ * program the BxCR registers to find out total sdram installed
+ */
+ total_size = program_bxcr(dimm_populated, iic0_dimm_addr,
+ num_dimm_banks);
+
+#ifdef CONFIG_PROG_SDRAM_TLB /* this define should eventually be removed */
+ /* and program tlb entries for this size (dynamic) */
+ program_tlb(0, 0, total_size, MY_TLB_WORD2_I_ENABLE);
+#endif
+
+ /*
+ * program SDRAM Clock Timing Register (SDRAM0_CLKTR)
+ */
+ mtsdram(SDRAM0_CLKTR, 0x40000000);
+
+ /*
+ * delay to ensure 200 usec has elapsed
+ */
+ udelay(400);
+
+ /*
+ * enable the memory controller
+ */
+ mfsdram(SDRAM0_CFG0, cfg0);
+ mtsdram(SDRAM0_CFG0, cfg0 | SDRAM_CFG0_DCEN);
+
+ /*
+ * wait for SDRAM_CFG0_DC_EN to complete
+ */
+ while (1) {
+ mfsdram(SDRAM0_MCSTS, mcsts);
+ if ((mcsts & SDRAM_MCSTS_MRSC) != 0)
+ break;
+ }
+
+ /*
+ * program SDRAM Timing Register 1, adding some delays
+ */
+ program_tr1();
+
+#ifdef CONFIG_DDR_ECC
+ /*
+ * If ecc is enabled, initialize the parity bits.
+ */
+ ecc_init(CONFIG_SYS_SDRAM_BASE, total_size);
+#endif
+
+ return total_size;
+}
+
+static unsigned char spd_read(uchar chip, uint addr)
+{
+ unsigned char data[2];
+
+#ifdef CONFIG_SYS_SIMULATE_SPD_EEPROM
+ if (chip == CONFIG_SYS_SIMULATE_SPD_EEPROM) {
+ /*
+ * Onboard spd eeprom requested -> simulate values
+ */
+ return cfg_simulate_spd_eeprom[addr];
+ }
+#endif /* CONFIG_SYS_SIMULATE_SPD_EEPROM */
+
+ if (i2c_probe(chip) == 0) {
+ if (i2c_read(chip, addr, 1, data, 1) == 0) {
+ return data[0];
+ }
+ }
+
+ return 0;
+}
+
+static void get_spd_info(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long dimm_found;
+ unsigned char num_of_bytes;
+ unsigned char total_size;
+
+ dimm_found = false;
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ num_of_bytes = 0;
+ total_size = 0;
+
+ num_of_bytes = spd_read(iic0_dimm_addr[dimm_num], 0);
+ total_size = spd_read(iic0_dimm_addr[dimm_num], 1);
+
+ if ((num_of_bytes != 0) && (total_size != 0)) {
+ dimm_populated[dimm_num] = true;
+ dimm_found = true;
+ debug("DIMM slot %lu: populated\n", dimm_num);
+ } else {
+ dimm_populated[dimm_num] = false;
+ debug("DIMM slot %lu: Not populated\n", dimm_num);
+ }
+ }
+
+ if (dimm_found == false) {
+ printf("ERROR - No memory installed. Install a DDR-SDRAM DIMM.\n\n");
+ spd_ddr_init_hang ();
+ }
+}
+
+static void check_mem_type(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned char dimm_type;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] == true) {
+ dimm_type = spd_read(iic0_dimm_addr[dimm_num], 2);
+ switch (dimm_type) {
+ case 7:
+ debug("DIMM slot %lu: DDR SDRAM detected\n", dimm_num);
+ break;
+ default:
+ printf("ERROR: Unsupported DIMM detected in slot %lu.\n",
+ dimm_num);
+ printf("Only DDR SDRAM DIMMs are supported.\n");
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ spd_ddr_init_hang ();
+ break;
+ }
+ }
+ }
+}
+
+static void check_volt_type(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long voltage_type;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] == true) {
+ voltage_type = spd_read(iic0_dimm_addr[dimm_num], 8);
+ if (voltage_type != 0x04) {
+ printf("ERROR: DIMM %lu with unsupported voltage level.\n",
+ dimm_num);
+ spd_ddr_init_hang ();
+ } else {
+ debug("DIMM %lu voltage level supported.\n", dimm_num);
+ }
+ break;
+ }
+ }
+}
+
+static void program_cfg0(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long cfg0;
+ unsigned long ecc_enabled;
+ unsigned char ecc;
+ unsigned char attributes;
+ unsigned long data_width;
+
+ /*
+ * get Memory Controller Options 0 data
+ */
+ mfsdram(SDRAM0_CFG0, cfg0);
+
+ /*
+ * clear bits
+ */
+ cfg0 &= ~(SDRAM_CFG0_DCEN | SDRAM_CFG0_MCHK_MASK |
+ SDRAM_CFG0_RDEN | SDRAM_CFG0_PMUD |
+ SDRAM_CFG0_DMWD_MASK |
+ SDRAM_CFG0_UIOS_MASK | SDRAM_CFG0_PDP);
+
+
+ /*
+ * FIXME: assume the DDR SDRAMs in both banks are the same
+ */
+ ecc_enabled = true;
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] == true) {
+ ecc = spd_read(iic0_dimm_addr[dimm_num], 11);
+ if (ecc != 0x02) {
+ ecc_enabled = false;
+ }
+
+ /*
+ * program Registered DIMM Enable
+ */
+ attributes = spd_read(iic0_dimm_addr[dimm_num], 21);
+ if ((attributes & 0x02) != 0x00) {
+ cfg0 |= SDRAM_CFG0_RDEN;
+ }
+
+ /*
+ * program DDR SDRAM Data Width
+ */
+ data_width =
+ (unsigned long)spd_read(iic0_dimm_addr[dimm_num],6) +
+ (((unsigned long)spd_read(iic0_dimm_addr[dimm_num],7)) << 8);
+ if (data_width == 64 || data_width == 72) {
+ cfg0 |= SDRAM_CFG0_DMWD_64;
+ } else if (data_width == 32 || data_width == 40) {
+ cfg0 |= SDRAM_CFG0_DMWD_32;
+ } else {
+ printf("WARNING: DIMM with datawidth of %lu bits.\n",
+ data_width);
+ printf("Only DIMMs with 32 or 64 bit datawidths supported.\n");
+ spd_ddr_init_hang ();
+ }
+ break;
+ }
+ }
+
+ /*
+ * program Memory Data Error Checking
+ */
+ if (ecc_enabled == true) {
+ cfg0 |= SDRAM_CFG0_MCHK_GEN;
+ } else {
+ cfg0 |= SDRAM_CFG0_MCHK_NON;
+ }
+
+ /*
+ * program Page Management Unit (0 == enabled)
+ */
+ cfg0 &= ~SDRAM_CFG0_PMUD;
+
+ /*
+ * program Memory Controller Options 0
+ * Note: DCEN must be enabled after all DDR SDRAM controller
+ * configuration registers get initialized.
+ */
+ mtsdram(SDRAM0_CFG0, cfg0);
+}
+
+static void program_cfg1(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long cfg1;
+ mfsdram(SDRAM0_CFG1, cfg1);
+
+ /*
+ * Self-refresh exit, disable PM
+ */
+ cfg1 &= ~(SDRAM_CFG1_SRE | SDRAM_CFG1_PMEN);
+
+ /*
+ * program Memory Controller Options 1
+ */
+ mtsdram(SDRAM0_CFG1, cfg1);
+}
+
+static void program_rtr(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long bus_period_x_10;
+ unsigned long refresh_rate = 0;
+ unsigned char refresh_rate_type;
+ unsigned long refresh_interval;
+ unsigned long sdram_rtr;
+ PPC4xx_SYS_INFO sys_info;
+
+ /*
+ * get the board info
+ */
+ get_sys_info(&sys_info);
+ bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10);
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] == true) {
+ refresh_rate_type = 0x7F & spd_read(iic0_dimm_addr[dimm_num], 12);
+ switch (refresh_rate_type) {
+ case 0x00:
+ refresh_rate = 15625;
+ break;
+ case 0x01:
+ refresh_rate = 15625/4;
+ break;
+ case 0x02:
+ refresh_rate = 15625/2;
+ break;
+ case 0x03:
+ refresh_rate = 15626*2;
+ break;
+ case 0x04:
+ refresh_rate = 15625*4;
+ break;
+ case 0x05:
+ refresh_rate = 15625*8;
+ break;
+ default:
+ printf("ERROR: DIMM %lu, unsupported refresh rate/type.\n",
+ dimm_num);
+ printf("Replace the DIMM module with a supported DIMM.\n");
+ break;
+ }
+
+ break;
+ }
+ }
+
+ refresh_interval = refresh_rate * 10 / bus_period_x_10;
+ sdram_rtr = (refresh_interval & 0x3ff8) << 16;
+
+ /*
+ * program Refresh Timer Register (SDRAM0_RTR)
+ */
+ mtsdram(SDRAM0_RTR, sdram_rtr);
+}
+
+static void program_tr0(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long tr0;
+ unsigned char wcsbc;
+ unsigned char t_rp_ns;
+ unsigned char t_rcd_ns;
+ unsigned char t_ras_ns;
+ unsigned long t_rp_clk;
+ unsigned long t_ras_rcd_clk;
+ unsigned long t_rcd_clk;
+ unsigned long t_rfc_clk;
+ unsigned long plb_check;
+ unsigned char cas_bit;
+ unsigned long cas_index;
+ unsigned char cas_2_0_available;
+ unsigned char cas_2_5_available;
+ unsigned char cas_3_0_available;
+ unsigned long cycle_time_ns_x_10[3];
+ unsigned long tcyc_3_0_ns_x_10;
+ unsigned long tcyc_2_5_ns_x_10;
+ unsigned long tcyc_2_0_ns_x_10;
+ unsigned long tcyc_reg;
+ unsigned long bus_period_x_10;
+ PPC4xx_SYS_INFO sys_info;
+ unsigned long residue;
+
+ /*
+ * get the board info
+ */
+ get_sys_info(&sys_info);
+ bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10);
+
+ /*
+ * get SDRAM Timing Register 0 (SDRAM_TR0) and clear bits
+ */
+ mfsdram(SDRAM0_TR0, tr0);
+ tr0 &= ~(SDRAM_TR0_SDWR_MASK | SDRAM_TR0_SDWD_MASK |
+ SDRAM_TR0_SDCL_MASK | SDRAM_TR0_SDPA_MASK |
+ SDRAM_TR0_SDCP_MASK | SDRAM_TR0_SDLD_MASK |
+ SDRAM_TR0_SDRA_MASK | SDRAM_TR0_SDRD_MASK);
+
+ /*
+ * initialization
+ */
+ wcsbc = 0;
+ t_rp_ns = 0;
+ t_rcd_ns = 0;
+ t_ras_ns = 0;
+ cas_2_0_available = true;
+ cas_2_5_available = true;
+ cas_3_0_available = true;
+ tcyc_2_0_ns_x_10 = 0;
+ tcyc_2_5_ns_x_10 = 0;
+ tcyc_3_0_ns_x_10 = 0;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] == true) {
+ wcsbc = spd_read(iic0_dimm_addr[dimm_num], 15);
+ t_rp_ns = spd_read(iic0_dimm_addr[dimm_num], 27) >> 2;
+ t_rcd_ns = spd_read(iic0_dimm_addr[dimm_num], 29) >> 2;
+ t_ras_ns = spd_read(iic0_dimm_addr[dimm_num], 30);
+ cas_bit = spd_read(iic0_dimm_addr[dimm_num], 18);
+
+ for (cas_index = 0; cas_index < 3; cas_index++) {
+ switch (cas_index) {
+ case 0:
+ tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 9);
+ break;
+ case 1:
+ tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 23);
+ break;
+ default:
+ tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 25);
+ break;
+ }
+
+ if ((tcyc_reg & 0x0F) >= 10) {
+ printf("ERROR: Tcyc incorrect for DIMM in slot %lu\n",
+ dimm_num);
+ spd_ddr_init_hang ();
+ }
+
+ cycle_time_ns_x_10[cas_index] =
+ (((tcyc_reg & 0xF0) >> 4) * 10) + (tcyc_reg & 0x0F);
+ }
+
+ cas_index = 0;
+
+ if ((cas_bit & 0x80) != 0) {
+ cas_index += 3;
+ } else if ((cas_bit & 0x40) != 0) {
+ cas_index += 2;
+ } else if ((cas_bit & 0x20) != 0) {
+ cas_index += 1;
+ }
+
+ if (((cas_bit & 0x10) != 0) && (cas_index < 3)) {
+ tcyc_3_0_ns_x_10 = cycle_time_ns_x_10[cas_index];
+ cas_index++;
+ } else {
+ if (cas_index != 0) {
+ cas_index++;
+ }
+ cas_3_0_available = false;
+ }
+
+ if (((cas_bit & 0x08) != 0) || (cas_index < 3)) {
+ tcyc_2_5_ns_x_10 = cycle_time_ns_x_10[cas_index];
+ cas_index++;
+ } else {
+ if (cas_index != 0) {
+ cas_index++;
+ }
+ cas_2_5_available = false;
+ }
+
+ if (((cas_bit & 0x04) != 0) || (cas_index < 3)) {
+ tcyc_2_0_ns_x_10 = cycle_time_ns_x_10[cas_index];
+ cas_index++;
+ } else {
+ if (cas_index != 0) {
+ cas_index++;
+ }
+ cas_2_0_available = false;
+ }
+
+ break;
+ }
+ }
+
+ /*
+ * Program SD_WR and SD_WCSBC fields
+ */
+ tr0 |= SDRAM_TR0_SDWR_2_CLK; /* Write Recovery: 2 CLK */
+ switch (wcsbc) {
+ case 0:
+ tr0 |= SDRAM_TR0_SDWD_0_CLK;
+ break;
+ default:
+ tr0 |= SDRAM_TR0_SDWD_1_CLK;
+ break;
+ }
+
+ /*
+ * Program SD_CASL field
+ */
+ if ((cas_2_0_available == true) &&
+ (bus_period_x_10 >= tcyc_2_0_ns_x_10)) {
+ tr0 |= SDRAM_TR0_SDCL_2_0_CLK;
+ } else if ((cas_2_5_available == true) &&
+ (bus_period_x_10 >= tcyc_2_5_ns_x_10)) {
+ tr0 |= SDRAM_TR0_SDCL_2_5_CLK;
+ } else if ((cas_3_0_available == true) &&
+ (bus_period_x_10 >= tcyc_3_0_ns_x_10)) {
+ tr0 |= SDRAM_TR0_SDCL_3_0_CLK;
+ } else {
+ printf("ERROR: No supported CAS latency with the installed DIMMs.\n");
+ printf("Only CAS latencies of 2.0, 2.5, and 3.0 are supported.\n");
+ printf("Make sure the PLB speed is within the supported range.\n");
+ spd_ddr_init_hang ();
+ }
+
+ /*
+ * Calculate Trp in clock cycles and round up if necessary
+ * Program SD_PTA field
+ */
+ t_rp_clk = sys_info.freqPLB * t_rp_ns / ONE_BILLION;
+ plb_check = ONE_BILLION * t_rp_clk / t_rp_ns;
+ if (sys_info.freqPLB != plb_check) {
+ t_rp_clk++;
+ }
+ switch ((unsigned long)t_rp_clk) {
+ case 0:
+ case 1:
+ case 2:
+ tr0 |= SDRAM_TR0_SDPA_2_CLK;
+ break;
+ case 3:
+ tr0 |= SDRAM_TR0_SDPA_3_CLK;
+ break;
+ default:
+ tr0 |= SDRAM_TR0_SDPA_4_CLK;
+ break;
+ }
+
+ /*
+ * Program SD_CTP field
+ */
+ t_ras_rcd_clk = sys_info.freqPLB * (t_ras_ns - t_rcd_ns) / ONE_BILLION;
+ plb_check = ONE_BILLION * t_ras_rcd_clk / (t_ras_ns - t_rcd_ns);
+ if (sys_info.freqPLB != plb_check) {
+ t_ras_rcd_clk++;
+ }
+ switch (t_ras_rcd_clk) {
+ case 0:
+ case 1:
+ case 2:
+ tr0 |= SDRAM_TR0_SDCP_2_CLK;
+ break;
+ case 3:
+ tr0 |= SDRAM_TR0_SDCP_3_CLK;
+ break;
+ case 4:
+ tr0 |= SDRAM_TR0_SDCP_4_CLK;
+ break;
+ default:
+ tr0 |= SDRAM_TR0_SDCP_5_CLK;
+ break;
+ }
+
+ /*
+ * Program SD_LDF field
+ */
+ tr0 |= SDRAM_TR0_SDLD_2_CLK;
+
+ /*
+ * Program SD_RFTA field
+ * FIXME tRFC hardcoded as 75 nanoseconds
+ */
+ t_rfc_clk = sys_info.freqPLB / (ONE_BILLION / 75);
+ residue = sys_info.freqPLB % (ONE_BILLION / 75);
+ if (residue >= (ONE_BILLION / 150)) {
+ t_rfc_clk++;
+ }
+ switch (t_rfc_clk) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ tr0 |= SDRAM_TR0_SDRA_6_CLK;
+ break;
+ case 7:
+ tr0 |= SDRAM_TR0_SDRA_7_CLK;
+ break;
+ case 8:
+ tr0 |= SDRAM_TR0_SDRA_8_CLK;
+ break;
+ case 9:
+ tr0 |= SDRAM_TR0_SDRA_9_CLK;
+ break;
+ case 10:
+ tr0 |= SDRAM_TR0_SDRA_10_CLK;
+ break;
+ case 11:
+ tr0 |= SDRAM_TR0_SDRA_11_CLK;
+ break;
+ case 12:
+ tr0 |= SDRAM_TR0_SDRA_12_CLK;
+ break;
+ default:
+ tr0 |= SDRAM_TR0_SDRA_13_CLK;
+ break;
+ }
+
+ /*
+ * Program SD_RCD field
+ */
+ t_rcd_clk = sys_info.freqPLB * t_rcd_ns / ONE_BILLION;
+ plb_check = ONE_BILLION * t_rcd_clk / t_rcd_ns;
+ if (sys_info.freqPLB != plb_check) {
+ t_rcd_clk++;
+ }
+ switch (t_rcd_clk) {
+ case 0:
+ case 1:
+ case 2:
+ tr0 |= SDRAM_TR0_SDRD_2_CLK;
+ break;
+ case 3:
+ tr0 |= SDRAM_TR0_SDRD_3_CLK;
+ break;
+ default:
+ tr0 |= SDRAM_TR0_SDRD_4_CLK;
+ break;
+ }
+
+ debug("tr0: %lx\n", tr0);
+ mtsdram(SDRAM0_TR0, tr0);
+}
+
+static int short_mem_test(void)
+{
+ unsigned long i, j;
+ unsigned long bxcr_num;
+ unsigned long *membase;
+ const unsigned long test[NUMMEMTESTS][NUMMEMWORDS] = {
+ {0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF},
+ {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000},
+ {0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555},
+ {0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA},
+ {0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+ 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A},
+ {0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+ 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5},
+ {0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+ 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA},
+ {0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+ 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55}};
+
+ for (bxcr_num = 0; bxcr_num < MAXBXCR; bxcr_num++) {
+ mtdcr(SDRAM0_CFGADDR, SDRAM0_B0CR + (bxcr_num << 2));
+ if ((mfdcr(SDRAM0_CFGDATA) & SDRAM_BXCR_SDBE) == SDRAM_BXCR_SDBE) {
+ /* Bank is enabled */
+ membase = (unsigned long*)
+ (mfdcr(SDRAM0_CFGDATA) & SDRAM_BXCR_SDBA_MASK);
+
+ /*
+ * Run the short memory test
+ */
+ for (i = 0; i < NUMMEMTESTS; i++) {
+ for (j = 0; j < NUMMEMWORDS; j++) {
+ /* printf("bank enabled base:%x\n", &membase[j]); */
+ membase[j] = test[i][j];
+ ppcDcbf((unsigned long)&(membase[j]));
+ }
+
+ for (j = 0; j < NUMMEMWORDS; j++) {
+ if (membase[j] != test[i][j]) {
+ ppcDcbf((unsigned long)&(membase[j]));
+ return 0;
+ }
+ ppcDcbf((unsigned long)&(membase[j]));
+ }
+
+ if (j < NUMMEMWORDS)
+ return 0;
+ }
+
+ /*
+ * see if the rdclt value passed
+ */
+ if (i < NUMMEMTESTS)
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void program_tr1(void)
+{
+ unsigned long tr0;
+ unsigned long tr1;
+ unsigned long cfg0;
+ unsigned long ecc_temp;
+ unsigned long dlycal;
+ unsigned long dly_val;
+ unsigned long k;
+ unsigned long max_pass_length;
+ unsigned long current_pass_length;
+ unsigned long current_fail_length;
+ unsigned long current_start;
+ unsigned long rdclt;
+ unsigned long rdclt_offset;
+ long max_start;
+ long max_end;
+ long rdclt_average;
+ unsigned char window_found;
+ unsigned char fail_found;
+ unsigned char pass_found;
+ PPC4xx_SYS_INFO sys_info;
+
+ /*
+ * get the board info
+ */
+ get_sys_info(&sys_info);
+
+ /*
+ * get SDRAM Timing Register 0 (SDRAM_TR0) and clear bits
+ */
+ mfsdram(SDRAM0_TR1, tr1);
+ tr1 &= ~(SDRAM_TR1_RDSS_MASK | SDRAM_TR1_RDSL_MASK |
+ SDRAM_TR1_RDCD_MASK | SDRAM_TR1_RDCT_MASK);
+
+ mfsdram(SDRAM0_TR0, tr0);
+ if (((tr0 & SDRAM_TR0_SDCL_MASK) == SDRAM_TR0_SDCL_2_5_CLK) &&
+ (sys_info.freqPLB > 100000000)) {
+ tr1 |= SDRAM_TR1_RDSS_TR2;
+ tr1 |= SDRAM_TR1_RDSL_STAGE3;
+ tr1 |= SDRAM_TR1_RDCD_RCD_1_2;
+ } else {
+ tr1 |= SDRAM_TR1_RDSS_TR1;
+ tr1 |= SDRAM_TR1_RDSL_STAGE2;
+ tr1 |= SDRAM_TR1_RDCD_RCD_0_0;
+ }
+
+ /*
+ * save CFG0 ECC setting to a temporary variable and turn ECC off
+ */
+ mfsdram(SDRAM0_CFG0, cfg0);
+ ecc_temp = cfg0 & SDRAM_CFG0_MCHK_MASK;
+ mtsdram(SDRAM0_CFG0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) | SDRAM_CFG0_MCHK_NON);
+
+ /*
+ * get the delay line calibration register value
+ */
+ mfsdram(SDRAM0_DLYCAL, dlycal);
+ dly_val = SDRAM_DLYCAL_DLCV_DECODE(dlycal) << 2;
+
+ max_pass_length = 0;
+ max_start = 0;
+ max_end = 0;
+ current_pass_length = 0;
+ current_fail_length = 0;
+ current_start = 0;
+ rdclt_offset = 0;
+ window_found = false;
+ fail_found = false;
+ pass_found = false;
+ debug("Starting memory test ");
+
+ for (k = 0; k < NUMHALFCYCLES; k++) {
+ for (rdclt = 0; rdclt < dly_val; rdclt++) {
+ /*
+ * Set the timing reg for the test.
+ */
+ mtsdram(SDRAM0_TR1, (tr1 | SDRAM_TR1_RDCT_ENCODE(rdclt)));
+
+ if (short_mem_test()) {
+ if (fail_found == true) {
+ pass_found = true;
+ if (current_pass_length == 0) {
+ current_start = rdclt_offset + rdclt;
+ }
+
+ current_fail_length = 0;
+ current_pass_length++;
+
+ if (current_pass_length > max_pass_length) {
+ max_pass_length = current_pass_length;
+ max_start = current_start;
+ max_end = rdclt_offset + rdclt;
+ }
+ }
+ } else {
+ current_pass_length = 0;
+ current_fail_length++;
+
+ if (current_fail_length >= (dly_val>>2)) {
+ if (fail_found == false) {
+ fail_found = true;
+ } else if (pass_found == true) {
+ window_found = true;
+ break;
+ }
+ }
+ }
+ }
+ debug(".");
+
+ if (window_found == true)
+ break;
+
+ tr1 = tr1 ^ SDRAM_TR1_RDCD_MASK;
+ rdclt_offset += dly_val;
+ }
+ debug("\n");
+
+ /*
+ * make sure we find the window
+ */
+ if (window_found == false) {
+ printf("ERROR: Cannot determine a common read delay.\n");
+ spd_ddr_init_hang ();
+ }
+
+ /*
+ * restore the orignal ECC setting
+ */
+ mtsdram(SDRAM0_CFG0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) | ecc_temp);
+
+ /*
+ * set the SDRAM TR1 RDCD value
+ */
+ tr1 &= ~SDRAM_TR1_RDCD_MASK;
+ if ((tr0 & SDRAM_TR0_SDCL_MASK) == SDRAM_TR0_SDCL_2_5_CLK) {
+ tr1 |= SDRAM_TR1_RDCD_RCD_1_2;
+ } else {
+ tr1 |= SDRAM_TR1_RDCD_RCD_0_0;
+ }
+
+ /*
+ * set the SDRAM TR1 RDCLT value
+ */
+ tr1 &= ~SDRAM_TR1_RDCT_MASK;
+ while (max_end >= (dly_val << 1)) {
+ max_end -= (dly_val << 1);
+ max_start -= (dly_val << 1);
+ }
+
+ rdclt_average = ((max_start + max_end) >> 1);
+
+ if (rdclt_average < 0) {
+ rdclt_average = 0;
+ }
+
+ if (rdclt_average >= dly_val) {
+ rdclt_average -= dly_val;
+ tr1 = tr1 ^ SDRAM_TR1_RDCD_MASK;
+ }
+ tr1 |= SDRAM_TR1_RDCT_ENCODE(rdclt_average);
+
+ debug("tr1: %lx\n", tr1);
+
+ /*
+ * program SDRAM Timing Register 1 TR1
+ */
+ mtsdram(SDRAM0_TR1, tr1);
+}
+
+static unsigned long program_bxcr(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long bank_base_addr;
+ unsigned long cr;
+ unsigned long i;
+ unsigned long j;
+ unsigned long temp;
+ unsigned char num_row_addr;
+ unsigned char num_col_addr;
+ unsigned char num_banks;
+ unsigned char bank_size_id;
+ unsigned long ctrl_bank_num[MAXBANKS];
+ unsigned long bx_cr_num;
+ unsigned long largest_size_index;
+ unsigned long largest_size;
+ unsigned long current_size_index;
+ BANKPARMS bank_parms[MAXBXCR];
+ unsigned long sorted_bank_num[MAXBXCR]; /* DDR Controller bank number table (sorted by size) */
+ unsigned long sorted_bank_size[MAXBXCR]; /* DDR Controller bank size table (sorted by size)*/
+
+ /*
+ * Set the BxCR regs. First, wipe out the bank config registers.
+ */
+ for (bx_cr_num = 0; bx_cr_num < MAXBXCR; bx_cr_num++) {
+ mtdcr(SDRAM0_CFGADDR, SDRAM0_B0CR + (bx_cr_num << 2));
+ mtdcr(SDRAM0_CFGDATA, 0x00000000);
+ bank_parms[bx_cr_num].bank_size_bytes = 0;
+ }
+
+#ifdef CONFIG_BAMBOO
+ /*
+ * This next section is hardware dependent and must be programmed
+ * to match the hardware. For bamboo, the following holds...
+ * 1. SDRAM0_B0CR: Bank 0 of dimm 0 ctrl_bank_num : 0 (soldered onboard)
+ * 2. SDRAM0_B1CR: Bank 0 of dimm 1 ctrl_bank_num : 1
+ * 3. SDRAM0_B2CR: Bank 1 of dimm 1 ctrl_bank_num : 1
+ * 4. SDRAM0_B3CR: Bank 0 of dimm 2 ctrl_bank_num : 3
+ * ctrl_bank_num corresponds to the first usable DDR controller bank number by DIMM
+ */
+ ctrl_bank_num[0] = 0;
+ ctrl_bank_num[1] = 1;
+ ctrl_bank_num[2] = 3;
+#else
+ /*
+ * Ocotea, Ebony and the other IBM/AMCC eval boards have
+ * 2 DIMM slots with each max 2 banks
+ */
+ ctrl_bank_num[0] = 0;
+ ctrl_bank_num[1] = 2;
+#endif
+
+ /*
+ * reset the bank_base address
+ */
+ bank_base_addr = CONFIG_SYS_SDRAM_BASE;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] == true) {
+ num_row_addr = spd_read(iic0_dimm_addr[dimm_num], 3);
+ num_col_addr = spd_read(iic0_dimm_addr[dimm_num], 4);
+ num_banks = spd_read(iic0_dimm_addr[dimm_num], 5);
+ bank_size_id = spd_read(iic0_dimm_addr[dimm_num], 31);
+ debug("DIMM%ld: row=%d col=%d banks=%d\n", dimm_num,
+ num_row_addr, num_col_addr, num_banks);
+
+ /*
+ * Set the SDRAM0_BxCR regs
+ */
+ cr = 0;
+ switch (bank_size_id) {
+ case 0x02:
+ cr |= SDRAM_BXCR_SDSZ_8;
+ break;
+ case 0x04:
+ cr |= SDRAM_BXCR_SDSZ_16;
+ break;
+ case 0x08:
+ cr |= SDRAM_BXCR_SDSZ_32;
+ break;
+ case 0x10:
+ cr |= SDRAM_BXCR_SDSZ_64;
+ break;
+ case 0x20:
+ cr |= SDRAM_BXCR_SDSZ_128;
+ break;
+ case 0x40:
+ cr |= SDRAM_BXCR_SDSZ_256;
+ break;
+ case 0x80:
+ cr |= SDRAM_BXCR_SDSZ_512;
+ break;
+ default:
+ printf("DDR-SDRAM: DIMM %lu BxCR configuration.\n",
+ dimm_num);
+ printf("ERROR: Unsupported value for the banksize: %d.\n",
+ bank_size_id);
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ spd_ddr_init_hang ();
+ }
+
+ switch (num_col_addr) {
+ case 0x08:
+ cr |= SDRAM_BXCR_SDAM_1;
+ break;
+ case 0x09:
+ cr |= SDRAM_BXCR_SDAM_2;
+ break;
+ case 0x0A:
+ cr |= SDRAM_BXCR_SDAM_3;
+ break;
+ case 0x0B:
+ cr |= SDRAM_BXCR_SDAM_4;
+ break;
+ default:
+ printf("DDR-SDRAM: DIMM %lu BxCR configuration.\n",
+ dimm_num);
+ printf("ERROR: Unsupported value for number of "
+ "column addresses: %d.\n", num_col_addr);
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ spd_ddr_init_hang ();
+ }
+
+ /*
+ * enable the bank
+ */
+ cr |= SDRAM_BXCR_SDBE;
+
+ for (i = 0; i < num_banks; i++) {
+ bank_parms[ctrl_bank_num[dimm_num]+i].bank_size_bytes =
+ (4 << 20) * bank_size_id;
+ bank_parms[ctrl_bank_num[dimm_num]+i].cr = cr;
+ debug("DIMM%ld-bank %ld (SDRAM0_B%ldCR): "
+ "bank_size_bytes=%ld\n",
+ dimm_num, i,
+ ctrl_bank_num[dimm_num] + i,
+ bank_parms[ctrl_bank_num[dimm_num] + i].bank_size_bytes);
+ }
+ }
+ }
+
+ /* Initialize sort tables */
+ for (i = 0; i < MAXBXCR; i++) {
+ sorted_bank_num[i] = i;
+ sorted_bank_size[i] = bank_parms[i].bank_size_bytes;
+ }
+
+ for (i = 0; i < MAXBXCR-1; i++) {
+ largest_size = sorted_bank_size[i];
+ largest_size_index = 255;
+
+ /* Find the largest remaining value */
+ for (j = i + 1; j < MAXBXCR; j++) {
+ if (sorted_bank_size[j] > largest_size) {
+ /* Save largest remaining value and its index */
+ largest_size = sorted_bank_size[j];
+ largest_size_index = j;
+ }
+ }
+
+ if (largest_size_index != 255) {
+ /* Swap the current and largest values */
+ current_size_index = sorted_bank_num[largest_size_index];
+ sorted_bank_size[largest_size_index] = sorted_bank_size[i];
+ sorted_bank_size[i] = largest_size;
+ sorted_bank_num[largest_size_index] = sorted_bank_num[i];
+ sorted_bank_num[i] = current_size_index;
+ }
+ }
+
+ /* Set the SDRAM0_BxCR regs thanks to sort tables */
+ for (bx_cr_num = 0, bank_base_addr = 0; bx_cr_num < MAXBXCR; bx_cr_num++) {
+ if (bank_parms[sorted_bank_num[bx_cr_num]].bank_size_bytes) {
+ mtdcr(SDRAM0_CFGADDR, SDRAM0_B0CR + (sorted_bank_num[bx_cr_num] << 2));
+ temp = mfdcr(SDRAM0_CFGDATA) & ~(SDRAM_BXCR_SDBA_MASK | SDRAM_BXCR_SDSZ_MASK |
+ SDRAM_BXCR_SDAM_MASK | SDRAM_BXCR_SDBE);
+ temp = temp | (bank_base_addr & SDRAM_BXCR_SDBA_MASK) |
+ bank_parms[sorted_bank_num[bx_cr_num]].cr;
+ mtdcr(SDRAM0_CFGDATA, temp);
+ bank_base_addr += bank_parms[sorted_bank_num[bx_cr_num]].bank_size_bytes;
+ debug("SDRAM0_B%ldCR=0x%08lx\n",
+ sorted_bank_num[bx_cr_num], temp);
+ }
+ }
+
+ return(bank_base_addr);
+}
+#endif /* CONFIG_SPD_EEPROM */
diff --git a/arch/powerpc/cpu/ppc4xx/44x_spd_ddr2.c b/arch/powerpc/cpu/ppc4xx/44x_spd_ddr2.c
new file mode 100644
index 0000000..def7ebf
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/44x_spd_ddr2.c
@@ -0,0 +1,3167 @@
+/*
+ * arch/powerpc/cpu/ppc4xx/44x_spd_ddr2.c
+ * This SPD SDRAM detection code supports AMCC PPC44x cpu's with a
+ * DDR2 controller (non Denali Core). Those currently are:
+ *
+ * 405: 405EX(r)
+ * 440/460: 440SP/440SPe/460EX/460GT
+ *
+ * Copyright (c) 2008 Nuovation System Designs, LLC
+ * Grant Erickson <gerickson@nuovations.com>
+
+ * (C) Copyright 2007-2009
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * COPYRIGHT AMCC CORPORATION 2004
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+/* define DEBUG for debugging output (obviously ;-)) */
+#if 0
+#define DEBUG
+#endif
+
+#include <common.h>
+#include <command.h>
+#include <asm/ppc4xx.h>
+#include <i2c.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <asm/cache.h>
+
+#include "ecc.h"
+
+#define PPC4xx_IBM_DDR2_DUMP_REGISTER(mnemonic) \
+ do { \
+ u32 data; \
+ mfsdram(SDRAM_##mnemonic, data); \
+ printf("%20s[%02x] = 0x%08X\n", \
+ "SDRAM_" #mnemonic, SDRAM_##mnemonic, data); \
+ } while (0)
+
+#define PPC4xx_IBM_DDR2_DUMP_MQ_REGISTER(mnemonic) \
+ do { \
+ u32 data; \
+ data = mfdcr(SDRAM_##mnemonic); \
+ printf("%20s[%02x] = 0x%08X\n", \
+ "SDRAM_" #mnemonic, SDRAM_##mnemonic, data); \
+ } while (0)
+
+#if !defined(CONFIG_NAND_U_BOOT) || defined(CONFIG_NAND_SPL)
+static void update_rdcc(void)
+{
+ u32 val;
+
+ /*
+ * Complete RDSS configuration as mentioned on page 7 of the AMCC
+ * PowerPC440SP/SPe DDR2 application note:
+ * "DDR1/DDR2 Initialization Sequence and Dynamic Tuning"
+ *
+ * Or item #10 "10. Complete RDSS configuration" in chapter
+ * "22.2.9 SDRAM Initialization" of AMCC PPC460EX/EXr/GT users
+ * manual.
+ */
+ mfsdram(SDRAM_RTSR, val);
+ if ((val & SDRAM_RTSR_TRK1SM_MASK) == SDRAM_RTSR_TRK1SM_ATPLS1) {
+ mfsdram(SDRAM_RDCC, val);
+ if ((val & SDRAM_RDCC_RDSS_MASK) != SDRAM_RDCC_RDSS_T4) {
+ val += 0x40000000;
+ mtsdram(SDRAM_RDCC, val);
+ }
+ }
+}
+#endif
+
+#if defined(CONFIG_440)
+/*
+ * This DDR2 setup code can dynamically setup the TLB entries for the DDR2
+ * memory region. Right now the cache should still be disabled in U-Boot
+ * because of the EMAC driver, that need its buffer descriptor to be located
+ * in non cached memory.
+ *
+ * If at some time this restriction doesn't apply anymore, just define
+ * CONFIG_4xx_DCACHE in the board config file and this code should setup
+ * everything correctly.
+ */
+#ifdef CONFIG_4xx_DCACHE
+/* enable caching on SDRAM */
+#define MY_TLB_WORD2_I_ENABLE 0
+#else
+/* disable caching on SDRAM */
+#define MY_TLB_WORD2_I_ENABLE TLB_WORD2_I_ENABLE
+#endif /* CONFIG_4xx_DCACHE */
+
+void dcbz_area(u32 start_address, u32 num_bytes);
+#endif /* CONFIG_440 */
+
+#define MAXRANKS 4
+#define MAXBXCF 4
+
+#define MULDIV64(m1, m2, d) (u32)(((u64)(m1) * (u64)(m2)) / (u64)(d))
+
+#if !defined(CONFIG_NAND_SPL)
+/*-----------------------------------------------------------------------------+
+ * sdram_memsize
+ *-----------------------------------------------------------------------------*/
+phys_size_t sdram_memsize(void)
+{
+ phys_size_t mem_size;
+ unsigned long mcopt2;
+ unsigned long mcstat;
+ unsigned long mb0cf;
+ unsigned long sdsz;
+ unsigned long i;
+
+ mem_size = 0;
+
+ mfsdram(SDRAM_MCOPT2, mcopt2);
+ mfsdram(SDRAM_MCSTAT, mcstat);
+
+ /* DDR controller must be enabled and not in self-refresh. */
+ /* Otherwise memsize is zero. */
+ if (((mcopt2 & SDRAM_MCOPT2_DCEN_MASK) == SDRAM_MCOPT2_DCEN_ENABLE)
+ && ((mcopt2 & SDRAM_MCOPT2_SREN_MASK) == SDRAM_MCOPT2_SREN_EXIT)
+ && ((mcstat & (SDRAM_MCSTAT_MIC_MASK | SDRAM_MCSTAT_SRMS_MASK))
+ == (SDRAM_MCSTAT_MIC_COMP | SDRAM_MCSTAT_SRMS_NOT_SF))) {
+ for (i = 0; i < MAXBXCF; i++) {
+ mfsdram(SDRAM_MB0CF + (i << 2), mb0cf);
+ /* Banks enabled */
+ if ((mb0cf & SDRAM_BXCF_M_BE_MASK) == SDRAM_BXCF_M_BE_ENABLE) {
+#if defined(CONFIG_440)
+ sdsz = mfdcr_any(SDRAM_R0BAS + i) & SDRAM_RXBAS_SDSZ_MASK;
+#else
+ sdsz = mb0cf & SDRAM_RXBAS_SDSZ_MASK;
+#endif
+ switch(sdsz) {
+ case SDRAM_RXBAS_SDSZ_8:
+ mem_size+=8;
+ break;
+ case SDRAM_RXBAS_SDSZ_16:
+ mem_size+=16;
+ break;
+ case SDRAM_RXBAS_SDSZ_32:
+ mem_size+=32;
+ break;
+ case SDRAM_RXBAS_SDSZ_64:
+ mem_size+=64;
+ break;
+ case SDRAM_RXBAS_SDSZ_128:
+ mem_size+=128;
+ break;
+ case SDRAM_RXBAS_SDSZ_256:
+ mem_size+=256;
+ break;
+ case SDRAM_RXBAS_SDSZ_512:
+ mem_size+=512;
+ break;
+ case SDRAM_RXBAS_SDSZ_1024:
+ mem_size+=1024;
+ break;
+ case SDRAM_RXBAS_SDSZ_2048:
+ mem_size+=2048;
+ break;
+ case SDRAM_RXBAS_SDSZ_4096:
+ mem_size+=4096;
+ break;
+ default:
+ printf("WARNING: Unsupported bank size (SDSZ=0x%lx)!\n"
+ , sdsz);
+ mem_size=0;
+ break;
+ }
+ }
+ }
+ }
+
+ return mem_size << 20;
+}
+
+/*-----------------------------------------------------------------------------+
+ * is_ecc_enabled
+ *-----------------------------------------------------------------------------*/
+static unsigned long is_ecc_enabled(void)
+{
+ unsigned long val;
+
+ mfsdram(SDRAM_MCOPT1, val);
+
+ return SDRAM_MCOPT1_MCHK_CHK_DECODE(val);
+}
+
+/*-----------------------------------------------------------------------------+
+ * board_add_ram_info
+ *-----------------------------------------------------------------------------*/
+void board_add_ram_info(int use_default)
+{
+ PPC4xx_SYS_INFO board_cfg;
+ u32 val;
+
+ if (is_ecc_enabled())
+ puts(" (ECC");
+ else
+ puts(" (ECC not");
+
+ get_sys_info(&board_cfg);
+
+#if defined(CONFIG_405EX)
+ val = board_cfg.freqPLB;
+#else
+ mfsdr(SDR0_DDR0, val);
+ val = MULDIV64((board_cfg.freqPLB), SDR0_DDR0_DDRM_DECODE(val), 1);
+#endif
+ printf(" enabled, %d MHz", (val * 2) / 1000000);
+
+ mfsdram(SDRAM_MMODE, val);
+ val = (val & SDRAM_MMODE_DCL_MASK) >> 4;
+ printf(", CL%d)", val);
+}
+#endif /* !CONFIG_NAND_SPL */
+
+#if defined(CONFIG_SPD_EEPROM)
+
+/*-----------------------------------------------------------------------------+
+ * Defines
+ *-----------------------------------------------------------------------------*/
+#define SDRAM_DDR1 1
+#define SDRAM_DDR2 2
+#define SDRAM_NONE 0
+
+#define MAXDIMMS 2
+#define MAX_SPD_BYTES 256 /* Max number of bytes on the DIMM's SPD EEPROM */
+
+#define ONE_BILLION 1000000000
+
+#define CMD_NOP (7 << 19)
+#define CMD_PRECHARGE (2 << 19)
+#define CMD_REFRESH (1 << 19)
+#define CMD_EMR (0 << 19)
+#define CMD_READ (5 << 19)
+#define CMD_WRITE (4 << 19)
+
+#define SELECT_MR (0 << 16)
+#define SELECT_EMR (1 << 16)
+#define SELECT_EMR2 (2 << 16)
+#define SELECT_EMR3 (3 << 16)
+
+/* MR */
+#define DLL_RESET 0x00000100
+
+#define WRITE_RECOV_2 (1 << 9)
+#define WRITE_RECOV_3 (2 << 9)
+#define WRITE_RECOV_4 (3 << 9)
+#define WRITE_RECOV_5 (4 << 9)
+#define WRITE_RECOV_6 (5 << 9)
+
+#define BURST_LEN_4 0x00000002
+
+/* EMR */
+#define ODT_0_OHM 0x00000000
+#define ODT_50_OHM 0x00000044
+#define ODT_75_OHM 0x00000004
+#define ODT_150_OHM 0x00000040
+
+#define ODS_FULL 0x00000000
+#define ODS_REDUCED 0x00000002
+#define OCD_CALIB_DEF 0x00000380
+
+/* defines for ODT (On Die Termination) of the 440SP(e) DDR2 controller */
+#define ODT_EB0R (0x80000000 >> 8)
+#define ODT_EB0W (0x80000000 >> 7)
+#define CALC_ODT_R(n) (ODT_EB0R << (n << 1))
+#define CALC_ODT_W(n) (ODT_EB0W << (n << 1))
+#define CALC_ODT_RW(n) (CALC_ODT_R(n) | CALC_ODT_W(n))
+
+/* Defines for the Read Cycle Delay test */
+#define NUMMEMTESTS 8
+#define NUMMEMWORDS 8
+#define NUMLOOPS 64 /* memory test loops */
+
+/*
+ * Newer PPC's like 440SPe, 460EX/GT can be equipped with more than 2GB of SDRAM.
+ * To support such configurations, we "only" map the first 2GB via the TLB's. We
+ * need some free virtual address space for the remaining peripherals like, SoC
+ * devices, FLASH etc.
+ *
+ * Note that ECC is currently not supported on configurations with more than 2GB
+ * SDRAM. This is because we only map the first 2GB on such systems, and therefore
+ * the ECC parity byte of the remaining area can't be written.
+ */
+
+/*
+ * Board-specific Platform code can reimplement spd_ddr_init_hang () if needed
+ */
+void __spd_ddr_init_hang (void)
+{
+ hang ();
+}
+void spd_ddr_init_hang (void) __attribute__((weak, alias("__spd_ddr_init_hang")));
+
+/*
+ * To provide an interface for board specific config values in this common
+ * DDR setup code, we implement he "weak" default functions here. They return
+ * the default value back to the caller.
+ *
+ * Please see include/configs/yucca.h for an example fora board specific
+ * implementation.
+ */
+u32 __ddr_wrdtr(u32 default_val)
+{
+ return default_val;
+}
+u32 ddr_wrdtr(u32) __attribute__((weak, alias("__ddr_wrdtr")));
+
+u32 __ddr_clktr(u32 default_val)
+{
+ return default_val;
+}
+u32 ddr_clktr(u32) __attribute__((weak, alias("__ddr_clktr")));
+
+
+/* Private Structure Definitions */
+
+/* enum only to ease code for cas latency setting */
+typedef enum ddr_cas_id {
+ DDR_CAS_2 = 20,
+ DDR_CAS_2_5 = 25,
+ DDR_CAS_3 = 30,
+ DDR_CAS_4 = 40,
+ DDR_CAS_5 = 50
+} ddr_cas_id_t;
+
+/*-----------------------------------------------------------------------------+
+ * Prototypes
+ *-----------------------------------------------------------------------------*/
+static void get_spd_info(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void check_mem_type(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void check_frequency(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void check_rank_number(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void check_voltage_type(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_memory_queue(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_codt(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_mode(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks,
+ ddr_cas_id_t *selected_cas,
+ int *write_recovery);
+static void program_tr(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_rtr(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_bxcf(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_copt1(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+static void program_initplr(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks,
+ ddr_cas_id_t selected_cas,
+ int write_recovery);
+#ifdef CONFIG_DDR_ECC
+static void program_ecc(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks,
+ unsigned long tlb_word2_i_value);
+#endif
+#if !defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION)
+static void program_DQS_calibration(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks);
+#ifdef HARD_CODED_DQS /* calibration test with hardvalues */
+static void test(void);
+#else
+static void DQS_calibration_process(void);
+#endif
+#endif
+
+static unsigned char spd_read(uchar chip, uint addr)
+{
+ unsigned char data[2];
+
+ if (i2c_probe(chip) == 0)
+ if (i2c_read(chip, addr, 1, data, 1) == 0)
+ return data[0];
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------------------+
+ * initdram. Initializes the 440SP Memory Queue and DDR SDRAM controller.
+ * Note: This routine runs from flash with a stack set up in the chip's
+ * sram space. It is important that the routine does not require .sbss, .bss or
+ * .data sections. It also cannot call routines that require these sections.
+ *-----------------------------------------------------------------------------*/
+/*-----------------------------------------------------------------------------
+ * Function: initdram
+ * Description: Configures SDRAM memory banks for DDR operation.
+ * Auto Memory Configuration option reads the DDR SDRAM EEPROMs
+ * via the IIC bus and then configures the DDR SDRAM memory
+ * banks appropriately. If Auto Memory Configuration is
+ * not used, it is assumed that no DIMM is plugged
+ *-----------------------------------------------------------------------------*/
+phys_size_t initdram(int board_type)
+{
+ unsigned char iic0_dimm_addr[] = SPD_EEPROM_ADDRESS;
+ unsigned long dimm_populated[MAXDIMMS] = {SDRAM_NONE, SDRAM_NONE};
+ unsigned long num_dimm_banks; /* on board dimm banks */
+ unsigned long val;
+ ddr_cas_id_t selected_cas = DDR_CAS_5; /* preset to silence compiler */
+ int write_recovery;
+ phys_size_t dram_size = 0;
+
+ num_dimm_banks = sizeof(iic0_dimm_addr);
+
+ /*------------------------------------------------------------------
+ * Reset the DDR-SDRAM controller.
+ *-----------------------------------------------------------------*/
+ mtsdr(SDR0_SRST, SDR0_SRST0_DMC);
+ mtsdr(SDR0_SRST, 0x00000000);
+
+ /*
+ * Make sure I2C controller is initialized
+ * before continuing.
+ */
+
+ /* switch to correct I2C bus */
+ I2C_SET_BUS(CONFIG_SYS_SPD_BUS_NUM);
+ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+ /*------------------------------------------------------------------
+ * Clear out the serial presence detect buffers.
+ * Perform IIC reads from the dimm. Fill in the spds.
+ * Check to see if the dimm slots are populated
+ *-----------------------------------------------------------------*/
+ get_spd_info(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Check the memory type for the dimms plugged.
+ *-----------------------------------------------------------------*/
+ check_mem_type(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Check the frequency supported for the dimms plugged.
+ *-----------------------------------------------------------------*/
+ check_frequency(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Check the total rank number.
+ *-----------------------------------------------------------------*/
+ check_rank_number(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Check the voltage type for the dimms plugged.
+ *-----------------------------------------------------------------*/
+ check_voltage_type(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Program SDRAM controller options 2 register
+ * Except Enabling of the memory controller.
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_MCOPT2, val);
+ mtsdram(SDRAM_MCOPT2,
+ (val &
+ ~(SDRAM_MCOPT2_SREN_MASK | SDRAM_MCOPT2_PMEN_MASK |
+ SDRAM_MCOPT2_IPTR_MASK | SDRAM_MCOPT2_XSRP_MASK |
+ SDRAM_MCOPT2_ISIE_MASK))
+ | (SDRAM_MCOPT2_SREN_ENTER | SDRAM_MCOPT2_PMEN_DISABLE |
+ SDRAM_MCOPT2_IPTR_IDLE | SDRAM_MCOPT2_XSRP_ALLOW |
+ SDRAM_MCOPT2_ISIE_ENABLE));
+
+ /*------------------------------------------------------------------
+ * Program SDRAM controller options 1 register
+ * Note: Does not enable the memory controller.
+ *-----------------------------------------------------------------*/
+ program_copt1(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM Controller On Die Termination Register
+ *-----------------------------------------------------------------*/
+ program_codt(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Program SDRAM refresh register.
+ *-----------------------------------------------------------------*/
+ program_rtr(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Program SDRAM mode register.
+ *-----------------------------------------------------------------*/
+ program_mode(dimm_populated, iic0_dimm_addr, num_dimm_banks,
+ &selected_cas, &write_recovery);
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM Write Data/DM/DQS Clock Timing Reg
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_WRDTR, val);
+ mtsdram(SDRAM_WRDTR, (val & ~(SDRAM_WRDTR_LLWP_MASK | SDRAM_WRDTR_WTR_MASK)) |
+ ddr_wrdtr(SDRAM_WRDTR_LLWP_1_CYC | SDRAM_WRDTR_WTR_90_DEG_ADV));
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM Clock Timing Register
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_CLKTR, val);
+ mtsdram(SDRAM_CLKTR, (val & ~SDRAM_CLKTR_CLKP_MASK) |
+ ddr_clktr(SDRAM_CLKTR_CLKP_0_DEG));
+
+ /*------------------------------------------------------------------
+ * Program the BxCF registers.
+ *-----------------------------------------------------------------*/
+ program_bxcf(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Program SDRAM timing registers.
+ *-----------------------------------------------------------------*/
+ program_tr(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Set the Extended Mode register
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_MEMODE, val);
+ mtsdram(SDRAM_MEMODE,
+ (val & ~(SDRAM_MEMODE_DIC_MASK | SDRAM_MEMODE_DLL_MASK |
+ SDRAM_MEMODE_RTT_MASK | SDRAM_MEMODE_DQS_MASK)) |
+ (SDRAM_MEMODE_DIC_NORMAL | SDRAM_MEMODE_DLL_ENABLE
+ | SDRAM_MEMODE_RTT_150OHM | SDRAM_MEMODE_DQS_ENABLE));
+
+ /*------------------------------------------------------------------
+ * Program Initialization preload registers.
+ *-----------------------------------------------------------------*/
+ program_initplr(dimm_populated, iic0_dimm_addr, num_dimm_banks,
+ selected_cas, write_recovery);
+
+ /*------------------------------------------------------------------
+ * Delay to ensure 200usec have elapsed since reset.
+ *-----------------------------------------------------------------*/
+ udelay(400);
+
+ /*------------------------------------------------------------------
+ * Set the memory queue core base addr.
+ *-----------------------------------------------------------------*/
+ program_memory_queue(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Program SDRAM controller options 2 register
+ * Enable the memory controller.
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_MCOPT2, val);
+ mtsdram(SDRAM_MCOPT2,
+ (val & ~(SDRAM_MCOPT2_SREN_MASK | SDRAM_MCOPT2_DCEN_MASK |
+ SDRAM_MCOPT2_IPTR_MASK | SDRAM_MCOPT2_ISIE_MASK)) |
+ SDRAM_MCOPT2_IPTR_EXECUTE);
+
+ /*------------------------------------------------------------------
+ * Wait for IPTR_EXECUTE init sequence to complete.
+ *-----------------------------------------------------------------*/
+ do {
+ mfsdram(SDRAM_MCSTAT, val);
+ } while ((val & SDRAM_MCSTAT_MIC_MASK) == SDRAM_MCSTAT_MIC_NOTCOMP);
+
+ /* enable the controller only after init sequence completes */
+ mfsdram(SDRAM_MCOPT2, val);
+ mtsdram(SDRAM_MCOPT2, (val | SDRAM_MCOPT2_DCEN_ENABLE));
+
+ /* Make sure delay-line calibration is done before proceeding */
+ do {
+ mfsdram(SDRAM_DLCR, val);
+ } while (!(val & SDRAM_DLCR_DLCS_COMPLETE));
+
+ /* get installed memory size */
+ dram_size = sdram_memsize();
+
+ /*
+ * Limit size to 2GB
+ */
+ if (dram_size > CONFIG_MAX_MEM_MAPPED)
+ dram_size = CONFIG_MAX_MEM_MAPPED;
+
+ /* and program tlb entries for this size (dynamic) */
+
+ /*
+ * Program TLB entries with caches enabled, for best performace
+ * while auto-calibrating and ECC generation
+ */
+ program_tlb(0, 0, dram_size, 0);
+
+ /*------------------------------------------------------------------
+ * DQS calibration.
+ *-----------------------------------------------------------------*/
+#if defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION)
+ DQS_autocalibration();
+#else
+ program_DQS_calibration(dimm_populated, iic0_dimm_addr, num_dimm_banks);
+#endif
+ /*
+ * Now complete RDSS configuration as mentioned on page 7 of the AMCC
+ * PowerPC440SP/SPe DDR2 application note:
+ * "DDR1/DDR2 Initialization Sequence and Dynamic Tuning"
+ */
+ update_rdcc();
+
+#ifdef CONFIG_DDR_ECC
+ /*------------------------------------------------------------------
+ * If ecc is enabled, initialize the parity bits.
+ *-----------------------------------------------------------------*/
+ program_ecc(dimm_populated, iic0_dimm_addr, num_dimm_banks, 0);
+#endif
+
+ /*
+ * Flush the dcache before removing the TLB with caches
+ * enabled. Otherwise this might lead to problems later on,
+ * e.g. while booting Linux (as seen on ICON-440SPe).
+ */
+ flush_dcache();
+
+ /*
+ * Now after initialization (auto-calibration and ECC generation)
+ * remove the TLB entries with caches enabled and program again with
+ * desired cache functionality
+ */
+ remove_tlb(0, dram_size);
+ program_tlb(0, 0, dram_size, MY_TLB_WORD2_I_ENABLE);
+
+ ppc4xx_ibm_ddr2_register_dump();
+
+ /*
+ * Clear potential errors resulting from auto-calibration.
+ * If not done, then we could get an interrupt later on when
+ * exceptions are enabled.
+ */
+ set_mcsr(get_mcsr());
+
+ return sdram_memsize();
+}
+
+static void get_spd_info(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long dimm_found;
+ unsigned char num_of_bytes;
+ unsigned char total_size;
+
+ dimm_found = false;
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ num_of_bytes = 0;
+ total_size = 0;
+
+ num_of_bytes = spd_read(iic0_dimm_addr[dimm_num], 0);
+ debug("\nspd_read(0x%x) returned %d\n",
+ iic0_dimm_addr[dimm_num], num_of_bytes);
+ total_size = spd_read(iic0_dimm_addr[dimm_num], 1);
+ debug("spd_read(0x%x) returned %d\n",
+ iic0_dimm_addr[dimm_num], total_size);
+
+ if ((num_of_bytes != 0) && (total_size != 0)) {
+ dimm_populated[dimm_num] = true;
+ dimm_found = true;
+ debug("DIMM slot %lu: populated\n", dimm_num);
+ } else {
+ dimm_populated[dimm_num] = false;
+ debug("DIMM slot %lu: Not populated\n", dimm_num);
+ }
+ }
+
+ if (dimm_found == false) {
+ printf("ERROR - No memory installed. Install a DDR-SDRAM DIMM.\n\n");
+ spd_ddr_init_hang ();
+ }
+}
+
+
+/*------------------------------------------------------------------
+ * For the memory DIMMs installed, this routine verifies that they
+ * really are DDR specific DIMMs.
+ *-----------------------------------------------------------------*/
+static void check_mem_type(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long dimm_type;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] == true) {
+ dimm_type = spd_read(iic0_dimm_addr[dimm_num], 2);
+ switch (dimm_type) {
+ case 1:
+ printf("ERROR: Standard Fast Page Mode DRAM DIMM detected in "
+ "slot %d.\n", (unsigned int)dimm_num);
+ printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ spd_ddr_init_hang ();
+ break;
+ case 2:
+ printf("ERROR: EDO DIMM detected in slot %d.\n",
+ (unsigned int)dimm_num);
+ printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ spd_ddr_init_hang ();
+ break;
+ case 3:
+ printf("ERROR: Pipelined Nibble DIMM detected in slot %d.\n",
+ (unsigned int)dimm_num);
+ printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ spd_ddr_init_hang ();
+ break;
+ case 4:
+ printf("ERROR: SDRAM DIMM detected in slot %d.\n",
+ (unsigned int)dimm_num);
+ printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ spd_ddr_init_hang ();
+ break;
+ case 5:
+ printf("ERROR: Multiplexed ROM DIMM detected in slot %d.\n",
+ (unsigned int)dimm_num);
+ printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ spd_ddr_init_hang ();
+ break;
+ case 6:
+ printf("ERROR: SGRAM DIMM detected in slot %d.\n",
+ (unsigned int)dimm_num);
+ printf("Only DDR and DDR2 SDRAM DIMMs are supported.\n");
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ spd_ddr_init_hang ();
+ break;
+ case 7:
+ debug("DIMM slot %lu: DDR1 SDRAM detected\n", dimm_num);
+ dimm_populated[dimm_num] = SDRAM_DDR1;
+ break;
+ case 8:
+ debug("DIMM slot %lu: DDR2 SDRAM detected\n", dimm_num);
+ dimm_populated[dimm_num] = SDRAM_DDR2;
+ break;
+ default:
+ printf("ERROR: Unknown DIMM detected in slot %d.\n",
+ (unsigned int)dimm_num);
+ printf("Only DDR1 and DDR2 SDRAM DIMMs are supported.\n");
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ spd_ddr_init_hang ();
+ break;
+ }
+ }
+ }
+ for (dimm_num = 1; dimm_num < num_dimm_banks; dimm_num++) {
+ if ((dimm_populated[dimm_num-1] != SDRAM_NONE)
+ && (dimm_populated[dimm_num] != SDRAM_NONE)
+ && (dimm_populated[dimm_num-1] != dimm_populated[dimm_num])) {
+ printf("ERROR: DIMM's DDR1 and DDR2 type can not be mixed.\n");
+ spd_ddr_init_hang ();
+ }
+ }
+}
+
+/*------------------------------------------------------------------
+ * For the memory DIMMs installed, this routine verifies that
+ * frequency previously calculated is supported.
+ *-----------------------------------------------------------------*/
+static void check_frequency(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long tcyc_reg;
+ unsigned long cycle_time;
+ unsigned long calc_cycle_time;
+ unsigned long sdram_freq;
+ unsigned long sdr_ddrpll;
+ PPC4xx_SYS_INFO board_cfg;
+
+ /*------------------------------------------------------------------
+ * Get the board configuration info.
+ *-----------------------------------------------------------------*/
+ get_sys_info(&board_cfg);
+
+ mfsdr(SDR0_DDR0, sdr_ddrpll);
+ sdram_freq = ((board_cfg.freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
+
+ /*
+ * calc_cycle_time is calculated from DDR frequency set by board/chip
+ * and is expressed in multiple of 10 picoseconds
+ * to match the way DIMM cycle time is calculated below.
+ */
+ calc_cycle_time = MULDIV64(ONE_BILLION, 100, sdram_freq);
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 9);
+ /*
+ * Byte 9, Cycle time for CAS Latency=X, is split into two nibbles:
+ * the higher order nibble (bits 4-7) designates the cycle time
+ * to a granularity of 1ns;
+ * the value presented by the lower order nibble (bits 0-3)
+ * has a granularity of .1ns and is added to the value designated
+ * by the higher nibble. In addition, four lines of the lower order
+ * nibble are assigned to support +.25,+.33, +.66 and +.75.
+ */
+ /* Convert from hex to decimal */
+ if ((tcyc_reg & 0x0F) == 0x0D)
+ cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) + 75;
+ else if ((tcyc_reg & 0x0F) == 0x0C)
+ cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) + 66;
+ else if ((tcyc_reg & 0x0F) == 0x0B)
+ cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) + 33;
+ else if ((tcyc_reg & 0x0F) == 0x0A)
+ cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) + 25;
+ else
+ cycle_time = (((tcyc_reg & 0xF0) >> 4) * 100) +
+ ((tcyc_reg & 0x0F)*10);
+ debug("cycle_time=%lu [10 picoseconds]\n", cycle_time);
+
+ if (cycle_time > (calc_cycle_time + 10)) {
+ /*
+ * the provided sdram cycle_time is too small
+ * for the available DIMM cycle_time.
+ * The additionnal 100ps is here to accept a small incertainty.
+ */
+ printf("ERROR: DRAM DIMM detected with cycle_time %d ps in "
+ "slot %d \n while calculated cycle time is %d ps.\n",
+ (unsigned int)(cycle_time*10),
+ (unsigned int)dimm_num,
+ (unsigned int)(calc_cycle_time*10));
+ printf("Replace the DIMM, or change DDR frequency via "
+ "strapping bits.\n\n");
+ spd_ddr_init_hang ();
+ }
+ }
+ }
+}
+
+/*------------------------------------------------------------------
+ * For the memory DIMMs installed, this routine verifies two
+ * ranks/banks maximum are availables.
+ *-----------------------------------------------------------------*/
+static void check_rank_number(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long dimm_rank;
+ unsigned long total_rank = 0;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ dimm_rank = spd_read(iic0_dimm_addr[dimm_num], 5);
+ if (((unsigned long)spd_read(iic0_dimm_addr[dimm_num], 2)) == 0x08)
+ dimm_rank = (dimm_rank & 0x0F) +1;
+ else
+ dimm_rank = dimm_rank & 0x0F;
+
+
+ if (dimm_rank > MAXRANKS) {
+ printf("ERROR: DRAM DIMM detected with %lu ranks in "
+ "slot %lu is not supported.\n", dimm_rank, dimm_num);
+ printf("Only %d ranks are supported for all DIMM.\n", MAXRANKS);
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ spd_ddr_init_hang ();
+ } else
+ total_rank += dimm_rank;
+ }
+ if (total_rank > MAXRANKS) {
+ printf("ERROR: DRAM DIMM detected with a total of %d ranks "
+ "for all slots.\n", (unsigned int)total_rank);
+ printf("Only %d ranks are supported for all DIMM.\n", MAXRANKS);
+ printf("Remove one of the DIMM modules.\n\n");
+ spd_ddr_init_hang ();
+ }
+ }
+}
+
+/*------------------------------------------------------------------
+ * only support 2.5V modules.
+ * This routine verifies this.
+ *-----------------------------------------------------------------*/
+static void check_voltage_type(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long voltage_type;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ voltage_type = spd_read(iic0_dimm_addr[dimm_num], 8);
+ switch (voltage_type) {
+ case 0x00:
+ printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n");
+ printf("This DIMM is 5.0 Volt/TTL.\n");
+ printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n",
+ (unsigned int)dimm_num);
+ spd_ddr_init_hang ();
+ break;
+ case 0x01:
+ printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n");
+ printf("This DIMM is LVTTL.\n");
+ printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n",
+ (unsigned int)dimm_num);
+ spd_ddr_init_hang ();
+ break;
+ case 0x02:
+ printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n");
+ printf("This DIMM is 1.5 Volt.\n");
+ printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n",
+ (unsigned int)dimm_num);
+ spd_ddr_init_hang ();
+ break;
+ case 0x03:
+ printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n");
+ printf("This DIMM is 3.3 Volt/TTL.\n");
+ printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n",
+ (unsigned int)dimm_num);
+ spd_ddr_init_hang ();
+ break;
+ case 0x04:
+ /* 2.5 Voltage only for DDR1 */
+ break;
+ case 0x05:
+ /* 1.8 Voltage only for DDR2 */
+ break;
+ default:
+ printf("ERROR: Only DIMMs DDR 2.5V or DDR2 1.8V are supported.\n");
+ printf("Replace the DIMM module in slot %d with a supported DIMM.\n\n",
+ (unsigned int)dimm_num);
+ spd_ddr_init_hang ();
+ break;
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------------+
+ * program_copt1.
+ *-----------------------------------------------------------------------------*/
+static void program_copt1(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long mcopt1;
+ unsigned long ecc_enabled;
+ unsigned long ecc = 0;
+ unsigned long data_width = 0;
+ unsigned long dimm_32bit;
+ unsigned long dimm_64bit;
+ unsigned long registered = 0;
+ unsigned long attribute = 0;
+ unsigned long buf0, buf1; /* TODO: code to be changed for IOP1.6 to support 4 DIMMs */
+ unsigned long bankcount;
+ unsigned long val;
+
+#ifdef CONFIG_DDR_ECC
+ ecc_enabled = true;
+#else
+ ecc_enabled = false;
+#endif
+ dimm_32bit = false;
+ dimm_64bit = false;
+ buf0 = false;
+ buf1 = false;
+
+ /*------------------------------------------------------------------
+ * Set memory controller options reg 1, SDRAM_MCOPT1.
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_MCOPT1, val);
+ mcopt1 = val & ~(SDRAM_MCOPT1_MCHK_MASK | SDRAM_MCOPT1_RDEN_MASK |
+ SDRAM_MCOPT1_PMU_MASK | SDRAM_MCOPT1_DMWD_MASK |
+ SDRAM_MCOPT1_UIOS_MASK | SDRAM_MCOPT1_BCNT_MASK |
+ SDRAM_MCOPT1_DDR_TYPE_MASK | SDRAM_MCOPT1_RWOO_MASK |
+ SDRAM_MCOPT1_WOOO_MASK | SDRAM_MCOPT1_DCOO_MASK |
+ SDRAM_MCOPT1_DREF_MASK);
+
+ mcopt1 |= SDRAM_MCOPT1_QDEP;
+ mcopt1 |= SDRAM_MCOPT1_PMU_OPEN;
+ mcopt1 |= SDRAM_MCOPT1_RWOO_DISABLED;
+ mcopt1 |= SDRAM_MCOPT1_WOOO_DISABLED;
+ mcopt1 |= SDRAM_MCOPT1_DCOO_DISABLED;
+ mcopt1 |= SDRAM_MCOPT1_DREF_NORMAL;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ /* test ecc support */
+ ecc = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 11);
+ if (ecc != 0x02) /* ecc not supported */
+ ecc_enabled = false;
+
+ /* test bank count */
+ bankcount = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 17);
+ if (bankcount == 0x04) /* bank count = 4 */
+ mcopt1 |= SDRAM_MCOPT1_4_BANKS;
+ else /* bank count = 8 */
+ mcopt1 |= SDRAM_MCOPT1_8_BANKS;
+
+ /* test for buffered/unbuffered, registered, differential clocks */
+ registered = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 20);
+ attribute = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 21);
+
+ /* TODO: code to be changed for IOP1.6 to support 4 DIMMs */
+ if (dimm_num == 0) {
+ if (dimm_populated[dimm_num] == SDRAM_DDR1) /* DDR1 type */
+ mcopt1 |= SDRAM_MCOPT1_DDR1_TYPE;
+ if (dimm_populated[dimm_num] == SDRAM_DDR2) /* DDR2 type */
+ mcopt1 |= SDRAM_MCOPT1_DDR2_TYPE;
+ if (registered == 1) { /* DDR2 always buffered */
+ /* TODO: what about above comments ? */
+ mcopt1 |= SDRAM_MCOPT1_RDEN;
+ buf0 = true;
+ } else {
+ /* TODO: the mask 0x02 doesn't match Samsung def for byte 21. */
+ if ((attribute & 0x02) == 0x00) {
+ /* buffered not supported */
+ buf0 = false;
+ } else {
+ mcopt1 |= SDRAM_MCOPT1_RDEN;
+ buf0 = true;
+ }
+ }
+ }
+ else if (dimm_num == 1) {
+ if (dimm_populated[dimm_num] == SDRAM_DDR1) /* DDR1 type */
+ mcopt1 |= SDRAM_MCOPT1_DDR1_TYPE;
+ if (dimm_populated[dimm_num] == SDRAM_DDR2) /* DDR2 type */
+ mcopt1 |= SDRAM_MCOPT1_DDR2_TYPE;
+ if (registered == 1) {
+ /* DDR2 always buffered */
+ mcopt1 |= SDRAM_MCOPT1_RDEN;
+ buf1 = true;
+ } else {
+ if ((attribute & 0x02) == 0x00) {
+ /* buffered not supported */
+ buf1 = false;
+ } else {
+ mcopt1 |= SDRAM_MCOPT1_RDEN;
+ buf1 = true;
+ }
+ }
+ }
+
+ /* Note that for DDR2 the byte 7 is reserved, but OK to keep code as is. */
+ data_width = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 6) +
+ (((unsigned long)spd_read(iic0_dimm_addr[dimm_num], 7)) << 8);
+
+ switch (data_width) {
+ case 72:
+ case 64:
+ dimm_64bit = true;
+ break;
+ case 40:
+ case 32:
+ dimm_32bit = true;
+ break;
+ default:
+ printf("WARNING: Detected a DIMM with a data width of %lu bits.\n",
+ data_width);
+ printf("Only DIMMs with 32 or 64 bit DDR-SDRAM widths are supported.\n");
+ break;
+ }
+ }
+ }
+
+ /* verify matching properties */
+ if ((dimm_populated[0] != SDRAM_NONE) && (dimm_populated[1] != SDRAM_NONE)) {
+ if (buf0 != buf1) {
+ printf("ERROR: DIMM's buffered/unbuffered, registered, clocking don't match.\n");
+ spd_ddr_init_hang ();
+ }
+ }
+
+ if ((dimm_64bit == true) && (dimm_32bit == true)) {
+ printf("ERROR: Cannot mix 32 bit and 64 bit DDR-SDRAM DIMMs together.\n");
+ spd_ddr_init_hang ();
+ } else if ((dimm_64bit == true) && (dimm_32bit == false)) {
+ mcopt1 |= SDRAM_MCOPT1_DMWD_64;
+ } else if ((dimm_64bit == false) && (dimm_32bit == true)) {
+ mcopt1 |= SDRAM_MCOPT1_DMWD_32;
+ } else {
+ printf("ERROR: Please install only 32 or 64 bit DDR-SDRAM DIMMs.\n\n");
+ spd_ddr_init_hang ();
+ }
+
+ if (ecc_enabled == true)
+ mcopt1 |= SDRAM_MCOPT1_MCHK_GEN;
+ else
+ mcopt1 |= SDRAM_MCOPT1_MCHK_NON;
+
+ mtsdram(SDRAM_MCOPT1, mcopt1);
+}
+
+/*-----------------------------------------------------------------------------+
+ * program_codt.
+ *-----------------------------------------------------------------------------*/
+static void program_codt(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long codt;
+ unsigned long modt0 = 0;
+ unsigned long modt1 = 0;
+ unsigned long modt2 = 0;
+ unsigned long modt3 = 0;
+ unsigned char dimm_num;
+ unsigned char dimm_rank;
+ unsigned char total_rank = 0;
+ unsigned char total_dimm = 0;
+ unsigned char dimm_type = 0;
+ unsigned char firstSlot = 0;
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM Controller On Die Termination Register
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_CODT, codt);
+ codt &= ~(SDRAM_CODT_DQS_SINGLE_END | SDRAM_CODT_CKSE_SINGLE_END);
+ codt |= SDRAM_CODT_IO_NMODE;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ dimm_rank = (unsigned long)spd_read(iic0_dimm_addr[dimm_num], 5);
+ if (((unsigned long)spd_read(iic0_dimm_addr[dimm_num], 2)) == 0x08) {
+ dimm_rank = (dimm_rank & 0x0F) + 1;
+ dimm_type = SDRAM_DDR2;
+ } else {
+ dimm_rank = dimm_rank & 0x0F;
+ dimm_type = SDRAM_DDR1;
+ }
+
+ total_rank += dimm_rank;
+ total_dimm++;
+ if ((dimm_num == 0) && (total_dimm == 1))
+ firstSlot = true;
+ else
+ firstSlot = false;
+ }
+ }
+ if (dimm_type == SDRAM_DDR2) {
+ codt |= SDRAM_CODT_DQS_1_8_V_DDR2;
+ if ((total_dimm == 1) && (firstSlot == true)) {
+ if (total_rank == 1) { /* PUUU */
+ codt |= CALC_ODT_R(0);
+ modt0 = CALC_ODT_W(0);
+ modt1 = 0x00000000;
+ modt2 = 0x00000000;
+ modt3 = 0x00000000;
+ }
+ if (total_rank == 2) { /* PPUU */
+ codt |= CALC_ODT_R(0) | CALC_ODT_R(1);
+ modt0 = CALC_ODT_W(0) | CALC_ODT_W(1);
+ modt1 = 0x00000000;
+ modt2 = 0x00000000;
+ modt3 = 0x00000000;
+ }
+ } else if ((total_dimm == 1) && (firstSlot != true)) {
+ if (total_rank == 1) { /* UUPU */
+ codt |= CALC_ODT_R(2);
+ modt0 = 0x00000000;
+ modt1 = 0x00000000;
+ modt2 = CALC_ODT_W(2);
+ modt3 = 0x00000000;
+ }
+ if (total_rank == 2) { /* UUPP */
+ codt |= CALC_ODT_R(2) | CALC_ODT_R(3);
+ modt0 = 0x00000000;
+ modt1 = 0x00000000;
+ modt2 = CALC_ODT_W(2) | CALC_ODT_W(3);
+ modt3 = 0x00000000;
+ }
+ }
+ if (total_dimm == 2) {
+ if (total_rank == 2) { /* PUPU */
+ codt |= CALC_ODT_R(0) | CALC_ODT_R(2);
+ modt0 = CALC_ODT_RW(2);
+ modt1 = 0x00000000;
+ modt2 = CALC_ODT_RW(0);
+ modt3 = 0x00000000;
+ }
+ if (total_rank == 4) { /* PPPP */
+ codt |= CALC_ODT_R(0) | CALC_ODT_R(1) |
+ CALC_ODT_R(2) | CALC_ODT_R(3);
+ modt0 = CALC_ODT_RW(2) | CALC_ODT_RW(3);
+ modt1 = 0x00000000;
+ modt2 = CALC_ODT_RW(0) | CALC_ODT_RW(1);
+ modt3 = 0x00000000;
+ }
+ }
+ } else {
+ codt |= SDRAM_CODT_DQS_2_5_V_DDR1;
+ modt0 = 0x00000000;
+ modt1 = 0x00000000;
+ modt2 = 0x00000000;
+ modt3 = 0x00000000;
+
+ if (total_dimm == 1) {
+ if (total_rank == 1)
+ codt |= 0x00800000;
+ if (total_rank == 2)
+ codt |= 0x02800000;
+ }
+ if (total_dimm == 2) {
+ if (total_rank == 2)
+ codt |= 0x08800000;
+ if (total_rank == 4)
+ codt |= 0x2a800000;
+ }
+ }
+
+ debug("nb of dimm %d\n", total_dimm);
+ debug("nb of rank %d\n", total_rank);
+ if (total_dimm == 1)
+ debug("dimm in slot %d\n", firstSlot);
+
+ mtsdram(SDRAM_CODT, codt);
+ mtsdram(SDRAM_MODT0, modt0);
+ mtsdram(SDRAM_MODT1, modt1);
+ mtsdram(SDRAM_MODT2, modt2);
+ mtsdram(SDRAM_MODT3, modt3);
+}
+
+/*-----------------------------------------------------------------------------+
+ * program_initplr.
+ *-----------------------------------------------------------------------------*/
+static void program_initplr(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks,
+ ddr_cas_id_t selected_cas,
+ int write_recovery)
+{
+ u32 cas = 0;
+ u32 odt = 0;
+ u32 ods = 0;
+ u32 mr;
+ u32 wr;
+ u32 emr;
+ u32 emr2;
+ u32 emr3;
+ int dimm_num;
+ int total_dimm = 0;
+
+ /******************************************************
+ ** Assumption: if more than one DIMM, all DIMMs are the same
+ ** as already checked in check_memory_type
+ ******************************************************/
+
+ if ((dimm_populated[0] == SDRAM_DDR1) || (dimm_populated[1] == SDRAM_DDR1)) {
+ mtsdram(SDRAM_INITPLR0, 0x81B80000);
+ mtsdram(SDRAM_INITPLR1, 0x81900400);
+ mtsdram(SDRAM_INITPLR2, 0x81810000);
+ mtsdram(SDRAM_INITPLR3, 0xff800162);
+ mtsdram(SDRAM_INITPLR4, 0x81900400);
+ mtsdram(SDRAM_INITPLR5, 0x86080000);
+ mtsdram(SDRAM_INITPLR6, 0x86080000);
+ mtsdram(SDRAM_INITPLR7, 0x81000062);
+ } else if ((dimm_populated[0] == SDRAM_DDR2) || (dimm_populated[1] == SDRAM_DDR2)) {
+ switch (selected_cas) {
+ case DDR_CAS_3:
+ cas = 3 << 4;
+ break;
+ case DDR_CAS_4:
+ cas = 4 << 4;
+ break;
+ case DDR_CAS_5:
+ cas = 5 << 4;
+ break;
+ default:
+ printf("ERROR: ucode error on selected_cas value %d", selected_cas);
+ spd_ddr_init_hang ();
+ break;
+ }
+
+#if 0
+ /*
+ * ToDo - Still a problem with the write recovery:
+ * On the Corsair CM2X512-5400C4 module, setting write recovery
+ * in the INITPLR reg to the value calculated in program_mode()
+ * results in not correctly working DDR2 memory (crash after
+ * relocation).
+ *
+ * So for now, set the write recovery to 3. This seems to work
+ * on the Corair module too.
+ *
+ * 2007-03-01, sr
+ */
+ switch (write_recovery) {
+ case 3:
+ wr = WRITE_RECOV_3;
+ break;
+ case 4:
+ wr = WRITE_RECOV_4;
+ break;
+ case 5:
+ wr = WRITE_RECOV_5;
+ break;
+ case 6:
+ wr = WRITE_RECOV_6;
+ break;
+ default:
+ printf("ERROR: write recovery not support (%d)", write_recovery);
+ spd_ddr_init_hang ();
+ break;
+ }
+#else
+ wr = WRITE_RECOV_3; /* test-only, see description above */
+#endif
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++)
+ if (dimm_populated[dimm_num] != SDRAM_NONE)
+ total_dimm++;
+ if (total_dimm == 1) {
+ odt = ODT_150_OHM;
+ ods = ODS_FULL;
+ } else if (total_dimm == 2) {
+ odt = ODT_75_OHM;
+ ods = ODS_REDUCED;
+ } else {
+ printf("ERROR: Unsupported number of DIMM's (%d)", total_dimm);
+ spd_ddr_init_hang ();
+ }
+
+ mr = CMD_EMR | SELECT_MR | BURST_LEN_4 | wr | cas;
+ emr = CMD_EMR | SELECT_EMR | odt | ods;
+ emr2 = CMD_EMR | SELECT_EMR2;
+ emr3 = CMD_EMR | SELECT_EMR3;
+ /* NOP - Wait 106 MemClk cycles */
+ mtsdram(SDRAM_INITPLR0, SDRAM_INITPLR_ENABLE | CMD_NOP |
+ SDRAM_INITPLR_IMWT_ENCODE(106));
+ udelay(1000);
+ /* precharge 4 MemClk cycles */
+ mtsdram(SDRAM_INITPLR1, SDRAM_INITPLR_ENABLE | CMD_PRECHARGE |
+ SDRAM_INITPLR_IMWT_ENCODE(4));
+ /* EMR2 - Wait tMRD (2 MemClk cycles) */
+ mtsdram(SDRAM_INITPLR2, SDRAM_INITPLR_ENABLE | emr2 |
+ SDRAM_INITPLR_IMWT_ENCODE(2));
+ /* EMR3 - Wait tMRD (2 MemClk cycles) */
+ mtsdram(SDRAM_INITPLR3, SDRAM_INITPLR_ENABLE | emr3 |
+ SDRAM_INITPLR_IMWT_ENCODE(2));
+ /* EMR DLL ENABLE - Wait tMRD (2 MemClk cycles) */
+ mtsdram(SDRAM_INITPLR4, SDRAM_INITPLR_ENABLE | emr |
+ SDRAM_INITPLR_IMWT_ENCODE(2));
+ /* MR w/ DLL reset - 200 cycle wait for DLL reset */
+ mtsdram(SDRAM_INITPLR5, SDRAM_INITPLR_ENABLE | mr | DLL_RESET |
+ SDRAM_INITPLR_IMWT_ENCODE(200));
+ udelay(1000);
+ /* precharge 4 MemClk cycles */
+ mtsdram(SDRAM_INITPLR6, SDRAM_INITPLR_ENABLE | CMD_PRECHARGE |
+ SDRAM_INITPLR_IMWT_ENCODE(4));
+ /* Refresh 25 MemClk cycles */
+ mtsdram(SDRAM_INITPLR7, SDRAM_INITPLR_ENABLE | CMD_REFRESH |
+ SDRAM_INITPLR_IMWT_ENCODE(25));
+ /* Refresh 25 MemClk cycles */
+ mtsdram(SDRAM_INITPLR8, SDRAM_INITPLR_ENABLE | CMD_REFRESH |
+ SDRAM_INITPLR_IMWT_ENCODE(25));
+ /* Refresh 25 MemClk cycles */
+ mtsdram(SDRAM_INITPLR9, SDRAM_INITPLR_ENABLE | CMD_REFRESH |
+ SDRAM_INITPLR_IMWT_ENCODE(25));
+ /* Refresh 25 MemClk cycles */
+ mtsdram(SDRAM_INITPLR10, SDRAM_INITPLR_ENABLE | CMD_REFRESH |
+ SDRAM_INITPLR_IMWT_ENCODE(25));
+ /* MR w/o DLL reset - Wait tMRD (2 MemClk cycles) */
+ mtsdram(SDRAM_INITPLR11, SDRAM_INITPLR_ENABLE | mr |
+ SDRAM_INITPLR_IMWT_ENCODE(2));
+ /* EMR OCD Default - Wait tMRD (2 MemClk cycles) */
+ mtsdram(SDRAM_INITPLR12, SDRAM_INITPLR_ENABLE | OCD_CALIB_DEF |
+ SDRAM_INITPLR_IMWT_ENCODE(2) | emr);
+ /* EMR OCD Exit */
+ mtsdram(SDRAM_INITPLR13, SDRAM_INITPLR_ENABLE | emr |
+ SDRAM_INITPLR_IMWT_ENCODE(2));
+ } else {
+ printf("ERROR: ucode error as unknown DDR type in program_initplr");
+ spd_ddr_init_hang ();
+ }
+}
+
+/*------------------------------------------------------------------
+ * This routine programs the SDRAM_MMODE register.
+ * the selected_cas is an output parameter, that will be passed
+ * by caller to call the above program_initplr( )
+ *-----------------------------------------------------------------*/
+static void program_mode(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks,
+ ddr_cas_id_t *selected_cas,
+ int *write_recovery)
+{
+ unsigned long dimm_num;
+ unsigned long sdram_ddr1;
+ unsigned long t_wr_ns;
+ unsigned long t_wr_clk;
+ unsigned long cas_bit;
+ unsigned long cas_index;
+ unsigned long sdram_freq;
+ unsigned long ddr_check;
+ unsigned long mmode;
+ unsigned long tcyc_reg;
+ unsigned long cycle_2_0_clk;
+ unsigned long cycle_2_5_clk;
+ unsigned long cycle_3_0_clk;
+ unsigned long cycle_4_0_clk;
+ unsigned long cycle_5_0_clk;
+ unsigned long max_2_0_tcyc_ns_x_100;
+ unsigned long max_2_5_tcyc_ns_x_100;
+ unsigned long max_3_0_tcyc_ns_x_100;
+ unsigned long max_4_0_tcyc_ns_x_100;
+ unsigned long max_5_0_tcyc_ns_x_100;
+ unsigned long cycle_time_ns_x_100[3];
+ PPC4xx_SYS_INFO board_cfg;
+ unsigned char cas_2_0_available;
+ unsigned char cas_2_5_available;
+ unsigned char cas_3_0_available;
+ unsigned char cas_4_0_available;
+ unsigned char cas_5_0_available;
+ unsigned long sdr_ddrpll;
+
+ /*------------------------------------------------------------------
+ * Get the board configuration info.
+ *-----------------------------------------------------------------*/
+ get_sys_info(&board_cfg);
+
+ mfsdr(SDR0_DDR0, sdr_ddrpll);
+ sdram_freq = MULDIV64((board_cfg.freqPLB), SDR0_DDR0_DDRM_DECODE(sdr_ddrpll), 1);
+ debug("sdram_freq=%lu\n", sdram_freq);
+
+ /*------------------------------------------------------------------
+ * Handle the timing. We need to find the worst case timing of all
+ * the dimm modules installed.
+ *-----------------------------------------------------------------*/
+ t_wr_ns = 0;
+ cas_2_0_available = true;
+ cas_2_5_available = true;
+ cas_3_0_available = true;
+ cas_4_0_available = true;
+ cas_5_0_available = true;
+ max_2_0_tcyc_ns_x_100 = 10;
+ max_2_5_tcyc_ns_x_100 = 10;
+ max_3_0_tcyc_ns_x_100 = 10;
+ max_4_0_tcyc_ns_x_100 = 10;
+ max_5_0_tcyc_ns_x_100 = 10;
+ sdram_ddr1 = true;
+
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ /* If a dimm is installed in a particular slot ... */
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ if (dimm_populated[dimm_num] == SDRAM_DDR1)
+ sdram_ddr1 = true;
+ else
+ sdram_ddr1 = false;
+
+ cas_bit = spd_read(iic0_dimm_addr[dimm_num], 18);
+ debug("cas_bit[SPD byte 18]=%02lx\n", cas_bit);
+
+ /* For a particular DIMM, grab the three CAS values it supports */
+ for (cas_index = 0; cas_index < 3; cas_index++) {
+ switch (cas_index) {
+ case 0:
+ tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 9);
+ break;
+ case 1:
+ tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 23);
+ break;
+ default:
+ tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 25);
+ break;
+ }
+
+ if ((tcyc_reg & 0x0F) >= 10) {
+ if ((tcyc_reg & 0x0F) == 0x0D) {
+ /* Convert from hex to decimal */
+ cycle_time_ns_x_100[cas_index] =
+ (((tcyc_reg & 0xF0) >> 4) * 100) + 75;
+ } else {
+ printf("ERROR: SPD reported Tcyc is incorrect for DIMM "
+ "in slot %d\n", (unsigned int)dimm_num);
+ spd_ddr_init_hang ();
+ }
+ } else {
+ /* Convert from hex to decimal */
+ cycle_time_ns_x_100[cas_index] =
+ (((tcyc_reg & 0xF0) >> 4) * 100) +
+ ((tcyc_reg & 0x0F)*10);
+ }
+ debug("cas_index=%lu: cycle_time_ns_x_100=%lu\n", cas_index,
+ cycle_time_ns_x_100[cas_index]);
+ }
+
+ /* The rest of this routine determines if CAS 2.0, 2.5, 3.0, 4.0 and 5.0 are */
+ /* supported for a particular DIMM. */
+ cas_index = 0;
+
+ if (sdram_ddr1) {
+ /*
+ * DDR devices use the following bitmask for CAS latency:
+ * Bit 7 6 5 4 3 2 1 0
+ * TBD 4.0 3.5 3.0 2.5 2.0 1.5 1.0
+ */
+ if (((cas_bit & 0x40) == 0x40) && (cas_index < 3) &&
+ (cycle_time_ns_x_100[cas_index] != 0)) {
+ max_4_0_tcyc_ns_x_100 = max(max_4_0_tcyc_ns_x_100,
+ cycle_time_ns_x_100[cas_index]);
+ cas_index++;
+ } else {
+ if (cas_index != 0)
+ cas_index++;
+ cas_4_0_available = false;
+ }
+
+ if (((cas_bit & 0x10) == 0x10) && (cas_index < 3) &&
+ (cycle_time_ns_x_100[cas_index] != 0)) {
+ max_3_0_tcyc_ns_x_100 = max(max_3_0_tcyc_ns_x_100,
+ cycle_time_ns_x_100[cas_index]);
+ cas_index++;
+ } else {
+ if (cas_index != 0)
+ cas_index++;
+ cas_3_0_available = false;
+ }
+
+ if (((cas_bit & 0x08) == 0x08) && (cas_index < 3) &&
+ (cycle_time_ns_x_100[cas_index] != 0)) {
+ max_2_5_tcyc_ns_x_100 = max(max_2_5_tcyc_ns_x_100,
+ cycle_time_ns_x_100[cas_index]);
+ cas_index++;
+ } else {
+ if (cas_index != 0)
+ cas_index++;
+ cas_2_5_available = false;
+ }
+
+ if (((cas_bit & 0x04) == 0x04) && (cas_index < 3) &&
+ (cycle_time_ns_x_100[cas_index] != 0)) {
+ max_2_0_tcyc_ns_x_100 = max(max_2_0_tcyc_ns_x_100,
+ cycle_time_ns_x_100[cas_index]);
+ cas_index++;
+ } else {
+ if (cas_index != 0)
+ cas_index++;
+ cas_2_0_available = false;
+ }
+ } else {
+ /*
+ * DDR2 devices use the following bitmask for CAS latency:
+ * Bit 7 6 5 4 3 2 1 0
+ * TBD 6.0 5.0 4.0 3.0 2.0 TBD TBD
+ */
+ if (((cas_bit & 0x20) == 0x20) && (cas_index < 3) &&
+ (cycle_time_ns_x_100[cas_index] != 0)) {
+ max_5_0_tcyc_ns_x_100 = max(max_5_0_tcyc_ns_x_100,
+ cycle_time_ns_x_100[cas_index]);
+ cas_index++;
+ } else {
+ if (cas_index != 0)
+ cas_index++;
+ cas_5_0_available = false;
+ }
+
+ if (((cas_bit & 0x10) == 0x10) && (cas_index < 3) &&
+ (cycle_time_ns_x_100[cas_index] != 0)) {
+ max_4_0_tcyc_ns_x_100 = max(max_4_0_tcyc_ns_x_100,
+ cycle_time_ns_x_100[cas_index]);
+ cas_index++;
+ } else {
+ if (cas_index != 0)
+ cas_index++;
+ cas_4_0_available = false;
+ }
+
+ if (((cas_bit & 0x08) == 0x08) && (cas_index < 3) &&
+ (cycle_time_ns_x_100[cas_index] != 0)) {
+ max_3_0_tcyc_ns_x_100 = max(max_3_0_tcyc_ns_x_100,
+ cycle_time_ns_x_100[cas_index]);
+ cas_index++;
+ } else {
+ if (cas_index != 0)
+ cas_index++;
+ cas_3_0_available = false;
+ }
+ }
+ }
+ }
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM mode, SDRAM_MMODE
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_MMODE, mmode);
+ mmode = mmode & ~(SDRAM_MMODE_WR_MASK | SDRAM_MMODE_DCL_MASK);
+
+ /* add 10 here because of rounding problems */
+ cycle_2_0_clk = MULDIV64(ONE_BILLION, 100, max_2_0_tcyc_ns_x_100) + 10;
+ cycle_2_5_clk = MULDIV64(ONE_BILLION, 100, max_2_5_tcyc_ns_x_100) + 10;
+ cycle_3_0_clk = MULDIV64(ONE_BILLION, 100, max_3_0_tcyc_ns_x_100) + 10;
+ cycle_4_0_clk = MULDIV64(ONE_BILLION, 100, max_4_0_tcyc_ns_x_100) + 10;
+ cycle_5_0_clk = MULDIV64(ONE_BILLION, 100, max_5_0_tcyc_ns_x_100) + 10;
+ debug("cycle_3_0_clk=%lu\n", cycle_3_0_clk);
+ debug("cycle_4_0_clk=%lu\n", cycle_4_0_clk);
+ debug("cycle_5_0_clk=%lu\n", cycle_5_0_clk);
+
+ if (sdram_ddr1 == true) { /* DDR1 */
+ if ((cas_2_0_available == true) &&
+ (sdram_freq <= cycle_2_0_clk)) {
+ mmode |= SDRAM_MMODE_DCL_DDR1_2_0_CLK;
+ *selected_cas = DDR_CAS_2;
+ } else if ((cas_2_5_available == true) &&
+ (sdram_freq <= cycle_2_5_clk)) {
+ mmode |= SDRAM_MMODE_DCL_DDR1_2_5_CLK;
+ *selected_cas = DDR_CAS_2_5;
+ } else if ((cas_3_0_available == true) &&
+ (sdram_freq <= cycle_3_0_clk)) {
+ mmode |= SDRAM_MMODE_DCL_DDR1_3_0_CLK;
+ *selected_cas = DDR_CAS_3;
+ } else {
+ printf("ERROR: Cannot find a supported CAS latency with the installed DIMMs.\n");
+ printf("Only DIMMs DDR1 with CAS latencies of 2.0, 2.5, and 3.0 are supported.\n");
+ printf("Make sure the PLB speed is within the supported range of the DIMMs.\n\n");
+ spd_ddr_init_hang ();
+ }
+ } else { /* DDR2 */
+ debug("cas_3_0_available=%d\n", cas_3_0_available);
+ debug("cas_4_0_available=%d\n", cas_4_0_available);
+ debug("cas_5_0_available=%d\n", cas_5_0_available);
+ if ((cas_3_0_available == true) &&
+ (sdram_freq <= cycle_3_0_clk)) {
+ mmode |= SDRAM_MMODE_DCL_DDR2_3_0_CLK;
+ *selected_cas = DDR_CAS_3;
+ } else if ((cas_4_0_available == true) &&
+ (sdram_freq <= cycle_4_0_clk)) {
+ mmode |= SDRAM_MMODE_DCL_DDR2_4_0_CLK;
+ *selected_cas = DDR_CAS_4;
+ } else if ((cas_5_0_available == true) &&
+ (sdram_freq <= cycle_5_0_clk)) {
+ mmode |= SDRAM_MMODE_DCL_DDR2_5_0_CLK;
+ *selected_cas = DDR_CAS_5;
+ } else {
+ printf("ERROR: Cannot find a supported CAS latency with the installed DIMMs.\n");
+ printf("Only DIMMs DDR2 with CAS latencies of 3.0, 4.0, and 5.0 are supported.\n");
+ printf("Make sure the PLB speed is within the supported range of the DIMMs.\n");
+ printf("cas3=%d cas4=%d cas5=%d\n",
+ cas_3_0_available, cas_4_0_available, cas_5_0_available);
+ printf("sdram_freq=%lu cycle3=%lu cycle4=%lu cycle5=%lu\n\n",
+ sdram_freq, cycle_3_0_clk, cycle_4_0_clk, cycle_5_0_clk);
+ spd_ddr_init_hang ();
+ }
+ }
+
+ if (sdram_ddr1 == true)
+ mmode |= SDRAM_MMODE_WR_DDR1;
+ else {
+
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ /* If a dimm is installed in a particular slot ... */
+ if (dimm_populated[dimm_num] != SDRAM_NONE)
+ t_wr_ns = max(t_wr_ns,
+ spd_read(iic0_dimm_addr[dimm_num], 36) >> 2);
+ }
+
+ /*
+ * convert from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_wr_clk = MULDIV64(sdram_freq, t_wr_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_wr_clk, t_wr_ns);
+ if (sdram_freq != ddr_check)
+ t_wr_clk++;
+
+ switch (t_wr_clk) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ mmode |= SDRAM_MMODE_WR_DDR2_3_CYC;
+ break;
+ case 4:
+ mmode |= SDRAM_MMODE_WR_DDR2_4_CYC;
+ break;
+ case 5:
+ mmode |= SDRAM_MMODE_WR_DDR2_5_CYC;
+ break;
+ default:
+ mmode |= SDRAM_MMODE_WR_DDR2_6_CYC;
+ break;
+ }
+ *write_recovery = t_wr_clk;
+ }
+
+ debug("CAS latency = %d\n", *selected_cas);
+ debug("Write recovery = %d\n", *write_recovery);
+
+ mtsdram(SDRAM_MMODE, mmode);
+}
+
+/*-----------------------------------------------------------------------------+
+ * program_rtr.
+ *-----------------------------------------------------------------------------*/
+static void program_rtr(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ PPC4xx_SYS_INFO board_cfg;
+ unsigned long max_refresh_rate;
+ unsigned long dimm_num;
+ unsigned long refresh_rate_type;
+ unsigned long refresh_rate;
+ unsigned long rint;
+ unsigned long sdram_freq;
+ unsigned long sdr_ddrpll;
+ unsigned long val;
+
+ /*------------------------------------------------------------------
+ * Get the board configuration info.
+ *-----------------------------------------------------------------*/
+ get_sys_info(&board_cfg);
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM Refresh Timing Register, SDRAM_RTR
+ *-----------------------------------------------------------------*/
+ mfsdr(SDR0_DDR0, sdr_ddrpll);
+ sdram_freq = ((board_cfg.freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
+
+ max_refresh_rate = 0;
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+
+ refresh_rate_type = spd_read(iic0_dimm_addr[dimm_num], 12);
+ refresh_rate_type &= 0x7F;
+ switch (refresh_rate_type) {
+ case 0:
+ refresh_rate = 15625;
+ break;
+ case 1:
+ refresh_rate = 3906;
+ break;
+ case 2:
+ refresh_rate = 7812;
+ break;
+ case 3:
+ refresh_rate = 31250;
+ break;
+ case 4:
+ refresh_rate = 62500;
+ break;
+ case 5:
+ refresh_rate = 125000;
+ break;
+ default:
+ refresh_rate = 0;
+ printf("ERROR: DIMM %d unsupported refresh rate/type.\n",
+ (unsigned int)dimm_num);
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ spd_ddr_init_hang ();
+ break;
+ }
+
+ max_refresh_rate = max(max_refresh_rate, refresh_rate);
+ }
+ }
+
+ rint = MULDIV64(sdram_freq, max_refresh_rate, ONE_BILLION);
+ mfsdram(SDRAM_RTR, val);
+ mtsdram(SDRAM_RTR, (val & ~SDRAM_RTR_RINT_MASK) |
+ (SDRAM_RTR_RINT_ENCODE(rint)));
+}
+
+/*------------------------------------------------------------------
+ * This routine programs the SDRAM_TRx registers.
+ *-----------------------------------------------------------------*/
+static void program_tr(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long sdram_ddr1;
+ unsigned long t_rp_ns;
+ unsigned long t_rcd_ns;
+ unsigned long t_rrd_ns;
+ unsigned long t_ras_ns;
+ unsigned long t_rc_ns;
+ unsigned long t_rfc_ns;
+ unsigned long t_wpc_ns;
+ unsigned long t_wtr_ns;
+ unsigned long t_rpc_ns;
+ unsigned long t_rp_clk;
+ unsigned long t_rcd_clk;
+ unsigned long t_rrd_clk;
+ unsigned long t_ras_clk;
+ unsigned long t_rc_clk;
+ unsigned long t_rfc_clk;
+ unsigned long t_wpc_clk;
+ unsigned long t_wtr_clk;
+ unsigned long t_rpc_clk;
+ unsigned long sdtr1, sdtr2, sdtr3;
+ unsigned long ddr_check;
+ unsigned long sdram_freq;
+ unsigned long sdr_ddrpll;
+
+ PPC4xx_SYS_INFO board_cfg;
+
+ /*------------------------------------------------------------------
+ * Get the board configuration info.
+ *-----------------------------------------------------------------*/
+ get_sys_info(&board_cfg);
+
+ mfsdr(SDR0_DDR0, sdr_ddrpll);
+ sdram_freq = ((board_cfg.freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
+
+ /*------------------------------------------------------------------
+ * Handle the timing. We need to find the worst case timing of all
+ * the dimm modules installed.
+ *-----------------------------------------------------------------*/
+ t_rp_ns = 0;
+ t_rrd_ns = 0;
+ t_rcd_ns = 0;
+ t_ras_ns = 0;
+ t_rc_ns = 0;
+ t_rfc_ns = 0;
+ t_wpc_ns = 0;
+ t_wtr_ns = 0;
+ t_rpc_ns = 0;
+ sdram_ddr1 = true;
+
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ /* If a dimm is installed in a particular slot ... */
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ if (dimm_populated[dimm_num] == SDRAM_DDR2)
+ sdram_ddr1 = true;
+ else
+ sdram_ddr1 = false;
+
+ t_rcd_ns = max(t_rcd_ns, spd_read(iic0_dimm_addr[dimm_num], 29) >> 2);
+ t_rrd_ns = max(t_rrd_ns, spd_read(iic0_dimm_addr[dimm_num], 28) >> 2);
+ t_rp_ns = max(t_rp_ns, spd_read(iic0_dimm_addr[dimm_num], 27) >> 2);
+ t_ras_ns = max(t_ras_ns, spd_read(iic0_dimm_addr[dimm_num], 30));
+ t_rc_ns = max(t_rc_ns, spd_read(iic0_dimm_addr[dimm_num], 41));
+ t_rfc_ns = max(t_rfc_ns, spd_read(iic0_dimm_addr[dimm_num], 42));
+ }
+ }
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM Timing Reg 1, SDRAM_TR1
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_SDTR1, sdtr1);
+ sdtr1 &= ~(SDRAM_SDTR1_LDOF_MASK | SDRAM_SDTR1_RTW_MASK |
+ SDRAM_SDTR1_WTWO_MASK | SDRAM_SDTR1_RTRO_MASK);
+
+ /* default values */
+ sdtr1 |= SDRAM_SDTR1_LDOF_2_CLK;
+ sdtr1 |= SDRAM_SDTR1_RTW_2_CLK;
+
+ /* normal operations */
+ sdtr1 |= SDRAM_SDTR1_WTWO_0_CLK;
+ sdtr1 |= SDRAM_SDTR1_RTRO_1_CLK;
+
+ mtsdram(SDRAM_SDTR1, sdtr1);
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM Timing Reg 2, SDRAM_TR2
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_SDTR2, sdtr2);
+ sdtr2 &= ~(SDRAM_SDTR2_RCD_MASK | SDRAM_SDTR2_WTR_MASK |
+ SDRAM_SDTR2_XSNR_MASK | SDRAM_SDTR2_WPC_MASK |
+ SDRAM_SDTR2_RPC_MASK | SDRAM_SDTR2_RP_MASK |
+ SDRAM_SDTR2_RRD_MASK);
+
+ /*
+ * convert t_rcd from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_rcd_clk = MULDIV64(sdram_freq, t_rcd_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_rcd_clk, t_rcd_ns);
+ if (sdram_freq != ddr_check)
+ t_rcd_clk++;
+
+ switch (t_rcd_clk) {
+ case 0:
+ case 1:
+ sdtr2 |= SDRAM_SDTR2_RCD_1_CLK;
+ break;
+ case 2:
+ sdtr2 |= SDRAM_SDTR2_RCD_2_CLK;
+ break;
+ case 3:
+ sdtr2 |= SDRAM_SDTR2_RCD_3_CLK;
+ break;
+ case 4:
+ sdtr2 |= SDRAM_SDTR2_RCD_4_CLK;
+ break;
+ default:
+ sdtr2 |= SDRAM_SDTR2_RCD_5_CLK;
+ break;
+ }
+
+ if (sdram_ddr1 == true) { /* DDR1 */
+ if (sdram_freq < 200000000) {
+ sdtr2 |= SDRAM_SDTR2_WTR_1_CLK;
+ sdtr2 |= SDRAM_SDTR2_WPC_2_CLK;
+ sdtr2 |= SDRAM_SDTR2_RPC_2_CLK;
+ } else {
+ sdtr2 |= SDRAM_SDTR2_WTR_2_CLK;
+ sdtr2 |= SDRAM_SDTR2_WPC_3_CLK;
+ sdtr2 |= SDRAM_SDTR2_RPC_2_CLK;
+ }
+ } else { /* DDR2 */
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ /* If a dimm is installed in a particular slot ... */
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ t_wpc_ns = max(t_wtr_ns, spd_read(iic0_dimm_addr[dimm_num], 36) >> 2);
+ t_wtr_ns = max(t_wtr_ns, spd_read(iic0_dimm_addr[dimm_num], 37) >> 2);
+ t_rpc_ns = max(t_rpc_ns, spd_read(iic0_dimm_addr[dimm_num], 38) >> 2);
+ }
+ }
+
+ /*
+ * convert from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_wpc_clk = MULDIV64(sdram_freq, t_wpc_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_wpc_clk, t_wpc_ns);
+ if (sdram_freq != ddr_check)
+ t_wpc_clk++;
+
+ switch (t_wpc_clk) {
+ case 0:
+ case 1:
+ case 2:
+ sdtr2 |= SDRAM_SDTR2_WPC_2_CLK;
+ break;
+ case 3:
+ sdtr2 |= SDRAM_SDTR2_WPC_3_CLK;
+ break;
+ case 4:
+ sdtr2 |= SDRAM_SDTR2_WPC_4_CLK;
+ break;
+ case 5:
+ sdtr2 |= SDRAM_SDTR2_WPC_5_CLK;
+ break;
+ default:
+ sdtr2 |= SDRAM_SDTR2_WPC_6_CLK;
+ break;
+ }
+
+ /*
+ * convert from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_wtr_clk = MULDIV64(sdram_freq, t_wtr_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_wtr_clk, t_wtr_ns);
+ if (sdram_freq != ddr_check)
+ t_wtr_clk++;
+
+ switch (t_wtr_clk) {
+ case 0:
+ case 1:
+ sdtr2 |= SDRAM_SDTR2_WTR_1_CLK;
+ break;
+ case 2:
+ sdtr2 |= SDRAM_SDTR2_WTR_2_CLK;
+ break;
+ case 3:
+ sdtr2 |= SDRAM_SDTR2_WTR_3_CLK;
+ break;
+ default:
+ sdtr2 |= SDRAM_SDTR2_WTR_4_CLK;
+ break;
+ }
+
+ /*
+ * convert from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_rpc_clk = MULDIV64(sdram_freq, t_rpc_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_rpc_clk, t_rpc_ns);
+ if (sdram_freq != ddr_check)
+ t_rpc_clk++;
+
+ switch (t_rpc_clk) {
+ case 0:
+ case 1:
+ case 2:
+ sdtr2 |= SDRAM_SDTR2_RPC_2_CLK;
+ break;
+ case 3:
+ sdtr2 |= SDRAM_SDTR2_RPC_3_CLK;
+ break;
+ default:
+ sdtr2 |= SDRAM_SDTR2_RPC_4_CLK;
+ break;
+ }
+ }
+
+ /* default value */
+ sdtr2 |= SDRAM_SDTR2_XSNR_16_CLK;
+
+ /*
+ * convert t_rrd from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_rrd_clk = MULDIV64(sdram_freq, t_rrd_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_rrd_clk, t_rrd_ns);
+ if (sdram_freq != ddr_check)
+ t_rrd_clk++;
+
+ if (t_rrd_clk == 3)
+ sdtr2 |= SDRAM_SDTR2_RRD_3_CLK;
+ else
+ sdtr2 |= SDRAM_SDTR2_RRD_2_CLK;
+
+ /*
+ * convert t_rp from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_rp_clk = MULDIV64(sdram_freq, t_rp_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_rp_clk, t_rp_ns);
+ if (sdram_freq != ddr_check)
+ t_rp_clk++;
+
+ switch (t_rp_clk) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ sdtr2 |= SDRAM_SDTR2_RP_3_CLK;
+ break;
+ case 4:
+ sdtr2 |= SDRAM_SDTR2_RP_4_CLK;
+ break;
+ case 5:
+ sdtr2 |= SDRAM_SDTR2_RP_5_CLK;
+ break;
+ case 6:
+ sdtr2 |= SDRAM_SDTR2_RP_6_CLK;
+ break;
+ default:
+ sdtr2 |= SDRAM_SDTR2_RP_7_CLK;
+ break;
+ }
+
+ mtsdram(SDRAM_SDTR2, sdtr2);
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM Timing Reg 3, SDRAM_TR3
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_SDTR3, sdtr3);
+ sdtr3 &= ~(SDRAM_SDTR3_RAS_MASK | SDRAM_SDTR3_RC_MASK |
+ SDRAM_SDTR3_XCS_MASK | SDRAM_SDTR3_RFC_MASK);
+
+ /*
+ * convert t_ras from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_ras_clk = MULDIV64(sdram_freq, t_ras_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_ras_clk, t_ras_ns);
+ if (sdram_freq != ddr_check)
+ t_ras_clk++;
+
+ sdtr3 |= SDRAM_SDTR3_RAS_ENCODE(t_ras_clk);
+
+ /*
+ * convert t_rc from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_rc_clk = MULDIV64(sdram_freq, t_rc_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_rc_clk, t_rc_ns);
+ if (sdram_freq != ddr_check)
+ t_rc_clk++;
+
+ sdtr3 |= SDRAM_SDTR3_RC_ENCODE(t_rc_clk);
+
+ /* default xcs value */
+ sdtr3 |= SDRAM_SDTR3_XCS;
+
+ /*
+ * convert t_rfc from nanoseconds to ddr clocks
+ * round up if necessary
+ */
+ t_rfc_clk = MULDIV64(sdram_freq, t_rfc_ns, ONE_BILLION);
+ ddr_check = MULDIV64(ONE_BILLION, t_rfc_clk, t_rfc_ns);
+ if (sdram_freq != ddr_check)
+ t_rfc_clk++;
+
+ sdtr3 |= SDRAM_SDTR3_RFC_ENCODE(t_rfc_clk);
+
+ mtsdram(SDRAM_SDTR3, sdtr3);
+}
+
+/*-----------------------------------------------------------------------------+
+ * program_bxcf.
+ *-----------------------------------------------------------------------------*/
+static void program_bxcf(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long num_col_addr;
+ unsigned long num_ranks;
+ unsigned long num_banks;
+ unsigned long mode;
+ unsigned long ind_rank;
+ unsigned long ind;
+ unsigned long ind_bank;
+ unsigned long bank_0_populated;
+
+ /*------------------------------------------------------------------
+ * Set the BxCF regs. First, wipe out the bank config registers.
+ *-----------------------------------------------------------------*/
+ mtsdram(SDRAM_MB0CF, 0x00000000);
+ mtsdram(SDRAM_MB1CF, 0x00000000);
+ mtsdram(SDRAM_MB2CF, 0x00000000);
+ mtsdram(SDRAM_MB3CF, 0x00000000);
+
+ mode = SDRAM_BXCF_M_BE_ENABLE;
+
+ bank_0_populated = 0;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ num_col_addr = spd_read(iic0_dimm_addr[dimm_num], 4);
+ num_ranks = spd_read(iic0_dimm_addr[dimm_num], 5);
+ if ((spd_read(iic0_dimm_addr[dimm_num], 2)) == 0x08)
+ num_ranks = (num_ranks & 0x0F) +1;
+ else
+ num_ranks = num_ranks & 0x0F;
+
+ num_banks = spd_read(iic0_dimm_addr[dimm_num], 17);
+
+ for (ind_bank = 0; ind_bank < 2; ind_bank++) {
+ if (num_banks == 4)
+ ind = 0;
+ else
+ ind = 5 << 8;
+ switch (num_col_addr) {
+ case 0x08:
+ mode |= (SDRAM_BXCF_M_AM_0 + ind);
+ break;
+ case 0x09:
+ mode |= (SDRAM_BXCF_M_AM_1 + ind);
+ break;
+ case 0x0A:
+ mode |= (SDRAM_BXCF_M_AM_2 + ind);
+ break;
+ case 0x0B:
+ mode |= (SDRAM_BXCF_M_AM_3 + ind);
+ break;
+ case 0x0C:
+ mode |= (SDRAM_BXCF_M_AM_4 + ind);
+ break;
+ default:
+ printf("DDR-SDRAM: DIMM %d BxCF configuration.\n",
+ (unsigned int)dimm_num);
+ printf("ERROR: Unsupported value for number of "
+ "column addresses: %d.\n", (unsigned int)num_col_addr);
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ spd_ddr_init_hang ();
+ }
+ }
+
+ if ((dimm_populated[dimm_num] != SDRAM_NONE)&& (dimm_num ==1))
+ bank_0_populated = 1;
+
+ for (ind_rank = 0; ind_rank < num_ranks; ind_rank++) {
+ mtsdram(SDRAM_MB0CF +
+ ((dimm_num + bank_0_populated + ind_rank) << 2),
+ mode);
+ }
+ }
+ }
+}
+
+/*------------------------------------------------------------------
+ * program memory queue.
+ *-----------------------------------------------------------------*/
+static void program_memory_queue(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ phys_size_t rank_base_addr;
+ unsigned long rank_reg;
+ phys_size_t rank_size_bytes;
+ unsigned long rank_size_id;
+ unsigned long num_ranks;
+ unsigned long baseadd_size;
+ unsigned long i;
+ unsigned long bank_0_populated = 0;
+ phys_size_t total_size = 0;
+
+ /*------------------------------------------------------------------
+ * Reset the rank_base_address.
+ *-----------------------------------------------------------------*/
+ rank_reg = SDRAM_R0BAS;
+
+ rank_base_addr = 0x00000000;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_populated[dimm_num] != SDRAM_NONE) {
+ num_ranks = spd_read(iic0_dimm_addr[dimm_num], 5);
+ if ((spd_read(iic0_dimm_addr[dimm_num], 2)) == 0x08)
+ num_ranks = (num_ranks & 0x0F) + 1;
+ else
+ num_ranks = num_ranks & 0x0F;
+
+ rank_size_id = spd_read(iic0_dimm_addr[dimm_num], 31);
+
+ /*------------------------------------------------------------------
+ * Set the sizes
+ *-----------------------------------------------------------------*/
+ baseadd_size = 0;
+ switch (rank_size_id) {
+ case 0x01:
+ baseadd_size |= SDRAM_RXBAS_SDSZ_1024;
+ total_size = 1024;
+ break;
+ case 0x02:
+ baseadd_size |= SDRAM_RXBAS_SDSZ_2048;
+ total_size = 2048;
+ break;
+ case 0x04:
+ baseadd_size |= SDRAM_RXBAS_SDSZ_4096;
+ total_size = 4096;
+ break;
+ case 0x08:
+ baseadd_size |= SDRAM_RXBAS_SDSZ_32;
+ total_size = 32;
+ break;
+ case 0x10:
+ baseadd_size |= SDRAM_RXBAS_SDSZ_64;
+ total_size = 64;
+ break;
+ case 0x20:
+ baseadd_size |= SDRAM_RXBAS_SDSZ_128;
+ total_size = 128;
+ break;
+ case 0x40:
+ baseadd_size |= SDRAM_RXBAS_SDSZ_256;
+ total_size = 256;
+ break;
+ case 0x80:
+ baseadd_size |= SDRAM_RXBAS_SDSZ_512;
+ total_size = 512;
+ break;
+ default:
+ printf("DDR-SDRAM: DIMM %d memory queue configuration.\n",
+ (unsigned int)dimm_num);
+ printf("ERROR: Unsupported value for the banksize: %d.\n",
+ (unsigned int)rank_size_id);
+ printf("Replace the DIMM module with a supported DIMM.\n\n");
+ spd_ddr_init_hang ();
+ }
+ rank_size_bytes = total_size << 20;
+
+ if ((dimm_populated[dimm_num] != SDRAM_NONE) && (dimm_num == 1))
+ bank_0_populated = 1;
+
+ for (i = 0; i < num_ranks; i++) {
+ mtdcr_any(rank_reg+i+dimm_num+bank_0_populated,
+ (SDRAM_RXBAS_SDBA_ENCODE(rank_base_addr) |
+ baseadd_size));
+ rank_base_addr += rank_size_bytes;
+ }
+ }
+ }
+
+#if defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_460SX)
+ /*
+ * Enable high bandwidth access
+ * This is currently not used, but with this setup
+ * it is possible to use it later on in e.g. the Linux
+ * EMAC driver for performance gain.
+ */
+ mtdcr(SDRAM_PLBADDULL, 0x00000000); /* MQ0_BAUL */
+ mtdcr(SDRAM_PLBADDUHB, 0x00000008); /* MQ0_BAUH */
+
+ /*
+ * Set optimal value for Memory Queue HB/LL Configuration registers
+ */
+ mtdcr(SDRAM_CONF1HB, (mfdcr(SDRAM_CONF1HB) & ~SDRAM_CONF1HB_MASK) |
+ SDRAM_CONF1HB_AAFR | SDRAM_CONF1HB_RPEN | SDRAM_CONF1HB_RFTE |
+ SDRAM_CONF1HB_RPLM | SDRAM_CONF1HB_WRCL);
+ mtdcr(SDRAM_CONF1LL, (mfdcr(SDRAM_CONF1LL) & ~SDRAM_CONF1LL_MASK) |
+ SDRAM_CONF1LL_AAFR | SDRAM_CONF1LL_RPEN | SDRAM_CONF1LL_RFTE |
+ SDRAM_CONF1LL_RPLM);
+ mtdcr(SDRAM_CONFPATHB, mfdcr(SDRAM_CONFPATHB) | SDRAM_CONFPATHB_TPEN);
+#endif
+}
+
+#ifdef CONFIG_DDR_ECC
+/*-----------------------------------------------------------------------------+
+ * program_ecc.
+ *-----------------------------------------------------------------------------*/
+static void program_ecc(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks,
+ unsigned long tlb_word2_i_value)
+{
+ unsigned long dimm_num;
+ unsigned long ecc;
+
+ ecc = 0;
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < MAXDIMMS; dimm_num++) {
+ /* If a dimm is installed in a particular slot ... */
+ if (dimm_populated[dimm_num] != SDRAM_NONE)
+ ecc = max(ecc, spd_read(iic0_dimm_addr[dimm_num], 11));
+ }
+ if (ecc == 0)
+ return;
+
+ do_program_ecc(tlb_word2_i_value);
+}
+#endif
+
+#if !defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION)
+/*-----------------------------------------------------------------------------+
+ * program_DQS_calibration.
+ *-----------------------------------------------------------------------------*/
+static void program_DQS_calibration(unsigned long *dimm_populated,
+ unsigned char *iic0_dimm_addr,
+ unsigned long num_dimm_banks)
+{
+ unsigned long val;
+
+#ifdef HARD_CODED_DQS /* calibration test with hardvalues */
+ mtsdram(SDRAM_RQDC, 0x80000037);
+ mtsdram(SDRAM_RDCC, 0x40000000);
+ mtsdram(SDRAM_RFDC, 0x000001DF);
+
+ test();
+#else
+ /*------------------------------------------------------------------
+ * Program RDCC register
+ * Read sample cycle auto-update enable
+ *-----------------------------------------------------------------*/
+
+ mfsdram(SDRAM_RDCC, val);
+ mtsdram(SDRAM_RDCC,
+ (val & ~(SDRAM_RDCC_RDSS_MASK | SDRAM_RDCC_RSAE_MASK))
+ | SDRAM_RDCC_RSAE_ENABLE);
+
+ /*------------------------------------------------------------------
+ * Program RQDC register
+ * Internal DQS delay mechanism enable
+ *-----------------------------------------------------------------*/
+ mtsdram(SDRAM_RQDC, (SDRAM_RQDC_RQDE_ENABLE|SDRAM_RQDC_RQFD_ENCODE(0x38)));
+
+ /*------------------------------------------------------------------
+ * Program RFDC register
+ * Set Feedback Fractional Oversample
+ * Auto-detect read sample cycle enable
+ * Set RFOS to 1/4 of memclk cycle (0x3f)
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_RFDC, val);
+ mtsdram(SDRAM_RFDC,
+ (val & ~(SDRAM_RFDC_ARSE_MASK | SDRAM_RFDC_RFOS_MASK |
+ SDRAM_RFDC_RFFD_MASK))
+ | (SDRAM_RFDC_ARSE_ENABLE | SDRAM_RFDC_RFOS_ENCODE(0x3f) |
+ SDRAM_RFDC_RFFD_ENCODE(0)));
+
+ DQS_calibration_process();
+#endif
+}
+
+static int short_mem_test(void)
+{
+ u32 *membase;
+ u32 bxcr_num;
+ u32 bxcf;
+ int i;
+ int j;
+ phys_size_t base_addr;
+ u32 test[NUMMEMTESTS][NUMMEMWORDS] = {
+ {0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF},
+ {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000},
+ {0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555},
+ {0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA},
+ {0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+ 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A},
+ {0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+ 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5},
+ {0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+ 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA},
+ {0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+ 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55} };
+ int l;
+
+ for (bxcr_num = 0; bxcr_num < MAXBXCF; bxcr_num++) {
+ mfsdram(SDRAM_MB0CF + (bxcr_num << 2), bxcf);
+
+ /* Banks enabled */
+ if ((bxcf & SDRAM_BXCF_M_BE_MASK) == SDRAM_BXCF_M_BE_ENABLE) {
+ /* Bank is enabled */
+
+ /*
+ * Only run test on accessable memory (below 2GB)
+ */
+ base_addr = SDRAM_RXBAS_SDBA_DECODE(mfdcr_any(SDRAM_R0BAS+bxcr_num));
+ if (base_addr >= CONFIG_MAX_MEM_MAPPED)
+ continue;
+
+ /*------------------------------------------------------------------
+ * Run the short memory test.
+ *-----------------------------------------------------------------*/
+ membase = (u32 *)(u32)base_addr;
+
+ for (i = 0; i < NUMMEMTESTS; i++) {
+ for (j = 0; j < NUMMEMWORDS; j++) {
+ membase[j] = test[i][j];
+ ppcDcbf((u32)&(membase[j]));
+ }
+ sync();
+ for (l=0; l<NUMLOOPS; l++) {
+ for (j = 0; j < NUMMEMWORDS; j++) {
+ if (membase[j] != test[i][j]) {
+ ppcDcbf((u32)&(membase[j]));
+ return 0;
+ }
+ ppcDcbf((u32)&(membase[j]));
+ }
+ sync();
+ }
+ }
+ } /* if bank enabled */
+ } /* for bxcf_num */
+
+ return 1;
+}
+
+#ifndef HARD_CODED_DQS
+/*-----------------------------------------------------------------------------+
+ * DQS_calibration_process.
+ *-----------------------------------------------------------------------------*/
+static void DQS_calibration_process(void)
+{
+ unsigned long rfdc_reg;
+ unsigned long rffd;
+ unsigned long val;
+ long rffd_average;
+ long max_start;
+ unsigned long dlycal;
+ unsigned long dly_val;
+ unsigned long max_pass_length;
+ unsigned long current_pass_length;
+ unsigned long current_fail_length;
+ unsigned long current_start;
+ long max_end;
+ unsigned char fail_found;
+ unsigned char pass_found;
+#if !defined(CONFIG_DDR_RQDC_FIXED)
+ int window_found;
+ u32 rqdc_reg;
+ u32 rqfd;
+ u32 rqfd_start;
+ u32 rqfd_average;
+ int loopi = 0;
+ char str[] = "Auto calibration -";
+ char slash[] = "\\|/-\\|/-";
+
+ /*------------------------------------------------------------------
+ * Test to determine the best read clock delay tuning bits.
+ *
+ * Before the DDR controller can be used, the read clock delay needs to be
+ * set. This is SDRAM_RQDC[RQFD] and SDRAM_RFDC[RFFD].
+ * This value cannot be hardcoded into the program because it changes
+ * depending on the board's setup and environment.
+ * To do this, all delay values are tested to see if they
+ * work or not. By doing this, you get groups of fails with groups of
+ * passing values. The idea is to find the start and end of a passing
+ * window and take the center of it to use as the read clock delay.
+ *
+ * A failure has to be seen first so that when we hit a pass, we know
+ * that it is truely the start of the window. If we get passing values
+ * to start off with, we don't know if we are at the start of the window.
+ *
+ * The code assumes that a failure will always be found.
+ * If a failure is not found, there is no easy way to get the middle
+ * of the passing window. I guess we can pretty much pick any value
+ * but some values will be better than others. Since the lowest speed
+ * we can clock the DDR interface at is 200 MHz (2x 100 MHz PLB speed),
+ * from experimentation it is safe to say you will always have a failure.
+ *-----------------------------------------------------------------*/
+
+ /* first fix RQDC[RQFD] to an average of 80 degre phase shift to find RFDC[RFFD] */
+ rqfd_start = 64; /* test-only: don't know if this is the _best_ start value */
+
+ puts(str);
+
+calibration_loop:
+ mfsdram(SDRAM_RQDC, rqdc_reg);
+ mtsdram(SDRAM_RQDC, (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) |
+ SDRAM_RQDC_RQFD_ENCODE(rqfd_start));
+#else /* CONFIG_DDR_RQDC_FIXED */
+ /*
+ * On Katmai the complete auto-calibration somehow doesn't seem to
+ * produce the best results, meaning optimal values for RQFD/RFFD.
+ * This was discovered by GDA using a high bandwidth scope,
+ * analyzing the DDR2 signals. GDA provided a fixed value for RQFD,
+ * so now on Katmai "only" RFFD is auto-calibrated.
+ */
+ mtsdram(SDRAM_RQDC, CONFIG_DDR_RQDC_FIXED);
+#endif /* CONFIG_DDR_RQDC_FIXED */
+
+ max_start = 0;
+
+ max_pass_length = 0;
+ max_start = 0;
+ max_end = 0;
+ current_pass_length = 0;
+ current_fail_length = 0;
+ current_start = 0;
+ fail_found = false;
+ pass_found = false;
+
+ /*
+ * get the delay line calibration register value
+ */
+ mfsdram(SDRAM_DLCR, dlycal);
+ dly_val = SDRAM_DLYCAL_DLCV_DECODE(dlycal) << 2;
+
+ for (rffd = 0; rffd <= SDRAM_RFDC_RFFD_MAX; rffd++) {
+ mfsdram(SDRAM_RFDC, rfdc_reg);
+ rfdc_reg &= ~(SDRAM_RFDC_RFFD_MASK);
+
+ /*------------------------------------------------------------------
+ * Set the timing reg for the test.
+ *-----------------------------------------------------------------*/
+ mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd));
+
+ /*------------------------------------------------------------------
+ * See if the rffd value passed.
+ *-----------------------------------------------------------------*/
+ if (short_mem_test()) {
+ if (fail_found == true) {
+ pass_found = true;
+ if (current_pass_length == 0)
+ current_start = rffd;
+
+ current_fail_length = 0;
+ current_pass_length++;
+
+ if (current_pass_length > max_pass_length) {
+ max_pass_length = current_pass_length;
+ max_start = current_start;
+ max_end = rffd;
+ }
+ }
+ } else {
+ current_pass_length = 0;
+ current_fail_length++;
+
+ if (current_fail_length >= (dly_val >> 2)) {
+ if (fail_found == false)
+ fail_found = true;
+ else if (pass_found == true)
+ break;
+ }
+ }
+ } /* for rffd */
+
+ /*------------------------------------------------------------------
+ * Set the average RFFD value
+ *-----------------------------------------------------------------*/
+ rffd_average = ((max_start + max_end) >> 1);
+
+ if (rffd_average < 0)
+ rffd_average = 0;
+
+ if (rffd_average > SDRAM_RFDC_RFFD_MAX)
+ rffd_average = SDRAM_RFDC_RFFD_MAX;
+ /* now fix RFDC[RFFD] found and find RQDC[RQFD] */
+ mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd_average));
+
+#if !defined(CONFIG_DDR_RQDC_FIXED)
+ max_pass_length = 0;
+ max_start = 0;
+ max_end = 0;
+ current_pass_length = 0;
+ current_fail_length = 0;
+ current_start = 0;
+ window_found = false;
+ fail_found = false;
+ pass_found = false;
+
+ for (rqfd = 0; rqfd <= SDRAM_RQDC_RQFD_MAX; rqfd++) {
+ mfsdram(SDRAM_RQDC, rqdc_reg);
+ rqdc_reg &= ~(SDRAM_RQDC_RQFD_MASK);
+
+ /*------------------------------------------------------------------
+ * Set the timing reg for the test.
+ *-----------------------------------------------------------------*/
+ mtsdram(SDRAM_RQDC, rqdc_reg | SDRAM_RQDC_RQFD_ENCODE(rqfd));
+
+ /*------------------------------------------------------------------
+ * See if the rffd value passed.
+ *-----------------------------------------------------------------*/
+ if (short_mem_test()) {
+ if (fail_found == true) {
+ pass_found = true;
+ if (current_pass_length == 0)
+ current_start = rqfd;
+
+ current_fail_length = 0;
+ current_pass_length++;
+
+ if (current_pass_length > max_pass_length) {
+ max_pass_length = current_pass_length;
+ max_start = current_start;
+ max_end = rqfd;
+ }
+ }
+ } else {
+ current_pass_length = 0;
+ current_fail_length++;
+
+ if (fail_found == false) {
+ fail_found = true;
+ } else if (pass_found == true) {
+ window_found = true;
+ break;
+ }
+ }
+ }
+
+ rqfd_average = ((max_start + max_end) >> 1);
+
+ /*------------------------------------------------------------------
+ * Make sure we found the valid read passing window. Halt if not
+ *-----------------------------------------------------------------*/
+ if (window_found == false) {
+ if (rqfd_start < SDRAM_RQDC_RQFD_MAX) {
+ putc('\b');
+ putc(slash[loopi++ % 8]);
+
+ /* try again from with a different RQFD start value */
+ rqfd_start++;
+ goto calibration_loop;
+ }
+
+ printf("\nERROR: Cannot determine a common read delay for the "
+ "DIMM(s) installed.\n");
+ debug("%s[%d] ERROR : \n", __FUNCTION__,__LINE__);
+ ppc4xx_ibm_ddr2_register_dump();
+ spd_ddr_init_hang ();
+ }
+
+ if (rqfd_average < 0)
+ rqfd_average = 0;
+
+ if (rqfd_average > SDRAM_RQDC_RQFD_MAX)
+ rqfd_average = SDRAM_RQDC_RQFD_MAX;
+
+ mtsdram(SDRAM_RQDC,
+ (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) |
+ SDRAM_RQDC_RQFD_ENCODE(rqfd_average));
+
+ blank_string(strlen(str));
+#endif /* CONFIG_DDR_RQDC_FIXED */
+
+ mfsdram(SDRAM_DLCR, val);
+ debug("%s[%d] DLCR: 0x%08lX\n", __FUNCTION__, __LINE__, val);
+ mfsdram(SDRAM_RQDC, val);
+ debug("%s[%d] RQDC: 0x%08lX\n", __FUNCTION__, __LINE__, val);
+ mfsdram(SDRAM_RFDC, val);
+ debug("%s[%d] RFDC: 0x%08lX\n", __FUNCTION__, __LINE__, val);
+ mfsdram(SDRAM_RDCC, val);
+ debug("%s[%d] RDCC: 0x%08lX\n", __FUNCTION__, __LINE__, val);
+}
+#else /* calibration test with hardvalues */
+/*-----------------------------------------------------------------------------+
+ * DQS_calibration_process.
+ *-----------------------------------------------------------------------------*/
+static void test(void)
+{
+ unsigned long dimm_num;
+ unsigned long ecc_temp;
+ unsigned long i, j;
+ unsigned long *membase;
+ unsigned long bxcf[MAXRANKS];
+ unsigned long val;
+ char window_found;
+ char begin_found[MAXDIMMS];
+ char end_found[MAXDIMMS];
+ char search_end[MAXDIMMS];
+ unsigned long test[NUMMEMTESTS][NUMMEMWORDS] = {
+ {0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF},
+ {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000},
+ {0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555},
+ {0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA},
+ {0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+ 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A},
+ {0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+ 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5},
+ {0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+ 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA},
+ {0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+ 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55} };
+
+ /*------------------------------------------------------------------
+ * Test to determine the best read clock delay tuning bits.
+ *
+ * Before the DDR controller can be used, the read clock delay needs to be
+ * set. This is SDRAM_RQDC[RQFD] and SDRAM_RFDC[RFFD].
+ * This value cannot be hardcoded into the program because it changes
+ * depending on the board's setup and environment.
+ * To do this, all delay values are tested to see if they
+ * work or not. By doing this, you get groups of fails with groups of
+ * passing values. The idea is to find the start and end of a passing
+ * window and take the center of it to use as the read clock delay.
+ *
+ * A failure has to be seen first so that when we hit a pass, we know
+ * that it is truely the start of the window. If we get passing values
+ * to start off with, we don't know if we are at the start of the window.
+ *
+ * The code assumes that a failure will always be found.
+ * If a failure is not found, there is no easy way to get the middle
+ * of the passing window. I guess we can pretty much pick any value
+ * but some values will be better than others. Since the lowest speed
+ * we can clock the DDR interface at is 200 MHz (2x 100 MHz PLB speed),
+ * from experimentation it is safe to say you will always have a failure.
+ *-----------------------------------------------------------------*/
+ mfsdram(SDRAM_MCOPT1, ecc_temp);
+ ecc_temp &= SDRAM_MCOPT1_MCHK_MASK;
+ mfsdram(SDRAM_MCOPT1, val);
+ mtsdram(SDRAM_MCOPT1, (val & ~SDRAM_MCOPT1_MCHK_MASK) |
+ SDRAM_MCOPT1_MCHK_NON);
+
+ window_found = false;
+ begin_found[0] = false;
+ end_found[0] = false;
+ search_end[0] = false;
+ begin_found[1] = false;
+ end_found[1] = false;
+ search_end[1] = false;
+
+ for (dimm_num = 0; dimm_num < MAXDIMMS; dimm_num++) {
+ mfsdram(SDRAM_MB0CF + (bxcr_num << 2), bxcf[bxcr_num]);
+
+ /* Banks enabled */
+ if ((bxcf[dimm_num] & SDRAM_BXCF_M_BE_MASK) == SDRAM_BXCF_M_BE_ENABLE) {
+
+ /* Bank is enabled */
+ membase =
+ (unsigned long*)(SDRAM_RXBAS_SDBA_DECODE(mfdcr_any(SDRAM_R0BAS+dimm_num)));
+
+ /*------------------------------------------------------------------
+ * Run the short memory test.
+ *-----------------------------------------------------------------*/
+ for (i = 0; i < NUMMEMTESTS; i++) {
+ for (j = 0; j < NUMMEMWORDS; j++) {
+ membase[j] = test[i][j];
+ ppcDcbf((u32)&(membase[j]));
+ }
+ sync();
+ for (j = 0; j < NUMMEMWORDS; j++) {
+ if (membase[j] != test[i][j]) {
+ ppcDcbf((u32)&(membase[j]));
+ break;
+ }
+ ppcDcbf((u32)&(membase[j]));
+ }
+ sync();
+ if (j < NUMMEMWORDS)
+ break;
+ }
+
+ /*------------------------------------------------------------------
+ * See if the rffd value passed.
+ *-----------------------------------------------------------------*/
+ if (i < NUMMEMTESTS) {
+ if ((end_found[dimm_num] == false) &&
+ (search_end[dimm_num] == true)) {
+ end_found[dimm_num] = true;
+ }
+ if ((end_found[0] == true) &&
+ (end_found[1] == true))
+ break;
+ } else {
+ if (begin_found[dimm_num] == false) {
+ begin_found[dimm_num] = true;
+ search_end[dimm_num] = true;
+ }
+ }
+ } else {
+ begin_found[dimm_num] = true;
+ end_found[dimm_num] = true;
+ }
+ }
+
+ if ((begin_found[0] == true) && (begin_found[1] == true))
+ window_found = true;
+
+ /*------------------------------------------------------------------
+ * Make sure we found the valid read passing window. Halt if not
+ *-----------------------------------------------------------------*/
+ if (window_found == false) {
+ printf("ERROR: Cannot determine a common read delay for the "
+ "DIMM(s) installed.\n");
+ spd_ddr_init_hang ();
+ }
+
+ /*------------------------------------------------------------------
+ * Restore the ECC variable to what it originally was
+ *-----------------------------------------------------------------*/
+ mtsdram(SDRAM_MCOPT1,
+ (ppcMfdcr_sdram(SDRAM_MCOPT1) & ~SDRAM_MCOPT1_MCHK_MASK)
+ | ecc_temp);
+}
+#endif /* !HARD_CODED_DQS */
+#endif /* !defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION) */
+
+#else /* CONFIG_SPD_EEPROM */
+
+/*-----------------------------------------------------------------------------
+ * Function: initdram
+ * Description: Configures the PPC4xx IBM DDR1/DDR2 SDRAM memory controller.
+ * The configuration is performed using static, compile-
+ * time parameters.
+ * Configures the PPC405EX(r) and PPC460EX/GT
+ *---------------------------------------------------------------------------*/
+phys_size_t initdram(int board_type)
+{
+ /*
+ * Only run this SDRAM init code once. For NAND booting
+ * targets like Kilauea, we call initdram() early from the
+ * 4k NAND booting image (CONFIG_NAND_SPL) from nand_boot().
+ * Later on the NAND U-Boot image runs (CONFIG_NAND_U_BOOT)
+ * which calls initdram() again. This time the controller
+ * mustn't be reconfigured again since we're already running
+ * from SDRAM.
+ */
+#if !defined(CONFIG_NAND_U_BOOT) || defined(CONFIG_NAND_SPL)
+ unsigned long val;
+
+#if defined(CONFIG_440)
+ mtdcr(SDRAM_R0BAS, CONFIG_SYS_SDRAM_R0BAS);
+ mtdcr(SDRAM_R1BAS, CONFIG_SYS_SDRAM_R1BAS);
+ mtdcr(SDRAM_R2BAS, CONFIG_SYS_SDRAM_R2BAS);
+ mtdcr(SDRAM_R3BAS, CONFIG_SYS_SDRAM_R3BAS);
+ mtdcr(SDRAM_PLBADDULL, CONFIG_SYS_SDRAM_PLBADDULL); /* MQ0_BAUL */
+ mtdcr(SDRAM_PLBADDUHB, CONFIG_SYS_SDRAM_PLBADDUHB); /* MQ0_BAUH */
+ mtdcr(SDRAM_CONF1LL, CONFIG_SYS_SDRAM_CONF1LL);
+ mtdcr(SDRAM_CONF1HB, CONFIG_SYS_SDRAM_CONF1HB);
+ mtdcr(SDRAM_CONFPATHB, CONFIG_SYS_SDRAM_CONFPATHB);
+#endif
+
+ /* Set Memory Bank Configuration Registers */
+
+ mtsdram(SDRAM_MB0CF, CONFIG_SYS_SDRAM0_MB0CF);
+ mtsdram(SDRAM_MB1CF, CONFIG_SYS_SDRAM0_MB1CF);
+ mtsdram(SDRAM_MB2CF, CONFIG_SYS_SDRAM0_MB2CF);
+ mtsdram(SDRAM_MB3CF, CONFIG_SYS_SDRAM0_MB3CF);
+
+ /* Set Memory Clock Timing Register */
+
+ mtsdram(SDRAM_CLKTR, CONFIG_SYS_SDRAM0_CLKTR);
+
+ /* Set Refresh Time Register */
+
+ mtsdram(SDRAM_RTR, CONFIG_SYS_SDRAM0_RTR);
+
+ /* Set SDRAM Timing Registers */
+
+ mtsdram(SDRAM_SDTR1, CONFIG_SYS_SDRAM0_SDTR1);
+ mtsdram(SDRAM_SDTR2, CONFIG_SYS_SDRAM0_SDTR2);
+ mtsdram(SDRAM_SDTR3, CONFIG_SYS_SDRAM0_SDTR3);
+
+ /* Set Mode and Extended Mode Registers */
+
+ mtsdram(SDRAM_MMODE, CONFIG_SYS_SDRAM0_MMODE);
+ mtsdram(SDRAM_MEMODE, CONFIG_SYS_SDRAM0_MEMODE);
+
+ /* Set Memory Controller Options 1 Register */
+
+ mtsdram(SDRAM_MCOPT1, CONFIG_SYS_SDRAM0_MCOPT1);
+
+ /* Set Manual Initialization Control Registers */
+
+ mtsdram(SDRAM_INITPLR0, CONFIG_SYS_SDRAM0_INITPLR0);
+ mtsdram(SDRAM_INITPLR1, CONFIG_SYS_SDRAM0_INITPLR1);
+ mtsdram(SDRAM_INITPLR2, CONFIG_SYS_SDRAM0_INITPLR2);
+ mtsdram(SDRAM_INITPLR3, CONFIG_SYS_SDRAM0_INITPLR3);
+ mtsdram(SDRAM_INITPLR4, CONFIG_SYS_SDRAM0_INITPLR4);
+ mtsdram(SDRAM_INITPLR5, CONFIG_SYS_SDRAM0_INITPLR5);
+ mtsdram(SDRAM_INITPLR6, CONFIG_SYS_SDRAM0_INITPLR6);
+ mtsdram(SDRAM_INITPLR7, CONFIG_SYS_SDRAM0_INITPLR7);
+ mtsdram(SDRAM_INITPLR8, CONFIG_SYS_SDRAM0_INITPLR8);
+ mtsdram(SDRAM_INITPLR9, CONFIG_SYS_SDRAM0_INITPLR9);
+ mtsdram(SDRAM_INITPLR10, CONFIG_SYS_SDRAM0_INITPLR10);
+ mtsdram(SDRAM_INITPLR11, CONFIG_SYS_SDRAM0_INITPLR11);
+ mtsdram(SDRAM_INITPLR12, CONFIG_SYS_SDRAM0_INITPLR12);
+ mtsdram(SDRAM_INITPLR13, CONFIG_SYS_SDRAM0_INITPLR13);
+ mtsdram(SDRAM_INITPLR14, CONFIG_SYS_SDRAM0_INITPLR14);
+ mtsdram(SDRAM_INITPLR15, CONFIG_SYS_SDRAM0_INITPLR15);
+
+ /* Set On-Die Termination Registers */
+
+ mtsdram(SDRAM_CODT, CONFIG_SYS_SDRAM0_CODT);
+ mtsdram(SDRAM_MODT0, CONFIG_SYS_SDRAM0_MODT0);
+ mtsdram(SDRAM_MODT1, CONFIG_SYS_SDRAM0_MODT1);
+
+ /* Set Write Timing Register */
+
+ mtsdram(SDRAM_WRDTR, CONFIG_SYS_SDRAM0_WRDTR);
+
+ /*
+ * Start Initialization by SDRAM0_MCOPT2[SREN] = 0 and
+ * SDRAM0_MCOPT2[IPTR] = 1
+ */
+
+ mtsdram(SDRAM_MCOPT2, (SDRAM_MCOPT2_SREN_EXIT |
+ SDRAM_MCOPT2_IPTR_EXECUTE));
+
+ /*
+ * Poll SDRAM0_MCSTAT[MIC] for assertion to indicate the
+ * completion of initialization.
+ */
+
+ do {
+ mfsdram(SDRAM_MCSTAT, val);
+ } while ((val & SDRAM_MCSTAT_MIC_MASK) != SDRAM_MCSTAT_MIC_COMP);
+
+ /* Set Delay Control Registers */
+
+ mtsdram(SDRAM_DLCR, CONFIG_SYS_SDRAM0_DLCR);
+
+#if !defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION)
+ mtsdram(SDRAM_RDCC, CONFIG_SYS_SDRAM0_RDCC);
+ mtsdram(SDRAM_RQDC, CONFIG_SYS_SDRAM0_RQDC);
+ mtsdram(SDRAM_RFDC, CONFIG_SYS_SDRAM0_RFDC);
+#endif /* !CONFIG_PPC4xx_DDR_AUTOCALIBRATION */
+
+ /*
+ * Enable Controller by SDRAM0_MCOPT2[DCEN] = 1:
+ */
+
+ mfsdram(SDRAM_MCOPT2, val);
+ mtsdram(SDRAM_MCOPT2, val | SDRAM_MCOPT2_DCEN_ENABLE);
+
+#if defined(CONFIG_440)
+ /*
+ * Program TLB entries with caches enabled, for best performace
+ * while auto-calibrating and ECC generation
+ */
+ program_tlb(0, 0, (CONFIG_SYS_MBYTES_SDRAM << 20), 0);
+#endif
+
+#if defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION)
+#if !defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL)
+ /*------------------------------------------------------------------
+ | DQS calibration.
+ +-----------------------------------------------------------------*/
+ DQS_autocalibration();
+#endif /* !defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL) */
+#endif /* CONFIG_PPC4xx_DDR_AUTOCALIBRATION */
+
+ /*
+ * Now complete RDSS configuration as mentioned on page 7 of the AMCC
+ * PowerPC440SP/SPe DDR2 application note:
+ * "DDR1/DDR2 Initialization Sequence and Dynamic Tuning"
+ */
+ update_rdcc();
+
+#if defined(CONFIG_DDR_ECC)
+ do_program_ecc(0);
+#endif /* defined(CONFIG_DDR_ECC) */
+
+#if defined(CONFIG_440)
+ /*
+ * Now after initialization (auto-calibration and ECC generation)
+ * remove the TLB entries with caches enabled and program again with
+ * desired cache functionality
+ */
+ remove_tlb(0, (CONFIG_SYS_MBYTES_SDRAM << 20));
+ program_tlb(0, 0, (CONFIG_SYS_MBYTES_SDRAM << 20), MY_TLB_WORD2_I_ENABLE);
+#endif
+
+ ppc4xx_ibm_ddr2_register_dump();
+
+#if defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION)
+ /*
+ * Clear potential errors resulting from auto-calibration.
+ * If not done, then we could get an interrupt later on when
+ * exceptions are enabled.
+ */
+ set_mcsr(get_mcsr());
+#endif /* CONFIG_PPC4xx_DDR_AUTOCALIBRATION */
+
+#endif /* !defined(CONFIG_NAND_U_BOOT) || defined(CONFIG_NAND_SPL) */
+
+ return (CONFIG_SYS_MBYTES_SDRAM << 20);
+}
+#endif /* CONFIG_SPD_EEPROM */
+
+#if !defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL)
+#if defined(CONFIG_440)
+u32 mfdcr_any(u32 dcr)
+{
+ u32 val;
+
+ switch (dcr) {
+ case SDRAM_R0BAS + 0:
+ val = mfdcr(SDRAM_R0BAS + 0);
+ break;
+ case SDRAM_R0BAS + 1:
+ val = mfdcr(SDRAM_R0BAS + 1);
+ break;
+ case SDRAM_R0BAS + 2:
+ val = mfdcr(SDRAM_R0BAS + 2);
+ break;
+ case SDRAM_R0BAS + 3:
+ val = mfdcr(SDRAM_R0BAS + 3);
+ break;
+ default:
+ printf("DCR %d not defined in case statement!!!\n", dcr);
+ val = 0; /* just to satisfy the compiler */
+ }
+
+ return val;
+}
+
+void mtdcr_any(u32 dcr, u32 val)
+{
+ switch (dcr) {
+ case SDRAM_R0BAS + 0:
+ mtdcr(SDRAM_R0BAS + 0, val);
+ break;
+ case SDRAM_R0BAS + 1:
+ mtdcr(SDRAM_R0BAS + 1, val);
+ break;
+ case SDRAM_R0BAS + 2:
+ mtdcr(SDRAM_R0BAS + 2, val);
+ break;
+ case SDRAM_R0BAS + 3:
+ mtdcr(SDRAM_R0BAS + 3, val);
+ break;
+ default:
+ printf("DCR %d not defined in case statement!!!\n", dcr);
+ }
+}
+#endif /* defined(CONFIG_440) */
+#endif /* !defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL) */
+
+inline void ppc4xx_ibm_ddr2_register_dump(void)
+{
+#if defined(DEBUG)
+ printf("\nPPC4xx IBM DDR2 Register Dump:\n");
+
+#if (defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT))
+ PPC4xx_IBM_DDR2_DUMP_MQ_REGISTER(R0BAS);
+ PPC4xx_IBM_DDR2_DUMP_MQ_REGISTER(R1BAS);
+ PPC4xx_IBM_DDR2_DUMP_MQ_REGISTER(R2BAS);
+ PPC4xx_IBM_DDR2_DUMP_MQ_REGISTER(R3BAS);
+#endif /* (defined(CONFIG_440SP) || ... */
+#if defined(CONFIG_405EX)
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(BESR);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(BEARL);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(BEARH);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(WMIRQ);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(PLBOPT);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(PUABA);
+#endif /* defined(CONFIG_405EX) */
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(MB0CF);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(MB1CF);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(MB2CF);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(MB3CF);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(MCSTAT);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(MCOPT1);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(MCOPT2);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(MODT0);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(MODT1);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(MODT2);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(MODT3);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(CODT);
+#if (defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT))
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(VVPR);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(OPARS);
+ /*
+ * OPART is only used as a trigger register.
+ *
+ * No data is contained in this register, and reading or writing
+ * to is can cause bad things to happen (hangs). Just skip it and
+ * report "N/A".
+ */
+ printf("%20s = N/A\n", "SDRAM_OPART");
+#endif /* defined(CONFIG_440SP) || ... */
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(RTR);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR0);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR1);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR2);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR3);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR4);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR5);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR6);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR7);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR8);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR9);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR10);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR11);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR12);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR13);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR14);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(INITPLR15);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(RQDC);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(RFDC);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(RDCC);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(DLCR);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(CLKTR);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(WRDTR);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(SDTR1);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(SDTR2);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(SDTR3);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(MMODE);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(MEMODE);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(ECCES);
+#if (defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT))
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(CID);
+#endif /* defined(CONFIG_440SP) || ... */
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(RID);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(FCSR);
+ PPC4xx_IBM_DDR2_DUMP_REGISTER(RTSR);
+#endif /* defined(DEBUG) */
+}
diff --git a/arch/powerpc/cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c b/arch/powerpc/cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c
new file mode 100644
index 0000000..3c87bfb
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c
@@ -0,0 +1,1256 @@
+/*
+ * arch/powerpc/cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c
+ * This SPD SDRAM detection code supports AMCC PPC44x cpu's with a
+ * DDR2 controller (non Denali Core). Those currently are:
+ *
+ * 405: 405EX
+ * 440/460: 440SP/440SPe/460EX/460GT/460SX
+ *
+ * (C) Copyright 2008 Applied Micro Circuits Corporation
+ * Adam Graham <agraham@amcc.com>
+ *
+ * (C) Copyright 2007-2008
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * COPYRIGHT AMCC CORPORATION 2004
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+/* define DEBUG for debugging output (obviously ;-)) */
+#undef DEBUG
+
+#include <common.h>
+#include <asm/ppc4xx.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+#include "ecc.h"
+
+/*
+ * Only compile the DDR auto-calibration code for NOR boot and
+ * not for NAND boot (NAND SPL and NAND U-Boot - NUB)
+ */
+#if !defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL)
+
+#define MAXBXCF 4
+#define SDRAM_RXBAS_SHIFT_1M 20
+
+#if defined(CONFIG_SYS_DECREMENT_PATTERNS)
+#define NUMMEMTESTS 24
+#else
+#define NUMMEMTESTS 8
+#endif /* CONFIG_SYS_DECREMENT_PATTERNS */
+#define NUMLOOPS 1 /* configure as you deem approporiate */
+#define NUMMEMWORDS 16
+
+#define SDRAM_RDCC_RDSS_VAL(n) SDRAM_RDCC_RDSS_DECODE(ddr_rdss_opt(n))
+
+/* Private Structure Definitions */
+
+struct autocal_regs {
+ u32 rffd;
+ u32 rqfd;
+};
+
+struct ddrautocal {
+ u32 rffd;
+ u32 rffd_min;
+ u32 rffd_max;
+ u32 rffd_size;
+ u32 rqfd;
+ u32 rqfd_size;
+ u32 rdcc;
+ u32 flags;
+};
+
+struct sdram_timing_clks {
+ u32 wrdtr;
+ u32 clktr;
+ u32 rdcc;
+ u32 flags;
+};
+
+struct autocal_clks {
+ struct sdram_timing_clks clocks;
+ struct ddrautocal autocal;
+};
+
+/*--------------------------------------------------------------------------+
+ * Prototypes
+ *--------------------------------------------------------------------------*/
+#if defined(CONFIG_PPC4xx_DDR_METHOD_A)
+static u32 DQS_calibration_methodA(struct ddrautocal *);
+static u32 program_DQS_calibration_methodA(struct ddrautocal *);
+#else
+static u32 DQS_calibration_methodB(struct ddrautocal *);
+static u32 program_DQS_calibration_methodB(struct ddrautocal *);
+#endif
+static int short_mem_test(u32 *);
+
+/*
+ * To provide an interface for board specific config values in this common
+ * DDR setup code, we implement he "weak" default functions here. They return
+ * the default value back to the caller.
+ *
+ * Please see include/configs/yucca.h for an example fora board specific
+ * implementation.
+ */
+
+#if !defined(CONFIG_SPD_EEPROM)
+u32 __ddr_wrdtr(u32 default_val)
+{
+ return default_val;
+}
+u32 ddr_wrdtr(u32) __attribute__((weak, alias("__ddr_wrdtr")));
+
+u32 __ddr_clktr(u32 default_val)
+{
+ return default_val;
+}
+u32 ddr_clktr(u32) __attribute__((weak, alias("__ddr_clktr")));
+
+/*
+ * Board-specific Platform code can reimplement spd_ddr_init_hang () if needed
+ */
+void __spd_ddr_init_hang(void)
+{
+ hang();
+}
+void
+spd_ddr_init_hang(void) __attribute__((weak, alias("__spd_ddr_init_hang")));
+#endif /* defined(CONFIG_SPD_EEPROM) */
+
+struct sdram_timing *__ddr_scan_option(struct sdram_timing *default_val)
+{
+ return default_val;
+}
+struct sdram_timing *ddr_scan_option(struct sdram_timing *)
+ __attribute__((weak, alias("__ddr_scan_option")));
+
+u32 __ddr_rdss_opt(u32 default_val)
+{
+ return default_val;
+}
+u32 ddr_rdss_opt(ulong) __attribute__((weak, alias("__ddr_rdss_opt")));
+
+
+static u32 *get_membase(int bxcr_num)
+{
+ u32 *membase;
+
+#if defined(SDRAM_R0BAS)
+ /* BAS from Memory Queue rank reg. */
+ membase =
+ (u32 *)(SDRAM_RXBAS_SDBA_DECODE(mfdcr_any(SDRAM_R0BAS+bxcr_num)));
+#else
+ {
+ ulong bxcf;
+
+ /* BAS from SDRAM_MBxCF mem rank reg. */
+ mfsdram(SDRAM_MB0CF + (bxcr_num<<2), bxcf);
+ membase = (u32 *)((bxcf & 0xfff80000) << 3);
+ }
+#endif
+
+ return membase;
+}
+
+static inline void ecc_clear_status_reg(void)
+{
+ mtsdram(SDRAM_ECCES, 0xffffffff);
+#if defined(SDRAM_R0BAS)
+ mtdcr(SDRAM_ERRSTATLL, 0xffffffff);
+#endif
+}
+
+/*
+ * Reset and relock memory DLL after SDRAM_CLKTR change
+ */
+static inline void relock_memory_DLL(void)
+{
+ u32 reg;
+
+ mtsdram(SDRAM_MCOPT2, SDRAM_MCOPT2_IPTR_EXECUTE);
+
+ do {
+ mfsdram(SDRAM_MCSTAT, reg);
+ } while (!(reg & SDRAM_MCSTAT_MIC_COMP));
+
+ mfsdram(SDRAM_MCOPT2, reg);
+ mtsdram(SDRAM_MCOPT2, reg | SDRAM_MCOPT2_DCEN_ENABLE);
+}
+
+static int ecc_check_status_reg(void)
+{
+ u32 ecc_status;
+
+ /*
+ * Compare suceeded, now check
+ * if got ecc error. If got an
+ * ecc error, then don't count
+ * this as a passing value
+ */
+ mfsdram(SDRAM_ECCES, ecc_status);
+ if (ecc_status != 0x00000000) {
+ /* clear on error */
+ ecc_clear_status_reg();
+ /* ecc check failure */
+ return 0;
+ }
+ ecc_clear_status_reg();
+ sync();
+
+ return 1;
+}
+
+/* return 1 if passes, 0 if fail */
+static int short_mem_test(u32 *base_address)
+{
+ int i, j, l;
+ u32 ecc_mode = 0;
+
+ ulong test[NUMMEMTESTS][NUMMEMWORDS] = {
+ /* 0 */ {0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF},
+ /* 1 */ {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000},
+ /* 2 */ {0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555},
+ /* 3 */ {0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA},
+ /* 4 */ {0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+ 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+ 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+ 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A},
+ /* 5 */ {0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+ 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+ 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+ 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5},
+ /* 6 */ {0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+ 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+ 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+ 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA},
+ /* 7 */ {0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+ 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+ 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+ 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55},
+
+#if defined(CONFIG_SYS_DECREMENT_PATTERNS)
+ /* 8 */ {0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff},
+ /* 9 */ {0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe,
+ 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe,
+ 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe,
+ 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe},
+ /* 10 */{0xfffdfffd, 0xfffdfffd, 0xfffdffff, 0xfffdfffd,
+ 0xfffdfffd, 0xfffdfffd, 0xfffdffff, 0xfffdfffd,
+ 0xfffdfffd, 0xfffdfffd, 0xfffdffff, 0xfffdfffd,
+ 0xfffdfffd, 0xfffdfffd, 0xfffdffff, 0xfffdfffd},
+ /* 11 */{0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc,
+ 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc,
+ 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc,
+ 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc},
+ /* 12 */{0xfffbfffb, 0xfffffffb, 0xfffffffb, 0xfffffffb,
+ 0xfffbfffb, 0xfffffffb, 0xfffffffb, 0xfffffffb,
+ 0xfffbfffb, 0xfffffffb, 0xfffffffb, 0xfffffffb,
+ 0xfffbfffb, 0xfffffffb, 0xfffffffb, 0xfffffffb},
+ /* 13 */{0xfffafffa, 0xfffafffa, 0xfffffffa, 0xfffafffa,
+ 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa,
+ 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa,
+ 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa},
+ /* 14 */{0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9,
+ 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9,
+ 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9,
+ 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9},
+ /* 15 */{0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8,
+ 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8,
+ 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8,
+ 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8},
+ /* 16 */{0xfff7fff7, 0xfff7ffff, 0xfff7fff7, 0xfff7fff7,
+ 0xfff7fff7, 0xfff7ffff, 0xfff7fff7, 0xfff7fff7,
+ 0xfff7fff7, 0xfff7ffff, 0xfff7fff7, 0xfff7fff7,
+ 0xfff7ffff, 0xfff7ffff, 0xfff7fff7, 0xfff7fff7},
+ /* 17 */{0xfff6fff5, 0xfff6ffff, 0xfff6fff6, 0xfff6fff7,
+ 0xfff6fff5, 0xfff6ffff, 0xfff6fff6, 0xfff6fff7,
+ 0xfff6fff5, 0xfff6ffff, 0xfff6fff6, 0xfff6fff7,
+ 0xfff6fff5, 0xfff6ffff, 0xfff6fff6, 0xfff6fff7},
+ /* 18 */{0xfff5fff4, 0xfff5ffff, 0xfff5fff5, 0xfff5fff5,
+ 0xfff5fff4, 0xfff5ffff, 0xfff5fff5, 0xfff5fff5,
+ 0xfff5fff4, 0xfff5ffff, 0xfff5fff5, 0xfff5fff5,
+ 0xfff5fff4, 0xfff5ffff, 0xfff5fff5, 0xfff5fff5},
+ /* 19 */{0xfff4fff3, 0xfff4ffff, 0xfff4fff4, 0xfff4fff4,
+ 0xfff4fff3, 0xfff4ffff, 0xfff4fff4, 0xfff4fff4,
+ 0xfff4fff3, 0xfff4ffff, 0xfff4fff4, 0xfff4fff4,
+ 0xfff4fff3, 0xfff4ffff, 0xfff4fff4, 0xfff4fff4},
+ /* 20 */{0xfff3fff2, 0xfff3ffff, 0xfff3fff3, 0xfff3fff3,
+ 0xfff3fff2, 0xfff3ffff, 0xfff3fff3, 0xfff3fff3,
+ 0xfff3fff2, 0xfff3ffff, 0xfff3fff3, 0xfff3fff3,
+ 0xfff3fff2, 0xfff3ffff, 0xfff3fff3, 0xfff3fff3},
+ /* 21 */{0xfff2ffff, 0xfff2ffff, 0xfff2fff2, 0xfff2fff2,
+ 0xfff2ffff, 0xfff2ffff, 0xfff2fff2, 0xfff2fff2,
+ 0xfff2ffff, 0xfff2ffff, 0xfff2fff2, 0xfff2fff2,
+ 0xfff2ffff, 0xfff2ffff, 0xfff2fff2, 0xfff2fff2},
+ /* 22 */{0xfff1ffff, 0xfff1ffff, 0xfff1fff1, 0xfff1fff1,
+ 0xfff1ffff, 0xfff1ffff, 0xfff1fff1, 0xfff1fff1,
+ 0xfff1ffff, 0xfff1ffff, 0xfff1fff1, 0xfff1fff1,
+ 0xfff1ffff, 0xfff1ffff, 0xfff1fff1, 0xfff1fff1},
+ /* 23 */{0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0,
+ 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0,
+ 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0,
+ 0xfff0fff0, 0xfff0fffe, 0xfff0fff0, 0xfff0fff0},
+#endif /* CONFIG_SYS_DECREMENT_PATTERNS */
+ };
+
+ mfsdram(SDRAM_MCOPT1, ecc_mode);
+ if ((ecc_mode & SDRAM_MCOPT1_MCHK_CHK_REP) ==
+ SDRAM_MCOPT1_MCHK_CHK_REP) {
+ ecc_clear_status_reg();
+ sync();
+ ecc_mode = 1;
+ } else {
+ ecc_mode = 0;
+ }
+
+ /*
+ * Run the short memory test.
+ */
+ for (i = 0; i < NUMMEMTESTS; i++) {
+ for (j = 0; j < NUMMEMWORDS; j++) {
+ base_address[j] = test[i][j];
+ ppcDcbf((ulong)&(base_address[j]));
+ }
+ sync();
+ iobarrier_rw();
+ for (l = 0; l < NUMLOOPS; l++) {
+ for (j = 0; j < NUMMEMWORDS; j++) {
+ if (base_address[j] != test[i][j]) {
+ ppcDcbf((u32)&(base_address[j]));
+ return 0;
+ } else {
+ if (ecc_mode) {
+ if (!ecc_check_status_reg())
+ return 0;
+ }
+ }
+ ppcDcbf((u32)&(base_address[j]));
+ } /* for (j = 0; j < NUMMEMWORDS; j++) */
+ sync();
+ iobarrier_rw();
+ } /* for (l=0; l<NUMLOOPS; l++) */
+ }
+
+ return 1;
+}
+
+#if defined(CONFIG_PPC4xx_DDR_METHOD_A)
+/*-----------------------------------------------------------------------------+
+| program_DQS_calibration_methodA.
++-----------------------------------------------------------------------------*/
+static u32 program_DQS_calibration_methodA(struct ddrautocal *ddrcal)
+{
+ u32 pass_result = 0;
+
+#ifdef DEBUG
+ ulong temp;
+
+ mfsdram(SDRAM_RDCC, temp);
+ debug("<%s>SDRAM_RDCC=0x%08x\n", __func__, temp);
+#endif
+
+ pass_result = DQS_calibration_methodA(ddrcal);
+
+ return pass_result;
+}
+
+/*
+ * DQS_calibration_methodA()
+ *
+ * Autocalibration Method A
+ *
+ * ARRAY [Entire DQS Range] DQS_Valid_Window ; initialized to all zeros
+ * ARRAY [Entire FDBK Range] FDBK_Valid_Window; initialized to all zeros
+ * MEMWRITE(addr, expected_data);
+ * for (i = 0; i < Entire DQS Range; i++) { RQDC.RQFD
+ * for (j = 0; j < Entire FDBK Range; j++) { RFDC.RFFD
+ * MEMREAD(addr, actual_data);
+ * if (actual_data == expected_data) {
+ * DQS_Valid_Window[i] = 1; RQDC.RQFD
+ * FDBK_Valid_Window[i][j] = 1; RFDC.RFFD
+ * }
+ * }
+ * }
+ */
+static u32 DQS_calibration_methodA(struct ddrautocal *cal)
+{
+ ulong rfdc_reg;
+ ulong rffd;
+
+ ulong rqdc_reg;
+ ulong rqfd;
+
+ u32 *membase;
+ ulong bxcf;
+ int rqfd_average;
+ int bxcr_num;
+ int rffd_average;
+ int pass;
+ u32 passed = 0;
+
+ int in_window;
+ struct autocal_regs curr_win_min;
+ struct autocal_regs curr_win_max;
+ struct autocal_regs best_win_min;
+ struct autocal_regs best_win_max;
+ struct autocal_regs loop_win_min;
+ struct autocal_regs loop_win_max;
+
+#ifdef DEBUG
+ ulong temp;
+#endif
+ ulong rdcc;
+
+ char slash[] = "\\|/-\\|/-";
+ int loopi = 0;
+
+ /* start */
+ in_window = 0;
+
+ memset(&curr_win_min, 0, sizeof(curr_win_min));
+ memset(&curr_win_max, 0, sizeof(curr_win_max));
+ memset(&best_win_min, 0, sizeof(best_win_min));
+ memset(&best_win_max, 0, sizeof(best_win_max));
+ memset(&loop_win_min, 0, sizeof(loop_win_min));
+ memset(&loop_win_max, 0, sizeof(loop_win_max));
+
+ rdcc = 0;
+
+ /*
+ * Program RDCC register
+ * Read sample cycle auto-update enable
+ */
+ mtsdram(SDRAM_RDCC,
+ ddr_rdss_opt(SDRAM_RDCC_RDSS_T2) | SDRAM_RDCC_RSAE_ENABLE);
+
+#ifdef DEBUG
+ mfsdram(SDRAM_RDCC, temp);
+ debug("<%s>SDRAM_RDCC=0x%x\n", __func__, temp);
+ mfsdram(SDRAM_RTSR, temp);
+ debug("<%s>SDRAM_RTSR=0x%x\n", __func__, temp);
+ mfsdram(SDRAM_FCSR, temp);
+ debug("<%s>SDRAM_FCSR=0x%x\n", __func__, temp);
+#endif
+
+ /*
+ * Program RQDC register
+ * Internal DQS delay mechanism enable
+ */
+ mtsdram(SDRAM_RQDC,
+ SDRAM_RQDC_RQDE_ENABLE | SDRAM_RQDC_RQFD_ENCODE(0x00));
+
+#ifdef DEBUG
+ mfsdram(SDRAM_RQDC, temp);
+ debug("<%s>SDRAM_RQDC=0x%x\n", __func__, temp);
+#endif
+
+ /*
+ * Program RFDC register
+ * Set Feedback Fractional Oversample
+ * Auto-detect read sample cycle enable
+ */
+ mtsdram(SDRAM_RFDC, SDRAM_RFDC_ARSE_ENABLE |
+ SDRAM_RFDC_RFOS_ENCODE(0) | SDRAM_RFDC_RFFD_ENCODE(0));
+
+#ifdef DEBUG
+ mfsdram(SDRAM_RFDC, temp);
+ debug("<%s>SDRAM_RFDC=0x%x\n", __func__, temp);
+#endif
+
+ putc(' ');
+ for (rqfd = 0; rqfd <= SDRAM_RQDC_RQFD_MAX; rqfd++) {
+
+ mfsdram(SDRAM_RQDC, rqdc_reg);
+ rqdc_reg &= ~(SDRAM_RQDC_RQFD_MASK);
+ mtsdram(SDRAM_RQDC, rqdc_reg | SDRAM_RQDC_RQFD_ENCODE(rqfd));
+
+ putc('\b');
+ putc(slash[loopi++ % 8]);
+
+ curr_win_min.rffd = 0;
+ curr_win_max.rffd = 0;
+ in_window = 0;
+
+ for (rffd = 0, pass = 0; rffd <= SDRAM_RFDC_RFFD_MAX; rffd++) {
+ mfsdram(SDRAM_RFDC, rfdc_reg);
+ rfdc_reg &= ~(SDRAM_RFDC_RFFD_MASK);
+ mtsdram(SDRAM_RFDC,
+ rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd));
+
+ for (bxcr_num = 0; bxcr_num < MAXBXCF; bxcr_num++) {
+ mfsdram(SDRAM_MB0CF + (bxcr_num<<2), bxcf);
+
+ /* Banks enabled */
+ if (bxcf & SDRAM_BXCF_M_BE_MASK) {
+ /* Bank is enabled */
+ membase = get_membase(bxcr_num);
+ pass = short_mem_test(membase);
+ } /* if bank enabled */
+ } /* for bxcr_num */
+
+ /* If this value passed update RFFD windows */
+ if (pass && !in_window) { /* at the start of window */
+ in_window = 1;
+ curr_win_min.rffd = curr_win_max.rffd = rffd;
+ curr_win_min.rqfd = curr_win_max.rqfd = rqfd;
+ mfsdram(SDRAM_RDCC, rdcc); /*record this value*/
+ } else if (!pass && in_window) { /* at end of window */
+ in_window = 0;
+ } else if (pass && in_window) { /* within the window */
+ curr_win_max.rffd = rffd;
+ curr_win_max.rqfd = rqfd;
+ }
+ /* else if (!pass && !in_window)
+ skip - no pass, not currently in a window */
+
+ if (in_window) {
+ if ((curr_win_max.rffd - curr_win_min.rffd) >
+ (best_win_max.rffd - best_win_min.rffd)) {
+ best_win_min.rffd = curr_win_min.rffd;
+ best_win_max.rffd = curr_win_max.rffd;
+
+ best_win_min.rqfd = curr_win_min.rqfd;
+ best_win_max.rqfd = curr_win_max.rqfd;
+ cal->rdcc = rdcc;
+ }
+ passed = 1;
+ }
+ } /* RFDC.RFFD */
+
+ /*
+ * save-off the best window results of the RFDC.RFFD
+ * for this RQDC.RQFD setting
+ */
+ /*
+ * if (just ended RFDC.RFDC loop pass window) >
+ * (prior RFDC.RFFD loop pass window)
+ */
+ if ((best_win_max.rffd - best_win_min.rffd) >
+ (loop_win_max.rffd - loop_win_min.rffd)) {
+ loop_win_min.rffd = best_win_min.rffd;
+ loop_win_max.rffd = best_win_max.rffd;
+ loop_win_min.rqfd = rqfd;
+ loop_win_max.rqfd = rqfd;
+ debug("RQFD.min 0x%08x, RQFD.max 0x%08x, "
+ "RFFD.min 0x%08x, RFFD.max 0x%08x\n",
+ loop_win_min.rqfd, loop_win_max.rqfd,
+ loop_win_min.rffd, loop_win_max.rffd);
+ }
+ } /* RQDC.RQFD */
+
+ putc('\b');
+
+ debug("\n");
+
+ if ((loop_win_min.rffd == 0) && (loop_win_max.rffd == 0) &&
+ (best_win_min.rffd == 0) && (best_win_max.rffd == 0) &&
+ (best_win_min.rqfd == 0) && (best_win_max.rqfd == 0)) {
+ passed = 0;
+ }
+
+ /*
+ * Need to program RQDC before RFDC.
+ */
+ debug("<%s> RQFD Min: 0x%x\n", __func__, loop_win_min.rqfd);
+ debug("<%s> RQFD Max: 0x%x\n", __func__, loop_win_max.rqfd);
+ rqfd_average = loop_win_max.rqfd;
+
+ if (rqfd_average < 0)
+ rqfd_average = 0;
+
+ if (rqfd_average > SDRAM_RQDC_RQFD_MAX)
+ rqfd_average = SDRAM_RQDC_RQFD_MAX;
+
+ debug("<%s> RFFD average: 0x%08x\n", __func__, rqfd_average);
+ mtsdram(SDRAM_RQDC, (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) |
+ SDRAM_RQDC_RQFD_ENCODE(rqfd_average));
+
+ debug("<%s> RFFD Min: 0x%08x\n", __func__, loop_win_min.rffd);
+ debug("<%s> RFFD Max: 0x%08x\n", __func__, loop_win_max.rffd);
+ rffd_average = ((loop_win_min.rffd + loop_win_max.rffd) / 2);
+
+ if (rffd_average < 0)
+ rffd_average = 0;
+
+ if (rffd_average > SDRAM_RFDC_RFFD_MAX)
+ rffd_average = SDRAM_RFDC_RFFD_MAX;
+
+ debug("<%s> RFFD average: 0x%08x\n", __func__, rffd_average);
+ mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd_average));
+
+ /* if something passed, then return the size of the largest window */
+ if (passed != 0) {
+ passed = loop_win_max.rffd - loop_win_min.rffd;
+ cal->rqfd = rqfd_average;
+ cal->rffd = rffd_average;
+ cal->rffd_min = loop_win_min.rffd;
+ cal->rffd_max = loop_win_max.rffd;
+ }
+
+ return (u32)passed;
+}
+
+#else /* !defined(CONFIG_PPC4xx_DDR_METHOD_A) */
+
+/*-----------------------------------------------------------------------------+
+| program_DQS_calibration_methodB.
++-----------------------------------------------------------------------------*/
+static u32 program_DQS_calibration_methodB(struct ddrautocal *ddrcal)
+{
+ u32 pass_result = 0;
+
+#ifdef DEBUG
+ ulong temp;
+#endif
+
+ /*
+ * Program RDCC register
+ * Read sample cycle auto-update enable
+ */
+ mtsdram(SDRAM_RDCC,
+ ddr_rdss_opt(SDRAM_RDCC_RDSS_T2) | SDRAM_RDCC_RSAE_ENABLE);
+
+#ifdef DEBUG
+ mfsdram(SDRAM_RDCC, temp);
+ debug("<%s>SDRAM_RDCC=0x%08x\n", __func__, temp);
+#endif
+
+ /*
+ * Program RQDC register
+ * Internal DQS delay mechanism enable
+ */
+ mtsdram(SDRAM_RQDC,
+#if defined(CONFIG_DDR_RQDC_START_VAL)
+ SDRAM_RQDC_RQDE_ENABLE |
+ SDRAM_RQDC_RQFD_ENCODE(CONFIG_DDR_RQDC_START_VAL));
+#else
+ SDRAM_RQDC_RQDE_ENABLE | SDRAM_RQDC_RQFD_ENCODE(0x38));
+#endif
+
+#ifdef DEBUG
+ mfsdram(SDRAM_RQDC, temp);
+ debug("<%s>SDRAM_RQDC=0x%08x\n", __func__, temp);
+#endif
+
+ /*
+ * Program RFDC register
+ * Set Feedback Fractional Oversample
+ * Auto-detect read sample cycle enable
+ */
+ mtsdram(SDRAM_RFDC, SDRAM_RFDC_ARSE_ENABLE |
+ SDRAM_RFDC_RFOS_ENCODE(0) |
+ SDRAM_RFDC_RFFD_ENCODE(0));
+
+#ifdef DEBUG
+ mfsdram(SDRAM_RFDC, temp);
+ debug("<%s>SDRAM_RFDC=0x%08x\n", __func__, temp);
+#endif
+
+ pass_result = DQS_calibration_methodB(ddrcal);
+
+ return pass_result;
+}
+
+/*
+ * DQS_calibration_methodB()
+ *
+ * Autocalibration Method B
+ *
+ * ARRAY [Entire DQS Range] DQS_Valid_Window ; initialized to all zeros
+ * ARRAY [Entire Feedback Range] FDBK_Valid_Window; initialized to all zeros
+ * MEMWRITE(addr, expected_data);
+ * Initialialize the DQS delay to 80 degrees (MCIF0_RRQDC[RQFD]=0x38).
+ *
+ * for (j = 0; j < Entire Feedback Range; j++) {
+ * MEMREAD(addr, actual_data);
+ * if (actual_data == expected_data) {
+ * FDBK_Valid_Window[j] = 1;
+ * }
+ * }
+ *
+ * Set MCIF0_RFDC[RFFD] to the middle of the FDBK_Valid_Window.
+ *
+ * for (i = 0; i < Entire DQS Range; i++) {
+ * MEMREAD(addr, actual_data);
+ * if (actual_data == expected_data) {
+ * DQS_Valid_Window[i] = 1;
+ * }
+ * }
+ *
+ * Set MCIF0_RRQDC[RQFD] to the middle of the DQS_Valid_Window.
+ */
+/*-----------------------------------------------------------------------------+
+| DQS_calibration_methodB.
++-----------------------------------------------------------------------------*/
+static u32 DQS_calibration_methodB(struct ddrautocal *cal)
+{
+ ulong rfdc_reg;
+#ifndef CONFIG_DDR_RFDC_FIXED
+ ulong rffd;
+#endif
+
+ ulong rqdc_reg;
+ ulong rqfd;
+
+ ulong rdcc;
+
+ u32 *membase;
+ ulong bxcf;
+ int rqfd_average;
+ int bxcr_num;
+ int rffd_average;
+ int pass;
+ uint passed = 0;
+
+ int in_window;
+ u32 curr_win_min, curr_win_max;
+ u32 best_win_min, best_win_max;
+ u32 size = 0;
+
+ /*------------------------------------------------------------------
+ | Test to determine the best read clock delay tuning bits.
+ |
+ | Before the DDR controller can be used, the read clock delay needs to
+ | be set. This is SDRAM_RQDC[RQFD] and SDRAM_RFDC[RFFD].
+ | This value cannot be hardcoded into the program because it changes
+ | depending on the board's setup and environment.
+ | To do this, all delay values are tested to see if they
+ | work or not. By doing this, you get groups of fails with groups of
+ | passing values. The idea is to find the start and end of a passing
+ | window and take the center of it to use as the read clock delay.
+ |
+ | A failure has to be seen first so that when we hit a pass, we know
+ | that it is truely the start of the window. If we get passing values
+ | to start off with, we don't know if we are at the start of the window
+ |
+ | The code assumes that a failure will always be found.
+ | If a failure is not found, there is no easy way to get the middle
+ | of the passing window. I guess we can pretty much pick any value
+ | but some values will be better than others. Since the lowest speed
+ | we can clock the DDR interface at is 200 MHz (2x 100 MHz PLB speed),
+ | from experimentation it is safe to say you will always have a failure
+ +-----------------------------------------------------------------*/
+
+ debug("\n\n");
+
+#if defined(CONFIG_DDR_RFDC_FIXED)
+ mtsdram(SDRAM_RFDC, CONFIG_DDR_RFDC_FIXED);
+ size = 512;
+ rffd_average = CONFIG_DDR_RFDC_FIXED & SDRAM_RFDC_RFFD_MASK;
+ mfsdram(SDRAM_RDCC, rdcc); /* record this value */
+ cal->rdcc = rdcc;
+#else /* CONFIG_DDR_RFDC_FIXED */
+ in_window = 0;
+ rdcc = 0;
+
+ curr_win_min = curr_win_max = 0;
+ best_win_min = best_win_max = 0;
+ for (rffd = 0; rffd <= SDRAM_RFDC_RFFD_MAX; rffd++) {
+ mfsdram(SDRAM_RFDC, rfdc_reg);
+ rfdc_reg &= ~(SDRAM_RFDC_RFFD_MASK);
+ mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd));
+
+ pass = 1;
+ for (bxcr_num = 0; bxcr_num < MAXBXCF; bxcr_num++) {
+ mfsdram(SDRAM_MB0CF + (bxcr_num<<2), bxcf);
+
+ /* Banks enabled */
+ if (bxcf & SDRAM_BXCF_M_BE_MASK) {
+ /* Bank is enabled */
+ membase = get_membase(bxcr_num);
+ pass &= short_mem_test(membase);
+ } /* if bank enabled */
+ } /* for bxcf_num */
+
+ /* If this value passed */
+ if (pass && !in_window) { /* start of passing window */
+ in_window = 1;
+ curr_win_min = curr_win_max = rffd;
+ mfsdram(SDRAM_RDCC, rdcc); /* record this value */
+ } else if (!pass && in_window) { /* end passing window */
+ in_window = 0;
+ } else if (pass && in_window) { /* within the passing window */
+ curr_win_max = rffd;
+ }
+
+ if (in_window) {
+ if ((curr_win_max - curr_win_min) >
+ (best_win_max - best_win_min)) {
+ best_win_min = curr_win_min;
+ best_win_max = curr_win_max;
+ cal->rdcc = rdcc;
+ }
+ passed = 1;
+ }
+ } /* for rffd */
+
+ if ((best_win_min == 0) && (best_win_max == 0))
+ passed = 0;
+ else
+ size = best_win_max - best_win_min;
+
+ debug("RFFD Min: 0x%x\n", best_win_min);
+ debug("RFFD Max: 0x%x\n", best_win_max);
+ rffd_average = ((best_win_min + best_win_max) / 2);
+
+ cal->rffd_min = best_win_min;
+ cal->rffd_max = best_win_max;
+
+ if (rffd_average < 0)
+ rffd_average = 0;
+
+ if (rffd_average > SDRAM_RFDC_RFFD_MAX)
+ rffd_average = SDRAM_RFDC_RFFD_MAX;
+
+ mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd_average));
+#endif /* CONFIG_DDR_RFDC_FIXED */
+
+ in_window = 0;
+
+ curr_win_min = curr_win_max = 0;
+ best_win_min = best_win_max = 0;
+ for (rqfd = 0; rqfd <= SDRAM_RQDC_RQFD_MAX; rqfd++) {
+ mfsdram(SDRAM_RQDC, rqdc_reg);
+ rqdc_reg &= ~(SDRAM_RQDC_RQFD_MASK);
+ mtsdram(SDRAM_RQDC, rqdc_reg | SDRAM_RQDC_RQFD_ENCODE(rqfd));
+
+ pass = 1;
+ for (bxcr_num = 0; bxcr_num < MAXBXCF; bxcr_num++) {
+
+ mfsdram(SDRAM_MB0CF + (bxcr_num<<2), bxcf);
+
+ /* Banks enabled */
+ if (bxcf & SDRAM_BXCF_M_BE_MASK) {
+ /* Bank is enabled */
+ membase = get_membase(bxcr_num);
+ pass &= short_mem_test(membase);
+ } /* if bank enabled */
+ } /* for bxcf_num */
+
+ /* If this value passed */
+ if (pass && !in_window) {
+ in_window = 1;
+ curr_win_min = curr_win_max = rqfd;
+ } else if (!pass && in_window) {
+ in_window = 0;
+ } else if (pass && in_window) {
+ curr_win_max = rqfd;
+ }
+
+ if (in_window) {
+ if ((curr_win_max - curr_win_min) >
+ (best_win_max - best_win_min)) {
+ best_win_min = curr_win_min;
+ best_win_max = curr_win_max;
+ }
+ passed = 1;
+ }
+ } /* for rqfd */
+
+ if ((best_win_min == 0) && (best_win_max == 0))
+ passed = 0;
+
+ debug("RQFD Min: 0x%x\n", best_win_min);
+ debug("RQFD Max: 0x%x\n", best_win_max);
+ rqfd_average = ((best_win_min + best_win_max) / 2);
+
+ if (rqfd_average < 0)
+ rqfd_average = 0;
+
+ if (rqfd_average > SDRAM_RQDC_RQFD_MAX)
+ rqfd_average = SDRAM_RQDC_RQFD_MAX;
+
+ mtsdram(SDRAM_RQDC, (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) |
+ SDRAM_RQDC_RQFD_ENCODE(rqfd_average));
+
+ mfsdram(SDRAM_RQDC, rqdc_reg);
+ mfsdram(SDRAM_RFDC, rfdc_reg);
+
+ /*
+ * Need to program RQDC before RFDC. The value is read above.
+ * That is the reason why auto cal not work.
+ * See, comments below.
+ */
+ mtsdram(SDRAM_RQDC, rqdc_reg);
+ mtsdram(SDRAM_RFDC, rfdc_reg);
+
+ debug("RQDC: 0x%08lX\n", rqdc_reg);
+ debug("RFDC: 0x%08lX\n", rfdc_reg);
+
+ /* if something passed, then return the size of the largest window */
+ if (passed != 0) {
+ passed = size;
+ cal->rqfd = rqfd_average;
+ cal->rffd = rffd_average;
+ }
+
+ return (uint)passed;
+}
+#endif /* defined(CONFIG_PPC4xx_DDR_METHOD_A) */
+
+/*
+ * Default table for DDR auto-calibration of all
+ * possible WRDTR and CLKTR values.
+ * Table format is:
+ * {SDRAM_WRDTR.[WDTR], SDRAM_CLKTR.[CKTR]}
+ *
+ * Table is terminated with {-1, -1} value pair.
+ *
+ * Board vendors can specify their own board specific subset of
+ * known working {SDRAM_WRDTR.[WDTR], SDRAM_CLKTR.[CKTR]} value
+ * pairs via a board defined ddr_scan_option() function.
+ */
+static struct sdram_timing full_scan_options[] = {
+ {0, 0}, {0, 1}, {0, 2}, {0, 3},
+ {1, 0}, {1, 1}, {1, 2}, {1, 3},
+ {2, 0}, {2, 1}, {2, 2}, {2, 3},
+ {3, 0}, {3, 1}, {3, 2}, {3, 3},
+ {4, 0}, {4, 1}, {4, 2}, {4, 3},
+ {5, 0}, {5, 1}, {5, 2}, {5, 3},
+ {6, 0}, {6, 1}, {6, 2}, {6, 3},
+ {-1, -1}
+};
+
+/*---------------------------------------------------------------------------+
+| DQS_calibration.
++----------------------------------------------------------------------------*/
+u32 DQS_autocalibration(void)
+{
+ u32 wdtr;
+ u32 clkp;
+ u32 result = 0;
+ u32 best_result = 0;
+ u32 best_rdcc;
+ struct ddrautocal ddrcal;
+ struct autocal_clks tcal;
+ ulong rfdc_reg;
+ ulong rqdc_reg;
+ u32 val;
+ int verbose_lvl = 0;
+ char *str;
+ char slash[] = "\\|/-\\|/-";
+ int loopi = 0;
+ struct sdram_timing *scan_list;
+
+#if defined(DEBUG_PPC4xx_DDR_AUTOCALIBRATION)
+ int i;
+ char tmp[64]; /* long enough for environment variables */
+#endif
+
+ memset(&tcal, 0, sizeof(tcal));
+
+ scan_list = ddr_scan_option(full_scan_options);
+
+ mfsdram(SDRAM_MCOPT1, val);
+ if ((val & SDRAM_MCOPT1_MCHK_CHK_REP) == SDRAM_MCOPT1_MCHK_CHK_REP)
+ str = "ECC Auto calibration -";
+ else
+ str = "Auto calibration -";
+
+ puts(str);
+
+#if defined(DEBUG_PPC4xx_DDR_AUTOCALIBRATION)
+ i = getenv_f("autocalib", tmp, sizeof(tmp));
+ if (i < 0)
+ strcpy(tmp, CONFIG_AUTOCALIB);
+
+ if (strcmp(tmp, "final") == 0) {
+ /* display the final autocalibration results only */
+ verbose_lvl = 1;
+ } else if (strcmp(tmp, "loop") == 0) {
+ /* display summary autocalibration info per iteration */
+ verbose_lvl = 2;
+ } else if (strcmp(tmp, "display") == 0) {
+ /* display full debug autocalibration window info. */
+ verbose_lvl = 3;
+ }
+#endif /* (DEBUG_PPC4xx_DDR_AUTOCALIBRATION) */
+
+ best_rdcc = (SDRAM_RDCC_RDSS_T4 >> 30);
+
+ while ((scan_list->wrdtr != -1) && (scan_list->clktr != -1)) {
+ wdtr = scan_list->wrdtr;
+ clkp = scan_list->clktr;
+
+ mfsdram(SDRAM_WRDTR, val);
+ val &= ~(SDRAM_WRDTR_LLWP_MASK | SDRAM_WRDTR_WTR_MASK);
+ mtsdram(SDRAM_WRDTR, (val |
+ ddr_wrdtr(SDRAM_WRDTR_LLWP_1_CYC | (wdtr << 25))));
+
+ mtsdram(SDRAM_CLKTR, clkp << 30);
+
+ relock_memory_DLL();
+
+ putc('\b');
+ putc(slash[loopi++ % 8]);
+
+#ifdef DEBUG
+ debug("\n");
+ debug("*** --------------\n");
+ mfsdram(SDRAM_WRDTR, val);
+ debug("*** SDRAM_WRDTR set to 0x%08x\n", val);
+ mfsdram(SDRAM_CLKTR, val);
+ debug("*** SDRAM_CLKTR set to 0x%08x\n", val);
+#endif
+
+ debug("\n");
+ if (verbose_lvl > 2) {
+ printf("*** SDRAM_WRDTR (wdtr) set to %d\n", wdtr);
+ printf("*** SDRAM_CLKTR (clkp) set to %d\n", clkp);
+ }
+
+ memset(&ddrcal, 0, sizeof(ddrcal));
+
+ /*
+ * DQS calibration.
+ */
+ /*
+ * program_DQS_calibration_method[A|B]() returns 0 if no
+ * passing RFDC.[RFFD] window is found or returns the size
+ * of the best passing window; in the case of a found passing
+ * window, the ddrcal will contain the values of the best
+ * window RQDC.[RQFD] and RFDC.[RFFD].
+ */
+
+ /*
+ * Call PPC4xx SDRAM DDR autocalibration methodA or methodB.
+ * Default is methodB.
+ * Defined the autocalibration method in the board specific
+ * header file.
+ * Please see include/configs/kilauea.h for an example for
+ * a board specific implementation.
+ */
+#if defined(CONFIG_PPC4xx_DDR_METHOD_A)
+ result = program_DQS_calibration_methodA(&ddrcal);
+#else
+ result = program_DQS_calibration_methodB(&ddrcal);
+#endif
+
+ sync();
+
+ /*
+ * Clear potential errors resulting from auto-calibration.
+ * If not done, then we could get an interrupt later on when
+ * exceptions are enabled.
+ */
+ set_mcsr(get_mcsr());
+
+ val = ddrcal.rdcc; /* RDCC from the best passing window */
+
+ udelay(100);
+
+ if (verbose_lvl > 1) {
+ char *tstr;
+ switch ((val >> 30)) {
+ case 0:
+ if (result != 0)
+ tstr = "T1";
+ else
+ tstr = "N/A";
+ break;
+ case 1:
+ tstr = "T2";
+ break;
+ case 2:
+ tstr = "T3";
+ break;
+ case 3:
+ tstr = "T4";
+ break;
+ default:
+ tstr = "unknown";
+ break;
+ }
+ printf("** WRDTR(%d) CLKTR(%d), Wind (%d), best (%d), "
+ "max-min(0x%04x)(0x%04x), RDCC: %s\n",
+ wdtr, clkp, result, best_result,
+ ddrcal.rffd_min, ddrcal.rffd_max, tstr);
+ }
+
+ /*
+ * The DQS calibration "result" is either "0"
+ * if no passing window was found, or is the
+ * size of the RFFD passing window.
+ */
+ /*
+ * want the lowest Read Sample Cycle Select
+ */
+ val = SDRAM_RDCC_RDSS_DECODE(val);
+ debug("*** (%d) (%d) current_rdcc, best_rdcc\n",
+ val, best_rdcc);
+
+ if ((result != 0) &&
+ (val >= SDRAM_RDCC_RDSS_VAL(SDRAM_RDCC_RDSS_T2))) {
+ if (((result == best_result) && (val < best_rdcc)) ||
+ ((result > best_result) && (val <= best_rdcc))) {
+ tcal.autocal.flags = 1;
+ debug("*** (%d)(%d) result passed window "
+ "size: 0x%08x, rqfd = 0x%08x, "
+ "rffd = 0x%08x, rdcc = 0x%08x\n",
+ wdtr, clkp, result, ddrcal.rqfd,
+ ddrcal.rffd, ddrcal.rdcc);
+
+ /*
+ * Save the SDRAM_WRDTR and SDRAM_CLKTR
+ * settings for the largest returned
+ * RFFD passing window size.
+ */
+ best_rdcc = val;
+ tcal.clocks.wrdtr = wdtr;
+ tcal.clocks.clktr = clkp;
+ tcal.clocks.rdcc = SDRAM_RDCC_RDSS_ENCODE(val);
+ tcal.autocal.rqfd = ddrcal.rqfd;
+ tcal.autocal.rffd = ddrcal.rffd;
+ best_result = result;
+
+ if (verbose_lvl > 2) {
+ printf("** (%d)(%d) "
+ "best result: 0x%04x\n",
+ wdtr, clkp,
+ best_result);
+ printf("** (%d)(%d) "
+ "best WRDTR: 0x%04x\n",
+ wdtr, clkp,
+ tcal.clocks.wrdtr);
+ printf("** (%d)(%d) "
+ "best CLKTR: 0x%04x\n",
+ wdtr, clkp,
+ tcal.clocks.clktr);
+ printf("** (%d)(%d) "
+ "best RQDC: 0x%04x\n",
+ wdtr, clkp,
+ tcal.autocal.rqfd);
+ printf("** (%d)(%d) "
+ "best RFDC: 0x%04x\n",
+ wdtr, clkp,
+ tcal.autocal.rffd);
+ printf("** (%d)(%d) "
+ "best RDCC: 0x%08x\n",
+ wdtr, clkp,
+ (u32)tcal.clocks.rdcc);
+ mfsdram(SDRAM_RTSR, val);
+ printf("** (%d)(%d) best "
+ "loop RTSR: 0x%08x\n",
+ wdtr, clkp, val);
+ mfsdram(SDRAM_FCSR, val);
+ printf("** (%d)(%d) best "
+ "loop FCSR: 0x%08x\n",
+ wdtr, clkp, val);
+ }
+ }
+ } /* if ((result != 0) && (val >= (ddr_rdss_opt()))) */
+ scan_list++;
+ } /* while ((scan_list->wrdtr != -1) && (scan_list->clktr != -1)) */
+
+ if (tcal.autocal.flags == 1) {
+ if (verbose_lvl > 0) {
+ printf("*** --------------\n");
+ printf("*** best_result window size: %d\n",
+ best_result);
+ printf("*** best_result WRDTR: 0x%04x\n",
+ tcal.clocks.wrdtr);
+ printf("*** best_result CLKTR: 0x%04x\n",
+ tcal.clocks.clktr);
+ printf("*** best_result RQFD: 0x%04x\n",
+ tcal.autocal.rqfd);
+ printf("*** best_result RFFD: 0x%04x\n",
+ tcal.autocal.rffd);
+ printf("*** best_result RDCC: 0x%04x\n",
+ tcal.clocks.rdcc);
+ printf("*** --------------\n");
+ printf("\n");
+ }
+
+ /*
+ * if got best passing result window, then lock in the
+ * best CLKTR, WRDTR, RQFD, and RFFD values
+ */
+ mfsdram(SDRAM_WRDTR, val);
+ mtsdram(SDRAM_WRDTR, (val &
+ ~(SDRAM_WRDTR_LLWP_MASK | SDRAM_WRDTR_WTR_MASK)) |
+ ddr_wrdtr(SDRAM_WRDTR_LLWP_1_CYC |
+ (tcal.clocks.wrdtr << 25)));
+
+ mtsdram(SDRAM_CLKTR, tcal.clocks.clktr << 30);
+
+ relock_memory_DLL();
+
+ mfsdram(SDRAM_RQDC, rqdc_reg);
+ rqdc_reg &= ~(SDRAM_RQDC_RQFD_MASK);
+ mtsdram(SDRAM_RQDC, rqdc_reg |
+ SDRAM_RQDC_RQFD_ENCODE(tcal.autocal.rqfd));
+
+ mfsdram(SDRAM_RQDC, rqdc_reg);
+ debug("*** best_result: read value SDRAM_RQDC 0x%08lx\n",
+ rqdc_reg);
+
+#if defined(CONFIG_DDR_RFDC_FIXED)
+ mtsdram(SDRAM_RFDC, CONFIG_DDR_RFDC_FIXED);
+#else /* CONFIG_DDR_RFDC_FIXED */
+ mfsdram(SDRAM_RFDC, rfdc_reg);
+ rfdc_reg &= ~(SDRAM_RFDC_RFFD_MASK);
+ mtsdram(SDRAM_RFDC, rfdc_reg |
+ SDRAM_RFDC_RFFD_ENCODE(tcal.autocal.rffd));
+#endif /* CONFIG_DDR_RFDC_FIXED */
+
+ mfsdram(SDRAM_RFDC, rfdc_reg);
+ debug("*** best_result: read value SDRAM_RFDC 0x%08lx\n",
+ rfdc_reg);
+ mfsdram(SDRAM_RDCC, val);
+ debug("*** SDRAM_RDCC 0x%08x\n", val);
+ } else {
+ /*
+ * no valid windows were found
+ */
+ printf("DQS memory calibration window can not be determined, "
+ "terminating u-boot.\n");
+ ppc4xx_ibm_ddr2_register_dump();
+ spd_ddr_init_hang();
+ }
+
+ blank_string(strlen(str));
+
+ return 0;
+}
+#else /* defined(CONFIG_NAND_U_BOOT) || defined(CONFIG_NAND_SPL) */
+u32 DQS_autocalibration(void)
+{
+ return 0;
+}
+#endif /* !defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL) */
diff --git a/arch/powerpc/cpu/ppc4xx/4xx_pci.c b/arch/powerpc/cpu/ppc4xx/4xx_pci.c
new file mode 100644
index 0000000..2ca355b
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/4xx_pci.c
@@ -0,0 +1,885 @@
+/*-----------------------------------------------------------------------------+
+ * This source code is dual-licensed. You may use it under the terms of
+ * the GNU General Public license version 2, or under the license below.
+ *
+ * This source code has been made available to you by IBM on an AS-IS
+ * basis. Anyone receiving this source is licensed under IBM
+ * copyrights to use it in any way he or she deems fit, including
+ * copying it, modifying it, compiling it, and redistributing it either
+ * with or without modifications. No license under IBM patents or
+ * patent applications is to be implied by the copyright license.
+ *
+ * Any user of this software should understand that IBM cannot provide
+ * technical support for this software and will not be responsible for
+ * any consequences resulting from the use of this software.
+ *
+ * Any person who transfers this source code or any derivative work
+ * must include the IBM copyright notice, this paragraph, and the
+ * preceding two paragraphs in the transferred software.
+ *
+ * COPYRIGHT I B M CORPORATION 1995
+ * LICENSED MATERIAL - PROGRAM PROPERTY OF I B M
+ *-----------------------------------------------------------------------------*/
+/*----------------------------------------------------------------------------+
+ *
+ * File Name: 405gp_pci.c
+ *
+ * Function: Initialization code for the 405GP PCI Configuration regs.
+ *
+ * Author: Mark Game
+ *
+ * Change Activity-
+ *
+ * Date Description of Change BY
+ * --------- --------------------- ---
+ * 09-Sep-98 Created MCG
+ * 02-Nov-98 Removed External arbiter selected message JWB
+ * 27-Nov-98 Zero out PTMBAR2 and disable in PTM2MS JWB
+ * 04-Jan-99 Zero out other unused PMM and PTM regs. Change bus scan MCG
+ * from (0 to n) to (1 to n).
+ * 17-May-99 Port to Walnut JWB
+ * 17-Jun-99 Updated for VGA support JWB
+ * 21-Jun-99 Updated to allow SRAM region to be a target from PCI bus JWB
+ * 19-Jul-99 Updated for 405GP pass 1 errata #26 (Low PCI subsequent MCG
+ * target latency timer values are not supported).
+ * Should be fixed in pass 2.
+ * 09-Sep-99 Removed use of PTM2 since the SRAM region no longer needs JWB
+ * to be a PCI target. Zero out PTMBAR2 and disable in PTM2MS.
+ * 10-Dec-99 Updated PCI_Write_CFG_Reg for pass2 errata #6 JWB
+ * 11-Jan-00 Ensure PMMxMAs disabled before setting PMMxLAs. This is not
+ * really required after a reset since PMMxMAs are already
+ * disabled but is a good practice nonetheless. JWB
+ * 12-Jun-01 stefan.roese@esd-electronics.com
+ * - PCI host/adapter handling reworked
+ * 09-Jul-01 stefan.roese@esd-electronics.com
+ * - PCI host now configures from device 0 (not 1) to max_dev,
+ * (host configures itself)
+ * - On CPCI-405 pci base address and size is generated from
+ * SDRAM and FLASH size (CFG regs not used anymore)
+ * - Some minor changes for CPCI-405-A (adapter version)
+ * 14-Sep-01 stefan.roese@esd-electronics.com
+ * - CONFIG_PCI_SCAN_SHOW added to print pci devices upon startup
+ * 28-Sep-01 stefan.roese@esd-electronics.com
+ * - Changed pci master configuration for linux compatibility
+ * (no need for bios_fixup() anymore)
+ * 26-Feb-02 stefan.roese@esd-electronics.com
+ * - Bug fixed in pci configuration (Andrew May)
+ * - Removed pci class code init for CPCI405 board
+ * 15-May-02 stefan.roese@esd-electronics.com
+ * - New vga device handling
+ * 29-May-02 stefan.roese@esd-electronics.com
+ * - PCI class code init added (if defined)
+ *----------------------------------------------------------------------------*/
+
+#include <common.h>
+#include <command.h>
+#include <asm/4xx_pci.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#ifdef CONFIG_PCI
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_405GP) || defined(CONFIG_405EP)
+
+#if defined(CONFIG_PMC405)
+ushort pmc405_pci_subsys_deviceid(void);
+#endif
+
+/*#define DEBUG*/
+
+/*
+ * Board-specific pci initialization
+ * Platform code can reimplement pci_pre_init() if needed
+ */
+int __pci_pre_init(struct pci_controller *hose)
+{
+#if defined(CONFIG_405EP)
+ /*
+ * Enable the internal PCI arbiter by default.
+ *
+ * On 405EP CPUs the internal arbiter can be controlled
+ * by the I2C strapping EEPROM. If you want to do so
+ * or if you want to disable the arbiter pci_pre_init()
+ * must be reimplemented without enabling the arbiter.
+ * The arbiter is enabled in this place because of
+ * compatibility reasons.
+ */
+ mtdcr(CPC0_PCI, mfdcr(CPC0_PCI) | CPC0_PCI_ARBIT_EN);
+#endif /* CONFIG_405EP */
+
+ return 1;
+}
+int pci_pre_init(struct pci_controller *hose)
+ __attribute__((weak, alias("__pci_pre_init")));
+
+int __is_pci_host(struct pci_controller *hose)
+{
+#if defined(CONFIG_405GP)
+ if (mfdcr(CPC0_PSR) & PSR_PCI_ARBIT_EN)
+ return 1;
+#elif defined (CONFIG_405EP)
+ if (mfdcr(CPC0_PCI) & CPC0_PCI_ARBIT_EN)
+ return 1;
+#endif
+ return 0;
+}
+int is_pci_host(struct pci_controller *hose) __attribute__((weak, alias("__is_pci_host")));
+
+/*-----------------------------------------------------------------------------+
+ * pci_init. Initializes the 405GP PCI Configuration regs.
+ *-----------------------------------------------------------------------------*/
+void pci_405gp_init(struct pci_controller *hose)
+{
+ int i, reg_num = 0;
+ bd_t *bd = gd->bd;
+
+ unsigned short temp_short;
+ unsigned long ptmpcila[2] = {CONFIG_SYS_PCI_PTM1PCI, CONFIG_SYS_PCI_PTM2PCI};
+#if defined(CONFIG_PCI_4xx_PTM_OVERWRITE)
+ char *ptmla_str, *ptmms_str;
+#endif
+ unsigned long ptmla[2] = {CONFIG_SYS_PCI_PTM1LA, CONFIG_SYS_PCI_PTM2LA};
+ unsigned long ptmms[2] = {CONFIG_SYS_PCI_PTM1MS, CONFIG_SYS_PCI_PTM2MS};
+#if defined(CONFIG_PIP405) || defined (CONFIG_MIP405)
+ unsigned long pmmla[3] = {0x80000000, 0xA0000000, 0};
+ unsigned long pmmma[3] = {0xE0000001, 0xE0000001, 0};
+ unsigned long pmmpcila[3] = {0x80000000, 0x00000000, 0};
+ unsigned long pmmpciha[3] = {0x00000000, 0x00000000, 0};
+#else
+ unsigned long pmmla[3] = {0x80000000, 0,0};
+ unsigned long pmmma[3] = {0xC0000001, 0,0};
+ unsigned long pmmpcila[3] = {0x80000000, 0,0};
+ unsigned long pmmpciha[3] = {0x00000000, 0,0};
+#endif
+#ifdef CONFIG_PCI_PNP
+#if (CONFIG_PCI_HOST == PCI_HOST_AUTO)
+ char *s;
+#endif
+#endif
+
+#if defined(CONFIG_PCI_4xx_PTM_OVERWRITE)
+ ptmla_str = getenv("ptm1la");
+ ptmms_str = getenv("ptm1ms");
+ if(NULL != ptmla_str && NULL != ptmms_str ) {
+ ptmla[0] = simple_strtoul (ptmla_str, NULL, 16);
+ ptmms[0] = simple_strtoul (ptmms_str, NULL, 16);
+ }
+
+ ptmla_str = getenv("ptm2la");
+ ptmms_str = getenv("ptm2ms");
+ if(NULL != ptmla_str && NULL != ptmms_str ) {
+ ptmla[1] = simple_strtoul (ptmla_str, NULL, 16);
+ ptmms[1] = simple_strtoul (ptmms_str, NULL, 16);
+ }
+#endif
+
+ /*
+ * Register the hose
+ */
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ /* ISA/PCI I/O space */
+ pci_set_region(hose->regions + reg_num++,
+ MIN_PCI_PCI_IOADDR,
+ MIN_PLB_PCI_IOADDR,
+ 0x10000,
+ PCI_REGION_IO);
+
+ /* PCI I/O space */
+ pci_set_region(hose->regions + reg_num++,
+ 0x00800000,
+ 0xe8800000,
+ 0x03800000,
+ PCI_REGION_IO);
+
+ reg_num = 2;
+
+ /* Memory spaces */
+ for (i=0; i<2; i++)
+ if (ptmms[i] & 1)
+ {
+ if (!i) hose->pci_fb = hose->regions + reg_num;
+
+ pci_set_region(hose->regions + reg_num++,
+ ptmpcila[i], ptmla[i],
+ ~(ptmms[i] & 0xfffff000) + 1,
+ PCI_REGION_MEM |
+ PCI_REGION_SYS_MEMORY);
+ }
+
+ /* PCI memory spaces */
+ for (i=0; i<3; i++)
+ if (pmmma[i] & 1)
+ {
+ pci_set_region(hose->regions + reg_num++,
+ pmmpcila[i], pmmla[i],
+ ~(pmmma[i] & 0xfffff000) + 1,
+ PCI_REGION_MEM);
+ }
+
+ hose->region_count = reg_num;
+
+ pci_setup_indirect(hose,
+ PCICFGADR,
+ PCICFGDATA);
+
+ if (hose->pci_fb)
+ pciauto_region_init(hose->pci_fb);
+
+ /* Let board change/modify hose & do initial checks */
+ if (pci_pre_init(hose) == 0) {
+ printf("PCI: Board-specific initialization failed.\n");
+ printf("PCI: Configuration aborted.\n");
+ return;
+ }
+
+ pci_register_hose(hose);
+
+ /*--------------------------------------------------------------------------+
+ * 405GP PCI Master configuration.
+ * Map one 512 MB range of PLB/processor addresses to PCI memory space.
+ * PLB address 0x80000000-0xBFFFFFFF ==> PCI address 0x80000000-0xBFFFFFFF
+ * Use byte reversed out routines to handle endianess.
+ *--------------------------------------------------------------------------*/
+ out32r(PMM0MA, (pmmma[0]&~0x1)); /* disable, configure PMMxLA, PMMxPCILA first */
+ out32r(PMM0LA, pmmla[0]);
+ out32r(PMM0PCILA, pmmpcila[0]);
+ out32r(PMM0PCIHA, pmmpciha[0]);
+ out32r(PMM0MA, pmmma[0]);
+
+ /*--------------------------------------------------------------------------+
+ * PMM1 is not used. Initialize them to zero.
+ *--------------------------------------------------------------------------*/
+ out32r(PMM1MA, (pmmma[1]&~0x1));
+ out32r(PMM1LA, pmmla[1]);
+ out32r(PMM1PCILA, pmmpcila[1]);
+ out32r(PMM1PCIHA, pmmpciha[1]);
+ out32r(PMM1MA, pmmma[1]);
+
+ /*--------------------------------------------------------------------------+
+ * PMM2 is not used. Initialize them to zero.
+ *--------------------------------------------------------------------------*/
+ out32r(PMM2MA, (pmmma[2]&~0x1));
+ out32r(PMM2LA, pmmla[2]);
+ out32r(PMM2PCILA, pmmpcila[2]);
+ out32r(PMM2PCIHA, pmmpciha[2]);
+ out32r(PMM2MA, pmmma[2]);
+
+ /*--------------------------------------------------------------------------+
+ * 405GP PCI Target configuration. (PTM1)
+ * Note: PTM1MS is hardwire enabled but we set the enable bit anyway.
+ *--------------------------------------------------------------------------*/
+ out32r(PTM1LA, ptmla[0]); /* insert address */
+ out32r(PTM1MS, ptmms[0]); /* insert size, enable bit is 1 */
+ pci_write_config_dword(PCIDEVID_405GP, PCI_BASE_ADDRESS_1, ptmpcila[0]);
+
+ /*--------------------------------------------------------------------------+
+ * 405GP PCI Target configuration. (PTM2)
+ *--------------------------------------------------------------------------*/
+ out32r(PTM2LA, ptmla[1]); /* insert address */
+ pci_write_config_dword(PCIDEVID_405GP, PCI_BASE_ADDRESS_2, ptmpcila[1]);
+
+ if (ptmms[1] == 0)
+ {
+ out32r(PTM2MS, 0x00000001); /* set enable bit */
+ pci_write_config_dword(PCIDEVID_405GP, PCI_BASE_ADDRESS_2, 0x00000000);
+ out32r(PTM2MS, 0x00000000); /* disable */
+ }
+ else
+ {
+ out32r(PTM2MS, ptmms[1]); /* insert size, enable bit is 1 */
+ }
+
+ /*
+ * Insert Subsystem Vendor and Device ID
+ */
+ pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_VENDOR_ID, CONFIG_SYS_PCI_SUBSYS_VENDORID);
+#ifdef CONFIG_CPCI405
+ if (is_pci_host(hose))
+ pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CONFIG_SYS_PCI_SUBSYS_DEVICEID);
+ else
+ pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CONFIG_SYS_PCI_SUBSYS_DEVICEID2);
+#else
+ pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CONFIG_SYS_PCI_SUBSYS_DEVICEID);
+#endif
+
+ /*
+ * Insert Class-code
+ */
+#ifdef CONFIG_SYS_PCI_CLASSCODE
+ pci_write_config_word(PCIDEVID_405GP, PCI_CLASS_SUB_CODE, CONFIG_SYS_PCI_CLASSCODE);
+#endif /* CONFIG_SYS_PCI_CLASSCODE */
+
+ /*--------------------------------------------------------------------------+
+ * If PCI speed = 66MHz, set 66MHz capable bit.
+ *--------------------------------------------------------------------------*/
+ if (bd->bi_pci_busfreq >= 66000000) {
+ pci_read_config_word(PCIDEVID_405GP, PCI_STATUS, &temp_short);
+ pci_write_config_word(PCIDEVID_405GP,PCI_STATUS,(temp_short|PCI_STATUS_66MHZ));
+ }
+
+#if (CONFIG_PCI_HOST != PCI_HOST_ADAPTER)
+#if (CONFIG_PCI_HOST == PCI_HOST_AUTO)
+ if (is_pci_host(hose) ||
+ (((s = getenv("pciscan")) != NULL) && (strcmp(s, "yes") == 0)))
+#endif
+ {
+ /*--------------------------------------------------------------------------+
+ * Write the 405GP PCI Configuration regs.
+ * Enable 405GP to be a master on the PCI bus (PMM).
+ * Enable 405GP to act as a PCI memory target (PTM).
+ *--------------------------------------------------------------------------*/
+ pci_read_config_word(PCIDEVID_405GP, PCI_COMMAND, &temp_short);
+ pci_write_config_word(PCIDEVID_405GP, PCI_COMMAND, temp_short |
+ PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+ }
+#endif
+
+#if defined(CONFIG_405EP)
+ /*
+ * on ppc405ep vendor/device id is not set
+ * The user manual says 0x1014 (IBM) / 0x0156 (405GP!)
+ * are the correct values.
+ */
+ pci_write_config_word(PCIDEVID_405GP, PCI_VENDOR_ID, PCI_VENDOR_ID_IBM);
+ pci_write_config_word(PCIDEVID_405GP,
+ PCI_DEVICE_ID, PCI_DEVICE_ID_IBM_405GP);
+#endif
+
+ /*
+ * Set HCE bit (Host Configuration Enabled)
+ */
+ pci_read_config_word(PCIDEVID_405GP, PCIBRDGOPT2, &temp_short);
+ pci_write_config_word(PCIDEVID_405GP, PCIBRDGOPT2, (temp_short | 0x0001));
+
+#ifdef CONFIG_PCI_PNP
+ /*--------------------------------------------------------------------------+
+ * Scan the PCI bus and configure devices found.
+ *--------------------------------------------------------------------------*/
+#if (CONFIG_PCI_HOST == PCI_HOST_AUTO)
+ if (is_pci_host(hose) ||
+ (((s = getenv("pciscan")) != NULL) && (strcmp(s, "yes") == 0)))
+#endif
+ {
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf("PCI: Bus Dev VenId DevId Class Int\n");
+#endif
+ hose->last_busno = pci_hose_scan(hose);
+ }
+#endif /* CONFIG_PCI_PNP */
+
+}
+
+/*
+ * drivers/pci/pci.c skips every host bridge but the 405GP since it could
+ * be set as an Adapter.
+ *
+ * I (Andrew May) don't know what we should do here, but I don't want
+ * the auto setup of a PCI device disabling what is done pci_405gp_init
+ * as has happened before.
+ */
+void pci_405gp_setup_bridge(struct pci_controller *hose, pci_dev_t dev,
+ struct pci_config_table *entry)
+{
+#ifdef DEBUG
+ printf("405gp_setup_bridge\n");
+#endif
+}
+
+/*
+ *
+ */
+
+void pci_405gp_fixup_irq(struct pci_controller *hose, pci_dev_t dev)
+{
+ unsigned char int_line = 0xff;
+
+ /*
+ * Write pci interrupt line register (cpci405 specific)
+ */
+ switch (PCI_DEV(dev) & 0x03)
+ {
+ case 0:
+ int_line = 27 + 2;
+ break;
+ case 1:
+ int_line = 27 + 3;
+ break;
+ case 2:
+ int_line = 27 + 0;
+ break;
+ case 3:
+ int_line = 27 + 1;
+ break;
+ }
+
+ pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, int_line);
+}
+
+void pci_405gp_setup_vga(struct pci_controller *hose, pci_dev_t dev,
+ struct pci_config_table *entry)
+{
+ unsigned int cmdstat = 0;
+
+ pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_prefetch, hose->pci_io);
+
+ /* always enable io space on vga boards */
+ pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &cmdstat);
+ cmdstat |= PCI_COMMAND_IO;
+ pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat);
+}
+
+#if !(defined(CONFIG_PIP405) || defined (CONFIG_MIP405)) && !(defined (CONFIG_SC3))
+
+/*
+ *As is these functs get called out of flash Not a horrible
+ *thing, but something to keep in mind. (no statics?)
+ */
+static struct pci_config_table pci_405gp_config_table[] = {
+/*if VendID is 0 it terminates the table search (ie Walnut)*/
+#ifdef CONFIG_SYS_PCI_SUBSYS_VENDORID
+ {CONFIG_SYS_PCI_SUBSYS_VENDORID, PCI_ANY_ID, PCI_CLASS_BRIDGE_HOST,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, pci_405gp_setup_bridge},
+#endif
+ {PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, pci_405gp_setup_vga},
+
+ {PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NOT_DEFINED_VGA,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, pci_405gp_setup_vga},
+
+ { }
+};
+
+static struct pci_controller hose = {
+ fixup_irq: pci_405gp_fixup_irq,
+ config_table: pci_405gp_config_table,
+};
+
+void pci_init_board(void)
+{
+ /*we want the ptrs to RAM not flash (ie don't use init list)*/
+ hose.fixup_irq = pci_405gp_fixup_irq;
+ hose.config_table = pci_405gp_config_table;
+ pci_405gp_init(&hose);
+}
+
+#endif
+
+#endif /* CONFIG_405GP */
+
+/*-----------------------------------------------------------------------------+
+ * CONFIG_440
+ *-----------------------------------------------------------------------------*/
+#if defined(CONFIG_440)
+
+#if defined(CONFIG_SYS_PCI_MASTER_INIT) || defined(CONFIG_SYS_PCI_TARGET_INIT)
+static struct pci_controller ppc440_hose = {0};
+#endif
+
+/*
+ * This routine is called to determine if a pci scan should be
+ * performed. With various hardware environments (especially cPCI and
+ * PPMC) it's insufficient to depend on the state of the arbiter enable
+ * bit in the strap register, or generic host/adapter assumptions.
+ *
+ * Rather than hard-code a bad assumption in the general 440 code, the
+ * 440 pci code requires the board to decide at runtime.
+ *
+ * Return 0 for adapter mode, non-zero for host (monarch) mode.
+ *
+ * Weak default implementation: "Normal" boards implement the PCI
+ * host functionality. This can be overridden for PCI adapter boards.
+ */
+int __is_pci_host(struct pci_controller *hose)
+{
+ return 1;
+}
+int is_pci_host(struct pci_controller *hose)
+ __attribute__((weak, alias("__is_pci_host")));
+
+#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
+ defined(CONFIG_440GR) || defined(CONFIG_440GRX)
+
+#if defined(CONFIG_SYS_PCI_TARGET_INIT)
+/*
+ * pci_target_init
+ *
+ * The bootstrap configuration provides default settings for the pci
+ * inbound map (PIM). But the bootstrap config choices are limited and
+ * may not be sufficient for a given board.
+ */
+void __pci_target_init(struct pci_controller *hose)
+{
+ /*
+ * Set up Direct MMIO registers
+ */
+
+ /*
+ * PowerPC440 EP PCI Master configuration.
+ * Map one 1Gig range of PLB/processor addresses to PCI memory space.
+ * PLB address 0xA0000000-0xDFFFFFFF ==> PCI address 0xA0000000-0xDFFFFFFF
+ * Use byte reversed out routines to handle endianess.
+ * Make this region non-prefetchable.
+ */
+ /* PMM0 Mask/Attribute - disabled b4 setting */
+ out_le32((void *)PCIL0_PMM0MA, 0x00000000);
+ /* PMM0 Local Address */
+ out_le32((void *)PCIL0_PMM0LA, CONFIG_SYS_PCI_MEMBASE);
+ /* PMM0 PCI Low Address */
+ out_le32((void *)PCIL0_PMM0PCILA, CONFIG_SYS_PCI_MEMBASE);
+ /* PMM0 PCI High Address */
+ out_le32((void *)PCIL0_PMM0PCIHA, 0x00000000);
+ /* 512M + No prefetching, and enable region */
+ out_le32((void *)PCIL0_PMM0MA, 0xE0000001);
+
+ /* PMM1 Mask/Attribute - disabled b4 setting */
+ out_le32((void *)PCIL0_PMM1MA, 0x00000000);
+ /* PMM1 Local Address */
+ out_le32((void *)PCIL0_PMM1LA, CONFIG_SYS_PCI_MEMBASE2);
+ /* PMM1 PCI Low Address */
+ out_le32((void *)PCIL0_PMM1PCILA, CONFIG_SYS_PCI_MEMBASE2);
+ /* PMM1 PCI High Address */
+ out_le32((void *)PCIL0_PMM1PCIHA, 0x00000000);
+ /* 512M + No prefetching, and enable region */
+ out_le32((void *)PCIL0_PMM1MA, 0xE0000001);
+
+ out_le32((void *)PCIL0_PTM1MS, 0x00000001); /* Memory Size/Attribute */
+ out_le32((void *)PCIL0_PTM1LA, 0); /* Local Addr. Reg */
+ out_le32((void *)PCIL0_PTM2MS, 0); /* Memory Size/Attribute */
+ out_le32((void *)PCIL0_PTM2LA, 0); /* Local Addr. Reg */
+
+ /*
+ * Set up Configuration registers
+ */
+
+ /* Program the board's subsystem id/vendor id */
+ pci_write_config_word(0, PCI_SUBSYSTEM_VENDOR_ID,
+ CONFIG_SYS_PCI_SUBSYS_VENDORID);
+ pci_write_config_word(0, PCI_SUBSYSTEM_ID, CONFIG_SYS_PCI_SUBSYS_ID);
+
+ /* Configure command register as bus master */
+ pci_write_config_word(0, PCI_COMMAND, PCI_COMMAND_MASTER);
+
+ /* 240nS PCI clock */
+ pci_write_config_word(0, PCI_LATENCY_TIMER, 1);
+
+ /* No error reporting */
+ pci_write_config_word(0, PCI_ERREN, 0);
+
+ pci_write_config_dword(0, PCI_BRDGOPT2, 0x00000101);
+}
+#endif /* CONFIG_SYS_PCI_TARGET_INIT */
+
+/*
+ * pci_pre_init
+ *
+ * This routine is called just prior to registering the hose and gives
+ * the board the opportunity to check things. Returning a value of zero
+ * indicates that things are bad & PCI initialization should be aborted.
+ *
+ * Different boards may wish to customize the pci controller structure
+ * (add regions, override default access routines, etc) or perform
+ * certain pre-initialization actions.
+ *
+ */
+int __pci_pre_init(struct pci_controller *hose)
+{
+ u32 reg;
+
+ /*
+ * Set priority for all PLB3 devices to 0.
+ * Set PLB3 arbiter to fair mode.
+ */
+ mfsdr(SDR0_AMP1, reg);
+ mtsdr(SDR0_AMP1, (reg & 0x000000FF) | 0x0000FF00);
+ reg = mfdcr(PLB3A0_ACR);
+ mtdcr(PLB3A0_ACR, reg | 0x80000000);
+
+ /*
+ * Set priority for all PLB4 devices to 0.
+ */
+ mfsdr(SDR0_AMP0, reg);
+ mtsdr(SDR0_AMP0, (reg & 0x000000FF) | 0x0000FF00);
+ reg = mfdcr(PLB4A0_ACR) | 0xa0000000;
+ mtdcr(PLB4A0_ACR, reg);
+
+ /*
+ * Set Nebula PLB4 arbiter to fair mode.
+ */
+ /* Segment0 */
+ reg = (mfdcr(PLB4A0_ACR) & ~PLB4Ax_ACR_PPM_MASK) | PLB4Ax_ACR_PPM_FAIR;
+ reg = (reg & ~PLB4Ax_ACR_HBU_MASK) | PLB4Ax_ACR_HBU_ENABLED;
+ reg = (reg & ~PLB4Ax_ACR_RDP_MASK) | PLB4Ax_ACR_RDP_4DEEP;
+ reg = (reg & ~PLB4Ax_ACR_WRP_MASK) | PLB4Ax_ACR_WRP_2DEEP;
+ mtdcr(PLB4A0_ACR, reg);
+
+ /* Segment1 */
+ reg = (mfdcr(PLB4A1_ACR) & ~PLB4Ax_ACR_PPM_MASK) | PLB4Ax_ACR_PPM_FAIR;
+ reg = (reg & ~PLB4Ax_ACR_HBU_MASK) | PLB4Ax_ACR_HBU_ENABLED;
+ reg = (reg & ~PLB4Ax_ACR_RDP_MASK) | PLB4Ax_ACR_RDP_4DEEP;
+ reg = (reg & ~PLB4Ax_ACR_WRP_MASK) | PLB4Ax_ACR_WRP_2DEEP;
+ mtdcr(PLB4A1_ACR, reg);
+
+#if defined(CONFIG_SYS_PCI_BOARD_FIXUP_IRQ)
+ hose->fixup_irq = board_pci_fixup_irq;
+#endif
+
+ return 1;
+}
+
+#else /* defined(CONFIG_440EP) ... */
+
+#if defined(CONFIG_SYS_PCI_TARGET_INIT)
+void __pci_target_init(struct pci_controller * hose)
+{
+ /*
+ * Disable everything
+ */
+ out_le32((void *)PCIL0_PIM0SA, 0); /* disable */
+ out_le32((void *)PCIL0_PIM1SA, 0); /* disable */
+ out_le32((void *)PCIL0_PIM2SA, 0); /* disable */
+ out_le32((void *)PCIL0_EROMBA, 0); /* disable expansion rom */
+
+ /*
+ * Map all of SDRAM to PCI address 0x0000_0000. Note that the 440
+ * strapping options do not support sizes such as 128/256 MB.
+ */
+ out_le32((void *)PCIL0_PIM0LAL, CONFIG_SYS_SDRAM_BASE);
+ out_le32((void *)PCIL0_PIM0LAH, 0);
+ out_le32((void *)PCIL0_PIM0SA, ~(gd->ram_size - 1) | 1);
+ out_le32((void *)PCIL0_BAR0, 0);
+
+ /*
+ * Program the board's subsystem id/vendor id
+ */
+ out_le16((void *)PCIL0_SBSYSVID, CONFIG_SYS_PCI_SUBSYS_VENDORID);
+ out_le16((void *)PCIL0_SBSYSID, CONFIG_SYS_PCI_SUBSYS_DEVICEID);
+
+ out_le16((void *)PCIL0_CMD, in_le16((void *)PCIL0_CMD) |
+ PCI_COMMAND_MEMORY);
+}
+#endif /* CONFIG_SYS_PCI_TARGET_INIT */
+
+int __pci_pre_init(struct pci_controller *hose)
+{
+ /*
+ * This board is always configured as the host & requires the
+ * PCI arbiter to be enabled.
+ */
+ if (!pci_arbiter_enabled()) {
+ printf("PCI: PCI Arbiter disabled!\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+#endif /* defined(CONFIG_440EP) ... */
+
+#if defined(CONFIG_SYS_PCI_TARGET_INIT)
+void pci_target_init(struct pci_controller * hose)
+ __attribute__((weak, alias("__pci_target_init")));
+#endif /* CONFIG_SYS_PCI_TARGET_INIT */
+
+int pci_pre_init(struct pci_controller *hose)
+ __attribute__((weak, alias("__pci_pre_init")));
+
+#if defined(CONFIG_SYS_PCI_MASTER_INIT)
+void __pci_master_init(struct pci_controller *hose)
+{
+ u16 reg;
+
+ /*
+ * Write the PowerPC440 EP PCI Configuration regs.
+ * Enable PowerPC440 EP to be a master on the PCI bus (PMM).
+ * Enable PowerPC440 EP to act as a PCI memory target (PTM).
+ */
+ pci_read_config_word(0, PCI_COMMAND, &reg);
+ pci_write_config_word(0, PCI_COMMAND, reg |
+ PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+}
+void pci_master_init(struct pci_controller *hose)
+ __attribute__((weak, alias("__pci_master_init")));
+#endif /* CONFIG_SYS_PCI_MASTER_INIT */
+
+#if defined(CONFIG_SYS_PCI_MASTER_INIT) || defined(CONFIG_SYS_PCI_TARGET_INIT)
+static int pci_440_init (struct pci_controller *hose)
+{
+ int reg_num = 0;
+
+#ifndef CONFIG_DISABLE_PISE_TEST
+ /*--------------------------------------------------------------------------+
+ * The PCI initialization sequence enable bit must be set ... if not abort
+ * pci setup since updating the bit requires chip reset.
+ *--------------------------------------------------------------------------*/
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+ unsigned long strap;
+
+ mfsdr(SDR0_SDSTP1,strap);
+ if ((strap & SDR0_SDSTP1_PISE_MASK) == 0) {
+ printf("PCI: SDR0_STRP1[PISE] not set.\n");
+ printf("PCI: Configuration aborted.\n");
+ return -1;
+ }
+#elif defined(CONFIG_440GP)
+ unsigned long strap;
+
+ strap = mfdcr(CPC0_STRP1);
+ if ((strap & CPC0_STRP1_PISE_MASK) == 0) {
+ printf("PCI: CPC0_STRP1[PISE] not set.\n");
+ printf("PCI: Configuration aborted.\n");
+ return -1;
+ }
+#endif
+#endif /* CONFIG_DISABLE_PISE_TEST */
+
+ /*--------------------------------------------------------------------------+
+ * PCI controller init
+ *--------------------------------------------------------------------------*/
+ hose->first_busno = 0;
+ hose->last_busno = 0;
+
+ /* PCI I/O space */
+ pci_set_region(hose->regions + reg_num++,
+ 0x00000000,
+ PCIL0_IOBASE,
+ 0x10000,
+ PCI_REGION_IO);
+
+ /* PCI memory space */
+ pci_set_region(hose->regions + reg_num++,
+ CONFIG_SYS_PCI_TARGBASE,
+ CONFIG_SYS_PCI_MEMBASE,
+#ifdef CONFIG_SYS_PCI_MEMSIZE
+ CONFIG_SYS_PCI_MEMSIZE,
+#else
+ 0x10000000,
+#endif
+ PCI_REGION_MEM );
+
+#if defined(CONFIG_PCI_SYS_MEM_BUS) && defined(CONFIG_PCI_SYS_MEM_PHYS) && \
+ defined(CONFIG_PCI_SYS_MEM_SIZE)
+ /* System memory space */
+ pci_set_region(hose->regions + reg_num++,
+ CONFIG_PCI_SYS_MEM_BUS,
+ CONFIG_PCI_SYS_MEM_PHYS,
+ CONFIG_PCI_SYS_MEM_SIZE,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY );
+#endif
+
+ hose->region_count = reg_num;
+
+ pci_setup_indirect(hose, PCIL0_CFGADR, PCIL0_CFGDATA);
+
+ /* Let board change/modify hose & do initial checks */
+ if (pci_pre_init(hose) == 0) {
+ printf("PCI: Board-specific initialization failed.\n");
+ printf("PCI: Configuration aborted.\n");
+ return -1;
+ }
+
+ pci_register_hose( hose );
+
+ /*--------------------------------------------------------------------------+
+ * PCI target init
+ *--------------------------------------------------------------------------*/
+#if defined(CONFIG_SYS_PCI_TARGET_INIT)
+ pci_target_init(hose); /* Let board setup pci target */
+#else
+ out16r( PCIL0_SBSYSVID, CONFIG_SYS_PCI_SUBSYS_VENDORID );
+ out16r( PCIL0_SBSYSID, CONFIG_SYS_PCI_SUBSYS_ID );
+ out16r( PCIL0_CLS, 0x00060000 ); /* Bridge, host bridge */
+#endif
+
+#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ out32r( PCIL0_BRDGOPT1, 0x04000060 ); /* PLB Rq pri highest */
+ out32r( PCIL0_BRDGOPT2, in32(PCIL0_BRDGOPT2) | 0x83 ); /* Enable host config, clear Timeout, ensure int src1 */
+#elif defined(PCIL0_BRDGOPT1)
+ out32r( PCIL0_BRDGOPT1, 0x10000060 ); /* PLB Rq pri highest */
+ out32r( PCIL0_BRDGOPT2, in32(PCIL0_BRDGOPT2) | 1 ); /* Enable host config */
+#endif
+
+ /*--------------------------------------------------------------------------+
+ * PCI master init: default is one 256MB region for PCI memory:
+ * 0x3_00000000 - 0x3_0FFFFFFF ==> CONFIG_SYS_PCI_MEMBASE
+ *--------------------------------------------------------------------------*/
+#if defined(CONFIG_SYS_PCI_MASTER_INIT)
+ pci_master_init(hose); /* Let board setup pci master */
+#else
+ out32r( PCIL0_POM0SA, 0 ); /* disable */
+ out32r( PCIL0_POM1SA, 0 ); /* disable */
+ out32r( PCIL0_POM2SA, 0 ); /* disable */
+#if defined(CONFIG_440SPE)
+ out32r( PCIL0_POM0LAL, 0x10000000 );
+ out32r( PCIL0_POM0LAH, 0x0000000c );
+#elif defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ out32r( PCIL0_POM0LAL, 0x20000000 );
+ out32r( PCIL0_POM0LAH, 0x0000000c );
+#else
+ out32r( PCIL0_POM0LAL, 0x00000000 );
+ out32r( PCIL0_POM0LAH, 0x00000003 );
+#endif
+ out32r( PCIL0_POM0PCIAL, CONFIG_SYS_PCI_MEMBASE );
+ out32r( PCIL0_POM0PCIAH, 0x00000000 );
+ out32r( PCIL0_POM0SA, 0xf0000001 ); /* 256MB, enabled */
+ out32r( PCIL0_STS, in32r( PCIL0_STS ) & ~0x0000fff8 );
+#endif
+
+ /*--------------------------------------------------------------------------+
+ * PCI host configuration -- we don't make any assumptions here ... the
+ * _board_must_indicate_ what to do -- there's just too many runtime
+ * scenarios in environments like cPCI, PPMC, etc. to make a determination
+ * based on hard-coded values or state of arbiter enable.
+ *--------------------------------------------------------------------------*/
+ if (is_pci_host(hose)) {
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf("PCI: Bus Dev VenId DevId Class Int\n");
+#endif
+#if !defined(CONFIG_440EP) && !defined(CONFIG_440GR) && \
+ !defined(CONFIG_440EPX) && !defined(CONFIG_440GRX)
+ out16r( PCIL0_CMD, in16r( PCIL0_CMD ) | PCI_COMMAND_MASTER);
+#endif
+ hose->last_busno = pci_hose_scan(hose);
+ }
+ return hose->last_busno;
+}
+#endif
+
+void pci_init_board(void)
+{
+ int busno = 0;
+
+ /*
+ * Only init PCI when either master or target functionality
+ * is selected.
+ */
+#if defined(CONFIG_SYS_PCI_MASTER_INIT) || defined(CONFIG_SYS_PCI_TARGET_INIT)
+ busno = pci_440_init(&ppc440_hose);
+ if (busno < 0)
+ return;
+#endif
+#if (defined(CONFIG_440SPE) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT)) && \
+ !defined(CONFIG_PCI_DISABLE_PCIE)
+ pcie_setup_hoses(busno + 1);
+#endif
+}
+
+#endif /* CONFIG_440 */
+
+#if defined(CONFIG_405EX)
+void pci_init_board(void)
+{
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf("PCI: Bus Dev VenId DevId Class Int\n");
+#endif
+ pcie_setup_hoses(0);
+}
+#endif /* CONFIG_405EX */
+
+#endif /* CONFIG_PCI */
diff --git a/arch/powerpc/cpu/ppc4xx/4xx_pcie.c b/arch/powerpc/cpu/ppc4xx/4xx_pcie.c
new file mode 100644
index 0000000..43b972f
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/4xx_pcie.c
@@ -0,0 +1,1292 @@
+/*
+ * (C) Copyright 2006 - 2008
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Roland Dreier <rolandd@cisco.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/* define DEBUG for debugging output (obviously ;-)) */
+#if 0
+#define DEBUG
+#endif
+
+#include <common.h>
+#include <pci.h>
+#include <asm/ppc4xx.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+
+#if (defined(CONFIG_440SPE) || defined(CONFIG_405EX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT)) && \
+ defined(CONFIG_PCI) && !defined(CONFIG_PCI_DISABLE_PCIE)
+
+#include <asm/4xx_pcie.h>
+
+enum {
+ PTYPE_ENDPOINT = 0x0,
+ PTYPE_LEGACY_ENDPOINT = 0x1,
+ PTYPE_ROOT_PORT = 0x4,
+
+ LNKW_X1 = 0x1,
+ LNKW_X4 = 0x4,
+ LNKW_X8 = 0x8
+};
+
+static struct pci_controller pcie_hose[CONFIG_SYS_PCIE_NR_PORTS];
+
+/*
+ * Per default, all cards are present, so we need to check if the
+ * link comes up.
+ */
+int __board_pcie_card_present(int port)
+{
+ return 1;
+}
+int board_pcie_card_present(int port)
+ __attribute__((weak, alias("__board_pcie_card_present")));
+
+/*
+ * Some boards have runtime detection of the first and last PCIe
+ * slot used, so let's provide weak default functions for the
+ * common version.
+ */
+int __board_pcie_first(void)
+{
+ return 0;
+}
+int board_pcie_first(void)
+ __attribute__((weak, alias("__board_pcie_first")));
+
+int __board_pcie_last(void)
+{
+ return CONFIG_SYS_PCIE_NR_PORTS - 1;
+}
+int board_pcie_last(void)
+ __attribute__((weak, alias("__board_pcie_last")));
+
+void __board_pcie_setup_port(int port, int rootpoint)
+{
+ /* noting in this weak default implementation */
+}
+void board_pcie_setup_port(int port, int rootpoint)
+ __attribute__((weak, alias("__board_pcie_setup_port")));
+
+void pcie_setup_hoses(int busno)
+{
+ struct pci_controller *hose;
+ int i, bus;
+ int ret = 0;
+ char *env;
+ unsigned int delay;
+ int first = board_pcie_first();
+ int last = board_pcie_last();
+
+ /*
+ * Assume we're called after the PCI(X) hose(s) are initialized,
+ * which takes bus ID 0... and therefore start numbering PCIe's
+ * from the next number.
+ */
+ bus = busno;
+
+ for (i = first; i <= last; i++) {
+ /*
+ * Some boards (e.g. Katmai) can detects via hardware
+ * if a PCIe card is plugged, so let's check this.
+ */
+ if (!board_pcie_card_present(i))
+ continue;
+
+ if (is_end_point(i)) {
+ board_pcie_setup_port(i, 0);
+ ret = ppc4xx_init_pcie_endport(i);
+ } else {
+ board_pcie_setup_port(i, 1);
+ ret = ppc4xx_init_pcie_rootport(i);
+ }
+ if (ret == -ENODEV)
+ continue;
+ if (ret) {
+ printf("PCIE%d: initialization as %s failed\n", i,
+ is_end_point(i) ? "endpoint" : "root-complex");
+ continue;
+ }
+
+ hose = &pcie_hose[i];
+ hose->first_busno = bus;
+ hose->last_busno = bus;
+ hose->current_busno = bus;
+
+ /* setup mem resource */
+ pci_set_region(hose->regions + 0,
+ CONFIG_SYS_PCIE_MEMBASE + i * CONFIG_SYS_PCIE_MEMSIZE,
+ CONFIG_SYS_PCIE_MEMBASE + i * CONFIG_SYS_PCIE_MEMSIZE,
+ CONFIG_SYS_PCIE_MEMSIZE,
+ PCI_REGION_MEM);
+ hose->region_count = 1;
+ pci_register_hose(hose);
+
+ if (is_end_point(i)) {
+ ppc4xx_setup_pcie_endpoint(hose, i);
+ /*
+ * Reson for no scanning is endpoint can not generate
+ * upstream configuration accesses.
+ */
+ } else {
+ ppc4xx_setup_pcie_rootpoint(hose, i);
+ env = getenv ("pciscandelay");
+ if (env != NULL) {
+ delay = simple_strtoul(env, NULL, 10);
+ if (delay > 5)
+ printf("Warning, expect noticable delay before "
+ "PCIe scan due to 'pciscandelay' value!\n");
+ mdelay(delay * 1000);
+ }
+
+ /*
+ * Config access can only go down stream
+ */
+ hose->last_busno = pci_hose_scan(hose);
+ bus = hose->last_busno + 1;
+ }
+ }
+}
+
+static int validate_endpoint(struct pci_controller *hose)
+{
+ if (hose->cfg_data == (u8 *)CONFIG_SYS_PCIE0_CFGBASE)
+ return (is_end_point(0));
+ else if (hose->cfg_data == (u8 *)CONFIG_SYS_PCIE1_CFGBASE)
+ return (is_end_point(1));
+#if CONFIG_SYS_PCIE_NR_PORTS > 2
+ else if (hose->cfg_data == (u8 *)CONFIG_SYS_PCIE2_CFGBASE)
+ return (is_end_point(2));
+#endif
+
+ return 0;
+}
+
+static u8* pcie_get_base(struct pci_controller *hose, unsigned int devfn)
+{
+ u8 *base = (u8*)hose->cfg_data;
+
+ /* use local configuration space for the first bus */
+ if (PCI_BUS(devfn) == 0) {
+ if (hose->cfg_data == (u8*)CONFIG_SYS_PCIE0_CFGBASE)
+ base = (u8*)CONFIG_SYS_PCIE0_XCFGBASE;
+ if (hose->cfg_data == (u8*)CONFIG_SYS_PCIE1_CFGBASE)
+ base = (u8*)CONFIG_SYS_PCIE1_XCFGBASE;
+#if CONFIG_SYS_PCIE_NR_PORTS > 2
+ if (hose->cfg_data == (u8*)CONFIG_SYS_PCIE2_CFGBASE)
+ base = (u8*)CONFIG_SYS_PCIE2_XCFGBASE;
+#endif
+ }
+
+ return base;
+}
+
+static void pcie_dmer_disable(void)
+{
+ mtdcr (DCRN_PEGPL_CFG(DCRN_PCIE0_BASE),
+ mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE0_BASE)) | GPL_DMER_MASK_DISA);
+ mtdcr (DCRN_PEGPL_CFG(DCRN_PCIE1_BASE),
+ mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE1_BASE)) | GPL_DMER_MASK_DISA);
+#if CONFIG_SYS_PCIE_NR_PORTS > 2
+ mtdcr (DCRN_PEGPL_CFG(DCRN_PCIE2_BASE),
+ mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE2_BASE)) | GPL_DMER_MASK_DISA);
+#endif
+}
+
+static void pcie_dmer_enable(void)
+{
+ mtdcr (DCRN_PEGPL_CFG (DCRN_PCIE0_BASE),
+ mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE0_BASE)) & ~GPL_DMER_MASK_DISA);
+ mtdcr (DCRN_PEGPL_CFG (DCRN_PCIE1_BASE),
+ mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE1_BASE)) & ~GPL_DMER_MASK_DISA);
+#if CONFIG_SYS_PCIE_NR_PORTS > 2
+ mtdcr (DCRN_PEGPL_CFG (DCRN_PCIE2_BASE),
+ mfdcr (DCRN_PEGPL_CFG(DCRN_PCIE2_BASE)) & ~GPL_DMER_MASK_DISA);
+#endif
+}
+
+static int pcie_read_config(struct pci_controller *hose, unsigned int devfn,
+ int offset, int len, u32 *val) {
+
+ *val = 0;
+
+ if (validate_endpoint(hose))
+ return 0; /* No upstream config access */
+
+ /*
+ * Bus numbers are relative to hose->first_busno
+ */
+ devfn -= PCI_BDF(hose->first_busno, 0, 0);
+
+ /*
+ * NOTICE: configuration space ranges are currenlty mapped only for
+ * the first 16 buses, so such limit must be imposed. In case more
+ * buses are required the TLB settings in board/amcc/<board>/init.S
+ * need to be altered accordingly (one bus takes 1 MB of memory space).
+ */
+ if (PCI_BUS(devfn) >= 16)
+ return 0;
+
+ /*
+ * Only single device/single function is supported for the primary and
+ * secondary buses of the 440SPe host bridge.
+ */
+ if ((!((PCI_FUNC(devfn) == 0) && (PCI_DEV(devfn) == 0))) &&
+ ((PCI_BUS(devfn) == 0) || (PCI_BUS(devfn) == 1)))
+ return 0;
+
+ pcie_get_base(hose, devfn);
+ offset += devfn << 4;
+
+ /*
+ * Reading from configuration space of non-existing device can
+ * generate transaction errors. For the read duration we suppress
+ * assertion of machine check exceptions to avoid those.
+ */
+ pcie_dmer_disable ();
+
+ debug("%s: cfg_data=%p offset=%08x\n", __func__,
+ hose->cfg_data, offset);
+ switch (len) {
+ case 1:
+ *val = in_8(hose->cfg_data + offset);
+ break;
+ case 2:
+ *val = in_le16((u16 *)(hose->cfg_data + offset));
+ break;
+ default:
+ *val = in_le32((u32*)(hose->cfg_data + offset));
+ break;
+ }
+
+ pcie_dmer_enable ();
+
+ return 0;
+}
+
+static int pcie_write_config(struct pci_controller *hose, unsigned int devfn,
+ int offset, int len, u32 val) {
+
+ if (validate_endpoint(hose))
+ return 0; /* No upstream config access */
+
+ /*
+ * Bus numbers are relative to hose->first_busno
+ */
+ devfn -= PCI_BDF(hose->first_busno, 0, 0);
+
+ /*
+ * Same constraints as in pcie_read_config().
+ */
+ if (PCI_BUS(devfn) >= 16)
+ return 0;
+
+ if ((!((PCI_FUNC(devfn) == 0) && (PCI_DEV(devfn) == 0))) &&
+ ((PCI_BUS(devfn) == 0) || (PCI_BUS(devfn) == 1)))
+ return 0;
+
+ pcie_get_base(hose, devfn);
+ offset += devfn << 4;
+
+ /*
+ * Suppress MCK exceptions, similar to pcie_read_config()
+ */
+ pcie_dmer_disable ();
+
+ switch (len) {
+ case 1:
+ out_8(hose->cfg_data + offset, val);
+ break;
+ case 2:
+ out_le16((u16 *)(hose->cfg_data + offset), val);
+ break;
+ default:
+ out_le32((u32 *)(hose->cfg_data + offset), val);
+ break;
+ }
+
+ pcie_dmer_enable ();
+
+ return 0;
+}
+
+int pcie_read_config_byte(struct pci_controller *hose,pci_dev_t dev,int offset,u8 *val)
+{
+ u32 v;
+ int rv;
+
+ rv = pcie_read_config(hose, dev, offset, 1, &v);
+ *val = (u8)v;
+ return rv;
+}
+
+int pcie_read_config_word(struct pci_controller *hose,pci_dev_t dev,int offset,u16 *val)
+{
+ u32 v;
+ int rv;
+
+ rv = pcie_read_config(hose, dev, offset, 2, &v);
+ *val = (u16)v;
+ return rv;
+}
+
+int pcie_read_config_dword(struct pci_controller *hose,pci_dev_t dev,int offset,u32 *val)
+{
+ u32 v;
+ int rv;
+
+ rv = pcie_read_config(hose, dev, offset, 3, &v);
+ *val = (u32)v;
+ return rv;
+}
+
+int pcie_write_config_byte(struct pci_controller *hose,pci_dev_t dev,int offset,u8 val)
+{
+ return pcie_write_config(hose,(u32)dev,offset,1,val);
+}
+
+int pcie_write_config_word(struct pci_controller *hose,pci_dev_t dev,int offset,u16 val)
+{
+ return pcie_write_config(hose,(u32)dev,offset,2,(u32 )val);
+}
+
+int pcie_write_config_dword(struct pci_controller *hose,pci_dev_t dev,int offset,u32 val)
+{
+ return pcie_write_config(hose,(u32)dev,offset,3,(u32 )val);
+}
+
+#if defined(CONFIG_440SPE)
+static void ppc4xx_setup_utl(u32 port) {
+
+ volatile void *utl_base = NULL;
+
+ /*
+ * Map UTL registers
+ */
+ switch (port) {
+ case 0:
+ mtdcr(DCRN_PEGPL_REGBAH(PCIE0), 0x0000000c);
+ mtdcr(DCRN_PEGPL_REGBAL(PCIE0), 0x20000000);
+ mtdcr(DCRN_PEGPL_REGMSK(PCIE0), 0x00007001);
+ mtdcr(DCRN_PEGPL_SPECIAL(PCIE0), 0x68782800);
+ break;
+
+ case 1:
+ mtdcr(DCRN_PEGPL_REGBAH(PCIE1), 0x0000000c);
+ mtdcr(DCRN_PEGPL_REGBAL(PCIE1), 0x20001000);
+ mtdcr(DCRN_PEGPL_REGMSK(PCIE1), 0x00007001);
+ mtdcr(DCRN_PEGPL_SPECIAL(PCIE1), 0x68782800);
+ break;
+
+ case 2:
+ mtdcr(DCRN_PEGPL_REGBAH(PCIE2), 0x0000000c);
+ mtdcr(DCRN_PEGPL_REGBAL(PCIE2), 0x20002000);
+ mtdcr(DCRN_PEGPL_REGMSK(PCIE2), 0x00007001);
+ mtdcr(DCRN_PEGPL_SPECIAL(PCIE2), 0x68782800);
+ break;
+ }
+ utl_base = (unsigned int *)(CONFIG_SYS_PCIE_BASE + 0x1000 * port);
+
+ /*
+ * Set buffer allocations and then assert VRB and TXE.
+ */
+ out_be32(utl_base + PEUTL_OUTTR, 0x08000000);
+ out_be32(utl_base + PEUTL_INTR, 0x02000000);
+ out_be32(utl_base + PEUTL_OPDBSZ, 0x10000000);
+ out_be32(utl_base + PEUTL_PBBSZ, 0x53000000);
+ out_be32(utl_base + PEUTL_IPHBSZ, 0x08000000);
+ out_be32(utl_base + PEUTL_IPDBSZ, 0x10000000);
+ out_be32(utl_base + PEUTL_RCIRQEN, 0x00f00000);
+ out_be32(utl_base + PEUTL_PCTL, 0x80800066);
+}
+
+static int check_error(void)
+{
+ u32 valPE0, valPE1, valPE2;
+ int err = 0;
+
+ /* SDR0_PEGPLLLCT1 reset */
+ if (!(valPE0 = SDR_READ(PESDR0_PLLLCT1) & 0x01000000))
+ printf("PCIE: SDR0_PEGPLLLCT1 reset error 0x%x\n", valPE0);
+
+ valPE0 = SDR_READ(PESDR0_RCSSET);
+ valPE1 = SDR_READ(PESDR1_RCSSET);
+ valPE2 = SDR_READ(PESDR2_RCSSET);
+
+ /* SDR0_PExRCSSET rstgu */
+ if (!(valPE0 & 0x01000000) ||
+ !(valPE1 & 0x01000000) ||
+ !(valPE2 & 0x01000000)) {
+ printf("PCIE: SDR0_PExRCSSET rstgu error\n");
+ err = -1;
+ }
+
+ /* SDR0_PExRCSSET rstdl */
+ if (!(valPE0 & 0x00010000) ||
+ !(valPE1 & 0x00010000) ||
+ !(valPE2 & 0x00010000)) {
+ printf("PCIE: SDR0_PExRCSSET rstdl error\n");
+ err = -1;
+ }
+
+ /* SDR0_PExRCSSET rstpyn */
+ if ((valPE0 & 0x00001000) ||
+ (valPE1 & 0x00001000) ||
+ (valPE2 & 0x00001000)) {
+ printf("PCIE: SDR0_PExRCSSET rstpyn error\n");
+ err = -1;
+ }
+
+ /* SDR0_PExRCSSET hldplb */
+ if ((valPE0 & 0x10000000) ||
+ (valPE1 & 0x10000000) ||
+ (valPE2 & 0x10000000)) {
+ printf("PCIE: SDR0_PExRCSSET hldplb error\n");
+ err = -1;
+ }
+
+ /* SDR0_PExRCSSET rdy */
+ if ((valPE0 & 0x00100000) ||
+ (valPE1 & 0x00100000) ||
+ (valPE2 & 0x00100000)) {
+ printf("PCIE: SDR0_PExRCSSET rdy error\n");
+ err = -1;
+ }
+
+ /* SDR0_PExRCSSET shutdown */
+ if ((valPE0 & 0x00000100) ||
+ (valPE1 & 0x00000100) ||
+ (valPE2 & 0x00000100)) {
+ printf("PCIE: SDR0_PExRCSSET shutdown error\n");
+ err = -1;
+ }
+ return err;
+}
+
+/*
+ * Initialize PCI Express core
+ */
+int ppc4xx_init_pcie(void)
+{
+ int time_out = 20;
+
+ /* Set PLL clock receiver to LVPECL */
+ SDR_WRITE(PESDR0_PLLLCT1, SDR_READ(PESDR0_PLLLCT1) | 1 << 28);
+
+ if (check_error()) {
+ printf("ERROR: failed to set PCIe reference clock receiver --"
+ "PESDR0_PLLLCT1 = 0x%08x\n", SDR_READ(PESDR0_PLLLCT1));
+
+ return -1;
+ }
+
+ /* Did resistance calibration work? */
+ if (!(SDR_READ(PESDR0_PLLLCT2) & 0x10000)) {
+ printf("ERROR: PCIe resistance calibration failed --"
+ "PESDR0_PLLLCT2 = 0x%08x\n", SDR_READ(PESDR0_PLLLCT2));
+
+ return -1;
+ }
+ /* De-assert reset of PCIe PLL, wait for lock */
+ SDR_WRITE(PESDR0_PLLLCT1, SDR_READ(PESDR0_PLLLCT1) & ~(1 << 24));
+ udelay(300); /* 300 uS is maximum time lock should take */
+
+ while (time_out) {
+ if (!(SDR_READ(PESDR0_PLLLCT3) & 0x10000000)) {
+ time_out--;
+ udelay(20); /* Wait 20 uS more if needed */
+ } else
+ break;
+ }
+ if (!time_out) {
+ printf("ERROR: PCIe PLL VCO output not locked to ref clock --"
+ "PESDR0_PLLLCTS=0x%08x\n", SDR_READ(PESDR0_PLLLCT3));
+
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+static void ppc4xx_setup_utl(u32 port)
+{
+ volatile void *utl_base = NULL;
+
+ /*
+ * Map UTL registers at 0x0801_n000 (4K 0xfff mask) PEGPLn_REGMSK
+ */
+ switch (port) {
+ case 0:
+ mtdcr(DCRN_PEGPL_REGBAH(PCIE0), U64_TO_U32_HIGH(CONFIG_SYS_PCIE0_UTLBASE));
+ mtdcr(DCRN_PEGPL_REGBAL(PCIE0), U64_TO_U32_LOW(CONFIG_SYS_PCIE0_UTLBASE));
+ mtdcr(DCRN_PEGPL_REGMSK(PCIE0), 0x00007001); /* BAM 11100000=4KB */
+ mtdcr(DCRN_PEGPL_SPECIAL(PCIE0), 0);
+ break;
+
+ case 1:
+ mtdcr(DCRN_PEGPL_REGBAH(PCIE1), U64_TO_U32_HIGH(CONFIG_SYS_PCIE0_UTLBASE));
+ mtdcr(DCRN_PEGPL_REGBAL(PCIE1), U64_TO_U32_LOW(CONFIG_SYS_PCIE0_UTLBASE)
+ + 0x1000);
+ mtdcr(DCRN_PEGPL_REGMSK(PCIE1), 0x00007001); /* BAM 11100000=4KB */
+ mtdcr(DCRN_PEGPL_SPECIAL(PCIE1), 0);
+ break;
+ }
+ utl_base = (unsigned int *)(CONFIG_SYS_PCIE_BASE + 0x1000 * port);
+
+ /*
+ * Set buffer allocations and then assert VRB and TXE.
+ */
+ out_be32(utl_base + PEUTL_PBCTL, 0x0800000c); /* PLBME, CRRE */
+ out_be32(utl_base + PEUTL_OUTTR, 0x08000000);
+ out_be32(utl_base + PEUTL_INTR, 0x02000000);
+ out_be32(utl_base + PEUTL_OPDBSZ, 0x04000000); /* OPD = 512 Bytes */
+ out_be32(utl_base + PEUTL_PBBSZ, 0x00000000); /* Max 512 Bytes */
+ out_be32(utl_base + PEUTL_IPHBSZ, 0x02000000);
+ out_be32(utl_base + PEUTL_IPDBSZ, 0x04000000); /* IPD = 512 Bytes */
+ out_be32(utl_base + PEUTL_RCIRQEN, 0x00f00000);
+ out_be32(utl_base + PEUTL_PCTL, 0x80800066); /* VRB,TXE,timeout=default */
+}
+
+/*
+ * TODO: double check PCI express SDR based on the latest user manual
+ * Some registers specified here no longer exist.. has to be
+ * updated based on the final EAS spec.
+ */
+static int check_error(void)
+{
+ u32 valPE0, valPE1;
+ int err = 0;
+
+ valPE0 = SDR_READ(SDRN_PESDR_RCSSET(0));
+ valPE1 = SDR_READ(SDRN_PESDR_RCSSET(1));
+
+ /* SDR0_PExRCSSET rstgu */
+ if (!(valPE0 & PESDRx_RCSSET_RSTGU) || !(valPE1 & PESDRx_RCSSET_RSTGU)) {
+ printf("PCIE: SDR0_PExRCSSET rstgu error\n");
+ err = -1;
+ }
+
+ /* SDR0_PExRCSSET rstdl */
+ if (!(valPE0 & PESDRx_RCSSET_RSTDL) || !(valPE1 & PESDRx_RCSSET_RSTDL)) {
+ printf("PCIE: SDR0_PExRCSSET rstdl error\n");
+ err = -1;
+ }
+
+ /* SDR0_PExRCSSET rstpyn */
+ if ((valPE0 & PESDRx_RCSSET_RSTPYN) || (valPE1 & PESDRx_RCSSET_RSTPYN)) {
+ printf("PCIE: SDR0_PExRCSSET rstpyn error\n");
+ err = -1;
+ }
+
+ /* SDR0_PExRCSSET hldplb */
+ if ((valPE0 & PESDRx_RCSSET_HLDPLB) || (valPE1 & PESDRx_RCSSET_HLDPLB)) {
+ printf("PCIE: SDR0_PExRCSSET hldplb error\n");
+ err = -1;
+ }
+
+ /* SDR0_PExRCSSET rdy */
+ if ((valPE0 & PESDRx_RCSSET_RDY) || (valPE1 & PESDRx_RCSSET_RDY)) {
+ printf("PCIE: SDR0_PExRCSSET rdy error\n");
+ err = -1;
+ }
+
+ return err;
+}
+
+/*
+ * Initialize PCI Express core as described in User Manual
+ * TODO: double check PE SDR PLL Register with the updated user manual.
+ */
+int ppc4xx_init_pcie(void)
+{
+ if (check_error())
+ return -1;
+
+ return 0;
+}
+#endif /* CONFIG_460EX */
+
+#if defined(CONFIG_405EX)
+static void ppc4xx_setup_utl(u32 port)
+{
+ u32 utl_base;
+
+ /*
+ * Map UTL registers at 0xef4f_n000 (4K 0xfff mask) PEGPLn_REGMSK
+ */
+ switch (port) {
+ case 0:
+ mtdcr(DCRN_PEGPL_REGBAH(PCIE0), 0x00000000);
+ mtdcr(DCRN_PEGPL_REGBAL(PCIE0), CONFIG_SYS_PCIE0_UTLBASE);
+ mtdcr(DCRN_PEGPL_REGMSK(PCIE0), 0x00007001); /* 4k region, valid */
+ mtdcr(DCRN_PEGPL_SPECIAL(PCIE0), 0);
+ break;
+
+ case 1:
+ mtdcr(DCRN_PEGPL_REGBAH(PCIE1), 0x00000000);
+ mtdcr(DCRN_PEGPL_REGBAL(PCIE1), CONFIG_SYS_PCIE1_UTLBASE);
+ mtdcr(DCRN_PEGPL_REGMSK(PCIE1), 0x00007001); /* 4k region, valid */
+ mtdcr(DCRN_PEGPL_SPECIAL(PCIE1), 0);
+
+ break;
+ }
+ utl_base = (port==0) ? CONFIG_SYS_PCIE0_UTLBASE : CONFIG_SYS_PCIE1_UTLBASE;
+
+ /*
+ * Set buffer allocations and then assert VRB and TXE.
+ */
+ out_be32((u32 *)(utl_base + PEUTL_OUTTR), 0x02000000);
+ out_be32((u32 *)(utl_base + PEUTL_INTR), 0x02000000);
+ out_be32((u32 *)(utl_base + PEUTL_OPDBSZ), 0x04000000);
+ out_be32((u32 *)(utl_base + PEUTL_PBBSZ), 0x21000000);
+ out_be32((u32 *)(utl_base + PEUTL_IPHBSZ), 0x02000000);
+ out_be32((u32 *)(utl_base + PEUTL_IPDBSZ), 0x04000000);
+ out_be32((u32 *)(utl_base + PEUTL_RCIRQEN), 0x00f00000);
+ out_be32((u32 *)(utl_base + PEUTL_PCTL), 0x80800066);
+
+ out_be32((u32 *)(utl_base + PEUTL_PBCTL), 0x0800000c);
+ out_be32((u32 *)(utl_base + PEUTL_RCSTA),
+ in_be32((u32 *)(utl_base + PEUTL_RCSTA)) | 0x000040000);
+}
+
+int ppc4xx_init_pcie(void)
+{
+ /*
+ * Nothing to do on 405EX
+ */
+ return 0;
+}
+#endif /* CONFIG_405EX */
+
+/*
+ * Board-specific pcie initialization
+ * Platform code can reimplement ppc4xx_init_pcie_port_hw() if needed
+ */
+
+/*
+ * Initialize various parts of the PCI Express core for our port:
+ *
+ * - Set as a root port and enable max width
+ * (PXIE0 -> X8, PCIE1 and PCIE2 -> X4).
+ * - Set up UTL configuration.
+ * - Increase SERDES drive strength to levels suggested by AMCC.
+ * - De-assert RSTPYN, RSTDL and RSTGU.
+ *
+ * NOTICE for 440SPE revB chip: PESDRn_UTLSET2 is not set - we leave it
+ * with default setting 0x11310000. The register has new fields,
+ * PESDRn_UTLSET2[LKINE] in particular: clearing it leads to PCIE core
+ * hang.
+ */
+#if defined(CONFIG_440SPE)
+int __ppc4xx_init_pcie_port_hw(int port, int rootport)
+{
+ u32 val = 1 << 24;
+ u32 utlset1;
+
+ if (rootport) {
+ val = PTYPE_ROOT_PORT << 20;
+ utlset1 = 0x21222222;
+ } else {
+ val = PTYPE_LEGACY_ENDPOINT << 20;
+ utlset1 = 0x20222222;
+ }
+
+ if (port == 0)
+ val |= LNKW_X8 << 12;
+ else
+ val |= LNKW_X4 << 12;
+
+ SDR_WRITE(SDRN_PESDR_DLPSET(port), val);
+ SDR_WRITE(SDRN_PESDR_UTLSET1(port), utlset1);
+ if (!ppc440spe_revB())
+ SDR_WRITE(SDRN_PESDR_UTLSET2(port), 0x11000000);
+ SDR_WRITE(SDRN_PESDR_HSSL0SET1(port), 0x35000000);
+ SDR_WRITE(SDRN_PESDR_HSSL1SET1(port), 0x35000000);
+ SDR_WRITE(SDRN_PESDR_HSSL2SET1(port), 0x35000000);
+ SDR_WRITE(SDRN_PESDR_HSSL3SET1(port), 0x35000000);
+ if (port == 0) {
+ SDR_WRITE(PESDR0_HSSL4SET1, 0x35000000);
+ SDR_WRITE(PESDR0_HSSL5SET1, 0x35000000);
+ SDR_WRITE(PESDR0_HSSL6SET1, 0x35000000);
+ SDR_WRITE(PESDR0_HSSL7SET1, 0x35000000);
+ }
+ SDR_WRITE(SDRN_PESDR_RCSSET(port), (SDR_READ(SDRN_PESDR_RCSSET(port)) &
+ ~(1 << 24 | 1 << 16)) | 1 << 12);
+
+ return 0;
+}
+#endif /* CONFIG_440SPE */
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+int __ppc4xx_init_pcie_port_hw(int port, int rootport)
+{
+ u32 val;
+ u32 utlset1;
+
+ if (rootport)
+ val = PTYPE_ROOT_PORT << 20;
+ else
+ val = PTYPE_LEGACY_ENDPOINT << 20;
+
+ if (port == 0) {
+ val |= LNKW_X1 << 12;
+ utlset1 = 0x20000000;
+ } else {
+ val |= LNKW_X4 << 12;
+ utlset1 = 0x20101101;
+ }
+
+ SDR_WRITE(SDRN_PESDR_DLPSET(port), val);
+ SDR_WRITE(SDRN_PESDR_UTLSET1(port), utlset1);
+ SDR_WRITE(SDRN_PESDR_UTLSET2(port), 0x01210000);
+
+ switch (port) {
+ case 0:
+ SDR_WRITE(PESDR0_L0CDRCTL, 0x00003230);
+ SDR_WRITE(PESDR0_L0DRV, 0x00000130);
+ SDR_WRITE(PESDR0_L0CLK, 0x00000006);
+
+ SDR_WRITE(PESDR0_PHY_CTL_RST,0x10000000);
+ break;
+
+ case 1:
+ SDR_WRITE(PESDR1_L0CDRCTL, 0x00003230);
+ SDR_WRITE(PESDR1_L1CDRCTL, 0x00003230);
+ SDR_WRITE(PESDR1_L2CDRCTL, 0x00003230);
+ SDR_WRITE(PESDR1_L3CDRCTL, 0x00003230);
+ SDR_WRITE(PESDR1_L0DRV, 0x00000130);
+ SDR_WRITE(PESDR1_L1DRV, 0x00000130);
+ SDR_WRITE(PESDR1_L2DRV, 0x00000130);
+ SDR_WRITE(PESDR1_L3DRV, 0x00000130);
+ SDR_WRITE(PESDR1_L0CLK, 0x00000006);
+ SDR_WRITE(PESDR1_L1CLK, 0x00000006);
+ SDR_WRITE(PESDR1_L2CLK, 0x00000006);
+ SDR_WRITE(PESDR1_L3CLK, 0x00000006);
+
+ SDR_WRITE(PESDR1_PHY_CTL_RST,0x10000000);
+ break;
+ }
+
+ SDR_WRITE(SDRN_PESDR_RCSSET(port), SDR_READ(SDRN_PESDR_RCSSET(port)) |
+ (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTPYN));
+
+ /* Poll for PHY reset */
+ switch (port) {
+ case 0:
+ while (!(SDR_READ(PESDR0_RSTSTA) & 0x1))
+ udelay(10);
+ break;
+ case 1:
+ while (!(SDR_READ(PESDR1_RSTSTA) & 0x1))
+ udelay(10);
+ break;
+ }
+
+ SDR_WRITE(SDRN_PESDR_RCSSET(port),
+ (SDR_READ(SDRN_PESDR_RCSSET(port)) &
+ ~(PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL)) |
+ PESDRx_RCSSET_RSTPYN);
+
+ return 0;
+}
+#endif /* CONFIG_440SPE */
+
+#if defined(CONFIG_405EX)
+int __ppc4xx_init_pcie_port_hw(int port, int rootport)
+{
+ u32 val;
+
+ if (rootport)
+ val = 0x00401000;
+ else
+ val = 0x00101000;
+
+ SDR_WRITE(SDRN_PESDR_DLPSET(port), val);
+ SDR_WRITE(SDRN_PESDR_UTLSET1(port), 0x00000000);
+ SDR_WRITE(SDRN_PESDR_UTLSET2(port), 0x01010000);
+ SDR_WRITE(SDRN_PESDR_PHYSET1(port), 0x720F0000);
+ SDR_WRITE(SDRN_PESDR_PHYSET2(port), 0x70600003);
+
+ /* Assert the PE0_PHY reset */
+ SDR_WRITE(SDRN_PESDR_RCSSET(port), 0x01010000);
+ udelay(1000);
+
+ /* deassert the PE0_hotreset */
+ if (is_end_point(port))
+ SDR_WRITE(SDRN_PESDR_RCSSET(port), 0x01111000);
+ else
+ SDR_WRITE(SDRN_PESDR_RCSSET(port), 0x01101000);
+
+ /* poll for phy !reset */
+ while (!(SDR_READ(SDRN_PESDR_PHYSTA(port)) & 0x00001000))
+ ;
+
+ /* deassert the PE0_gpl_utl_reset */
+ SDR_WRITE(SDRN_PESDR_RCSSET(port), 0x00101000);
+
+ if (port == 0)
+ mtdcr(DCRN_PEGPL_CFG(PCIE0), 0x10000000); /* guarded on */
+ else
+ mtdcr(DCRN_PEGPL_CFG(PCIE1), 0x10000000); /* guarded on */
+
+ return 0;
+}
+#endif /* CONFIG_405EX */
+
+int ppc4xx_init_pcie_port_hw(int port, int rootport)
+__attribute__((weak, alias("__ppc4xx_init_pcie_port_hw")));
+
+/*
+ * We map PCI Express configuration access into the 512MB regions
+ *
+ * NOTICE: revB is very strict about PLB real addressess and ranges to
+ * be mapped for config space; it seems to only work with d_nnnn_nnnn
+ * range (hangs the core upon config transaction attempts when set
+ * otherwise) while revA uses c_nnnn_nnnn.
+ *
+ * For 440SPe revA:
+ * PCIE0: 0xc_4000_0000
+ * PCIE1: 0xc_8000_0000
+ * PCIE2: 0xc_c000_0000
+ *
+ * For 440SPe revB:
+ * PCIE0: 0xd_0000_0000
+ * PCIE1: 0xd_2000_0000
+ * PCIE2: 0xd_4000_0000
+ *
+ * For 405EX:
+ * PCIE0: 0xa000_0000
+ * PCIE1: 0xc000_0000
+ *
+ * For 460EX/GT:
+ * PCIE0: 0xd_0000_0000
+ * PCIE1: 0xd_2000_0000
+ */
+static inline u64 ppc4xx_get_cfgaddr(int port)
+{
+#if defined(CONFIG_405EX)
+ if (port == 0)
+ return (u64)CONFIG_SYS_PCIE0_CFGBASE;
+ else
+ return (u64)CONFIG_SYS_PCIE1_CFGBASE;
+#endif
+#if defined(CONFIG_440SPE)
+ if (ppc440spe_revB()) {
+ switch (port) {
+ default: /* to satisfy compiler */
+ case 0:
+ return 0x0000000d00000000ULL;
+ case 1:
+ return 0x0000000d20000000ULL;
+ case 2:
+ return 0x0000000d40000000ULL;
+ }
+ } else {
+ switch (port) {
+ default: /* to satisfy compiler */
+ case 0:
+ return 0x0000000c40000000ULL;
+ case 1:
+ return 0x0000000c80000000ULL;
+ case 2:
+ return 0x0000000cc0000000ULL;
+ }
+ }
+#endif
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ if (port == 0)
+ return 0x0000000d00000000ULL;
+ else
+ return 0x0000000d20000000ULL;
+#endif
+}
+
+/*
+ * 4xx boards as endpoint and root point setup
+ * and
+ * testing inbound and out bound windows
+ *
+ * 4xx boards can be plugged into another 4xx boards or you can get PCI-E
+ * cable which can be used to setup loop back from one port to another port.
+ * Please rememeber that unless there is a endpoint plugged in to root port it
+ * will not initialize. It is the same in case of endpoint , unless there is
+ * root port attached it will not initialize.
+ *
+ * In this release of software all the PCI-E ports are configured as either
+ * endpoint or rootpoint.In future we will have support for selective ports
+ * setup as endpoint and root point in single board.
+ *
+ * Once your board came up as root point , you can verify by reading
+ * /proc/bus/pci/devices. Where you can see the configuration registers
+ * of endpoint device attached to the port.
+ *
+ * Enpoint cofiguration can be verified by connecting 4xx board to any
+ * host or another 4xx board. Then try to scan the device. In case of
+ * linux use "lspci" or appripriate os command.
+ *
+ * How do I verify the inbound and out bound windows ? (4xx to 4xx)
+ * in this configuration inbound and outbound windows are setup to access
+ * sram memroy area. SRAM is at 0x4 0000 0000 , on PLB bus. This address
+ * is mapped at 0x90000000. From u-boot prompt write data 0xb000 0000,
+ * This is waere your POM(PLB out bound memory window) mapped. then
+ * read the data from other 4xx board's u-boot prompt at address
+ * 0x9000 0000(SRAM). Data should match.
+ * In case of inbound , write data to u-boot command prompt at 0xb000 0000
+ * which is mapped to 0x4 0000 0000. Now on rootpoint yucca u-boot prompt check
+ * data at 0x9000 0000(SRAM).Data should match.
+ */
+int ppc4xx_init_pcie_port(int port, int rootport)
+{
+ static int core_init;
+ volatile u32 val = 0;
+ int attempts;
+ u64 addr;
+ u32 low, high;
+
+ if (!core_init) {
+ if (ppc4xx_init_pcie())
+ return -1;
+ ++core_init;
+ }
+
+ /*
+ * Initialize various parts of the PCI Express core for our port
+ */
+ ppc4xx_init_pcie_port_hw(port, rootport);
+
+ /*
+ * Notice: the following delay has critical impact on device
+ * initialization - if too short (<50ms) the link doesn't get up.
+ */
+ mdelay(100);
+
+ val = SDR_READ(SDRN_PESDR_RCSSTS(port));
+ if (val & (1 << 20)) {
+ printf("PCIE%d: PGRST failed %08x\n", port, val);
+ return -1;
+ }
+
+ /*
+ * Verify link is up
+ */
+ val = SDR_READ(SDRN_PESDR_LOOP(port));
+ if (!(val & 0x00001000)) {
+ printf("PCIE%d: link is not up.\n", port);
+ return -ENODEV;
+ }
+
+ /*
+ * Setup UTL registers - but only on revA!
+ * We use default settings for revB chip.
+ */
+ if (!ppc440spe_revB())
+ ppc4xx_setup_utl(port);
+
+ /*
+ * We map PCI Express configuration access into the 512MB regions
+ */
+ addr = ppc4xx_get_cfgaddr(port);
+ low = U64_TO_U32_LOW(addr);
+ high = U64_TO_U32_HIGH(addr);
+
+ switch (port) {
+ case 0:
+ mtdcr(DCRN_PEGPL_CFGBAH(PCIE0), high);
+ mtdcr(DCRN_PEGPL_CFGBAL(PCIE0), low);
+ mtdcr(DCRN_PEGPL_CFGMSK(PCIE0), 0xe0000001); /* 512MB region, valid */
+ break;
+ case 1:
+ mtdcr(DCRN_PEGPL_CFGBAH(PCIE1), high);
+ mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), low);
+ mtdcr(DCRN_PEGPL_CFGMSK(PCIE1), 0xe0000001); /* 512MB region, valid */
+ break;
+#if CONFIG_SYS_PCIE_NR_PORTS > 2
+ case 2:
+ mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), high);
+ mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), low);
+ mtdcr(DCRN_PEGPL_CFGMSK(PCIE2), 0xe0000001); /* 512MB region, valid */
+ break;
+#endif
+ }
+
+ /*
+ * Check for VC0 active and assert RDY.
+ */
+ attempts = 10;
+ while(!(SDR_READ(SDRN_PESDR_RCSSTS(port)) & (1 << 16))) {
+ if (!(attempts--)) {
+ printf("PCIE%d: VC0 not active\n", port);
+ return -1;
+ }
+ mdelay(1000);
+ }
+ SDR_WRITE(SDRN_PESDR_RCSSET(port),
+ SDR_READ(SDRN_PESDR_RCSSET(port)) | 1 << 20);
+ mdelay(100);
+
+ return 0;
+}
+
+int ppc4xx_init_pcie_rootport(int port)
+{
+ return ppc4xx_init_pcie_port(port, 1);
+}
+
+int ppc4xx_init_pcie_endport(int port)
+{
+ return ppc4xx_init_pcie_port(port, 0);
+}
+
+void ppc4xx_setup_pcie_rootpoint(struct pci_controller *hose, int port)
+{
+ volatile void *mbase = NULL;
+
+ pci_set_ops(hose,
+ pcie_read_config_byte,
+ pcie_read_config_word,
+ pcie_read_config_dword,
+ pcie_write_config_byte,
+ pcie_write_config_word,
+ pcie_write_config_dword);
+
+ switch (port) {
+ case 0:
+ mbase = (u32 *)CONFIG_SYS_PCIE0_XCFGBASE;
+ hose->cfg_data = (u8 *)CONFIG_SYS_PCIE0_CFGBASE;
+ break;
+ case 1:
+ mbase = (u32 *)CONFIG_SYS_PCIE1_XCFGBASE;
+ hose->cfg_data = (u8 *)CONFIG_SYS_PCIE1_CFGBASE;
+ break;
+#if CONFIG_SYS_PCIE_NR_PORTS > 2
+ case 2:
+ mbase = (u32 *)CONFIG_SYS_PCIE2_XCFGBASE;
+ hose->cfg_data = (u8 *)CONFIG_SYS_PCIE2_CFGBASE;
+ break;
+#endif
+ }
+
+ /*
+ * Set bus numbers on our root port
+ */
+ out_8((u8 *)mbase + PCI_PRIMARY_BUS, 0);
+ out_8((u8 *)mbase + PCI_SECONDARY_BUS, 1);
+ out_8((u8 *)mbase + PCI_SUBORDINATE_BUS, 1);
+
+ /*
+ * Set up outbound translation to hose->mem_space from PLB
+ * addresses at an offset of 0xd_0000_0000. We set the low
+ * bits of the mask to 11 to turn off splitting into 8
+ * subregions and to enable the outbound translation.
+ */
+ out_le32(mbase + PECFG_POM0LAH, 0x00000000);
+ out_le32(mbase + PECFG_POM0LAL, CONFIG_SYS_PCIE_MEMBASE +
+ port * CONFIG_SYS_PCIE_MEMSIZE);
+ debug("PECFG_POM0LA=%08x.%08x\n", in_le32(mbase + PECFG_POM0LAH),
+ in_le32(mbase + PECFG_POM0LAL));
+
+ switch (port) {
+ case 0:
+ mtdcr(DCRN_PEGPL_OMR1BAH(PCIE0), CONFIG_SYS_PCIE_ADDR_HIGH);
+ mtdcr(DCRN_PEGPL_OMR1BAL(PCIE0), CONFIG_SYS_PCIE_MEMBASE +
+ port * CONFIG_SYS_PCIE_MEMSIZE);
+ mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE0), 0x7fffffff);
+ mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE0),
+ ~(CONFIG_SYS_PCIE_MEMSIZE - 1) | 3);
+ debug("0:PEGPL_OMR1BA=%08x.%08x MSK=%08x.%08x\n",
+ mfdcr(DCRN_PEGPL_OMR1BAH(PCIE0)),
+ mfdcr(DCRN_PEGPL_OMR1BAL(PCIE0)),
+ mfdcr(DCRN_PEGPL_OMR1MSKH(PCIE0)),
+ mfdcr(DCRN_PEGPL_OMR1MSKL(PCIE0)));
+ break;
+ case 1:
+ mtdcr(DCRN_PEGPL_OMR1BAH(PCIE1), CONFIG_SYS_PCIE_ADDR_HIGH);
+ mtdcr(DCRN_PEGPL_OMR1BAL(PCIE1), CONFIG_SYS_PCIE_MEMBASE +
+ port * CONFIG_SYS_PCIE_MEMSIZE);
+ mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE1), 0x7fffffff);
+ mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE1),
+ ~(CONFIG_SYS_PCIE_MEMSIZE - 1) | 3);
+ debug("1:PEGPL_OMR1BA=%08x.%08x MSK=%08x.%08x\n",
+ mfdcr(DCRN_PEGPL_OMR1BAH(PCIE1)),
+ mfdcr(DCRN_PEGPL_OMR1BAL(PCIE1)),
+ mfdcr(DCRN_PEGPL_OMR1MSKH(PCIE1)),
+ mfdcr(DCRN_PEGPL_OMR1MSKL(PCIE1)));
+ break;
+#if CONFIG_SYS_PCIE_NR_PORTS > 2
+ case 2:
+ mtdcr(DCRN_PEGPL_OMR1BAH(PCIE2), CONFIG_SYS_PCIE_ADDR_HIGH);
+ mtdcr(DCRN_PEGPL_OMR1BAL(PCIE2), CONFIG_SYS_PCIE_MEMBASE +
+ port * CONFIG_SYS_PCIE_MEMSIZE);
+ mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE2), 0x7fffffff);
+ mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE2),
+ ~(CONFIG_SYS_PCIE_MEMSIZE - 1) | 3);
+ debug("2:PEGPL_OMR1BA=%08x.%08x MSK=%08x.%08x\n",
+ mfdcr(DCRN_PEGPL_OMR1BAH(PCIE2)),
+ mfdcr(DCRN_PEGPL_OMR1BAL(PCIE2)),
+ mfdcr(DCRN_PEGPL_OMR1MSKH(PCIE2)),
+ mfdcr(DCRN_PEGPL_OMR1MSKL(PCIE2)));
+ break;
+#endif
+ }
+
+ /* Set up 4GB inbound memory window at 0 */
+ out_le32(mbase + PCI_BASE_ADDRESS_0, 0);
+ out_le32(mbase + PCI_BASE_ADDRESS_1, 0);
+ out_le32(mbase + PECFG_BAR0HMPA, 0x7ffffff);
+ out_le32(mbase + PECFG_BAR0LMPA, 0);
+
+ out_le32(mbase + PECFG_PIM01SAH, 0xffff0000);
+ out_le32(mbase + PECFG_PIM01SAL, 0x00000000);
+ out_le32(mbase + PECFG_PIM0LAL, 0);
+ out_le32(mbase + PECFG_PIM0LAH, 0);
+ out_le32(mbase + PECFG_PIM1LAL, 0x00000000);
+ out_le32(mbase + PECFG_PIM1LAH, 0x00000004);
+ out_le32(mbase + PECFG_PIMEN, 0x1);
+
+ /* Enable I/O, Mem, and Busmaster cycles */
+ out_le16((u16 *)(mbase + PCI_COMMAND),
+ in_le16((u16 *)(mbase + PCI_COMMAND)) |
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+ /* Set Device and Vendor Id */
+ out_le16(mbase + 0x200, 0xaaa0 + port);
+ out_le16(mbase + 0x202, 0xbed0 + port);
+
+ /* Set Class Code to PCI-PCI bridge and Revision Id to 1 */
+ out_le32(mbase + 0x208, 0x06040001);
+
+ printf("PCIE%d: successfully set as root-complex\n", port);
+}
+
+int ppc4xx_setup_pcie_endpoint(struct pci_controller *hose, int port)
+{
+ volatile void *mbase = NULL;
+ int attempts = 0;
+
+ pci_set_ops(hose,
+ pcie_read_config_byte,
+ pcie_read_config_word,
+ pcie_read_config_dword,
+ pcie_write_config_byte,
+ pcie_write_config_word,
+ pcie_write_config_dword);
+
+ switch (port) {
+ case 0:
+ mbase = (u32 *)CONFIG_SYS_PCIE0_XCFGBASE;
+ hose->cfg_data = (u8 *)CONFIG_SYS_PCIE0_CFGBASE;
+ break;
+ case 1:
+ mbase = (u32 *)CONFIG_SYS_PCIE1_XCFGBASE;
+ hose->cfg_data = (u8 *)CONFIG_SYS_PCIE1_CFGBASE;
+ break;
+#if defined(CONFIG_SYS_PCIE2_CFGBASE)
+ case 2:
+ mbase = (u32 *)CONFIG_SYS_PCIE2_XCFGBASE;
+ hose->cfg_data = (u8 *)CONFIG_SYS_PCIE2_CFGBASE;
+ break;
+#endif
+ }
+
+ /*
+ * Set up outbound translation to hose->mem_space from PLB
+ * addresses at an offset of 0xd_0000_0000. We set the low
+ * bits of the mask to 11 to turn off splitting into 8
+ * subregions and to enable the outbound translation.
+ */
+ out_le32(mbase + PECFG_POM0LAH, 0x00001ff8);
+ out_le32(mbase + PECFG_POM0LAL, 0x00001000);
+
+ switch (port) {
+ case 0:
+ mtdcr(DCRN_PEGPL_OMR1BAH(PCIE0), CONFIG_SYS_PCIE_ADDR_HIGH);
+ mtdcr(DCRN_PEGPL_OMR1BAL(PCIE0), CONFIG_SYS_PCIE_MEMBASE +
+ port * CONFIG_SYS_PCIE_MEMSIZE);
+ mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE0), 0x7fffffff);
+ mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE0),
+ ~(CONFIG_SYS_PCIE_MEMSIZE - 1) | 3);
+ break;
+ case 1:
+ mtdcr(DCRN_PEGPL_OMR1BAH(PCIE1), CONFIG_SYS_PCIE_ADDR_HIGH);
+ mtdcr(DCRN_PEGPL_OMR1BAL(PCIE1), CONFIG_SYS_PCIE_MEMBASE +
+ port * CONFIG_SYS_PCIE_MEMSIZE);
+ mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE1), 0x7fffffff);
+ mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE1),
+ ~(CONFIG_SYS_PCIE_MEMSIZE - 1) | 3);
+ break;
+#if CONFIG_SYS_PCIE_NR_PORTS > 2
+ case 2:
+ mtdcr(DCRN_PEGPL_OMR1BAH(PCIE2), CONFIG_SYS_PCIE_ADDR_HIGH);
+ mtdcr(DCRN_PEGPL_OMR1BAL(PCIE2), CONFIG_SYS_PCIE_MEMBASE +
+ port * CONFIG_SYS_PCIE_MEMSIZE);
+ mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE2), 0x7fffffff);
+ mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE2),
+ ~(CONFIG_SYS_PCIE_MEMSIZE - 1) | 3);
+ break;
+#endif
+ }
+
+ /* Set up 64MB inbound memory window at 0 */
+ out_le32(mbase + PCI_BASE_ADDRESS_0, 0);
+ out_le32(mbase + PCI_BASE_ADDRESS_1, 0);
+
+ out_le32(mbase + PECFG_PIM01SAH, 0xffffffff);
+ out_le32(mbase + PECFG_PIM01SAL, 0xfc000000);
+
+ /* Setup BAR0 */
+ out_le32(mbase + PECFG_BAR0HMPA, 0x7fffffff);
+ out_le32(mbase + PECFG_BAR0LMPA, 0xfc000000 | PCI_BASE_ADDRESS_MEM_TYPE_64);
+
+ /* Disable BAR1 & BAR2 */
+ out_le32(mbase + PECFG_BAR1MPA, 0);
+ out_le32(mbase + PECFG_BAR2HMPA, 0);
+ out_le32(mbase + PECFG_BAR2LMPA, 0);
+
+ out_le32(mbase + PECFG_PIM0LAL, U64_TO_U32_LOW(CONFIG_SYS_PCIE_INBOUND_BASE));
+ out_le32(mbase + PECFG_PIM0LAH, U64_TO_U32_HIGH(CONFIG_SYS_PCIE_INBOUND_BASE));
+ out_le32(mbase + PECFG_PIMEN, 0x1);
+
+ /* Enable I/O, Mem, and Busmaster cycles */
+ out_le16((u16 *)(mbase + PCI_COMMAND),
+ in_le16((u16 *)(mbase + PCI_COMMAND)) |
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ out_le16(mbase + 0x200, 0xcaad); /* Setting vendor ID */
+ out_le16(mbase + 0x202, 0xfeed); /* Setting device ID */
+
+ /* Set Class Code to Processor/PPC */
+ out_le32(mbase + 0x208, 0x0b200001);
+
+ attempts = 10;
+ while(!(SDR_READ(SDRN_PESDR_RCSSTS(port)) & (1 << 8))) {
+ if (!(attempts--)) {
+ printf("PCIE%d: BME not active\n", port);
+ return -1;
+ }
+ mdelay(1000);
+ }
+
+ printf("PCIE%d: successfully set as endpoint\n", port);
+
+ return 0;
+}
+#endif /* CONFIG_440SPE && CONFIG_PCI */
diff --git a/arch/powerpc/cpu/ppc4xx/4xx_uart.c b/arch/powerpc/cpu/ppc4xx/4xx_uart.c
new file mode 100644
index 0000000..2ab185f
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/4xx_uart.c
@@ -0,0 +1,307 @@
+/*
+ * (C) Copyright 2000-2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2010
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This source code is dual-licensed. You may use it under the terms of the
+ * GNU General Public License version 2, or under the license below.
+ *
+ * This source code has been made available to you by IBM on an AS-IS
+ * basis. Anyone receiving this source is licensed under IBM
+ * copyrights to use it in any way he or she deems fit, including
+ * copying it, modifying it, compiling it, and redistributing it either
+ * with or without modifications. No license under IBM patents or
+ * patent applications is to be implied by the copyright license.
+ *
+ * Any user of this software should understand that IBM cannot provide
+ * technical support for this software and will not be responsible for
+ * any consequences resulting from the use of this software.
+ *
+ * Any person who transfers this source code or any derivative work
+ * must include the IBM copyright notice, this paragraph, and the
+ * preceding two paragraphs in the transferred software.
+ *
+ * COPYRIGHT I B M CORPORATION 1995
+ * LICENSED MATERIAL - PROGRAM PROPERTY OF I B M
+ */
+
+#include <common.h>
+#include <commproc.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <watchdog.h>
+#include <asm/ppc4xx.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
+ defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
+ defined(CONFIG_405EX) || defined(CONFIG_440)
+
+#if defined(CONFIG_440)
+
+#if defined(CONFIG_440GP)
+#define CR0_MASK 0x3fff0000
+#define CR0_EXTCLK_ENA 0x00600000
+#define CR0_UDIV_POS 16
+#define UDIV_SUBTRACT 1
+#define UART0_SDR CPC0_CR0
+#define MFREG(a, d) d = mfdcr(a)
+#define MTREG(a, d) mtdcr(a, d)
+#else /* #if defined(CONFIG_440GP) */
+/* all other 440 PPC's access clock divider via sdr register */
+#define CR0_MASK 0xdfffffff
+#define CR0_EXTCLK_ENA 0x00800000
+#define CR0_UDIV_POS 0
+#define UDIV_SUBTRACT 0
+#define UART0_SDR SDR0_UART0
+#define UART1_SDR SDR0_UART1
+#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
+ defined(CONFIG_440GR) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT)
+#define UART2_SDR SDR0_UART2
+#endif
+#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
+ defined(CONFIG_440GR) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT)
+#define UART3_SDR SDR0_UART3
+#endif
+#define MFREG(a, d) mfsdr(a, d)
+#define MTREG(a, d) mtsdr(a, d)
+#endif /* #if defined(CONFIG_440GP) */
+#elif defined(CONFIG_405EP) || defined(CONFIG_405EZ)
+#define UCR0_MASK 0x0000007f
+#define UCR1_MASK 0x00007f00
+#define UCR0_UDIV_POS 0
+#define UCR1_UDIV_POS 8
+#define UDIV_MAX 127
+#elif defined(CONFIG_405EX)
+#define MFREG(a, d) mfsdr(a, d)
+#define MTREG(a, d) mtsdr(a, d)
+#define CR0_MASK 0x000000ff
+#define CR0_EXTCLK_ENA 0x00800000
+#define CR0_UDIV_POS 0
+#define UDIV_SUBTRACT 0
+#define UART0_SDR SDR0_UART0
+#define UART1_SDR SDR0_UART1
+#else /* CONFIG_405GP || CONFIG_405CR */
+#define CR0_MASK 0x00001fff
+#define CR0_EXTCLK_ENA 0x000000c0
+#define CR0_UDIV_POS 1
+#define UDIV_MAX 32
+#endif
+
+#if defined(CONFIG_405EP) && defined(CONFIG_SYS_EXT_SERIAL_CLOCK)
+#error "External serial clock not supported on AMCC PPC405EP!"
+#endif
+
+#if (defined(CONFIG_405EX) || defined(CONFIG_405EZ) || \
+ defined(CONFIG_440)) && !defined(CONFIG_SYS_EXT_SERIAL_CLOCK)
+/*
+ * For some SoC's, the cpu clock is on divider chain A, UART on
+ * divider chain B ... so cpu clock is irrelevant. Get the
+ * "optimized" values that are subject to the 1/2 opb clock
+ * constraint.
+ */
+static u16 serial_bdiv(int baudrate, u32 *udiv)
+{
+ sys_info_t sysinfo;
+ u32 div; /* total divisor udiv * bdiv */
+ u32 umin; /* minimum udiv */
+ u16 diff; /* smallest diff */
+ u16 idiff; /* current diff */
+ u16 ibdiv; /* current bdiv */
+ u32 i;
+ u32 est; /* current estimate */
+ u32 max;
+#if defined(CONFIG_405EZ)
+ u32 cpr_pllc;
+ u32 plloutb;
+ u32 reg;
+#endif
+
+ get_sys_info(&sysinfo);
+
+#if defined(CONFIG_405EZ)
+ /* check the pll feedback source */
+ mfcpr(CPR0_PLLC, cpr_pllc);
+ plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
+ sysinfo.pllFwdDivB : sysinfo.pllFwdDiv) *
+ sysinfo.pllFbkDiv) / sysinfo.pllFwdDivB);
+ div = plloutb / (16 * baudrate); /* total divisor */
+ umin = (plloutb / get_OPB_freq()) << 1; /* 2 x OPB divisor */
+ max = 256; /* highest possible */
+#else /* 405EZ */
+ div = sysinfo.freqPLB / (16 * baudrate); /* total divisor */
+ umin = sysinfo.pllOpbDiv << 1; /* 2 x OPB divisor */
+ max = 32; /* highest possible */
+#endif /* 405EZ */
+
+ *udiv = diff = max;
+
+ /*
+ * i is the test udiv value -- start with the largest
+ * possible (max) to minimize serial clock and constrain
+ * search to umin.
+ */
+ for (i = max; i > umin; i--) {
+ ibdiv = div / i;
+ est = i * ibdiv;
+ idiff = (est > div) ? (est - div) : (div - est);
+ if (idiff == 0) {
+ *udiv = i;
+ break; /* can't do better */
+ } else if (idiff < diff) {
+ *udiv = i; /* best so far */
+ diff = idiff; /* update lowest diff*/
+ }
+ }
+
+#if defined(CONFIG_405EZ)
+ mfcpr(CPR0_PERD0, reg);
+ reg &= ~0x0000ffff;
+ reg |= ((*udiv - 0) << 8) | (*udiv - 0);
+ mtcpr(CPR0_PERD0, reg);
+#endif
+
+ return div / *udiv;
+}
+#endif /* #if (defined(CONFIG_405EP) ... */
+
+/*
+ * This function returns the UART clock used by the common
+ * NS16550 driver. Additionally the SoC internal divisors for
+ * optimal UART baudrate are configured.
+ */
+int get_serial_clock(void)
+{
+ u32 clk;
+ u32 udiv;
+#if !defined(CONFIG_405EZ)
+ u32 reg;
+#endif
+#if !defined(CONFIG_SYS_EXT_SERIAL_CLOCK)
+ PPC4xx_SYS_INFO sys_info;
+#endif
+
+ /*
+ * Programming of the internal divisors is SoC specific.
+ * Let's handle this in some #ifdef's for the SoC's.
+ */
+
+#if defined(CONFIG_405CR) || defined(CONFIG_405GP)
+ reg = mfdcr(CPC0_CR0) & ~CR0_MASK;
+#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
+ clk = CONFIG_SYS_EXT_SERIAL_CLOCK;
+ udiv = 1;
+ reg |= CR0_EXTCLK_ENA;
+#else /* CONFIG_SYS_EXT_SERIAL_CLOCK */
+ clk = gd->cpu_clk;
+#ifdef CONFIG_SYS_405_UART_ERRATA_59
+ udiv = 31; /* Errata 59: stuck at 31 */
+#else /* CONFIG_SYS_405_UART_ERRATA_59 */
+ {
+ u32 tmp = CONFIG_SYS_BASE_BAUD * 16;
+
+ udiv = (clk + tmp / 2) / tmp;
+ }
+ if (udiv > UDIV_MAX) /* max. n bits for udiv */
+ udiv = UDIV_MAX;
+#endif /* CONFIG_SYS_405_UART_ERRATA_59 */
+#endif /* CONFIG_SYS_EXT_SERIAL_CLOCK */
+ reg |= (udiv - 1) << CR0_UDIV_POS; /* set the UART divisor */
+ mtdcr (CPC0_CR0, reg);
+#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
+ clk = CONFIG_SYS_EXT_SERIAL_CLOCK;
+#else
+ clk = CONFIG_SYS_BASE_BAUD * 16;
+#endif
+#endif /* CONFIG_405CR */
+
+#if defined(CONFIG_405EP)
+ {
+ u32 tmp = CONFIG_SYS_BASE_BAUD * 16;
+
+ reg = mfdcr(CPC0_UCR) & ~(UCR0_MASK | UCR1_MASK);
+ clk = gd->cpu_clk;
+ udiv = (clk + tmp / 2) / tmp;
+ if (udiv > UDIV_MAX) /* max. n bits for udiv */
+ udiv = UDIV_MAX;
+ }
+ reg |= udiv << UCR0_UDIV_POS; /* set the UART divisor */
+ reg |= udiv << UCR1_UDIV_POS; /* set the UART divisor */
+ mtdcr(CPC0_UCR, reg);
+ clk = CONFIG_SYS_BASE_BAUD * 16;
+#endif /* CONFIG_405EP */
+
+#if defined(CONFIG_405EX) || defined(CONFIG_440)
+ MFREG(UART0_SDR, reg);
+ reg &= ~CR0_MASK;
+
+#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
+ reg |= CR0_EXTCLK_ENA;
+ udiv = 1;
+ clk = CONFIG_SYS_EXT_SERIAL_CLOCK;
+#else /* CONFIG_SYS_EXT_SERIAL_CLOCK */
+ clk = gd->baudrate * serial_bdiv(gd->baudrate, &udiv) * 16;
+#endif /* CONFIG_SYS_EXT_SERIAL_CLOCK */
+
+ reg |= (udiv - UDIV_SUBTRACT) << CR0_UDIV_POS; /* set the UART divisor */
+
+ /*
+ * Configure input clock to baudrate generator for all
+ * available serial ports here
+ */
+ MTREG(UART0_SDR, reg);
+#if defined(UART1_SDR)
+ MTREG(UART1_SDR, reg);
+#endif
+#if defined(UART2_SDR)
+ MTREG(UART2_SDR, reg);
+#endif
+#if defined(UART3_SDR)
+ MTREG(UART3_SDR, reg);
+#endif
+#endif /* CONFIG_405EX ... */
+
+#if defined(CONFIG_405EZ)
+ clk = gd->baudrate * serial_bdiv(gd->baudrate, &udiv) * 16;
+#endif /* CONFIG_405EZ */
+
+ /*
+ * Correct UART frequency in bd-info struct now that
+ * the UART divisor is available
+ */
+#ifdef CONFIG_SYS_EXT_SERIAL_CLOCK
+ gd->arch.uart_clk = CONFIG_SYS_EXT_SERIAL_CLOCK;
+#else
+ get_sys_info(&sys_info);
+ gd->arch.uart_clk = sys_info.freqUART / udiv;
+#endif
+
+ return clk;
+}
+#endif /* CONFIG_405GP || CONFIG_405CR */
diff --git a/arch/powerpc/cpu/ppc4xx/Makefile b/arch/powerpc/cpu/ppc4xx/Makefile
new file mode 100644
index 0000000..e301dc6
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/Makefile
@@ -0,0 +1,91 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(CPU).o
+
+START := resetvec.o
+START += start.o
+
+SOBJS := cache.o
+SOBJS += dcr.o
+SOBJS += kgdb.o
+
+COBJS := 40x_spd_sdram.o
+
+ifndef CONFIG_NAND_SPL
+ifndef CONFIG_NAND_U_BOOT
+COBJS += 44x_spd_ddr.o
+endif
+endif
+COBJS-$(CONFIG_SDRAM_PPC4xx_IBM_DDR2) += 44x_spd_ddr2.o
+COBJS-$(CONFIG_PPC4xx_DDR_AUTOCALIBRATION) += 4xx_ibm_ddr2_autocalib.o
+COBJS += 4xx_pci.o
+COBJS += 4xx_pcie.o
+COBJS += bedbug_405.o
+COBJS-$(CONFIG_CMD_CHIP_CONFIG) += cmd_chip_config.o
+COBJS += cpu.o
+COBJS += cpu_init.o
+COBJS += denali_data_eye.o
+COBJS += denali_spd_ddr2.o
+COBJS += ecc.o
+COBJS-$(CONFIG_CMD_ECCTEST) += cmd_ecctest.o
+COBJS += fdt.o
+COBJS += interrupts.o
+COBJS-$(CONFIG_CMD_REGINFO) += reginfo.o
+COBJS += sdram.o
+COBJS += speed.o
+COBJS += tlb.o
+COBJS += traps.o
+COBJS += usb.o
+COBJS += usb_ohci.o
+COBJS-$(CONFIG_XILINX_440) += xilinx_irq.o
+ifndef CONFIG_XILINX_440
+COBJS += 4xx_uart.o
+COBJS += gpio.o
+COBJS += miiphy.o
+COBJS += uic.o
+endif
+
+ifdef CONFIG_SPL_BUILD
+COBJS-y += spl_boot.o
+endif
+
+SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS) $(COBJS-y))
+START := $(addprefix $(obj),$(START))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/powerpc/cpu/ppc4xx/bedbug_405.c b/arch/powerpc/cpu/ppc4xx/bedbug_405.c
new file mode 100644
index 0000000..e1500cc
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/bedbug_405.c
@@ -0,0 +1,308 @@
+/*
+ * Bedbug Functions specific to the PPC405 chip
+ */
+
+#include <common.h>
+#include <command.h>
+#include <linux/ctype.h>
+#include <bedbug/type.h>
+#include <bedbug/bedbug.h>
+#include <bedbug/regs.h>
+#include <bedbug/ppc.h>
+
+#if defined(CONFIG_CMD_BEDBUG) && defined(CONFIG_4xx)
+
+#define MAX_BREAK_POINTS 4
+
+extern CPU_DEBUG_CTX bug_ctx;
+
+void bedbug405_init __P ((void));
+void bedbug405_do_break __P ((cmd_tbl_t *, int, int, char * const []));
+void bedbug405_break_isr __P ((struct pt_regs *));
+int bedbug405_find_empty __P ((void));
+int bedbug405_set __P ((int, unsigned long));
+int bedbug405_clear __P ((int));
+
+
+/* ======================================================================
+ * Initialize the global bug_ctx structure for the AMCC PPC405. Clear all
+ * of the breakpoints.
+ * ====================================================================== */
+
+void bedbug405_init (void)
+{
+ int i;
+
+ /* -------------------------------------------------- */
+
+ bug_ctx.hw_debug_enabled = 0;
+ bug_ctx.stopped = 0;
+ bug_ctx.current_bp = 0;
+ bug_ctx.regs = NULL;
+
+ bug_ctx.do_break = bedbug405_do_break;
+ bug_ctx.break_isr = bedbug405_break_isr;
+ bug_ctx.find_empty = bedbug405_find_empty;
+ bug_ctx.set = bedbug405_set;
+ bug_ctx.clear = bedbug405_clear;
+
+ for (i = 1; i <= MAX_BREAK_POINTS; ++i)
+ (*bug_ctx.clear) (i);
+
+ puts ("BEDBUG:ready\n");
+ return;
+} /* bedbug_init_breakpoints */
+
+
+
+/* ======================================================================
+ * Set/clear/show one of the hardware breakpoints for the 405. The "off"
+ * string will disable a specific breakpoint. The "show" string will
+ * display the current breakpoints. Otherwise an address will set a
+ * breakpoint at that address. Setting a breakpoint uses the CPU-specific
+ * set routine which will assign a breakpoint number.
+ * ====================================================================== */
+
+void bedbug405_do_break (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+ long addr = 0; /* Address to break at */
+ int which_bp; /* Breakpoint number */
+
+ /* -------------------------------------------------- */
+
+ if (argc < 2) {
+ cmd_usage(cmdtp);
+ return;
+ }
+
+ /* Turn off a breakpoint */
+
+ if (strcmp (argv[1], "off") == 0) {
+ if (bug_ctx.hw_debug_enabled == 0) {
+ printf ("No breakpoints enabled\n");
+ return;
+ }
+
+ which_bp = simple_strtoul (argv[2], NULL, 10);
+
+ if (bug_ctx.clear)
+ (*bug_ctx.clear) (which_bp);
+
+ printf ("Breakpoint %d removed\n", which_bp);
+ return;
+ }
+
+ /* Show a list of breakpoints */
+
+ if (strcmp (argv[1], "show") == 0) {
+ for (which_bp = 1; which_bp <= MAX_BREAK_POINTS; ++which_bp) {
+
+ switch (which_bp) {
+ case 1:
+ addr = GET_IAC1 ();
+ break;
+ case 2:
+ addr = GET_IAC2 ();
+ break;
+ case 3:
+ addr = GET_IAC3 ();
+ break;
+ case 4:
+ addr = GET_IAC4 ();
+ break;
+ }
+
+ printf ("Breakpoint [%d]: ", which_bp);
+ if (addr == 0)
+ printf ("NOT SET\n");
+ else
+ disppc ((unsigned char *) addr, 0, 1, bedbug_puts,
+ F_RADHEX);
+ }
+ return;
+ }
+
+ /* Set a breakpoint at the address */
+
+ if (!isdigit (argv[1][0])) {
+ cmd_usage(cmdtp);
+ return;
+ }
+
+ addr = simple_strtoul (argv[1], NULL, 16) & 0xfffffffc;
+
+ if ((bug_ctx.set) && (which_bp = (*bug_ctx.set) (0, addr)) > 0) {
+ printf ("Breakpoint [%d]: ", which_bp);
+ disppc ((unsigned char *) addr, 0, 1, bedbug_puts, F_RADHEX);
+ }
+
+ return;
+} /* bedbug405_do_break */
+
+
+
+/* ======================================================================
+ * Handle a breakpoint. First determine which breakpoint was hit by
+ * looking at the DeBug Status Register (DBSR), clear the breakpoint
+ * and enter a mini main loop. Stay in the loop until the stopped flag
+ * in the debug context is cleared.
+ * ====================================================================== */
+
+void bedbug405_break_isr (struct pt_regs *regs)
+{
+ unsigned long dbsr_val; /* Value of the DBSR */
+ unsigned long addr = 0; /* Address stopped at */
+
+ /* -------------------------------------------------- */
+
+ dbsr_val = GET_DBSR ();
+
+ if (dbsr_val & DBSR_IA1) {
+ bug_ctx.current_bp = 1;
+ addr = GET_IAC1 ();
+ SET_DBSR (DBSR_IA1); /* Write a 1 to clear */
+ } else if (dbsr_val & DBSR_IA2) {
+ bug_ctx.current_bp = 2;
+ addr = GET_IAC2 ();
+ SET_DBSR (DBSR_IA2); /* Write a 1 to clear */
+ } else if (dbsr_val & DBSR_IA3) {
+ bug_ctx.current_bp = 3;
+ addr = GET_IAC3 ();
+ SET_DBSR (DBSR_IA3); /* Write a 1 to clear */
+ } else if (dbsr_val & DBSR_IA4) {
+ bug_ctx.current_bp = 4;
+ addr = GET_IAC4 ();
+ SET_DBSR (DBSR_IA4); /* Write a 1 to clear */
+ }
+
+ bedbug_main_loop (addr, regs);
+ return;
+} /* bedbug405_break_isr */
+
+
+
+/* ======================================================================
+ * Look through all of the hardware breakpoints available to see if one
+ * is unused.
+ * ====================================================================== */
+
+int bedbug405_find_empty (void)
+{
+ /* -------------------------------------------------- */
+
+ if (GET_IAC1 () == 0)
+ return 1;
+
+ if (GET_IAC2 () == 0)
+ return 2;
+
+ if (GET_IAC3 () == 0)
+ return 3;
+
+ if (GET_IAC4 () == 0)
+ return 4;
+
+ return 0;
+} /* bedbug405_find_empty */
+
+
+
+/* ======================================================================
+ * Set a breakpoint. If 'which_bp' is zero then find an unused breakpoint
+ * number, otherwise reassign the given breakpoint. If hardware debugging
+ * is not enabled, then turn it on via the MSR and DBCR0. Set the break
+ * address in the appropriate IACx register and enable proper address
+ * beakpoint in DBCR0.
+ * ====================================================================== */
+
+int bedbug405_set (int which_bp, unsigned long addr)
+{
+ /* -------------------------------------------------- */
+
+ /* Only look if which_bp == 0, else use which_bp */
+ if ((bug_ctx.find_empty) && (!which_bp) &&
+ (which_bp = (*bug_ctx.find_empty) ()) == 0) {
+ printf ("All breakpoints in use\n");
+ return 0;
+ }
+
+ if (which_bp < 1 || which_bp > MAX_BREAK_POINTS) {
+ printf ("Invalid break point # %d\n", which_bp);
+ return 0;
+ }
+
+ if (!bug_ctx.hw_debug_enabled) {
+ SET_MSR (GET_MSR () | 0x200); /* set MSR[ DE ] */
+ SET_DBCR0 (GET_DBCR0 () | DBCR0_IDM);
+ bug_ctx.hw_debug_enabled = 1;
+ }
+
+ switch (which_bp) {
+ case 1:
+ SET_IAC1 (addr);
+ SET_DBCR0 (GET_DBCR0 () | DBCR0_IA1);
+ break;
+
+ case 2:
+ SET_IAC2 (addr);
+ SET_DBCR0 (GET_DBCR0 () | DBCR0_IA2);
+ break;
+
+ case 3:
+ SET_IAC3 (addr);
+ SET_DBCR0 (GET_DBCR0 () | DBCR0_IA3);
+ break;
+
+ case 4:
+ SET_IAC4 (addr);
+ SET_DBCR0 (GET_DBCR0 () | DBCR0_IA4);
+ break;
+ }
+
+ return which_bp;
+} /* bedbug405_set */
+
+
+
+/* ======================================================================
+ * Disable a specific breakoint by setting the appropriate IACx register
+ * to zero and claring the instruction address breakpoint in DBCR0.
+ * ====================================================================== */
+
+int bedbug405_clear (int which_bp)
+{
+ /* -------------------------------------------------- */
+
+ if (which_bp < 1 || which_bp > MAX_BREAK_POINTS) {
+ printf ("Invalid break point # (%d)\n", which_bp);
+ return -1;
+ }
+
+ switch (which_bp) {
+ case 1:
+ SET_IAC1 (0);
+ SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA1);
+ break;
+
+ case 2:
+ SET_IAC2 (0);
+ SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA2);
+ break;
+
+ case 3:
+ SET_IAC3 (0);
+ SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA3);
+ break;
+
+ case 4:
+ SET_IAC4 (0);
+ SET_DBCR0 (GET_DBCR0 () & ~DBCR0_IA4);
+ break;
+ }
+
+ return 0;
+} /* bedbug405_clear */
+
+
+/* ====================================================================== */
+#endif
diff --git a/arch/powerpc/cpu/ppc4xx/cache.S b/arch/powerpc/cpu/ppc4xx/cache.S
new file mode 100644
index 0000000..757d7da
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/cache.S
@@ -0,0 +1,235 @@
+/*
+ * This file contains miscellaneous low-level functions.
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <config.h>
+#include <config.h>
+#include <asm/ppc4xx.h>
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+/*
+ * Flush instruction cache.
+ */
+_GLOBAL(invalidate_icache)
+ iccci r0,r0
+ isync
+ blr
+
+/*
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
+ *
+ * flush_icache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(flush_icache_range)
+ li r5,L1_CACHE_BYTES-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,L1_CACHE_SHIFT
+ beqlr
+ mtctr r4
+ mr r6,r3
+1: dcbst 0,r3
+ addi r3,r3,L1_CACHE_BYTES
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ mtctr r4
+2: icbi 0,r6
+ addi r6,r6,L1_CACHE_BYTES
+ bdnz 2b
+ sync /* additional sync needed on g4 */
+ isync
+ blr
+
+/*
+ * Write any modified data cache blocks out to memory.
+ * Does not invalidate the corresponding cache lines (especially for
+ * any corresponding instruction cache).
+ *
+ * clean_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(clean_dcache_range)
+ li r5,L1_CACHE_BYTES-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,L1_CACHE_SHIFT
+ beqlr
+ mtctr r4
+
+1: dcbst 0,r3
+ addi r3,r3,L1_CACHE_BYTES
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ blr
+
+/*
+ * Write any modified data cache blocks out to memory and invalidate them.
+ * Does not invalidate the corresponding instruction cache blocks.
+ *
+ * flush_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(flush_dcache_range)
+ li r5,L1_CACHE_BYTES-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,L1_CACHE_SHIFT
+ beqlr
+ mtctr r4
+
+1: dcbf 0,r3
+ addi r3,r3,L1_CACHE_BYTES
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ blr
+
+/*
+ * Like above, but invalidate the D-cache. This is used by the 8xx
+ * to invalidate the cache so the PPC core doesn't get stale data
+ * from the CPM (no cache snooping here :-).
+ *
+ * invalidate_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(invalidate_dcache_range)
+ li r5,L1_CACHE_BYTES-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,L1_CACHE_SHIFT
+ beqlr
+ mtctr r4
+
+1: dcbi 0,r3
+ addi r3,r3,L1_CACHE_BYTES
+ bdnz 1b
+ sync /* wait for dcbi's to get to ram */
+ blr
+
+/*
+ * 40x cores have 8K or 16K dcache and 32 byte line size.
+ * 44x has a 32K dcache and 32 byte line size.
+ * 8xx has 1, 2, 4, 8K variants.
+ * For now, cover the worst case of the 44x.
+ * Must be called with external interrupts disabled.
+ */
+#define CACHE_NWAYS 64
+#define CACHE_NLINES 32
+
+_GLOBAL(flush_dcache)
+ li r4,(2 * CACHE_NWAYS * CACHE_NLINES)
+ mtctr r4
+ lis r5,0
+1: lwz r3,0(r5) /* Load one word from every line */
+ addi r5,r5,L1_CACHE_BYTES
+ bdnz 1b
+ sync
+ blr
+
+_GLOBAL(invalidate_dcache)
+ addi r6,0,0x0000 /* clear GPR 6 */
+ /* Do loop for # of dcache congruence classes. */
+ lis r7,(CONFIG_SYS_DCACHE_SIZE / L1_CACHE_BYTES / 2)@ha /* TBS for large sized cache */
+ ori r7,r7,(CONFIG_SYS_DCACHE_SIZE / L1_CACHE_BYTES / 2)@l
+ /* NOTE: dccci invalidates both */
+ mtctr r7 /* ways in the D cache */
+..dcloop:
+ dccci 0,r6 /* invalidate line */
+ addi r6,r6,L1_CACHE_BYTES /* bump to next line */
+ bdnz ..dcloop
+ sync
+ blr
+
+/*
+ * Cache functions.
+ *
+ * NOTE: currently the 440s run with dcache _disabled_ once relocated to DRAM,
+ * although for some cache-ralated calls stubs have to be provided to satisfy
+ * symbols resolution.
+ * Icache-related functions are used in POST framework.
+ *
+ */
+#ifdef CONFIG_440
+
+ .globl dcache_disable
+ .globl dcache_enable
+ .globl icache_disable
+ .globl icache_enable
+dcache_disable:
+dcache_enable:
+icache_disable:
+icache_enable:
+ blr
+
+ .globl dcache_status
+ .globl icache_status
+dcache_status:
+icache_status:
+ mr r3, 0
+ blr
+
+#else /* CONFIG_440 */
+
+ .globl icache_enable
+icache_enable:
+ mflr r8
+ bl invalidate_icache
+ mtlr r8
+ isync
+ addis r3,r0, 0xc000 /* set bit 0 */
+ mticcr r3
+ blr
+
+ .globl icache_disable
+icache_disable:
+ addis r3,r0, 0x0000 /* clear bit 0 */
+ mticcr r3
+ isync
+ blr
+
+ .globl icache_status
+icache_status:
+ mficcr r3
+ srwi r3, r3, 31 /* >>31 => select bit 0 */
+ blr
+
+ .globl dcache_enable
+dcache_enable:
+ mflr r8
+ bl invalidate_dcache
+ mtlr r8
+ isync
+ addis r3,r0, 0x8000 /* set bit 0 */
+ mtdccr r3
+ blr
+
+ .globl dcache_disable
+dcache_disable:
+ mflr r8
+ bl flush_dcache
+ mtlr r8
+ addis r3,r0, 0x0000 /* clear bit 0 */
+ mtdccr r3
+ blr
+
+ .globl dcache_status
+dcache_status:
+ mfdccr r3
+ srwi r3, r3, 31 /* >>31 => select bit 0 */
+ blr
+
+#endif /* CONFIG_440 */
diff --git a/arch/powerpc/cpu/ppc4xx/cmd_chip_config.c b/arch/powerpc/cpu/ppc4xx/cmd_chip_config.c
new file mode 100644
index 0000000..72c5aec
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/cmd_chip_config.c
@@ -0,0 +1,148 @@
+/*
+ * (C) Copyright 2008-2009
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * (C) Copyright 2009
+ * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <i2c.h>
+#include <asm/ppc4xx_config.h>
+#include <asm/io.h>
+
+static void print_configs(int cur_config_nr)
+{
+ int i;
+
+ for (i = 0; i < ppc4xx_config_count; i++) {
+ printf("%-16s - %s", ppc4xx_config_val[i].label,
+ ppc4xx_config_val[i].description);
+ if (i == cur_config_nr)
+ printf(" ***");
+ printf("\n");
+ }
+
+}
+
+static int do_chip_config(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int i;
+ int ret;
+ int cur_config_nr = -1;
+ u8 cur_config[CONFIG_4xx_CONFIG_BLOCKSIZE];
+
+ /*
+ * First switch to correct I2C bus. This is I2C bus 0
+ * for all currently available 4xx derivats.
+ */
+ I2C_SET_BUS(0);
+
+#ifdef CONFIG_CMD_EEPROM
+ ret = eeprom_read(CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR,
+ CONFIG_4xx_CONFIG_I2C_EEPROM_OFFSET,
+ cur_config, CONFIG_4xx_CONFIG_BLOCKSIZE);
+#else
+ ret = i2c_read(CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR,
+ CONFIG_4xx_CONFIG_I2C_EEPROM_OFFSET,
+ 1, cur_config, CONFIG_4xx_CONFIG_BLOCKSIZE);
+#endif
+ if (ret) {
+ printf("Error reading EEPROM at addr 0x%x\n",
+ CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR);
+ return -1;
+ }
+
+ /*
+ * Search the current configuration
+ */
+ for (i = 0; i < ppc4xx_config_count; i++) {
+ if (memcmp(cur_config, ppc4xx_config_val[i].val,
+ CONFIG_4xx_CONFIG_BLOCKSIZE) == 0)
+ cur_config_nr = i;
+ }
+
+ if (cur_config_nr == -1) {
+ printf("Warning: The I2C bootstrap values don't match any"
+ " of the available options!\n");
+ printf("I2C bootstrap EEPROM values are (I2C address 0x%02x):\n",
+ CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR);
+ for (i = 0; i < CONFIG_4xx_CONFIG_BLOCKSIZE; i++) {
+ printf("%02x ", cur_config[i]);
+ }
+ printf("\n");
+ }
+
+ if (argc < 2) {
+ printf("Available configurations (I2C address 0x%02x):\n",
+ CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR);
+ print_configs(cur_config_nr);
+ return 0;
+ }
+
+ for (i = 0; i < ppc4xx_config_count; i++) {
+ /*
+ * Search for configuration name/label
+ */
+ if (strcmp(argv[1], ppc4xx_config_val[i].label) == 0) {
+ printf("Using configuration:\n%-16s - %s\n",
+ ppc4xx_config_val[i].label,
+ ppc4xx_config_val[i].description);
+
+#ifdef CONFIG_CMD_EEPROM
+ ret = eeprom_write(CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR,
+ CONFIG_4xx_CONFIG_I2C_EEPROM_OFFSET,
+ ppc4xx_config_val[i].val,
+ CONFIG_4xx_CONFIG_BLOCKSIZE);
+#else
+ ret = i2c_write(CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR,
+ CONFIG_4xx_CONFIG_I2C_EEPROM_OFFSET,
+ 1, ppc4xx_config_val[i].val,
+ CONFIG_4xx_CONFIG_BLOCKSIZE);
+#endif
+ udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
+ if (ret) {
+ printf("Error updating EEPROM at addr 0x%x\n",
+ CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR);
+ return -1;
+ }
+
+ printf("done (dump via 'i2c md %x 0.1 %x')\n",
+ CONFIG_4xx_CONFIG_I2C_EEPROM_ADDR,
+ CONFIG_4xx_CONFIG_BLOCKSIZE);
+ printf("Reset the board for the changes to"
+ " take effect\n");
+ return 0;
+ }
+ }
+
+ printf("Configuration %s not found!\n", argv[1]);
+ print_configs(cur_config_nr);
+ return -1;
+}
+
+U_BOOT_CMD(
+ chip_config, 2, 0, do_chip_config,
+ "program the I2C bootstrap EEPROM",
+ "[config-label]"
+);
diff --git a/arch/powerpc/cpu/ppc4xx/cmd_ecctest.c b/arch/powerpc/cpu/ppc4xx/cmd_ecctest.c
new file mode 100644
index 0000000..231f69e
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/cmd_ecctest.c
@@ -0,0 +1,279 @@
+/*
+ * (C) Copyright 2010
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <asm/ppc4xx.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/cache.h>
+
+#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR) || \
+ defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
+#if defined(CONFIG_DDR_ECC) || defined(CONFIG_SDRAM_ECC)
+
+#if defined(CONFIG_405EX)
+/*
+ * Currently only 405EX uses 16bit data bus width as an alternative
+ * option to 32bit data width (SDRAM0_MCOPT1_WDTH)
+ */
+#define SDRAM_DATA_ALT_WIDTH 2
+#else
+#define SDRAM_DATA_ALT_WIDTH 8
+#endif
+
+#if defined(CONFIG_SYS_OCM_BASE)
+#define CONFIG_FUNC_ISRAM_ADDR CONFIG_SYS_OCM_BASE
+#endif
+
+#if defined(CONFIG_SYS_ISRAM_BASE)
+#define CONFIG_FUNC_ISRAM_ADDR CONFIG_SYS_ISRAM_BASE
+#endif
+
+#if !defined(CONFIG_FUNC_ISRAM_ADDR)
+#error "No internal SRAM/OCM provided!"
+#endif
+
+#define force_inline inline __attribute__ ((always_inline))
+
+static inline void machine_check_disable(void)
+{
+ mtmsr(mfmsr() & ~MSR_ME);
+}
+
+static inline void machine_check_enable(void)
+{
+ mtmsr(mfmsr() | MSR_ME);
+}
+
+/*
+ * These helper functions need to be inlined, since they
+ * are called from the functions running from internal SRAM.
+ * SDRAM operation is forbidden at that time, so calling
+ * functions in SDRAM has to be avoided.
+ */
+static force_inline void wait_ddr_idle(void)
+{
+ u32 val;
+
+ do {
+ mfsdram(SDRAM_MCSTAT, val);
+ } while ((val & SDRAM_MCSTAT_IDLE_MASK) == SDRAM_MCSTAT_IDLE_NOT);
+}
+
+static force_inline void recalibrate_ddr(void)
+{
+ u32 val;
+
+ /*
+ * Rewrite RQDC & RFDC to calibrate again. If this is not
+ * done, the SDRAM controller is working correctly after
+ * changing the MCOPT1_MCHK bits.
+ */
+ mfsdram(SDRAM_RQDC, val);
+ mtsdram(SDRAM_RQDC, val);
+ mfsdram(SDRAM_RFDC, val);
+ mtsdram(SDRAM_RFDC, val);
+}
+
+static force_inline void set_mcopt1_mchk(u32 bits)
+{
+ u32 val;
+
+ wait_ddr_idle();
+ mfsdram(SDRAM_MCOPT1, val);
+ mtsdram(SDRAM_MCOPT1, (val & ~SDRAM_MCOPT1_MCHK_MASK) | bits);
+ recalibrate_ddr();
+}
+
+/*
+ * The next 2 functions are copied to internal SRAM/OCM and run
+ * there. No function calls allowed here. No SDRAM acitivity should
+ * be done here.
+ */
+static void inject_ecc_error(void *ptr, int par)
+{
+ /*
+ * Taken from PPC460EX/EXr/GT users manual (Rev 1.21)
+ * 22.2.17.13 ECC Diagnostics
+ *
+ * Items 1 ... 5 are already done by now, running from RAM
+ * with ECC enabled
+ */
+
+ out_be32(ptr, 0x00000000);
+ in_be32(ptr);
+
+ /* 6. Set memory controller to no error checking */
+ set_mcopt1_mchk(SDRAM_MCOPT1_MCHK_NON);
+
+ /* 7. Modify one or two bits for error simulation */
+ if (par == 1)
+ out_be32(ptr, in_be32(ptr) ^ 0x00000001);
+ else
+ out_be32(ptr, in_be32(ptr) ^ 0x00000003);
+
+ /* 8. Wait for SDRAM idle */
+ in_be32(ptr);
+ set_mcopt1_mchk(SDRAM_MCOPT1_MCHK_CHK_REP);
+
+ /* Wait for SDRAM idle */
+ wait_ddr_idle();
+
+ /* Continue with 9. in calling function... */
+}
+
+static void rewrite_ecc_parity(void *ptr, int par)
+{
+ u32 current_address = (u32)ptr;
+ u32 end_address;
+ u32 address_increment;
+ u32 mcopt1;
+
+ /*
+ * Fill ECC parity byte again. Otherwise further accesses to
+ * the failure address will result in exceptions.
+ */
+
+ /* Wait for SDRAM idle */
+ in_be32(0x00000000);
+ set_mcopt1_mchk(SDRAM_MCOPT1_MCHK_GEN);
+
+ /* ECC bit set method for non-cached memory */
+ mfsdram(SDRAM_MCOPT1, mcopt1);
+ if ((mcopt1 & SDRAM_MCOPT1_DMWD_MASK) == SDRAM_MCOPT1_DMWD_32)
+ address_increment = 4;
+ else
+ address_increment = SDRAM_DATA_ALT_WIDTH;
+ end_address = current_address + CONFIG_SYS_CACHELINE_SIZE;
+
+ while (current_address < end_address) {
+ *((unsigned long *)current_address) = 0;
+ current_address += address_increment;
+ }
+
+ set_mcopt1_mchk(SDRAM_MCOPT1_MCHK_CHK_REP);
+
+ /* Wait for SDRAM idle */
+ wait_ddr_idle();
+}
+
+static int do_ecctest(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ u32 old_val;
+ u32 val;
+ u32 *ptr;
+ void (*sram_func)(u32 *, int);
+ int error;
+
+ if (argc < 3) {
+ return cmd_usage(cmdtp);
+ }
+
+ ptr = (u32 *)simple_strtoul(argv[1], NULL, 16);
+ error = simple_strtoul(argv[2], NULL, 16);
+ if ((error < 1) || (error > 2)) {
+ return cmd_usage(cmdtp);
+ }
+
+ printf("Using address %p for %d bit ECC error injection\n",
+ ptr, error);
+
+ /*
+ * Save value to restore it later on
+ */
+ old_val = in_be32(ptr);
+
+ /*
+ * Copy ECC injection function into internal SRAM/OCM
+ */
+ sram_func = (void *)CONFIG_FUNC_ISRAM_ADDR;
+ memcpy((void *)CONFIG_FUNC_ISRAM_ADDR, inject_ecc_error, 0x10000);
+
+ /*
+ * Disable interrupts and exceptions before calling this
+ * function in internal SRAM/OCM
+ */
+ disable_interrupts();
+ machine_check_disable();
+ eieio();
+
+ /*
+ * Jump to ECC simulation function in internal SRAM/OCM
+ */
+ (*sram_func)(ptr, error);
+
+ /* 10. Read the corresponding address */
+ val = in_be32(ptr);
+
+ /*
+ * Read and print ECC status register/info:
+ * The faulting address is only known upon uncorrectable ECC
+ * errors.
+ */
+ mfsdram(SDRAM_ECCES, val);
+ if (val & SDRAM_ECCES_CE)
+ printf("ECC: Correctable error\n");
+ if (val & SDRAM_ECCES_UE) {
+ printf("ECC: Uncorrectable error at 0x%02x%08x\n",
+ mfdcr(SDRAM_ERRADDULL), mfdcr(SDRAM_ERRADDLLL));
+ }
+
+ /*
+ * Clear pending interrupts/exceptions
+ */
+ mtsdram(SDRAM_ECCES, 0xffffffff);
+ mtdcr(SDRAM_ERRSTATLL, 0xff000000);
+ set_mcsr(get_mcsr());
+
+ /* Now enable interrupts and exceptions again */
+ eieio();
+ machine_check_enable();
+ enable_interrupts();
+
+ /*
+ * The ECC parity byte need to be re-written for the
+ * corresponding address. Otherwise future accesses to it
+ * will result in exceptions.
+ *
+ * Jump to ECC parity generation function
+ */
+ memcpy((void *)CONFIG_FUNC_ISRAM_ADDR, rewrite_ecc_parity, 0x10000);
+ (*sram_func)(ptr, 0);
+
+ /*
+ * Restore value in corresponding address
+ */
+ out_be32(ptr, old_val);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ ecctest, 3, 0, do_ecctest,
+ "Test ECC by single and double error bit injection",
+ "address 1/2"
+);
+
+#endif /* defined(CONFIG_DDR_ECC) || defined(CONFIG_SDRAM_ECC) */
+#endif /* defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)... */
diff --git a/arch/powerpc/cpu/ppc4xx/config.mk b/arch/powerpc/cpu/ppc4xx/config.mk
new file mode 100644
index 0000000..f5cbbbd
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/config.mk
@@ -0,0 +1,34 @@
+#
+# (C) Copyright 2000-2010
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_RELFLAGS += -meabi
+PLATFORM_CPPFLAGS += -DCONFIG_4xx -ffixed-r2 -mstring -msoft-float
+
+cfg=$(shell grep configs $(OBJTREE)/include/config.h | sed 's/.*<\(configs.*\)>/\1/')
+is440:=$(shell grep CONFIG_440 $(TOPDIR)/include/$(cfg))
+
+ifneq (,$(findstring CONFIG_440,$(is440)))
+PLATFORM_CPPFLAGS += -Wa,-m440 -mcpu=440
+else
+PLATFORM_CPPFLAGS += -Wa,-m405 -mcpu=405
+endif
diff --git a/arch/powerpc/cpu/ppc4xx/cpu.c b/arch/powerpc/cpu/ppc4xx/cpu.c
new file mode 100644
index 0000000..60aba8c
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/cpu.c
@@ -0,0 +1,751 @@
+/*
+ * (C) Copyright 2000-2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * CPU specific code
+ *
+ * written or collected and sometimes rewritten by
+ * Magnus Damm <damm@bitsmart.com>
+ *
+ * minor modifications by
+ * Wolfgang Denk <wd@denx.de>
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <asm/cache.h>
+#include <asm/ppc4xx.h>
+#include <netdev.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void board_reset(void);
+
+/*
+ * To provide an interface to detect CPU number for boards that support
+ * more then one CPU, we implement the "weak" default functions here.
+ *
+ * Returns CPU number
+ */
+int __get_cpu_num(void)
+{
+ return NA_OR_UNKNOWN_CPU;
+}
+int get_cpu_num(void) __attribute__((weak, alias("__get_cpu_num")));
+
+#if defined(CONFIG_PCI)
+#if defined(CONFIG_405GP) || \
+ defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+
+#define PCI_ASYNC
+
+static int pci_async_enabled(void)
+{
+#if defined(CONFIG_405GP)
+ return (mfdcr(CPC0_PSR) & PSR_PCI_ASYNC_EN);
+#endif
+
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ unsigned long val;
+
+ mfsdr(SDR0_SDSTP1, val);
+ return (val & SDR0_SDSTP1_PAME_MASK);
+#endif
+}
+#endif
+#endif /* CONFIG_PCI */
+
+#if defined(CONFIG_PCI) && \
+ !defined(CONFIG_405) && !defined(CONFIG_405EX)
+int pci_arbiter_enabled(void)
+{
+#if defined(CONFIG_405GP)
+ return (mfdcr(CPC0_PSR) & PSR_PCI_ARBIT_EN);
+#endif
+
+#if defined(CONFIG_405EP)
+ return (mfdcr(CPC0_PCI) & CPC0_PCI_ARBIT_EN);
+#endif
+
+#if defined(CONFIG_440GP)
+ return (mfdcr(CPC0_STRP1) & CPC0_STRP1_PAE_MASK);
+#endif
+
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+ unsigned long val;
+
+ mfsdr(SDR0_XCR0, val);
+ return (val & SDR0_XCR0_PAE_MASK);
+#endif
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ unsigned long val;
+
+ mfsdr(SDR0_PCI0, val);
+ return (val & SDR0_PCI0_PAE_MASK);
+#endif
+}
+#endif
+
+#if defined(CONFIG_405EP)
+#define I2C_BOOTROM
+
+static int i2c_bootrom_enabled(void)
+{
+#if defined(CONFIG_405EP)
+ return (mfdcr(CPC0_BOOT) & CPC0_BOOT_SEP);
+#else
+ unsigned long val;
+
+ mfsdr(SDR0_SDCS0, val);
+ return (val & SDR0_SDCS_SDD);
+#endif
+}
+#endif
+
+#if defined(CONFIG_440GX)
+#define SDR0_PINSTP_SHIFT 29
+static char *bootstrap_str[] = {
+ "EBC (16 bits)",
+ "EBC (8 bits)",
+ "EBC (32 bits)",
+ "EBC (8 bits)",
+ "PCI",
+ "I2C (Addr 0x54)",
+ "Reserved",
+ "I2C (Addr 0x50)",
+};
+static char bootstrap_char[] = { 'A', 'B', 'C', 'B', 'D', 'E', 'x', 'F' };
+#endif
+
+#if defined(CONFIG_440SP) || defined(CONFIG_440SPE)
+#define SDR0_PINSTP_SHIFT 30
+static char *bootstrap_str[] = {
+ "EBC (8 bits)",
+ "PCI",
+ "I2C (Addr 0x54)",
+ "I2C (Addr 0x50)",
+};
+static char bootstrap_char[] = { 'A', 'B', 'C', 'D'};
+#endif
+
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
+#define SDR0_PINSTP_SHIFT 29
+static char *bootstrap_str[] = {
+ "EBC (8 bits)",
+ "PCI",
+ "NAND (8 bits)",
+ "EBC (16 bits)",
+ "EBC (16 bits)",
+ "I2C (Addr 0x54)",
+ "PCI",
+ "I2C (Addr 0x52)",
+};
+static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'G', 'F', 'H' };
+#endif
+
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+#define SDR0_PINSTP_SHIFT 29
+static char *bootstrap_str[] = {
+ "EBC (8 bits)",
+ "EBC (16 bits)",
+ "EBC (16 bits)",
+ "NAND (8 bits)",
+ "PCI",
+ "I2C (Addr 0x54)",
+ "PCI",
+ "I2C (Addr 0x52)",
+};
+static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'G', 'F', 'H' };
+#endif
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+#define SDR0_PINSTP_SHIFT 29
+static char *bootstrap_str[] = {
+ "EBC (8 bits)",
+ "EBC (16 bits)",
+ "PCI",
+ "PCI",
+ "EBC (16 bits)",
+ "NAND (8 bits)",
+ "I2C (Addr 0x54)", /* A8 */
+ "I2C (Addr 0x52)", /* A4 */
+};
+static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' };
+#endif
+
+#if defined(CONFIG_460SX)
+#define SDR0_PINSTP_SHIFT 29
+static char *bootstrap_str[] = {
+ "EBC (8 bits)",
+ "EBC (16 bits)",
+ "EBC (32 bits)",
+ "NAND (8 bits)",
+ "I2C (Addr 0x54)", /* A8 */
+ "I2C (Addr 0x52)", /* A4 */
+};
+static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'G' };
+#endif
+
+#if defined(CONFIG_405EZ)
+#define SDR0_PINSTP_SHIFT 28
+static char *bootstrap_str[] = {
+ "EBC (8 bits)",
+ "SPI (fast)",
+ "NAND (512 page, 4 addr cycle)",
+ "I2C (Addr 0x50)",
+ "EBC (32 bits)",
+ "I2C (Addr 0x50)",
+ "NAND (2K page, 5 addr cycle)",
+ "I2C (Addr 0x50)",
+ "EBC (16 bits)",
+ "Reserved",
+ "NAND (2K page, 4 addr cycle)",
+ "I2C (Addr 0x50)",
+ "NAND (512 page, 3 addr cycle)",
+ "I2C (Addr 0x50)",
+ "SPI (slow)",
+ "I2C (Addr 0x50)",
+};
+static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', \
+ 'I', 'x', 'K', 'L', 'M', 'N', 'O', 'P' };
+#endif
+
+#if defined(CONFIG_405EX)
+#define SDR0_PINSTP_SHIFT 29
+static char *bootstrap_str[] = {
+ "EBC (8 bits)",
+ "EBC (16 bits)",
+ "EBC (16 bits)",
+ "NAND (8 bits)",
+ "NAND (8 bits)",
+ "I2C (Addr 0x54)",
+ "EBC (8 bits)",
+ "I2C (Addr 0x52)",
+};
+static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'G', 'F', 'H' };
+#endif
+#if defined(CONFIG_APM821XX)
+#define SDR0_PINSTP_SHIFT 29
+static char *bootstrap_str[] = {
+ "RESERVED",
+ "RESERVED",
+ "RESERVED",
+ "NAND (8 bits)",
+ "NOR (8 bits)",
+ "NOR (8 bits) w/PLL Bypassed",
+ "I2C (Addr 0x54)",
+ "I2C (Addr 0x52)",
+};
+static char bootstrap_char[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' };
+#endif
+
+#if defined(SDR0_PINSTP_SHIFT)
+static int bootstrap_option(void)
+{
+ unsigned long val;
+
+ mfsdr(SDR0_PINSTP, val);
+ return ((val & 0xf0000000) >> SDR0_PINSTP_SHIFT);
+}
+#endif /* SDR0_PINSTP_SHIFT */
+
+
+#if defined(CONFIG_440GP)
+static int do_chip_reset (unsigned long sys0, unsigned long sys1)
+{
+ /* Changes to CPC0_SYS0 and CPC0_SYS1 require chip
+ * reset.
+ */
+ mtdcr (CPC0_CR0, mfdcr (CPC0_CR0) | 0x80000000); /* Set SWE */
+ mtdcr (CPC0_SYS0, sys0);
+ mtdcr (CPC0_SYS1, sys1);
+ mtdcr (CPC0_CR0, mfdcr (CPC0_CR0) & ~0x80000000); /* Clr SWE */
+ mtspr (SPRN_DBCR0, 0x20000000); /* Reset the chip */
+
+ return 1;
+}
+#endif /* CONFIG_440GP */
+
+
+int checkcpu (void)
+{
+#if !defined(CONFIG_405) /* not used on Xilinx 405 FPGA implementations */
+ uint pvr = get_pvr();
+ ulong clock = gd->cpu_clk;
+ char buf[32];
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ u32 reg;
+#endif
+
+ char addstr[64] = "";
+ sys_info_t sys_info;
+ int cpu_num;
+
+ cpu_num = get_cpu_num();
+ if (cpu_num >= 0)
+ printf("CPU%d: ", cpu_num);
+ else
+ puts("CPU: ");
+
+ get_sys_info(&sys_info);
+
+#if defined(CONFIG_XILINX_440)
+ puts("IBM PowerPC ");
+#else
+ puts("AMCC PowerPC ");
+#endif
+
+ switch (pvr) {
+
+#if !defined(CONFIG_440)
+ case PVR_405GP_RB:
+ puts("405GP Rev. B");
+ break;
+
+ case PVR_405GP_RC:
+ puts("405GP Rev. C");
+ break;
+
+ case PVR_405GP_RD:
+ puts("405GP Rev. D");
+ break;
+
+#ifdef CONFIG_405GP
+ case PVR_405GP_RE: /* 405GP rev E and 405CR rev C have same PVR */
+ puts("405GP Rev. E");
+ break;
+#endif
+
+ case PVR_405CR_RA:
+ puts("405CR Rev. A");
+ break;
+
+ case PVR_405CR_RB:
+ puts("405CR Rev. B");
+ break;
+
+#ifdef CONFIG_405CR
+ case PVR_405CR_RC: /* 405GP rev E and 405CR rev C have same PVR */
+ puts("405CR Rev. C");
+ break;
+#endif
+
+ case PVR_405GPR_RB:
+ puts("405GPr Rev. B");
+ break;
+
+ case PVR_405EP_RB:
+ puts("405EP Rev. B");
+ break;
+
+ case PVR_405EZ_RA:
+ puts("405EZ Rev. A");
+ break;
+
+ case PVR_405EX1_RA:
+ puts("405EX Rev. A");
+ strcpy(addstr, "Security support");
+ break;
+
+ case PVR_405EXR2_RA:
+ puts("405EXr Rev. A");
+ strcpy(addstr, "No Security support");
+ break;
+
+ case PVR_405EX1_RC:
+ puts("405EX Rev. C");
+ strcpy(addstr, "Security support");
+ break;
+
+ case PVR_405EX2_RC:
+ puts("405EX Rev. C");
+ strcpy(addstr, "No Security support");
+ break;
+
+ case PVR_405EXR1_RC:
+ puts("405EXr Rev. C");
+ strcpy(addstr, "Security support");
+ break;
+
+ case PVR_405EXR2_RC:
+ puts("405EXr Rev. C");
+ strcpy(addstr, "No Security support");
+ break;
+
+ case PVR_405EX1_RD:
+ puts("405EX Rev. D");
+ strcpy(addstr, "Security support");
+ break;
+
+ case PVR_405EX2_RD:
+ puts("405EX Rev. D");
+ strcpy(addstr, "No Security support");
+ break;
+
+ case PVR_405EXR1_RD:
+ puts("405EXr Rev. D");
+ strcpy(addstr, "Security support");
+ break;
+
+ case PVR_405EXR2_RD:
+ puts("405EXr Rev. D");
+ strcpy(addstr, "No Security support");
+ break;
+
+#else /* CONFIG_440 */
+
+#if defined(CONFIG_440GP)
+ case PVR_440GP_RB:
+ puts("440GP Rev. B");
+ /* See errata 1.12: CHIP_4 */
+ if ((mfdcr(CPC0_SYS0) != mfdcr(CPC0_STRP0)) ||
+ (mfdcr(CPC0_SYS1) != mfdcr(CPC0_STRP1)) ){
+ puts ( "\n\t CPC0_SYSx DCRs corrupted. "
+ "Resetting chip ...\n");
+ udelay( 1000 * 1000 ); /* Give time for serial buf to clear */
+ do_chip_reset ( mfdcr(CPC0_STRP0),
+ mfdcr(CPC0_STRP1) );
+ }
+ break;
+
+ case PVR_440GP_RC:
+ puts("440GP Rev. C");
+ break;
+#endif /* CONFIG_440GP */
+
+ case PVR_440GX_RA:
+ puts("440GX Rev. A");
+ break;
+
+ case PVR_440GX_RB:
+ puts("440GX Rev. B");
+ break;
+
+ case PVR_440GX_RC:
+ puts("440GX Rev. C");
+ break;
+
+ case PVR_440GX_RF:
+ puts("440GX Rev. F");
+ break;
+
+ case PVR_440EP_RA:
+ puts("440EP Rev. A");
+ break;
+
+#ifdef CONFIG_440EP
+ case PVR_440EP_RB: /* 440EP rev B and 440GR rev A have same PVR */
+ puts("440EP Rev. B");
+ break;
+
+ case PVR_440EP_RC: /* 440EP rev C and 440GR rev B have same PVR */
+ puts("440EP Rev. C");
+ break;
+#endif /* CONFIG_440EP */
+
+#ifdef CONFIG_440GR
+ case PVR_440GR_RA: /* 440EP rev B and 440GR rev A have same PVR */
+ puts("440GR Rev. A");
+ break;
+
+ case PVR_440GR_RB: /* 440EP rev C and 440GR rev B have same PVR */
+ puts("440GR Rev. B");
+ break;
+#endif /* CONFIG_440GR */
+
+#ifdef CONFIG_440EPX
+ case PVR_440EPX1_RA: /* 440EPx rev A and 440GRx rev A have same PVR */
+ puts("440EPx Rev. A");
+ strcpy(addstr, "Security/Kasumi support");
+ break;
+
+ case PVR_440EPX2_RA: /* 440EPx rev A and 440GRx rev A have same PVR */
+ puts("440EPx Rev. A");
+ strcpy(addstr, "No Security/Kasumi support");
+ break;
+#endif /* CONFIG_440EPX */
+
+#ifdef CONFIG_440GRX
+ case PVR_440GRX1_RA: /* 440EPx rev A and 440GRx rev A have same PVR */
+ puts("440GRx Rev. A");
+ strcpy(addstr, "Security/Kasumi support");
+ break;
+
+ case PVR_440GRX2_RA: /* 440EPx rev A and 440GRx rev A have same PVR */
+ puts("440GRx Rev. A");
+ strcpy(addstr, "No Security/Kasumi support");
+ break;
+#endif /* CONFIG_440GRX */
+
+ case PVR_440SP_6_RAB:
+ puts("440SP Rev. A/B");
+ strcpy(addstr, "RAID 6 support");
+ break;
+
+ case PVR_440SP_RAB:
+ puts("440SP Rev. A/B");
+ strcpy(addstr, "No RAID 6 support");
+ break;
+
+ case PVR_440SP_6_RC:
+ puts("440SP Rev. C");
+ strcpy(addstr, "RAID 6 support");
+ break;
+
+ case PVR_440SP_RC:
+ puts("440SP Rev. C");
+ strcpy(addstr, "No RAID 6 support");
+ break;
+
+ case PVR_440SPe_6_RA:
+ puts("440SPe Rev. A");
+ strcpy(addstr, "RAID 6 support");
+ break;
+
+ case PVR_440SPe_RA:
+ puts("440SPe Rev. A");
+ strcpy(addstr, "No RAID 6 support");
+ break;
+
+ case PVR_440SPe_6_RB:
+ puts("440SPe Rev. B");
+ strcpy(addstr, "RAID 6 support");
+ break;
+
+ case PVR_440SPe_RB:
+ puts("440SPe Rev. B");
+ strcpy(addstr, "No RAID 6 support");
+ break;
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ case PVR_460EX_RA:
+ puts("460EX Rev. A");
+ strcpy(addstr, "No Security/Kasumi support");
+ break;
+
+ case PVR_460EX_SE_RA:
+ puts("460EX Rev. A");
+ strcpy(addstr, "Security/Kasumi support");
+ break;
+
+ case PVR_460EX_RB:
+ puts("460EX Rev. B");
+ mfsdr(SDR0_ECID3, reg);
+ if (reg & 0x00100000)
+ strcpy(addstr, "No Security/Kasumi support");
+ else
+ strcpy(addstr, "Security/Kasumi support");
+ break;
+
+ case PVR_460GT_RA:
+ puts("460GT Rev. A");
+ strcpy(addstr, "No Security/Kasumi support");
+ break;
+
+ case PVR_460GT_SE_RA:
+ puts("460GT Rev. A");
+ strcpy(addstr, "Security/Kasumi support");
+ break;
+
+ case PVR_460GT_RB:
+ puts("460GT Rev. B");
+ mfsdr(SDR0_ECID3, reg);
+ if (reg & 0x00100000)
+ strcpy(addstr, "No Security/Kasumi support");
+ else
+ strcpy(addstr, "Security/Kasumi support");
+ break;
+#endif
+
+ case PVR_460SX_RA:
+ puts("460SX Rev. A");
+ strcpy(addstr, "Security support");
+ break;
+
+ case PVR_460SX_RA_V1:
+ puts("460SX Rev. A");
+ strcpy(addstr, "No Security support");
+ break;
+
+ case PVR_460GX_RA:
+ puts("460GX Rev. A");
+ strcpy(addstr, "Security support");
+ break;
+
+ case PVR_460GX_RA_V1:
+ puts("460GX Rev. A");
+ strcpy(addstr, "No Security support");
+ break;
+
+ case PVR_APM821XX_RA:
+ puts("APM821XX Rev. A");
+ strcpy(addstr, "Security support");
+ break;
+
+ case PVR_VIRTEX5:
+ puts("440x5 VIRTEX5");
+ break;
+#endif /* CONFIG_440 */
+
+ default:
+ printf (" UNKNOWN (PVR=%08x)", pvr);
+ break;
+ }
+
+ printf (" at %s MHz (PLB=%lu OPB=%lu EBC=%lu",
+ strmhz(buf, clock),
+ sys_info.freqPLB / 1000000,
+ get_OPB_freq() / 1000000,
+ sys_info.freqEBC / 1000000);
+#if defined(CONFIG_PCI) && \
+ (defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
+ defined(CONFIG_440GR) || defined(CONFIG_440GRX))
+ printf(" PCI=%lu MHz", sys_info.freqPCI / 1000000);
+#endif
+ printf(")\n");
+
+ if (addstr[0] != 0)
+ printf(" %s\n", addstr);
+
+#if defined(I2C_BOOTROM)
+ printf (" I2C boot EEPROM %sabled\n", i2c_bootrom_enabled() ? "en" : "dis");
+#endif /* I2C_BOOTROM */
+#if defined(SDR0_PINSTP_SHIFT)
+ printf (" Bootstrap Option %c - ", bootstrap_char[bootstrap_option()]);
+ printf ("Boot ROM Location %s", bootstrap_str[bootstrap_option()]);
+#ifdef CONFIG_NAND_U_BOOT
+ puts(", booting from NAND");
+#endif /* CONFIG_NAND_U_BOOT */
+ putc('\n');
+#endif /* SDR0_PINSTP_SHIFT */
+
+#if defined(CONFIG_PCI) && !defined(CONFIG_405EX)
+ printf (" Internal PCI arbiter %sabled", pci_arbiter_enabled() ? "en" : "dis");
+#endif
+
+#if defined(CONFIG_PCI) && defined(PCI_ASYNC)
+ if (pci_async_enabled()) {
+ printf (", PCI async ext clock used");
+ } else {
+ printf (", PCI sync clock at %lu MHz",
+ sys_info.freqPLB / sys_info.pllPciDiv / 1000000);
+ }
+#endif
+
+#if defined(CONFIG_PCI) && !defined(CONFIG_405EX)
+ putc('\n');
+#endif
+
+#if defined(CONFIG_405EP) || defined(CONFIG_405EZ) || defined(CONFIG_405EX)
+ printf (" 16 kB I-Cache 16 kB D-Cache");
+#elif defined(CONFIG_440)
+ printf (" 32 kB I-Cache 32 kB D-Cache");
+#else
+ printf (" 16 kB I-Cache %d kB D-Cache",
+ ((pvr | 0x00000001) == PVR_405GPR_RB) ? 16 : 8);
+#endif
+
+#endif /* !defined(CONFIG_405) */
+
+ putc ('\n');
+
+ return 0;
+}
+
+int ppc440spe_revB() {
+ unsigned int pvr;
+
+ pvr = get_pvr();
+ if ((pvr == PVR_440SPe_6_RB) || (pvr == PVR_440SPe_RB))
+ return 1;
+ else
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+#if defined(CONFIG_BOARD_RESET)
+ board_reset();
+#else
+#if defined(CONFIG_SYS_4xx_RESET_TYPE)
+ mtspr(SPRN_DBCR0, CONFIG_SYS_4xx_RESET_TYPE << 28);
+#else
+ /*
+ * Initiate system reset in debug control register DBCR
+ */
+ mtspr(SPRN_DBCR0, 0x30000000);
+#endif /* defined(CONFIG_SYS_4xx_RESET_TYPE) */
+#endif /* defined(CONFIG_BOARD_RESET) */
+
+ return 1;
+}
+
+
+/*
+ * Get timebase clock frequency
+ */
+unsigned long get_tbclk (void)
+{
+ sys_info_t sys_info;
+
+ get_sys_info(&sys_info);
+ return (sys_info.freqProcessor);
+}
+
+
+#if defined(CONFIG_WATCHDOG)
+void watchdog_reset(void)
+{
+ int re_enable = disable_interrupts();
+ reset_4xx_watchdog();
+ if (re_enable) enable_interrupts();
+}
+
+void reset_4xx_watchdog(void)
+{
+ /*
+ * Clear TSR(WIS) bit
+ */
+ mtspr(SPRN_TSR, 0x40000000);
+}
+#endif /* CONFIG_WATCHDOG */
+
+/*
+ * Initializes on-chip ethernet controllers.
+ * to override, implement board_eth_init()
+ */
+int cpu_eth_init(bd_t *bis)
+{
+#if defined(CONFIG_PPC4xx_EMAC)
+ ppc_4xx_eth_initialize(bis);
+#endif
+ return 0;
+}
diff --git a/arch/powerpc/cpu/ppc4xx/cpu_init.c b/arch/powerpc/cpu/ppc4xx/cpu_init.c
new file mode 100644
index 0000000..970a8c1
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/cpu_init.c
@@ -0,0 +1,559 @@
+/*
+ * (C) Copyright 2000-2007
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <asm/ppc4xx-emac.h>
+#include <asm/processor.h>
+#include <asm/ppc4xx-gpio.h>
+#include <asm/ppc4xx.h>
+
+#if defined(CONFIG_405GP) || defined(CONFIG_405EP)
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+#ifndef CONFIG_SYS_PLL_RECONFIG
+#define CONFIG_SYS_PLL_RECONFIG 0
+#endif
+
+#if defined(CONFIG_440EPX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT)
+static void reset_with_rli(void)
+{
+ u32 reg;
+
+ /*
+ * Set reload inhibit so configuration will persist across
+ * processor resets
+ */
+ mfcpr(CPR0_ICFG, reg);
+ reg |= CPR0_ICFG_RLI_MASK;
+ mtcpr(CPR0_ICFG, reg);
+
+ /* Reset processor if configuration changed */
+ __asm__ __volatile__ ("sync; isync");
+ mtspr(SPRN_DBCR0, 0x20000000);
+}
+#endif
+
+void reconfigure_pll(u32 new_cpu_freq)
+{
+#if defined(CONFIG_440EPX)
+ int reset_needed = 0;
+ u32 reg, temp;
+ u32 prbdv0, target_prbdv0, /* CLK_PRIMBD */
+ fwdva, target_fwdva, fwdvb, target_fwdvb, /* CLK_PLLD */
+ fbdv, target_fbdv, lfbdv, target_lfbdv,
+ perdv0, target_perdv0, /* CLK_PERD */
+ spcid0, target_spcid0; /* CLK_SPCID */
+
+ /* Reconfigure clocks if necessary.
+ * See PPC440EPx User's Manual, sections 8.2 and 14 */
+ if (new_cpu_freq == 667) {
+ target_prbdv0 = 2;
+ target_fwdva = 2;
+ target_fwdvb = 4;
+ target_fbdv = 20;
+ target_lfbdv = 1;
+ target_perdv0 = 4;
+ target_spcid0 = 4;
+
+ mfcpr(CPR0_PRIMBD0, reg);
+ temp = (reg & PRBDV_MASK) >> 24;
+ prbdv0 = temp ? temp : 8;
+ if (prbdv0 != target_prbdv0) {
+ reg &= ~PRBDV_MASK;
+ reg |= ((target_prbdv0 == 8 ? 0 : target_prbdv0) << 24);
+ mtcpr(CPR0_PRIMBD0, reg);
+ reset_needed = 1;
+ }
+
+ mfcpr(CPR0_PLLD, reg);
+
+ temp = (reg & PLLD_FWDVA_MASK) >> 16;
+ fwdva = temp ? temp : 16;
+
+ temp = (reg & PLLD_FWDVB_MASK) >> 8;
+ fwdvb = temp ? temp : 8;
+
+ temp = (reg & PLLD_FBDV_MASK) >> 24;
+ fbdv = temp ? temp : 32;
+
+ temp = (reg & PLLD_LFBDV_MASK);
+ lfbdv = temp ? temp : 64;
+
+ if (fwdva != target_fwdva || fbdv != target_fbdv || lfbdv != target_lfbdv) {
+ reg &= ~(PLLD_FWDVA_MASK | PLLD_FWDVB_MASK |
+ PLLD_FBDV_MASK | PLLD_LFBDV_MASK);
+ reg |= ((target_fwdva == 16 ? 0 : target_fwdva) << 16) |
+ ((target_fwdvb == 8 ? 0 : target_fwdvb) << 8) |
+ ((target_fbdv == 32 ? 0 : target_fbdv) << 24) |
+ (target_lfbdv == 64 ? 0 : target_lfbdv);
+ mtcpr(CPR0_PLLD, reg);
+ reset_needed = 1;
+ }
+
+ mfcpr(CPR0_PERD, reg);
+ perdv0 = (reg & CPR0_PERD_PERDV0_MASK) >> 24;
+ if (perdv0 != target_perdv0) {
+ reg &= ~CPR0_PERD_PERDV0_MASK;
+ reg |= (target_perdv0 << 24);
+ mtcpr(CPR0_PERD, reg);
+ reset_needed = 1;
+ }
+
+ mfcpr(CPR0_SPCID, reg);
+ temp = (reg & CPR0_SPCID_SPCIDV0_MASK) >> 24;
+ spcid0 = temp ? temp : 4;
+ if (spcid0 != target_spcid0) {
+ reg &= ~CPR0_SPCID_SPCIDV0_MASK;
+ reg |= ((target_spcid0 == 4 ? 0 : target_spcid0) << 24);
+ mtcpr(CPR0_SPCID, reg);
+ reset_needed = 1;
+ }
+ }
+
+ /* Get current value of FWDVA.*/
+ mfcpr(CPR0_PLLD, reg);
+ temp = (reg & PLLD_FWDVA_MASK) >> 16;
+
+ /*
+ * Check to see if FWDVA has been set to value of 1. if it has we must
+ * modify it.
+ */
+ if (temp == 1) {
+ /*
+ * Load register that contains current boot strapping option.
+ */
+ mfcpr(CPR0_ICFG, reg);
+ /*
+ * Strapping option bits (ICS) are already in correct position,
+ * only masking needed.
+ */
+ reg &= CPR0_ICFG_ICS_MASK;
+
+ if ((reg == BOOT_STRAP_OPTION_A) || (reg == BOOT_STRAP_OPTION_B) ||
+ (reg == BOOT_STRAP_OPTION_D) || (reg == BOOT_STRAP_OPTION_E)) {
+ mfcpr(CPR0_PLLD, reg);
+
+ /* Get current value of fbdv. */
+ temp = (reg & PLLD_FBDV_MASK) >> 24;
+ fbdv = temp ? temp : 32;
+
+ /* Get current value of lfbdv. */
+ temp = (reg & PLLD_LFBDV_MASK);
+ lfbdv = temp ? temp : 64;
+
+ /*
+ * Get current value of FWDVA. Assign current FWDVA to
+ * new FWDVB.
+ */
+ mfcpr(CPR0_PLLD, reg);
+ target_fwdvb = (reg & PLLD_FWDVA_MASK) >> 16;
+ fwdvb = target_fwdvb ? target_fwdvb : 8;
+
+ /*
+ * Get current value of FWDVB. Assign current FWDVB to
+ * new FWDVA.
+ */
+ target_fwdva = (reg & PLLD_FWDVB_MASK) >> 8;
+ fwdva = target_fwdva ? target_fwdva : 16;
+
+ /*
+ * Update CPR0_PLLD with switched FWDVA and FWDVB.
+ */
+ reg &= ~(PLLD_FWDVA_MASK | PLLD_FWDVB_MASK |
+ PLLD_FBDV_MASK | PLLD_LFBDV_MASK);
+ reg |= ((fwdva == 16 ? 0 : fwdva) << 16) |
+ ((fwdvb == 8 ? 0 : fwdvb) << 8) |
+ ((fbdv == 32 ? 0 : fbdv) << 24) |
+ (lfbdv == 64 ? 0 : lfbdv);
+ mtcpr(CPR0_PLLD, reg);
+
+ /* Acknowledge that a reset is required. */
+ reset_needed = 1;
+ }
+ }
+
+ /* Now reset the CPU if needed */
+ if (reset_needed)
+ reset_with_rli();
+#endif
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ u32 reg;
+
+ /*
+ * See "9.2.1.1 Booting with Option E" in the 460EX/GT
+ * users manual
+ */
+ mfcpr(CPR0_PLLC, reg);
+ if ((reg & (CPR0_PLLC_RST | CPR0_PLLC_ENG)) == CPR0_PLLC_RST) {
+ /*
+ * Set engage bit
+ */
+ reg = (reg & ~CPR0_PLLC_RST) | CPR0_PLLC_ENG;
+ mtcpr(CPR0_PLLC, reg);
+
+ /* Now reset the CPU */
+ reset_with_rli();
+ }
+#endif
+}
+
+#ifdef CONFIG_SYS_4xx_CHIP_21_ERRATA
+void
+chip_21_errata(void)
+{
+ /*
+ * See rev 1.09 of the 405EX/405EXr errata. CHIP_21 says that
+ * sometimes reading the PVR and/or SDR0_ECID results in incorrect
+ * values. Since the rev-D chip uses the SDR0_ECID bits to control
+ * internal features, that means the second PCIe or ethernet of an EX
+ * variant could fail to work. Also, security features of both EX and
+ * EXr might be incorrectly disabled.
+ *
+ * The suggested workaround is as follows (covering rev-C and rev-D):
+ *
+ * 1.Read the PVR and SDR0_ECID3.
+ *
+ * 2.If the PVR matches an expected Revision C PVR value AND if
+ * SDR0_ECID3[12:15] is different from PVR[28:31], then processor is
+ * Revision C: continue executing the initialization code (no reset
+ * required). else go to step 3.
+ *
+ * 3.If the PVR matches an expected Revision D PVR value AND if
+ * SDR0_ECID3[10:11] matches its expected value, then continue
+ * executing initialization code, no reset required. else write
+ * DBCR0[RST] = 0b11 to generate a SysReset.
+ */
+
+ u32 pvr;
+ u32 pvr_28_31;
+ u32 ecid3;
+ u32 ecid3_10_11;
+ u32 ecid3_12_15;
+
+ /* Step 1: */
+ pvr = get_pvr();
+ mfsdr(SDR0_ECID3, ecid3);
+
+ /* Step 2: */
+ pvr_28_31 = pvr & 0xf;
+ ecid3_10_11 = (ecid3 >> 20) & 0x3;
+ ecid3_12_15 = (ecid3 >> 16) & 0xf;
+ if ((pvr == CONFIG_405EX_CHIP21_PVR_REV_C) &&
+ (pvr_28_31 != ecid3_12_15)) {
+ /* No reset required. */
+ return;
+ }
+
+ /* Step 3: */
+ if ((pvr == CONFIG_405EX_CHIP21_PVR_REV_D) &&
+ (ecid3_10_11 == CONFIG_405EX_CHIP21_ECID3_REV_D)) {
+ /* No reset required. */
+ return;
+ }
+
+ /* Reset required. */
+ __asm__ __volatile__ ("sync; isync");
+ mtspr(SPRN_DBCR0, 0x30000000);
+}
+#endif
+
+/*
+ * Breath some life into the CPU...
+ *
+ * Reconfigure PLL if necessary,
+ * set up the memory map,
+ * initialize a bunch of registers
+ */
+void
+cpu_init_f (void)
+{
+#if defined(CONFIG_WATCHDOG) || defined(CONFIG_440GX) || defined(CONFIG_460EX)
+ u32 val;
+#endif
+
+#ifdef CONFIG_SYS_4xx_CHIP_21_ERRATA
+ chip_21_errata();
+#endif
+
+ reconfigure_pll(CONFIG_SYS_PLL_RECONFIG);
+
+#if (defined(CONFIG_405EP) || defined (CONFIG_405EX)) && \
+ !defined(CONFIG_APM821XX) &&!defined(CONFIG_SYS_4xx_GPIO_TABLE)
+ /*
+ * GPIO0 setup (select GPIO or alternate function)
+ */
+#if defined(CONFIG_SYS_GPIO0_OR)
+ out32(GPIO0_OR, CONFIG_SYS_GPIO0_OR); /* set initial state of output pins */
+#endif
+#if defined(CONFIG_SYS_GPIO0_ODR)
+ out32(GPIO0_ODR, CONFIG_SYS_GPIO0_ODR); /* open-drain select */
+#endif
+ out32(GPIO0_OSRH, CONFIG_SYS_GPIO0_OSRH); /* output select */
+ out32(GPIO0_OSRL, CONFIG_SYS_GPIO0_OSRL);
+ out32(GPIO0_ISR1H, CONFIG_SYS_GPIO0_ISR1H); /* input select */
+ out32(GPIO0_ISR1L, CONFIG_SYS_GPIO0_ISR1L);
+ out32(GPIO0_TSRH, CONFIG_SYS_GPIO0_TSRH); /* three-state select */
+ out32(GPIO0_TSRL, CONFIG_SYS_GPIO0_TSRL);
+#if defined(CONFIG_SYS_GPIO0_ISR2H)
+ out32(GPIO0_ISR2H, CONFIG_SYS_GPIO0_ISR2H);
+ out32(GPIO0_ISR2L, CONFIG_SYS_GPIO0_ISR2L);
+#endif
+#if defined (CONFIG_SYS_GPIO0_TCR)
+ out32(GPIO0_TCR, CONFIG_SYS_GPIO0_TCR); /* enable output driver for outputs */
+#endif
+#endif /* CONFIG_405EP ... && !CONFIG_SYS_4xx_GPIO_TABLE */
+
+#if defined (CONFIG_405EP)
+ /*
+ * Set EMAC noise filter bits
+ */
+ mtdcr(CPC0_EPCTL, CPC0_EPCTL_E0NFE | CPC0_EPCTL_E1NFE);
+#endif /* CONFIG_405EP */
+
+#if defined(CONFIG_SYS_4xx_GPIO_TABLE)
+ gpio_set_chip_configuration();
+#endif /* CONFIG_SYS_4xx_GPIO_TABLE */
+
+ /*
+ * External Bus Controller (EBC) Setup
+ */
+#if (defined(CONFIG_SYS_EBC_PB0AP) && defined(CONFIG_SYS_EBC_PB0CR))
+#if (defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
+ defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
+ defined(CONFIG_405EX) || defined(CONFIG_405))
+ /*
+ * Move the next instructions into icache, since these modify the flash
+ * we are running from!
+ */
+ asm volatile(" bl 0f" ::: "lr");
+ asm volatile("0: mflr 3" ::: "r3");
+ asm volatile(" addi 4, 0, 14" ::: "r4");
+ asm volatile(" mtctr 4" ::: "ctr");
+ asm volatile("1: icbt 0, 3");
+ asm volatile(" addi 3, 3, 32" ::: "r3");
+ asm volatile(" bdnz 1b" ::: "ctr", "cr0");
+ asm volatile(" addis 3, 0, 0x0" ::: "r3");
+ asm volatile(" ori 3, 3, 0xA000" ::: "r3");
+ asm volatile(" mtctr 3" ::: "ctr");
+ asm volatile("2: bdnz 2b" ::: "ctr", "cr0");
+#endif
+
+ mtebc(PB0AP, CONFIG_SYS_EBC_PB0AP);
+ mtebc(PB0CR, CONFIG_SYS_EBC_PB0CR);
+#endif
+
+#if (defined(CONFIG_SYS_EBC_PB1AP) && defined(CONFIG_SYS_EBC_PB1CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 1))
+ mtebc(PB1AP, CONFIG_SYS_EBC_PB1AP);
+ mtebc(PB1CR, CONFIG_SYS_EBC_PB1CR);
+#endif
+
+#if (defined(CONFIG_SYS_EBC_PB2AP) && defined(CONFIG_SYS_EBC_PB2CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 2))
+ mtebc(PB2AP, CONFIG_SYS_EBC_PB2AP);
+ mtebc(PB2CR, CONFIG_SYS_EBC_PB2CR);
+#endif
+
+#if (defined(CONFIG_SYS_EBC_PB3AP) && defined(CONFIG_SYS_EBC_PB3CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 3))
+ mtebc(PB3AP, CONFIG_SYS_EBC_PB3AP);
+ mtebc(PB3CR, CONFIG_SYS_EBC_PB3CR);
+#endif
+
+#if (defined(CONFIG_SYS_EBC_PB4AP) && defined(CONFIG_SYS_EBC_PB4CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 4))
+ mtebc(PB4AP, CONFIG_SYS_EBC_PB4AP);
+ mtebc(PB4CR, CONFIG_SYS_EBC_PB4CR);
+#endif
+
+#if (defined(CONFIG_SYS_EBC_PB5AP) && defined(CONFIG_SYS_EBC_PB5CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 5))
+ mtebc(PB5AP, CONFIG_SYS_EBC_PB5AP);
+ mtebc(PB5CR, CONFIG_SYS_EBC_PB5CR);
+#endif
+
+#if (defined(CONFIG_SYS_EBC_PB6AP) && defined(CONFIG_SYS_EBC_PB6CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 6))
+ mtebc(PB6AP, CONFIG_SYS_EBC_PB6AP);
+ mtebc(PB6CR, CONFIG_SYS_EBC_PB6CR);
+#endif
+
+#if (defined(CONFIG_SYS_EBC_PB7AP) && defined(CONFIG_SYS_EBC_PB7CR) && !(CONFIG_SYS_INIT_DCACHE_CS == 7))
+ mtebc(PB7AP, CONFIG_SYS_EBC_PB7AP);
+ mtebc(PB7CR, CONFIG_SYS_EBC_PB7CR);
+#endif
+
+#if defined (CONFIG_SYS_EBC_CFG)
+ mtebc(EBC0_CFG, CONFIG_SYS_EBC_CFG);
+#endif
+
+#if defined(CONFIG_WATCHDOG)
+ val = mfspr(SPRN_TCR);
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR)
+ val |= 0xb8000000; /* generate system reset after 1.34 seconds */
+#elif defined(CONFIG_440EPX)
+ val |= 0xb0000000; /* generate system reset after 1.34 seconds */
+#else
+ val |= 0xf0000000; /* generate system reset after 2.684 seconds */
+#endif
+#if defined(CONFIG_SYS_4xx_RESET_TYPE)
+ val &= ~0x30000000; /* clear WRC bits */
+ val |= CONFIG_SYS_4xx_RESET_TYPE << 28; /* set board specific WRC type */
+#endif
+ mtspr(SPRN_TCR, val);
+
+ val = mfspr(SPRN_TSR);
+ val |= 0x80000000; /* enable watchdog timer */
+ mtspr(SPRN_TSR, val);
+
+ reset_4xx_watchdog();
+#endif /* CONFIG_WATCHDOG */
+
+#if defined(CONFIG_440GX)
+ /* Take the GX out of compatibility mode
+ * Travis Sawyer, 9 Mar 2004
+ * NOTE: 440gx user manual inconsistency here
+ * Compatibility mode and Ethernet Clock select are not
+ * correct in the manual
+ */
+ mfsdr(SDR0_MFR, val);
+ val &= ~0x10000000;
+ mtsdr(SDR0_MFR,val);
+#endif /* CONFIG_440GX */
+
+#if defined(CONFIG_460EX)
+ /*
+ * Set SDR0_AHB_CFG[A2P_INCR4] (bit 24) and
+ * clear SDR0_AHB_CFG[A2P_PROT2] (bit 25) for a new 460EX errata
+ * regarding concurrent use of AHB USB OTG, USB 2.0 host and SATA
+ */
+ mfsdr(SDR0_AHB_CFG, val);
+ val |= 0x80;
+ val &= ~0x40;
+ mtsdr(SDR0_AHB_CFG, val);
+ mfsdr(SDR0_USB2HOST_CFG, val);
+ val &= ~0xf00;
+ val |= 0x400;
+ mtsdr(SDR0_USB2HOST_CFG, val);
+#endif /* CONFIG_460EX */
+
+#if defined(CONFIG_405EX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_460SX) || defined(CONFIG_APM821XX)
+ /*
+ * Set PLB4 arbiter (Segment 0 and 1) to 4 deep pipeline read
+ */
+ mtdcr(PLB4A0_ACR, (mfdcr(PLB4A0_ACR) & ~PLB4Ax_ACR_RDP_MASK) |
+ PLB4Ax_ACR_RDP_4DEEP);
+ mtdcr(PLB4A1_ACR, (mfdcr(PLB4A1_ACR) & ~PLB4Ax_ACR_RDP_MASK) |
+ PLB4Ax_ACR_RDP_4DEEP);
+#endif /* CONFIG_440SP/SPE || CONFIG_460EX/GT || CONFIG_405EX */
+}
+
+/*
+ * initialize higher level parts of CPU like time base and timers
+ */
+int cpu_init_r (void)
+{
+#if defined(CONFIG_405GP)
+ uint pvr = get_pvr();
+
+ /*
+ * Set edge conditioning circuitry on PPC405GPr
+ * for compatibility to existing PPC405GP designs.
+ */
+ if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
+ mtdcr(CPC0_ECR, 0x60606000);
+ }
+#endif /* defined(CONFIG_405GP) */
+
+ return 0;
+}
+
+#if defined(CONFIG_PCI) && \
+ (defined(CONFIG_440EP) || defined(CONFIG_440EPX) || \
+ defined(CONFIG_440GR) || defined(CONFIG_440GRX))
+/*
+ * 440EP(x)/GR(x) PCI async/sync clocking restriction:
+ *
+ * In asynchronous PCI mode, the synchronous PCI clock must meet
+ * certain requirements. The following equation describes the
+ * relationship that must be maintained between the asynchronous PCI
+ * clock and synchronous PCI clock. Select an appropriate PCI:PLB
+ * ratio to maintain the relationship:
+ *
+ * AsyncPCIClk - 1MHz <= SyncPCIclock <= (2 * AsyncPCIClk) - 1MHz
+ */
+static int ppc4xx_pci_sync_clock_ok(u32 sync, u32 async)
+{
+ if (((async - 1000000) > sync) || (sync > ((2 * async) - 1000000)))
+ return 0;
+ else
+ return 1;
+}
+
+int ppc4xx_pci_sync_clock_config(u32 async)
+{
+ sys_info_t sys_info;
+ u32 sync;
+ int div;
+ u32 reg;
+ u32 spcid_val[] = {
+ CPR0_SPCID_SPCIDV0_DIV1, CPR0_SPCID_SPCIDV0_DIV2,
+ CPR0_SPCID_SPCIDV0_DIV3, CPR0_SPCID_SPCIDV0_DIV4 };
+
+ get_sys_info(&sys_info);
+ sync = sys_info.freqPCI;
+
+ /*
+ * First check if the equation above is met
+ */
+ if (!ppc4xx_pci_sync_clock_ok(sync, async)) {
+ /*
+ * Reconfigure PCI sync clock to meet the equation.
+ * Start with highest possible PCI sync frequency
+ * (divider 1).
+ */
+ for (div = 1; div <= 4; div++) {
+ sync = sys_info.freqPLB / div;
+ if (ppc4xx_pci_sync_clock_ok(sync, async))
+ break;
+ }
+
+ if (div <= 4) {
+ mtcpr(CPR0_SPCID, spcid_val[div]);
+
+ mfcpr(CPR0_ICFG, reg);
+ reg |= CPR0_ICFG_RLI_MASK;
+ mtcpr(CPR0_ICFG, reg);
+
+ /* do chip reset */
+ mtspr(SPRN_DBCR0, 0x20000000);
+ } else {
+ /* Impossible to configure the PCI sync clock */
+ return -1;
+ }
+ }
+
+ return 0;
+}
+#endif
diff --git a/arch/powerpc/cpu/ppc4xx/dcr.S b/arch/powerpc/cpu/ppc4xx/dcr.S
new file mode 100644
index 0000000..e668e05
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/dcr.S
@@ -0,0 +1,198 @@
+/*
+ * (C) Copyright 2001
+ * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <config.h>
+
+#if defined(CONFIG_4xx) && defined(CONFIG_CMD_SETGETDCR)
+
+#include <asm/ppc4xx.h>
+
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#define _ASMLANGUAGE
+
+/*****************************************************************************
+ *
+ * XXX - DANGER
+ * These routines make use of self modifying code. DO NOT CALL THEM
+ * UNTIL THEY ARE RELOCATED TO RAM. Additionally, I do not
+ * recommend them for use in anything other than an interactive
+ * debugging environment. This is mainly due to performance reasons.
+ *
+ ****************************************************************************/
+
+/*
+ * static void _create_MFDCR(unsigned short dcrn)
+ *
+ * Builds a 'mfdcr' instruction for get_dcr
+ * function.
+ */
+ .section ".text"
+ .align 2
+ .type _create_MFDCR,@function
+_create_MFDCR:
+ /*
+ * Build up a 'mfdcr' instruction formatted as follows:
+ *
+ * OPCD | RT | DCRF | XO | CR |
+ * ---------------|--------------|--------------|----|
+ * 0 5 | 6 10 | 11 20 | 21 30 | 31 |
+ * | | DCRN | | |
+ * 31 | %r3 | (5..9|0..4) | 323 | 0 |
+ *
+ * Where:
+ * OPCD = opcode - 31
+ * RT = destination register - %r3 return register
+ * DCRF = DCRN # with upper and lower halves swapped
+ * XO = extended opcode - 323
+ * CR = CR[CR0] NOT undefined - 0
+ */
+ rlwinm r0, r3, 27, 27, 31 /* OPCD = 31 */
+ rlwinm r3, r3, 5, 22, 26
+ or r3, r3, r0
+ slwi r3, r3, 10
+ oris r3, r3, 0x3e30 /* RT = %r3 */
+ ori r3, r3, 323 /* XO = 323 */
+ slwi r3, r3, 1 /* CR = 0 */
+
+ mflr r4
+ stw r3, 0(r4) /* Store instr in get_dcr() */
+ dcbst r0, r4 /* Make sure val is written out */
+ sync /* Wait for write to complete */
+ icbi r0, r4 /* Make sure old instr is dumped */
+ isync /* Wait for icbi to complete */
+
+ blr
+.Lfe1: .size _create_MFDCR,.Lfe1-_create_MFDCR
+/* end _create_MFDCR() */
+
+/*
+ * static void _create_MTDCR(unsigned short dcrn, unsigned long value)
+ *
+ * Builds a 'mtdcr' instruction for set_dcr
+ * function.
+ */
+ .section ".text"
+ .align 2
+ .type _create_MTDCR,@function
+_create_MTDCR:
+ /*
+ * Build up a 'mtdcr' instruction formatted as follows:
+ *
+ * OPCD | RS | DCRF | XO | CR |
+ * ---------------|--------------|--------------|----|
+ * 0 5 | 6 10 | 11 20 | 21 30 | 31 |
+ * | | DCRN | | |
+ * 31 | %r3 | (5..9|0..4) | 451 | 0 |
+ *
+ * Where:
+ * OPCD = opcode - 31
+ * RS = source register - %r4
+ * DCRF = dest. DCRN # with upper and lower halves swapped
+ * XO = extended opcode - 451
+ * CR = CR[CR0] NOT undefined - 0
+ */
+ rlwinm r0, r3, 27, 27, 31 /* OPCD = 31 */
+ rlwinm r3, r3, 5, 22, 26
+ or r3, r3, r0
+ slwi r3, r3, 10
+ oris r3, r3, 0x3e40 /* RS = %r4 */
+ ori r3, r3, 451 /* XO = 451 */
+ slwi r3, r3, 1 /* CR = 0 */
+
+ mflr r5
+ stw r3, 0(r5) /* Store instr in set_dcr() */
+ dcbst r0, r5 /* Make sure val is written out */
+ sync /* Wait for write to complete */
+ icbi r0, r5 /* Make sure old instr is dumped */
+ isync /* Wait for icbi to complete */
+
+ blr
+.Lfe2: .size _create_MTDCR,.Lfe2-_create_MTDCR
+/* end _create_MTDCR() */
+
+
+/*
+ * unsigned long get_dcr(unsigned short dcrn)
+ *
+ * Return a given DCR's value.
+ */
+ /* */
+ /* XXX - This is self modifying code, hence */
+ /* it is in the data section. */
+ /* */
+ .section ".data"
+ .align 2
+ .globl get_dcr
+ .type get_dcr,@function
+get_dcr:
+ mflr r0 /* Get link register */
+ stwu r1, -32(r1) /* Save back chain and move SP */
+ stw r0, +36(r1) /* Save link register */
+
+ bl _create_MFDCR /* Build following instruction */
+ /* XXX - we build this instuction up on the fly. */
+ .long 0 /* Get DCR's value */
+
+ lwz r0, +36(r1) /* Get saved link register */
+ mtlr r0 /* Restore link register */
+ addi r1, r1, +32 /* Remove frame from stack */
+ blr /* Return to calling function */
+.Lfe3: .size get_dcr,.Lfe3-get_dcr
+/* end get_dcr() */
+
+
+/*
+ * unsigned void set_dcr(unsigned short dcrn, unsigned long value)
+ *
+ * Return a given DCR's value.
+ */
+ /*
+ * XXX - This is self modifying code, hence
+ * it is in the data section.
+ */
+ .section ".data"
+ .align 2
+ .globl set_dcr
+ .type set_dcr,@function
+set_dcr:
+ mflr r0 /* Get link register */
+ stwu r1, -32(r1) /* Save back chain and move SP */
+ stw r0, +36(r1) /* Save link register */
+
+ bl _create_MTDCR /* Build following instruction */
+ /* XXX - we build this instuction up on the fly. */
+ .long 0 /* Set DCR's value */
+
+ lwz r0, +36(r1) /* Get saved link register */
+ mtlr r0 /* Restore link register */
+ addi r1, r1, +32 /* Remove frame from stack */
+ blr /* Return to calling function */
+.Lfe4: .size set_dcr,.Lfe4-set_dcr
+/* end set_dcr() */
+#endif
diff --git a/arch/powerpc/cpu/ppc4xx/denali_data_eye.c b/arch/powerpc/cpu/ppc4xx/denali_data_eye.c
new file mode 100644
index 0000000..19b65be
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/denali_data_eye.c
@@ -0,0 +1,389 @@
+/*
+ * arch/powerpc/cpu/ppc4xx/denali_data_eye.c
+ * Extracted from board/amcc/sequoia/sdram.c by Larry Johnson <lrj@acm.org>.
+ *
+ * (C) Copyright 2006
+ * Sylvie Gohl, AMCC/IBM, gohl.sylvie@fr.ibm.com
+ * Jacqueline Pira-Ferriol, AMCC/IBM, jpira-ferriol@fr.ibm.com
+ * Thierry Roman, AMCC/IBM, thierry_roman@fr.ibm.com
+ * Alain Saurel, AMCC/IBM, alain.saurel@fr.ibm.com
+ * Robert Snyder, AMCC/IBM, rob.snyder@fr.ibm.com
+ *
+ * (C) Copyright 2006-2007
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* define DEBUG for debugging output (obviously ;-)) */
+#if 0
+#define DEBUG
+#endif
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/ppc4xx.h>
+
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+/*-----------------------------------------------------------------------------+
+ * denali_wait_for_dlllock.
+ +----------------------------------------------------------------------------*/
+int denali_wait_for_dlllock(void)
+{
+ u32 val;
+ int wait;
+
+ /* -----------------------------------------------------------+
+ * Wait for the DCC master delay line to finish calibration
+ * ----------------------------------------------------------*/
+ for (wait = 0; wait != 0xffff; ++wait) {
+ mfsdram(DDR0_17, val);
+ if (DDR0_17_DLLLOCKREG_DECODE(val)) {
+ /* dlllockreg bit on */
+ return 0;
+ }
+ }
+ debug("0x%04x: DDR0_17 Value (dlllockreg bit): 0x%08x\n", wait, val);
+ debug("Waiting for dlllockreg bit to raise\n");
+ return -1;
+}
+
+#if defined(CONFIG_DDR_DATA_EYE)
+#define DDR_DCR_BASE 0x10
+#define ddrcfga (DDR_DCR_BASE+0x0) /* DDR configuration address reg */
+#define ddrcfgd (DDR_DCR_BASE+0x1) /* DDR configuration data reg */
+
+/*-----------------------------------------------------------------------------+
+ * wait_for_dram_init_complete.
+ +----------------------------------------------------------------------------*/
+static int wait_for_dram_init_complete(void)
+{
+ unsigned long val;
+ int wait = 0;
+
+ /* --------------------------------------------------------------+
+ * Wait for 'DRAM initialization complete' bit in status register
+ * -------------------------------------------------------------*/
+ mtdcr(ddrcfga, DDR0_00);
+
+ while (wait != 0xffff) {
+ val = mfdcr(ddrcfgd);
+ if ((val & DDR0_00_INT_STATUS_BIT6) == DDR0_00_INT_STATUS_BIT6)
+ /* 'DRAM initialization complete' bit */
+ return 0;
+ else
+ wait++;
+ }
+ debug("DRAM initialization complete bit in status register did not "
+ "rise\n");
+ return -1;
+}
+
+#define NUM_TRIES 64
+#define NUM_READS 10
+
+/*-----------------------------------------------------------------------------+
+ * denali_core_search_data_eye.
+ +----------------------------------------------------------------------------*/
+void denali_core_search_data_eye(void)
+{
+ int k, j;
+ u32 val;
+ u32 wr_dqs_shift, dqs_out_shift, dll_dqs_delay_X;
+ u32 max_passing_cases = 0, wr_dqs_shift_with_max_passing_cases = 0;
+ u32 passing_cases = 0, dll_dqs_delay_X_sw_val = 0;
+ u32 dll_dqs_delay_X_start_window = 0, dll_dqs_delay_X_end_window = 0;
+ volatile u32 *ram_pointer;
+ u32 test[NUM_TRIES] = {
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+ 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+ 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+ 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+ 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+ 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+ 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+ 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55
+ };
+
+ ram_pointer = (volatile u32 *)(CONFIG_SYS_SDRAM_BASE);
+
+ for (wr_dqs_shift = 64; wr_dqs_shift < 96; wr_dqs_shift++) {
+ /* for (wr_dqs_shift=1; wr_dqs_shift<96; wr_dqs_shift++) { */
+
+ /* -----------------------------------------------------------+
+ * De-assert 'start' parameter.
+ * ----------------------------------------------------------*/
+ mtdcr(ddrcfga, DDR0_02);
+ val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) |
+ DDR0_02_START_OFF;
+ mtdcr(ddrcfgd, val);
+
+ /* -----------------------------------------------------------+
+ * Set 'wr_dqs_shift'
+ * ----------------------------------------------------------*/
+ mtdcr(ddrcfga, DDR0_09);
+ val = (mfdcr(ddrcfgd) & ~DDR0_09_WR_DQS_SHIFT_MASK) |
+ DDR0_09_WR_DQS_SHIFT_ENCODE(wr_dqs_shift);
+ mtdcr(ddrcfgd, val);
+
+ /* -----------------------------------------------------------+
+ * Set 'dqs_out_shift' = wr_dqs_shift + 32
+ * ----------------------------------------------------------*/
+ dqs_out_shift = wr_dqs_shift + 32;
+ mtdcr(ddrcfga, DDR0_22);
+ val = (mfdcr(ddrcfgd) & ~DDR0_22_DQS_OUT_SHIFT_MASK) |
+ DDR0_22_DQS_OUT_SHIFT_ENCODE(dqs_out_shift);
+ mtdcr(ddrcfgd, val);
+
+ passing_cases = 0;
+
+ for (dll_dqs_delay_X = 1; dll_dqs_delay_X < 64;
+ dll_dqs_delay_X++) {
+ /* for (dll_dqs_delay_X=1; dll_dqs_delay_X<128;
+ dll_dqs_delay_X++) { */
+ /* -----------------------------------------------------------+
+ * Set 'dll_dqs_delay_X'.
+ * ----------------------------------------------------------*/
+ /* dll_dqs_delay_0 */
+ mtdcr(ddrcfga, DDR0_17);
+ val = (mfdcr(ddrcfgd) & ~DDR0_17_DLL_DQS_DELAY_0_MASK)
+ | DDR0_17_DLL_DQS_DELAY_0_ENCODE(dll_dqs_delay_X);
+ mtdcr(ddrcfgd, val);
+ /* dll_dqs_delay_1 to dll_dqs_delay_4 */
+ mtdcr(ddrcfga, DDR0_18);
+ val = (mfdcr(ddrcfgd) & ~DDR0_18_DLL_DQS_DELAY_X_MASK)
+ | DDR0_18_DLL_DQS_DELAY_4_ENCODE(dll_dqs_delay_X)
+ | DDR0_18_DLL_DQS_DELAY_3_ENCODE(dll_dqs_delay_X)
+ | DDR0_18_DLL_DQS_DELAY_2_ENCODE(dll_dqs_delay_X)
+ | DDR0_18_DLL_DQS_DELAY_1_ENCODE(dll_dqs_delay_X);
+ mtdcr(ddrcfgd, val);
+ /* dll_dqs_delay_5 to dll_dqs_delay_8 */
+ mtdcr(ddrcfga, DDR0_19);
+ val = (mfdcr(ddrcfgd) & ~DDR0_19_DLL_DQS_DELAY_X_MASK)
+ | DDR0_19_DLL_DQS_DELAY_8_ENCODE(dll_dqs_delay_X)
+ | DDR0_19_DLL_DQS_DELAY_7_ENCODE(dll_dqs_delay_X)
+ | DDR0_19_DLL_DQS_DELAY_6_ENCODE(dll_dqs_delay_X)
+ | DDR0_19_DLL_DQS_DELAY_5_ENCODE(dll_dqs_delay_X);
+ mtdcr(ddrcfgd, val);
+ /* clear any ECC errors */
+ mtdcr(ddrcfga, DDR0_00);
+ mtdcr(ddrcfgd,
+ mfdcr(ddrcfgd) | DDR0_00_INT_ACK_ENCODE(0x3C));
+
+ sync();
+ eieio();
+
+ /* -----------------------------------------------------------+
+ * Assert 'start' parameter.
+ * ----------------------------------------------------------*/
+ mtdcr(ddrcfga, DDR0_02);
+ val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) |
+ DDR0_02_START_ON;
+ mtdcr(ddrcfgd, val);
+
+ sync();
+ eieio();
+
+ /* -----------------------------------------------------------+
+ * Wait for the DCC master delay line to finish calibration
+ * ----------------------------------------------------------*/
+ if (denali_wait_for_dlllock() != 0) {
+ printf("dll lock did not occur !!!\n");
+ printf("denali_core_search_data_eye!!!\n");
+ printf("wr_dqs_shift = %d - dll_dqs_delay_X = "
+ "%d\n", wr_dqs_shift, dll_dqs_delay_X);
+ hang();
+ }
+ sync();
+ eieio();
+
+ if (wait_for_dram_init_complete() != 0) {
+ printf("dram init complete did not occur!!!\n");
+ printf("denali_core_search_data_eye!!!\n");
+ printf("wr_dqs_shift = %d - dll_dqs_delay_X = "
+ "%d\n", wr_dqs_shift, dll_dqs_delay_X);
+ hang();
+ }
+ udelay(100); /* wait 100us to ensure init is really completed !!! */
+
+ /* write values */
+ for (j = 0; j < NUM_TRIES; j++) {
+ ram_pointer[j] = test[j];
+
+ /* clear any cache at ram location */
+ __asm__("dcbf 0,%0": :"r"(&ram_pointer[j]));
+ }
+
+ /* read values back */
+ for (j = 0; j < NUM_TRIES; j++) {
+ for (k = 0; k < NUM_READS; k++) {
+ /* clear any cache at ram location */
+ __asm__("dcbf 0,%0": :"r"(&ram_pointer
+ [j]));
+
+ if (ram_pointer[j] != test[j])
+ break;
+ }
+
+ /* read error */
+ if (k != NUM_READS)
+ break;
+ }
+
+ /* See if the dll_dqs_delay_X value passed. */
+ mtdcr(ddrcfga, DDR0_00);
+ if (j < NUM_TRIES
+ || (DDR0_00_INT_STATUS_DECODE(mfdcr(ddrcfgd)) &
+ 0x3F)) {
+ /* Failed */
+ passing_cases = 0;
+ /* break; */
+ } else {
+ /* Passed */
+ if (passing_cases == 0)
+ dll_dqs_delay_X_sw_val =
+ dll_dqs_delay_X;
+ passing_cases++;
+ if (passing_cases >= max_passing_cases) {
+ max_passing_cases = passing_cases;
+ wr_dqs_shift_with_max_passing_cases =
+ wr_dqs_shift;
+ dll_dqs_delay_X_start_window =
+ dll_dqs_delay_X_sw_val;
+ dll_dqs_delay_X_end_window =
+ dll_dqs_delay_X;
+ }
+ }
+
+ /* -----------------------------------------------------------+
+ * De-assert 'start' parameter.
+ * ----------------------------------------------------------*/
+ mtdcr(ddrcfga, DDR0_02);
+ val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) |
+ DDR0_02_START_OFF;
+ mtdcr(ddrcfgd, val);
+ } /* for (dll_dqs_delay_X=0; dll_dqs_delay_X<128; dll_dqs_delay_X++) */
+ } /* for (wr_dqs_shift=0; wr_dqs_shift<96; wr_dqs_shift++) */
+
+ /* -----------------------------------------------------------+
+ * Largest passing window is now detected.
+ * ----------------------------------------------------------*/
+
+ /* Compute dll_dqs_delay_X value */
+ dll_dqs_delay_X = (dll_dqs_delay_X_end_window +
+ dll_dqs_delay_X_start_window) / 2;
+ wr_dqs_shift = wr_dqs_shift_with_max_passing_cases;
+
+ debug("DQS calibration - Window detected:\n");
+ debug("max_passing_cases = %d\n", max_passing_cases);
+ debug("wr_dqs_shift = %d\n", wr_dqs_shift);
+ debug("dll_dqs_delay_X = %d\n", dll_dqs_delay_X);
+ debug("dll_dqs_delay_X window = %d - %d\n",
+ dll_dqs_delay_X_start_window, dll_dqs_delay_X_end_window);
+
+ /* -----------------------------------------------------------+
+ * De-assert 'start' parameter.
+ * ----------------------------------------------------------*/
+ mtdcr(ddrcfga, DDR0_02);
+ val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) | DDR0_02_START_OFF;
+ mtdcr(ddrcfgd, val);
+
+ /* -----------------------------------------------------------+
+ * Set 'wr_dqs_shift'
+ * ----------------------------------------------------------*/
+ mtdcr(ddrcfga, DDR0_09);
+ val = (mfdcr(ddrcfgd) & ~DDR0_09_WR_DQS_SHIFT_MASK)
+ | DDR0_09_WR_DQS_SHIFT_ENCODE(wr_dqs_shift);
+ mtdcr(ddrcfgd, val);
+ debug("DDR0_09=0x%08x\n", val);
+
+ /* -----------------------------------------------------------+
+ * Set 'dqs_out_shift' = wr_dqs_shift + 32
+ * ----------------------------------------------------------*/
+ dqs_out_shift = wr_dqs_shift + 32;
+ mtdcr(ddrcfga, DDR0_22);
+ val = (mfdcr(ddrcfgd) & ~DDR0_22_DQS_OUT_SHIFT_MASK)
+ | DDR0_22_DQS_OUT_SHIFT_ENCODE(dqs_out_shift);
+ mtdcr(ddrcfgd, val);
+ debug("DDR0_22=0x%08x\n", val);
+
+ /* -----------------------------------------------------------+
+ * Set 'dll_dqs_delay_X'.
+ * ----------------------------------------------------------*/
+ /* dll_dqs_delay_0 */
+ mtdcr(ddrcfga, DDR0_17);
+ val = (mfdcr(ddrcfgd) & ~DDR0_17_DLL_DQS_DELAY_0_MASK)
+ | DDR0_17_DLL_DQS_DELAY_0_ENCODE(dll_dqs_delay_X);
+ mtdcr(ddrcfgd, val);
+ debug("DDR0_17=0x%08x\n", val);
+
+ /* dll_dqs_delay_1 to dll_dqs_delay_4 */
+ mtdcr(ddrcfga, DDR0_18);
+ val = (mfdcr(ddrcfgd) & ~DDR0_18_DLL_DQS_DELAY_X_MASK)
+ | DDR0_18_DLL_DQS_DELAY_4_ENCODE(dll_dqs_delay_X)
+ | DDR0_18_DLL_DQS_DELAY_3_ENCODE(dll_dqs_delay_X)
+ | DDR0_18_DLL_DQS_DELAY_2_ENCODE(dll_dqs_delay_X)
+ | DDR0_18_DLL_DQS_DELAY_1_ENCODE(dll_dqs_delay_X);
+ mtdcr(ddrcfgd, val);
+ debug("DDR0_18=0x%08x\n", val);
+
+ /* dll_dqs_delay_5 to dll_dqs_delay_8 */
+ mtdcr(ddrcfga, DDR0_19);
+ val = (mfdcr(ddrcfgd) & ~DDR0_19_DLL_DQS_DELAY_X_MASK)
+ | DDR0_19_DLL_DQS_DELAY_8_ENCODE(dll_dqs_delay_X)
+ | DDR0_19_DLL_DQS_DELAY_7_ENCODE(dll_dqs_delay_X)
+ | DDR0_19_DLL_DQS_DELAY_6_ENCODE(dll_dqs_delay_X)
+ | DDR0_19_DLL_DQS_DELAY_5_ENCODE(dll_dqs_delay_X);
+ mtdcr(ddrcfgd, val);
+ debug("DDR0_19=0x%08x\n", val);
+
+ /* -----------------------------------------------------------+
+ * Assert 'start' parameter.
+ * ----------------------------------------------------------*/
+ mtdcr(ddrcfga, DDR0_02);
+ val = (mfdcr(ddrcfgd) & ~DDR0_02_START_MASK) | DDR0_02_START_ON;
+ mtdcr(ddrcfgd, val);
+
+ sync();
+ eieio();
+
+ /* -----------------------------------------------------------+
+ * Wait for the DCC master delay line to finish calibration
+ * ----------------------------------------------------------*/
+ if (denali_wait_for_dlllock() != 0) {
+ printf("dll lock did not occur !!!\n");
+ hang();
+ }
+ sync();
+ eieio();
+
+ if (wait_for_dram_init_complete() != 0) {
+ printf("dram init complete did not occur !!!\n");
+ hang();
+ }
+ udelay(100); /* wait 100us to ensure init is really completed !!! */
+}
+#endif /* defined(CONFIG_DDR_DATA_EYE) */
+#endif /* defined(CONFIG_440EPX) || defined(CONFIG_440GRX) */
diff --git a/arch/powerpc/cpu/ppc4xx/denali_spd_ddr2.c b/arch/powerpc/cpu/ppc4xx/denali_spd_ddr2.c
new file mode 100644
index 0000000..3ceab32
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/denali_spd_ddr2.c
@@ -0,0 +1,1249 @@
+/*
+ * arch/powerpc/cpu/ppc4xx/denali_spd_ddr2.c
+ * This SPD SDRAM detection code supports AMCC PPC44x CPUs with a Denali-core
+ * DDR2 controller, specifically the 440EPx/GRx.
+ *
+ * (C) Copyright 2007-2008
+ * Larry Johnson, lrj@acm.org.
+ *
+ * Based primarily on arch/powerpc/cpu/ppc4xx/4xx_spd_ddr2.c, which is...
+ *
+ * (C) Copyright 2007
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * COPYRIGHT AMCC CORPORATION 2004
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+/* define DEBUG for debugging output (obviously ;-)) */
+#if 0
+#define DEBUG
+#endif
+
+#include <common.h>
+#include <command.h>
+#include <asm/ppc4xx.h>
+#include <i2c.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <asm/cache.h>
+
+#if defined(CONFIG_SPD_EEPROM) && \
+ (defined(CONFIG_440EPX) || defined(CONFIG_440GRX))
+
+/*-----------------------------------------------------------------------------+
+ * Defines
+ *-----------------------------------------------------------------------------*/
+#define MAXDIMMS 2
+#define MAXRANKS 2
+
+#define ONE_BILLION 1000000000
+
+#define MULDIV64(m1, m2, d) (u32)(((u64)(m1) * (u64)(m2)) / (u64)(d))
+
+#define DLL_DQS_DELAY 0x19
+#define DLL_DQS_BYPASS 0x0B
+#define DQS_OUT_SHIFT 0x7F
+
+/*
+ * This DDR2 setup code can dynamically setup the TLB entries for the DDR2 memory
+ * region. Right now the cache should still be disabled in U-Boot because of the
+ * EMAC driver, that need it's buffer descriptor to be located in non cached
+ * memory.
+ *
+ * If at some time this restriction doesn't apply anymore, just define
+ * CONFIG_4xx_DCACHE in the board config file and this code should setup
+ * everything correctly.
+ */
+#if defined(CONFIG_4xx_DCACHE)
+#define MY_TLB_WORD2_I_ENABLE 0 /* enable caching on SDRAM */
+#else
+#define MY_TLB_WORD2_I_ENABLE TLB_WORD2_I_ENABLE /* disable caching on SDRAM */
+#endif
+
+/*-----------------------------------------------------------------------------+
+ * Prototypes
+ *-----------------------------------------------------------------------------*/
+extern int denali_wait_for_dlllock(void);
+extern void denali_core_search_data_eye(void);
+extern void dcbz_area(u32 start_address, u32 num_bytes);
+
+/*
+ * Board-specific Platform code can reimplement spd_ddr_init_hang () if needed
+ */
+void __spd_ddr_init_hang(void)
+{
+ hang();
+}
+void spd_ddr_init_hang(void)
+ __attribute__ ((weak, alias("__spd_ddr_init_hang")));
+
+#if defined(DEBUG)
+static void print_mcsr(void)
+{
+ printf("MCSR = 0x%08X\n", mfspr(SPRN_MCSR));
+}
+
+static void denali_sdram_register_dump(void)
+{
+ unsigned int sdram_data;
+
+ printf("\n Register Dump:\n");
+ mfsdram(DDR0_00, sdram_data);
+ printf(" DDR0_00 = 0x%08X", sdram_data);
+ mfsdram(DDR0_01, sdram_data);
+ printf(" DDR0_01 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_02, sdram_data);
+ printf(" DDR0_02 = 0x%08X", sdram_data);
+ mfsdram(DDR0_03, sdram_data);
+ printf(" DDR0_03 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_04, sdram_data);
+ printf(" DDR0_04 = 0x%08X", sdram_data);
+ mfsdram(DDR0_05, sdram_data);
+ printf(" DDR0_05 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_06, sdram_data);
+ printf(" DDR0_06 = 0x%08X", sdram_data);
+ mfsdram(DDR0_07, sdram_data);
+ printf(" DDR0_07 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_08, sdram_data);
+ printf(" DDR0_08 = 0x%08X", sdram_data);
+ mfsdram(DDR0_09, sdram_data);
+ printf(" DDR0_09 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_10, sdram_data);
+ printf(" DDR0_10 = 0x%08X", sdram_data);
+ mfsdram(DDR0_11, sdram_data);
+ printf(" DDR0_11 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_12, sdram_data);
+ printf(" DDR0_12 = 0x%08X", sdram_data);
+ mfsdram(DDR0_14, sdram_data);
+ printf(" DDR0_14 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_17, sdram_data);
+ printf(" DDR0_17 = 0x%08X", sdram_data);
+ mfsdram(DDR0_18, sdram_data);
+ printf(" DDR0_18 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_19, sdram_data);
+ printf(" DDR0_19 = 0x%08X", sdram_data);
+ mfsdram(DDR0_20, sdram_data);
+ printf(" DDR0_20 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_21, sdram_data);
+ printf(" DDR0_21 = 0x%08X", sdram_data);
+ mfsdram(DDR0_22, sdram_data);
+ printf(" DDR0_22 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_23, sdram_data);
+ printf(" DDR0_23 = 0x%08X", sdram_data);
+ mfsdram(DDR0_24, sdram_data);
+ printf(" DDR0_24 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_25, sdram_data);
+ printf(" DDR0_25 = 0x%08X", sdram_data);
+ mfsdram(DDR0_26, sdram_data);
+ printf(" DDR0_26 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_27, sdram_data);
+ printf(" DDR0_27 = 0x%08X", sdram_data);
+ mfsdram(DDR0_28, sdram_data);
+ printf(" DDR0_28 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_31, sdram_data);
+ printf(" DDR0_31 = 0x%08X", sdram_data);
+ mfsdram(DDR0_32, sdram_data);
+ printf(" DDR0_32 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_33, sdram_data);
+ printf(" DDR0_33 = 0x%08X", sdram_data);
+ mfsdram(DDR0_34, sdram_data);
+ printf(" DDR0_34 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_35, sdram_data);
+ printf(" DDR0_35 = 0x%08X", sdram_data);
+ mfsdram(DDR0_36, sdram_data);
+ printf(" DDR0_36 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_37, sdram_data);
+ printf(" DDR0_37 = 0x%08X", sdram_data);
+ mfsdram(DDR0_38, sdram_data);
+ printf(" DDR0_38 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_39, sdram_data);
+ printf(" DDR0_39 = 0x%08X", sdram_data);
+ mfsdram(DDR0_40, sdram_data);
+ printf(" DDR0_40 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_41, sdram_data);
+ printf(" DDR0_41 = 0x%08X", sdram_data);
+ mfsdram(DDR0_42, sdram_data);
+ printf(" DDR0_42 = 0x%08X\n", sdram_data);
+ mfsdram(DDR0_43, sdram_data);
+ printf(" DDR0_43 = 0x%08X", sdram_data);
+ mfsdram(DDR0_44, sdram_data);
+ printf(" DDR0_44 = 0x%08X\n", sdram_data);
+}
+#else
+static inline void denali_sdram_register_dump(void)
+{
+}
+
+inline static void print_mcsr(void)
+{
+}
+#endif /* defined(DEBUG) */
+
+static int is_ecc_enabled(void)
+{
+ u32 val;
+
+ mfsdram(DDR0_22, val);
+ return 0x3 == DDR0_22_CTRL_RAW_DECODE(val);
+}
+
+static unsigned char spd_read(u8 chip, unsigned int addr)
+{
+ u8 data[2];
+
+ if (0 != i2c_probe(chip) || 0 != i2c_read(chip, addr, 1, data, 1)) {
+ debug("spd_read(0x%02X, 0x%02X) failed\n", chip, addr);
+ return 0;
+ }
+ debug("spd_read(0x%02X, 0x%02X) returned 0x%02X\n",
+ chip, addr, data[0]);
+ return data[0];
+}
+
+static unsigned long get_tcyc(unsigned char reg)
+{
+ /*
+ * Byte 9, et al: Cycle time for CAS Latency=X, is split into two
+ * nibbles: the higher order nibble (bits 4-7) designates the cycle time
+ * to a granularity of 1ns; the value presented by the lower order
+ * nibble (bits 0-3) has a granularity of .1ns and is added to the value
+ * designated by the higher nibble. In addition, four lines of the lower
+ * order nibble are assigned to support +.25, +.33, +.66, and +.75.
+ */
+
+ unsigned char subfield_b = reg & 0x0F;
+
+ switch (subfield_b & 0x0F) {
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ case 0x8:
+ case 0x9:
+ return 1000 * (reg >> 4) + 100 * subfield_b;
+ case 0xA:
+ return 1000 * (reg >> 4) + 250;
+ case 0xB:
+ return 1000 * (reg >> 4) + 333;
+ case 0xC:
+ return 1000 * (reg >> 4) + 667;
+ case 0xD:
+ return 1000 * (reg >> 4) + 750;
+ }
+ return 0;
+}
+
+/*------------------------------------------------------------------
+ * Find the installed DIMMs, make sure that the are DDR2, and fill
+ * in the dimm_ranks array. Then dimm_ranks[dimm_num] > 0 iff the
+ * DIMM and dimm_num is present.
+ * Note: Because there are only two chip-select lines, it is assumed
+ * that a board with a single socket can support two ranks on that
+ * socket, while a board with two sockets can support only one rank
+ * on each socket.
+ *-----------------------------------------------------------------*/
+static void get_spd_info(unsigned long dimm_ranks[],
+ unsigned long *ranks,
+ unsigned char const iic0_dimm_addr[],
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long dimm_found = false;
+ unsigned long const max_ranks_per_dimm = (1 == num_dimm_banks) ? 2 : 1;
+ unsigned char num_of_bytes;
+ unsigned char total_size;
+
+ *ranks = 0;
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ num_of_bytes = 0;
+ total_size = 0;
+
+ num_of_bytes = spd_read(iic0_dimm_addr[dimm_num], 0);
+ total_size = spd_read(iic0_dimm_addr[dimm_num], 1);
+ if ((num_of_bytes != 0) && (total_size != 0)) {
+ unsigned char const dimm_type =
+ spd_read(iic0_dimm_addr[dimm_num], 2);
+
+ unsigned long ranks_on_dimm =
+ (spd_read(iic0_dimm_addr[dimm_num], 5) & 0x07) + 1;
+
+ if (8 != dimm_type) {
+ switch (dimm_type) {
+ case 1:
+ printf("ERROR: Standard Fast Page Mode "
+ "DRAM DIMM");
+ break;
+ case 2:
+ printf("ERROR: EDO DIMM");
+ break;
+ case 3:
+ printf("ERROR: Pipelined Nibble DIMM");
+ break;
+ case 4:
+ printf("ERROR: SDRAM DIMM");
+ break;
+ case 5:
+ printf("ERROR: Multiplexed ROM DIMM");
+ break;
+ case 6:
+ printf("ERROR: SGRAM DIMM");
+ break;
+ case 7:
+ printf("ERROR: DDR1 DIMM");
+ break;
+ default:
+ printf("ERROR: Unknown DIMM (type %d)",
+ (unsigned int)dimm_type);
+ break;
+ }
+ printf(" detected in slot %lu.\n", dimm_num);
+ printf("Only DDR2 SDRAM DIMMs are supported."
+ "\n");
+ printf("Replace the module with a DDR2 DIMM."
+ "\n\n");
+ spd_ddr_init_hang();
+ }
+ dimm_found = true;
+ debug("DIMM slot %lu: populated with %lu-rank DDR2 DIMM"
+ "\n", dimm_num, ranks_on_dimm);
+ if (ranks_on_dimm > max_ranks_per_dimm) {
+ printf("WARNING: DRAM DIMM in slot %lu has %lu "
+ "ranks.\n", dimm_num, ranks_on_dimm);
+ if (1 == max_ranks_per_dimm) {
+ printf("Only one rank will be used.\n");
+ } else {
+ printf
+ ("Only two ranks will be used.\n");
+ }
+ ranks_on_dimm = max_ranks_per_dimm;
+ }
+ dimm_ranks[dimm_num] = ranks_on_dimm;
+ *ranks += ranks_on_dimm;
+ } else {
+ dimm_ranks[dimm_num] = 0;
+ debug("DIMM slot %lu: Not populated\n", dimm_num);
+ }
+ }
+ if (dimm_found == false) {
+ printf("ERROR: No memory installed.\n");
+ printf("Install at least one DDR2 DIMM.\n\n");
+ spd_ddr_init_hang();
+ }
+ debug("Total number of ranks = %ld\n", *ranks);
+}
+
+/*------------------------------------------------------------------
+ * For the memory DIMMs installed, this routine verifies that
+ * frequency previously calculated is supported.
+ *-----------------------------------------------------------------*/
+static void check_frequency(unsigned long *dimm_ranks,
+ unsigned char const iic0_dimm_addr[],
+ unsigned long num_dimm_banks,
+ unsigned long sdram_freq)
+{
+ unsigned long dimm_num;
+ unsigned long cycle_time;
+ unsigned long calc_cycle_time;
+
+ /*
+ * calc_cycle_time is calculated from DDR frequency set by board/chip
+ * and is expressed in picoseconds to match the way DIMM cycle time is
+ * calculated below.
+ */
+ calc_cycle_time = MULDIV64(ONE_BILLION, 1000, sdram_freq);
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_ranks[dimm_num]) {
+ cycle_time =
+ get_tcyc(spd_read(iic0_dimm_addr[dimm_num], 9));
+ debug("cycle_time=%ld ps\n", cycle_time);
+
+ if (cycle_time > (calc_cycle_time + 10)) {
+ /*
+ * the provided sdram cycle_time is too small
+ * for the available DIMM cycle_time. The
+ * additionnal 10ps is here to accept a small
+ * incertainty.
+ */
+ printf
+ ("ERROR: DRAM DIMM detected with cycle_time %d ps in "
+ "slot %d \n while calculated cycle time is %d ps.\n",
+ (unsigned int)cycle_time,
+ (unsigned int)dimm_num,
+ (unsigned int)calc_cycle_time);
+ printf
+ ("Replace the DIMM, or change DDR frequency via "
+ "strapping bits.\n\n");
+ spd_ddr_init_hang();
+ }
+ }
+ }
+}
+
+/*------------------------------------------------------------------
+ * This routine gets size information for the installed memory
+ * DIMMs.
+ *-----------------------------------------------------------------*/
+static void get_dimm_size(unsigned long dimm_ranks[],
+ unsigned char const iic0_dimm_addr[],
+ unsigned long num_dimm_banks,
+ unsigned long *const rows,
+ unsigned long *const banks,
+ unsigned long *const cols, unsigned long *const width)
+{
+ unsigned long dimm_num;
+
+ *rows = 0;
+ *banks = 0;
+ *cols = 0;
+ *width = 0;
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_ranks[dimm_num]) {
+ unsigned long t;
+
+ /* Rows */
+ t = spd_read(iic0_dimm_addr[dimm_num], 3);
+ if (0 == *rows) {
+ *rows = t;
+ } else if (t != *rows) {
+ printf("ERROR: DRAM DIMM modules do not all "
+ "have the same number of rows.\n\n");
+ spd_ddr_init_hang();
+ }
+ /* Banks */
+ t = spd_read(iic0_dimm_addr[dimm_num], 17);
+ if (0 == *banks) {
+ *banks = t;
+ } else if (t != *banks) {
+ printf("ERROR: DRAM DIMM modules do not all "
+ "have the same number of banks.\n\n");
+ spd_ddr_init_hang();
+ }
+ /* Columns */
+ t = spd_read(iic0_dimm_addr[dimm_num], 4);
+ if (0 == *cols) {
+ *cols = t;
+ } else if (t != *cols) {
+ printf("ERROR: DRAM DIMM modules do not all "
+ "have the same number of columns.\n\n");
+ spd_ddr_init_hang();
+ }
+ /* Data width */
+ t = spd_read(iic0_dimm_addr[dimm_num], 6);
+ if (0 == *width) {
+ *width = t;
+ } else if (t != *width) {
+ printf("ERROR: DRAM DIMM modules do not all "
+ "have the same data width.\n\n");
+ spd_ddr_init_hang();
+ }
+ }
+ }
+ debug("Number of rows = %ld\n", *rows);
+ debug("Number of columns = %ld\n", *cols);
+ debug("Number of banks = %ld\n", *banks);
+ debug("Data width = %ld\n", *width);
+ if (*rows > 14) {
+ printf("ERROR: DRAM DIMM modules have %lu address rows.\n",
+ *rows);
+ printf("Only modules with 14 or fewer rows are supported.\n\n");
+ spd_ddr_init_hang();
+ }
+ if (4 != *banks && 8 != *banks) {
+ printf("ERROR: DRAM DIMM modules have %lu banks.\n", *banks);
+ printf("Only modules with 4 or 8 banks are supported.\n\n");
+ spd_ddr_init_hang();
+ }
+ if (*cols > 12) {
+ printf("ERROR: DRAM DIMM modules have %lu address columns.\n",
+ *cols);
+ printf("Only modules with 12 or fewer columns are "
+ "supported.\n\n");
+ spd_ddr_init_hang();
+ }
+ if (32 != *width && 40 != *width && 64 != *width && 72 != *width) {
+ printf("ERROR: DRAM DIMM modules have a width of %lu bit.\n",
+ *width);
+ printf("Only modules with widths of 32, 40, 64, and 72 bits "
+ "are supported.\n\n");
+ spd_ddr_init_hang();
+ }
+}
+
+/*------------------------------------------------------------------
+ * Only 1.8V modules are supported. This routine verifies this.
+ *-----------------------------------------------------------------*/
+static void check_voltage_type(unsigned long dimm_ranks[],
+ unsigned char const iic0_dimm_addr[],
+ unsigned long num_dimm_banks)
+{
+ unsigned long dimm_num;
+ unsigned long voltage_type;
+
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ if (dimm_ranks[dimm_num]) {
+ voltage_type = spd_read(iic0_dimm_addr[dimm_num], 8);
+ if (0x05 != voltage_type) { /* 1.8V for DDR2 */
+ printf("ERROR: Slot %lu provides 1.8V for DDR2 "
+ "DIMMs.\n", dimm_num);
+ switch (voltage_type) {
+ case 0x00:
+ printf("This DIMM is 5.0 Volt/TTL.\n");
+ break;
+ case 0x01:
+ printf("This DIMM is LVTTL.\n");
+ break;
+ case 0x02:
+ printf("This DIMM is 1.5 Volt.\n");
+ break;
+ case 0x03:
+ printf("This DIMM is 3.3 Volt/TTL.\n");
+ break;
+ case 0x04:
+ printf("This DIMM is 2.5 Volt.\n");
+ break;
+ default:
+ printf("This DIMM is an unknown "
+ "voltage.\n");
+ break;
+ }
+ printf("Replace it with a 1.8V DDR2 DIMM.\n\n");
+ spd_ddr_init_hang();
+ }
+ }
+ }
+}
+
+static void program_ddr0_03(unsigned long dimm_ranks[],
+ unsigned char const iic0_dimm_addr[],
+ unsigned long num_dimm_banks,
+ unsigned long sdram_freq,
+ unsigned long rows, unsigned long *cas_latency)
+{
+ unsigned long dimm_num;
+ unsigned long cas_index;
+ unsigned long cycle_2_0_clk;
+ unsigned long cycle_3_0_clk;
+ unsigned long cycle_4_0_clk;
+ unsigned long cycle_5_0_clk;
+ unsigned long max_2_0_tcyc_ps = 100;
+ unsigned long max_3_0_tcyc_ps = 100;
+ unsigned long max_4_0_tcyc_ps = 100;
+ unsigned long max_5_0_tcyc_ps = 100;
+ unsigned char cas_available = 0x3C; /* value for DDR2 */
+ u32 ddr0_03 = DDR0_03_BSTLEN_ENCODE(0x2) | DDR0_03_INITAREF_ENCODE(0x2);
+ unsigned int const tcyc_addr[3] = { 9, 23, 25 };
+
+ /*------------------------------------------------------------------
+ * Get the board configuration info.
+ *-----------------------------------------------------------------*/
+ debug("sdram_freq = %ld\n", sdram_freq);
+
+ /*------------------------------------------------------------------
+ * Handle the timing. We need to find the worst case timing of all
+ * the dimm modules installed.
+ *-----------------------------------------------------------------*/
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ /* If a dimm is installed in a particular slot ... */
+ if (dimm_ranks[dimm_num]) {
+ unsigned char const cas_bit =
+ spd_read(iic0_dimm_addr[dimm_num], 18);
+ unsigned char cas_mask;
+
+ cas_available &= cas_bit;
+ for (cas_mask = 0x80; cas_mask; cas_mask >>= 1) {
+ if (cas_bit & cas_mask)
+ break;
+ }
+ debug("cas_bit (SPD byte 18) = %02X, cas_mask = %02X\n",
+ cas_bit, cas_mask);
+
+ for (cas_index = 0; cas_index < 3;
+ cas_mask >>= 1, cas_index++) {
+ unsigned long cycle_time_ps;
+
+ if (!(cas_available & cas_mask)) {
+ continue;
+ }
+ cycle_time_ps =
+ get_tcyc(spd_read(iic0_dimm_addr[dimm_num],
+ tcyc_addr[cas_index]));
+
+ debug("cas_index = %ld: cycle_time_ps = %ld\n",
+ cas_index, cycle_time_ps);
+ /*
+ * DDR2 devices use the following bitmask for CAS latency:
+ * Bit 7 6 5 4 3 2 1 0
+ * TBD 6.0 5.0 4.0 3.0 2.0 TBD TBD
+ */
+ switch (cas_mask) {
+ case 0x20:
+ max_5_0_tcyc_ps =
+ max(max_5_0_tcyc_ps, cycle_time_ps);
+ break;
+ case 0x10:
+ max_4_0_tcyc_ps =
+ max(max_4_0_tcyc_ps, cycle_time_ps);
+ break;
+ case 0x08:
+ max_3_0_tcyc_ps =
+ max(max_3_0_tcyc_ps, cycle_time_ps);
+ break;
+ case 0x04:
+ max_2_0_tcyc_ps =
+ max(max_2_0_tcyc_ps, cycle_time_ps);
+ break;
+ }
+ }
+ }
+ }
+ debug("cas_available (bit map) = 0x%02X\n", cas_available);
+
+ /*------------------------------------------------------------------
+ * Set the SDRAM mode, SDRAM_MMODE
+ *-----------------------------------------------------------------*/
+
+ /* add 10 here because of rounding problems */
+ cycle_2_0_clk = MULDIV64(ONE_BILLION, 1000, max_2_0_tcyc_ps) + 10;
+ cycle_3_0_clk = MULDIV64(ONE_BILLION, 1000, max_3_0_tcyc_ps) + 10;
+ cycle_4_0_clk = MULDIV64(ONE_BILLION, 1000, max_4_0_tcyc_ps) + 10;
+ cycle_5_0_clk = MULDIV64(ONE_BILLION, 1000, max_5_0_tcyc_ps) + 10;
+ debug("cycle_2_0_clk = %ld\n", cycle_2_0_clk);
+ debug("cycle_3_0_clk = %ld\n", cycle_3_0_clk);
+ debug("cycle_4_0_clk = %ld\n", cycle_4_0_clk);
+ debug("cycle_5_0_clk = %ld\n", cycle_5_0_clk);
+
+ if ((cas_available & 0x04) && (sdram_freq <= cycle_2_0_clk)) {
+ *cas_latency = 2;
+ ddr0_03 |= DDR0_03_CASLAT_ENCODE(0x2) |
+ DDR0_03_CASLAT_LIN_ENCODE(0x4);
+ } else if ((cas_available & 0x08) && (sdram_freq <= cycle_3_0_clk)) {
+ *cas_latency = 3;
+ ddr0_03 |= DDR0_03_CASLAT_ENCODE(0x3) |
+ DDR0_03_CASLAT_LIN_ENCODE(0x6);
+ } else if ((cas_available & 0x10) && (sdram_freq <= cycle_4_0_clk)) {
+ *cas_latency = 4;
+ ddr0_03 |= DDR0_03_CASLAT_ENCODE(0x4) |
+ DDR0_03_CASLAT_LIN_ENCODE(0x8);
+ } else if ((cas_available & 0x20) && (sdram_freq <= cycle_5_0_clk)) {
+ *cas_latency = 5;
+ ddr0_03 |= DDR0_03_CASLAT_ENCODE(0x5) |
+ DDR0_03_CASLAT_LIN_ENCODE(0xA);
+ } else {
+ printf("ERROR: Cannot find a supported CAS latency with the "
+ "installed DIMMs.\n");
+ printf("Only DDR2 DIMMs with CAS latencies of 2.0, 3.0, 4.0, "
+ "and 5.0 are supported.\n");
+ printf("Make sure the PLB speed is within the supported range "
+ "of the DIMMs.\n");
+ printf("sdram_freq=%ld cycle2=%ld cycle3=%ld cycle4=%ld "
+ "cycle5=%ld\n\n", sdram_freq, cycle_2_0_clk,
+ cycle_3_0_clk, cycle_4_0_clk, cycle_5_0_clk);
+ spd_ddr_init_hang();
+ }
+ debug("CAS latency = %ld\n", *cas_latency);
+ mtsdram(DDR0_03, ddr0_03);
+}
+
+static void program_ddr0_04(unsigned long dimm_ranks[],
+ unsigned char const iic0_dimm_addr[],
+ unsigned long num_dimm_banks,
+ unsigned long sdram_freq)
+{
+ unsigned long dimm_num;
+ unsigned long t_rc_ps = 0;
+ unsigned long t_rrd_ps = 0;
+ unsigned long t_rtp_ps = 0;
+ unsigned long t_rc_clk;
+ unsigned long t_rrd_clk;
+ unsigned long t_rtp_clk;
+
+ /*------------------------------------------------------------------
+ * Handle the timing. We need to find the worst case timing of all
+ * the dimm modules installed.
+ *-----------------------------------------------------------------*/
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ /* If a dimm is installed in a particular slot ... */
+ if (dimm_ranks[dimm_num]) {
+ unsigned long ps;
+
+ /* tRC */
+ ps = 1000 * spd_read(iic0_dimm_addr[dimm_num], 41);
+ switch (spd_read(iic0_dimm_addr[dimm_num], 40) >> 4) {
+ case 0x1:
+ ps += 250;
+ break;
+ case 0x2:
+ ps += 333;
+ break;
+ case 0x3:
+ ps += 500;
+ break;
+ case 0x4:
+ ps += 667;
+ break;
+ case 0x5:
+ ps += 750;
+ break;
+ }
+ t_rc_ps = max(t_rc_ps, ps);
+ /* tRRD */
+ ps = 250 * spd_read(iic0_dimm_addr[dimm_num], 28);
+ t_rrd_ps = max(t_rrd_ps, ps);
+ /* tRTP */
+ ps = 250 * spd_read(iic0_dimm_addr[dimm_num], 38);
+ t_rtp_ps = max(t_rtp_ps, ps);
+ }
+ }
+ debug("t_rc_ps = %ld\n", t_rc_ps);
+ t_rc_clk = (MULDIV64(sdram_freq, t_rc_ps, ONE_BILLION) + 999) / 1000;
+ debug("t_rrd_ps = %ld\n", t_rrd_ps);
+ t_rrd_clk = (MULDIV64(sdram_freq, t_rrd_ps, ONE_BILLION) + 999) / 1000;
+ debug("t_rtp_ps = %ld\n", t_rtp_ps);
+ t_rtp_clk = (MULDIV64(sdram_freq, t_rtp_ps, ONE_BILLION) + 999) / 1000;
+ mtsdram(DDR0_04, DDR0_04_TRC_ENCODE(t_rc_clk) |
+ DDR0_04_TRRD_ENCODE(t_rrd_clk) |
+ DDR0_04_TRTP_ENCODE(t_rtp_clk));
+}
+
+static void program_ddr0_05(unsigned long dimm_ranks[],
+ unsigned char const iic0_dimm_addr[],
+ unsigned long num_dimm_banks,
+ unsigned long sdram_freq)
+{
+ unsigned long dimm_num;
+ unsigned long t_rp_ps = 0;
+ unsigned long t_ras_ps = 0;
+ unsigned long t_rp_clk;
+ unsigned long t_ras_clk;
+ u32 ddr0_05 = DDR0_05_TMRD_ENCODE(0x2) | DDR0_05_TEMRS_ENCODE(0x2);
+
+ /*------------------------------------------------------------------
+ * Handle the timing. We need to find the worst case timing of all
+ * the dimm modules installed.
+ *-----------------------------------------------------------------*/
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ /* If a dimm is installed in a particular slot ... */
+ if (dimm_ranks[dimm_num]) {
+ unsigned long ps;
+
+ /* tRP */
+ ps = 250 * spd_read(iic0_dimm_addr[dimm_num], 27);
+ t_rp_ps = max(t_rp_ps, ps);
+ /* tRAS */
+ ps = 1000 * spd_read(iic0_dimm_addr[dimm_num], 30);
+ t_ras_ps = max(t_ras_ps, ps);
+ }
+ }
+ debug("t_rp_ps = %ld\n", t_rp_ps);
+ t_rp_clk = (MULDIV64(sdram_freq, t_rp_ps, ONE_BILLION) + 999) / 1000;
+ debug("t_ras_ps = %ld\n", t_ras_ps);
+ t_ras_clk = (MULDIV64(sdram_freq, t_ras_ps, ONE_BILLION) + 999) / 1000;
+ mtsdram(DDR0_05, ddr0_05 | DDR0_05_TRP_ENCODE(t_rp_clk) |
+ DDR0_05_TRAS_MIN_ENCODE(t_ras_clk));
+}
+
+static void program_ddr0_06(unsigned long dimm_ranks[],
+ unsigned char const iic0_dimm_addr[],
+ unsigned long num_dimm_banks,
+ unsigned long sdram_freq)
+{
+ unsigned long dimm_num;
+ unsigned char spd_40;
+ unsigned long t_wtr_ps = 0;
+ unsigned long t_rfc_ps = 0;
+ unsigned long t_wtr_clk;
+ unsigned long t_rfc_clk;
+ u32 ddr0_06 =
+ DDR0_06_WRITEINTERP_ENCODE(0x1) | DDR0_06_TDLL_ENCODE(200);
+
+ /*------------------------------------------------------------------
+ * Handle the timing. We need to find the worst case timing of all
+ * the dimm modules installed.
+ *-----------------------------------------------------------------*/
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ /* If a dimm is installed in a particular slot ... */
+ if (dimm_ranks[dimm_num]) {
+ unsigned long ps;
+
+ /* tWTR */
+ ps = 250 * spd_read(iic0_dimm_addr[dimm_num], 37);
+ t_wtr_ps = max(t_wtr_ps, ps);
+ /* tRFC */
+ ps = 1000 * spd_read(iic0_dimm_addr[dimm_num], 42);
+ spd_40 = spd_read(iic0_dimm_addr[dimm_num], 40);
+ ps += 256000 * (spd_40 & 0x01);
+ switch ((spd_40 & 0x0E) >> 1) {
+ case 0x1:
+ ps += 250;
+ break;
+ case 0x2:
+ ps += 333;
+ break;
+ case 0x3:
+ ps += 500;
+ break;
+ case 0x4:
+ ps += 667;
+ break;
+ case 0x5:
+ ps += 750;
+ break;
+ }
+ t_rfc_ps = max(t_rfc_ps, ps);
+ }
+ }
+ debug("t_wtr_ps = %ld\n", t_wtr_ps);
+ t_wtr_clk = (MULDIV64(sdram_freq, t_wtr_ps, ONE_BILLION) + 999) / 1000;
+ debug("t_rfc_ps = %ld\n", t_rfc_ps);
+ t_rfc_clk = (MULDIV64(sdram_freq, t_rfc_ps, ONE_BILLION) + 999) / 1000;
+ mtsdram(DDR0_06, ddr0_06 | DDR0_06_TWTR_ENCODE(t_wtr_clk) |
+ DDR0_06_TRFC_ENCODE(t_rfc_clk));
+}
+
+static void program_ddr0_10(unsigned long dimm_ranks[], unsigned long ranks)
+{
+ unsigned long csmap;
+
+ if (2 == ranks) {
+ /* Both chip selects in use */
+ csmap = 0x03;
+ } else {
+ /* One chip select in use */
+ csmap = (1 == dimm_ranks[0]) ? 0x1 : 0x2;
+ }
+ mtsdram(DDR0_10, DDR0_10_WRITE_MODEREG_ENCODE(0x0) |
+ DDR0_10_CS_MAP_ENCODE(csmap) |
+ DDR0_10_OCD_ADJUST_PUP_CS_0_ENCODE(0));
+}
+
+static void program_ddr0_11(unsigned long sdram_freq)
+{
+ unsigned long const t_xsnr_ps = 200000; /* 200 ns */
+ unsigned long t_xsnr_clk;
+
+ debug("t_xsnr_ps = %ld\n", t_xsnr_ps);
+ t_xsnr_clk =
+ (MULDIV64(sdram_freq, t_xsnr_ps, ONE_BILLION) + 999) / 1000;
+ mtsdram(DDR0_11, DDR0_11_SREFRESH_ENCODE(0) |
+ DDR0_11_TXSNR_ENCODE(t_xsnr_clk) | DDR0_11_TXSR_ENCODE(200));
+}
+
+static void program_ddr0_22(unsigned long dimm_ranks[],
+ unsigned char const iic0_dimm_addr[],
+ unsigned long num_dimm_banks, unsigned long width)
+{
+#if defined(CONFIG_DDR_ECC)
+ unsigned long dimm_num;
+ unsigned long ecc_available = width >= 64;
+ u32 ddr0_22 = DDR0_22_DQS_OUT_SHIFT_BYPASS_ENCODE(0x26) |
+ DDR0_22_DQS_OUT_SHIFT_ENCODE(DQS_OUT_SHIFT) |
+ DDR0_22_DLL_DQS_BYPASS_8_ENCODE(DLL_DQS_BYPASS);
+
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ /* If a dimm is installed in a particular slot ... */
+ if (dimm_ranks[dimm_num]) {
+ /* Check for ECC */
+ if (0 == (spd_read(iic0_dimm_addr[dimm_num], 11) &
+ 0x02)) {
+ ecc_available = false;
+ }
+ }
+ }
+ if (ecc_available) {
+ debug("ECC found on all DIMMs present\n");
+ mtsdram(DDR0_22, ddr0_22 | DDR0_22_CTRL_RAW_ENCODE(0x3));
+ } else {
+ debug("ECC not found on some or all DIMMs present\n");
+ mtsdram(DDR0_22, ddr0_22 | DDR0_22_CTRL_RAW_ENCODE(0x0));
+ }
+#else
+ mtsdram(DDR0_22, DDR0_22_CTRL_RAW_ENCODE(0x0) |
+ DDR0_22_DQS_OUT_SHIFT_BYPASS_ENCODE(0x26) |
+ DDR0_22_DQS_OUT_SHIFT_ENCODE(DQS_OUT_SHIFT) |
+ DDR0_22_DLL_DQS_BYPASS_8_ENCODE(DLL_DQS_BYPASS));
+#endif /* defined(CONFIG_DDR_ECC) */
+}
+
+static void program_ddr0_24(unsigned long ranks)
+{
+ u32 ddr0_24 = DDR0_24_RTT_PAD_TERMINATION_ENCODE(0x1) | /* 75 ohm */
+ DDR0_24_ODT_RD_MAP_CS1_ENCODE(0x0);
+
+ if (2 == ranks) {
+ /* Both chip selects in use */
+ ddr0_24 |= DDR0_24_ODT_WR_MAP_CS1_ENCODE(0x1) |
+ DDR0_24_ODT_WR_MAP_CS0_ENCODE(0x2);
+ } else {
+ /* One chip select in use */
+ /* One of the two fields added to ddr0_24 is a "don't care" */
+ ddr0_24 |= DDR0_24_ODT_WR_MAP_CS1_ENCODE(0x2) |
+ DDR0_24_ODT_WR_MAP_CS0_ENCODE(0x1);
+ }
+ mtsdram(DDR0_24, ddr0_24);
+}
+
+static void program_ddr0_26(unsigned long sdram_freq)
+{
+ unsigned long const t_ref_ps = 7800000; /* 7.8 us. refresh */
+ /* TODO: check definition of tRAS_MAX */
+ unsigned long const t_ras_max_ps = 9 * t_ref_ps;
+ unsigned long t_ras_max_clk;
+ unsigned long t_ref_clk;
+
+ /* Round down t_ras_max_clk and t_ref_clk */
+ debug("t_ras_max_ps = %ld\n", t_ras_max_ps);
+ t_ras_max_clk = MULDIV64(sdram_freq, t_ras_max_ps, ONE_BILLION) / 1000;
+ debug("t_ref_ps = %ld\n", t_ref_ps);
+ t_ref_clk = MULDIV64(sdram_freq, t_ref_ps, ONE_BILLION) / 1000;
+ mtsdram(DDR0_26, DDR0_26_TRAS_MAX_ENCODE(t_ras_max_clk) |
+ DDR0_26_TREF_ENCODE(t_ref_clk));
+}
+
+static void program_ddr0_27(unsigned long sdram_freq)
+{
+ unsigned long const t_init_ps = 200000000; /* 200 us. init */
+ unsigned long t_init_clk;
+
+ debug("t_init_ps = %ld\n", t_init_ps);
+ t_init_clk =
+ (MULDIV64(sdram_freq, t_init_ps, ONE_BILLION) + 999) / 1000;
+ mtsdram(DDR0_27, DDR0_27_EMRS_DATA_ENCODE(0x0000) |
+ DDR0_27_TINIT_ENCODE(t_init_clk));
+}
+
+static void program_ddr0_43(unsigned long dimm_ranks[],
+ unsigned char const iic0_dimm_addr[],
+ unsigned long num_dimm_banks,
+ unsigned long sdram_freq,
+ unsigned long cols, unsigned long banks)
+{
+ unsigned long dimm_num;
+ unsigned long t_wr_ps = 0;
+ unsigned long t_wr_clk;
+ u32 ddr0_43 = DDR0_43_APREBIT_ENCODE(10) |
+ DDR0_43_COLUMN_SIZE_ENCODE(12 - cols) |
+ DDR0_43_EIGHT_BANK_MODE_ENCODE(8 == banks ? 1 : 0);
+
+ /*------------------------------------------------------------------
+ * Handle the timing. We need to find the worst case timing of all
+ * the dimm modules installed.
+ *-----------------------------------------------------------------*/
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ /* If a dimm is installed in a particular slot ... */
+ if (dimm_ranks[dimm_num]) {
+ unsigned long ps;
+
+ ps = 250 * spd_read(iic0_dimm_addr[dimm_num], 36);
+ t_wr_ps = max(t_wr_ps, ps);
+ }
+ }
+ debug("t_wr_ps = %ld\n", t_wr_ps);
+ t_wr_clk = (MULDIV64(sdram_freq, t_wr_ps, ONE_BILLION) + 999) / 1000;
+ mtsdram(DDR0_43, ddr0_43 | DDR0_43_TWR_ENCODE(t_wr_clk));
+}
+
+static void program_ddr0_44(unsigned long dimm_ranks[],
+ unsigned char const iic0_dimm_addr[],
+ unsigned long num_dimm_banks,
+ unsigned long sdram_freq)
+{
+ unsigned long dimm_num;
+ unsigned long t_rcd_ps = 0;
+ unsigned long t_rcd_clk;
+
+ /*------------------------------------------------------------------
+ * Handle the timing. We need to find the worst case timing of all
+ * the dimm modules installed.
+ *-----------------------------------------------------------------*/
+ /* loop through all the DIMM slots on the board */
+ for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) {
+ /* If a dimm is installed in a particular slot ... */
+ if (dimm_ranks[dimm_num]) {
+ unsigned long ps;
+
+ ps = 250 * spd_read(iic0_dimm_addr[dimm_num], 29);
+ t_rcd_ps = max(t_rcd_ps, ps);
+ }
+ }
+ debug("t_rcd_ps = %ld\n", t_rcd_ps);
+ t_rcd_clk = (MULDIV64(sdram_freq, t_rcd_ps, ONE_BILLION) + 999) / 1000;
+ mtsdram(DDR0_44, DDR0_44_TRCD_ENCODE(t_rcd_clk));
+}
+
+/*-----------------------------------------------------------------------------+
+ * initdram. Initializes the 440EPx/GPx DDR SDRAM controller.
+ * Note: This routine runs from flash with a stack set up in the chip's
+ * sram space. It is important that the routine does not require .sbss, .bss or
+ * .data sections. It also cannot call routines that require these sections.
+ *-----------------------------------------------------------------------------*/
+/*-----------------------------------------------------------------------------
+ * Function: initdram
+ * Description: Configures SDRAM memory banks for DDR operation.
+ * Auto Memory Configuration option reads the DDR SDRAM EEPROMs
+ * via the IIC bus and then configures the DDR SDRAM memory
+ * banks appropriately. If Auto Memory Configuration is
+ * not used, it is assumed that no DIMM is plugged
+ *-----------------------------------------------------------------------------*/
+phys_size_t initdram(int board_type)
+{
+ unsigned char const iic0_dimm_addr[] = SPD_EEPROM_ADDRESS;
+ unsigned long dimm_ranks[MAXDIMMS];
+ unsigned long ranks;
+ unsigned long rows;
+ unsigned long banks;
+ unsigned long cols;
+ unsigned long width;
+ unsigned long const sdram_freq = get_bus_freq(0);
+ unsigned long const num_dimm_banks = sizeof(iic0_dimm_addr); /* on board dimm banks */
+ unsigned long cas_latency = 0; /* to quiet initialization warning */
+ unsigned long dram_size;
+
+ debug("\nEntering initdram()\n");
+
+ /*------------------------------------------------------------------
+ * Stop the DDR-SDRAM controller.
+ *-----------------------------------------------------------------*/
+ mtsdram(DDR0_02, DDR0_02_START_ENCODE(0));
+
+ /*
+ * Make sure I2C controller is initialized
+ * before continuing.
+ */
+ /* switch to correct I2C bus */
+ I2C_SET_BUS(CONFIG_SYS_SPD_BUS_NUM);
+ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+ /*------------------------------------------------------------------
+ * Clear out the serial presence detect buffers.
+ * Perform IIC reads from the dimm. Fill in the spds.
+ * Check to see if the dimm slots are populated
+ *-----------------------------------------------------------------*/
+ get_spd_info(dimm_ranks, &ranks, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Check the frequency supported for the dimms plugged.
+ *-----------------------------------------------------------------*/
+ check_frequency(dimm_ranks, iic0_dimm_addr, num_dimm_banks, sdram_freq);
+
+ /*------------------------------------------------------------------
+ * Check and get size information.
+ *-----------------------------------------------------------------*/
+ get_dimm_size(dimm_ranks, iic0_dimm_addr, num_dimm_banks, &rows, &banks,
+ &cols, &width);
+
+ /*------------------------------------------------------------------
+ * Check the voltage type for the dimms plugged.
+ *-----------------------------------------------------------------*/
+ check_voltage_type(dimm_ranks, iic0_dimm_addr, num_dimm_banks);
+
+ /*------------------------------------------------------------------
+ * Program registers for SDRAM controller.
+ *-----------------------------------------------------------------*/
+ mtsdram(DDR0_00, DDR0_00_DLL_INCREMENT_ENCODE(0x19) |
+ DDR0_00_DLL_START_POINT_DECODE(0x0A));
+
+ mtsdram(DDR0_01, DDR0_01_PLB0_DB_CS_LOWER_ENCODE(0x01) |
+ DDR0_01_PLB0_DB_CS_UPPER_ENCODE(0x00) |
+ DDR0_01_INT_MASK_ENCODE(0xFF));
+
+ program_ddr0_03(dimm_ranks, iic0_dimm_addr, num_dimm_banks, sdram_freq,
+ rows, &cas_latency);
+
+ program_ddr0_04(dimm_ranks, iic0_dimm_addr, num_dimm_banks, sdram_freq);
+
+ program_ddr0_05(dimm_ranks, iic0_dimm_addr, num_dimm_banks, sdram_freq);
+
+ program_ddr0_06(dimm_ranks, iic0_dimm_addr, num_dimm_banks, sdram_freq);
+
+ /*
+ * TODO: tFAW not found in SPD. Value of 13 taken from Sequoia
+ * board SDRAM, but may be overly conservative.
+ */
+ mtsdram(DDR0_07, DDR0_07_NO_CMD_INIT_ENCODE(0) |
+ DDR0_07_TFAW_ENCODE(13) |
+ DDR0_07_AUTO_REFRESH_MODE_ENCODE(1) |
+ DDR0_07_AREFRESH_ENCODE(0));
+
+ mtsdram(DDR0_08, DDR0_08_WRLAT_ENCODE(cas_latency - 1) |
+ DDR0_08_TCPD_ENCODE(200) | DDR0_08_DQS_N_EN_ENCODE(0) |
+ DDR0_08_DDRII_ENCODE(1));
+
+ mtsdram(DDR0_09, DDR0_09_OCD_ADJUST_PDN_CS_0_ENCODE(0x00) |
+ DDR0_09_RTT_0_ENCODE(0x1) |
+ DDR0_09_WR_DQS_SHIFT_BYPASS_ENCODE(0x1D) |
+ DDR0_09_WR_DQS_SHIFT_ENCODE(DQS_OUT_SHIFT - 0x20));
+
+ program_ddr0_10(dimm_ranks, ranks);
+
+ program_ddr0_11(sdram_freq);
+
+ mtsdram(DDR0_12, DDR0_12_TCKE_ENCODE(3));
+
+ mtsdram(DDR0_14, DDR0_14_DLL_BYPASS_MODE_ENCODE(0) |
+ DDR0_14_REDUC_ENCODE(width <= 40 ? 1 : 0) |
+ DDR0_14_REG_DIMM_ENABLE_ENCODE(0));
+
+ mtsdram(DDR0_17, DDR0_17_DLL_DQS_DELAY_0_ENCODE(DLL_DQS_DELAY));
+
+ mtsdram(DDR0_18, DDR0_18_DLL_DQS_DELAY_4_ENCODE(DLL_DQS_DELAY) |
+ DDR0_18_DLL_DQS_DELAY_3_ENCODE(DLL_DQS_DELAY) |
+ DDR0_18_DLL_DQS_DELAY_2_ENCODE(DLL_DQS_DELAY) |
+ DDR0_18_DLL_DQS_DELAY_1_ENCODE(DLL_DQS_DELAY));
+
+ mtsdram(DDR0_19, DDR0_19_DLL_DQS_DELAY_8_ENCODE(DLL_DQS_DELAY) |
+ DDR0_19_DLL_DQS_DELAY_7_ENCODE(DLL_DQS_DELAY) |
+ DDR0_19_DLL_DQS_DELAY_6_ENCODE(DLL_DQS_DELAY) |
+ DDR0_19_DLL_DQS_DELAY_5_ENCODE(DLL_DQS_DELAY));
+
+ mtsdram(DDR0_20, DDR0_20_DLL_DQS_BYPASS_3_ENCODE(DLL_DQS_BYPASS) |
+ DDR0_20_DLL_DQS_BYPASS_2_ENCODE(DLL_DQS_BYPASS) |
+ DDR0_20_DLL_DQS_BYPASS_1_ENCODE(DLL_DQS_BYPASS) |
+ DDR0_20_DLL_DQS_BYPASS_0_ENCODE(DLL_DQS_BYPASS));
+
+ mtsdram(DDR0_21, DDR0_21_DLL_DQS_BYPASS_7_ENCODE(DLL_DQS_BYPASS) |
+ DDR0_21_DLL_DQS_BYPASS_6_ENCODE(DLL_DQS_BYPASS) |
+ DDR0_21_DLL_DQS_BYPASS_5_ENCODE(DLL_DQS_BYPASS) |
+ DDR0_21_DLL_DQS_BYPASS_4_ENCODE(DLL_DQS_BYPASS));
+
+ program_ddr0_22(dimm_ranks, iic0_dimm_addr, num_dimm_banks, width);
+
+ mtsdram(DDR0_23, DDR0_23_ODT_RD_MAP_CS0_ENCODE(0x0) |
+ DDR0_23_FWC_ENCODE(0));
+
+ program_ddr0_24(ranks);
+
+ program_ddr0_26(sdram_freq);
+
+ program_ddr0_27(sdram_freq);
+
+ mtsdram(DDR0_28, DDR0_28_EMRS3_DATA_ENCODE(0x0000) |
+ DDR0_28_EMRS2_DATA_ENCODE(0x0000));
+
+ mtsdram(DDR0_31, DDR0_31_XOR_CHECK_BITS_ENCODE(0x0000));
+
+ mtsdram(DDR0_42, DDR0_42_ADDR_PINS_ENCODE(14 - rows) |
+ DDR0_42_CASLAT_LIN_GATE_ENCODE(2 * cas_latency));
+
+ program_ddr0_43(dimm_ranks, iic0_dimm_addr, num_dimm_banks, sdram_freq,
+ cols, banks);
+
+ program_ddr0_44(dimm_ranks, iic0_dimm_addr, num_dimm_banks, sdram_freq);
+
+ denali_sdram_register_dump();
+
+ dram_size = (width >= 64) ? 8 : 4;
+ dram_size *= 1 << cols;
+ dram_size *= banks;
+ dram_size *= 1 << rows;
+ dram_size *= ranks;
+ debug("dram_size = %lu\n", dram_size);
+
+ /* Start the SDRAM controler */
+ mtsdram(DDR0_02, DDR0_02_START_ENCODE(1));
+ denali_wait_for_dlllock();
+
+#if defined(CONFIG_DDR_DATA_EYE)
+ /*
+ * Map the first 1 MiB of memory in the TLB, and perform the data eye
+ * search.
+ */
+ program_tlb(0, CONFIG_SYS_SDRAM_BASE, TLB_1MB_SIZE, TLB_WORD2_I_ENABLE);
+ denali_core_search_data_eye();
+ denali_sdram_register_dump();
+ remove_tlb(CONFIG_SYS_SDRAM_BASE, TLB_1MB_SIZE);
+#endif
+
+#if defined(CONFIG_ZERO_SDRAM) || defined(CONFIG_DDR_ECC)
+ program_tlb(0, CONFIG_SYS_SDRAM_BASE, dram_size, 0);
+ sync();
+ /* Zero the memory */
+ debug("Zeroing SDRAM...");
+#if defined(CONFIG_SYS_MEM_TOP_HIDE)
+ dcbz_area(CONFIG_SYS_SDRAM_BASE, dram_size - CONFIG_SYS_MEM_TOP_HIDE);
+#else
+#error Please define CONFIG_SYS_MEM_TOP_HIDE (see README) in your board config file
+#endif
+ /* Write modified dcache lines back to memory */
+ clean_dcache_range(CONFIG_SYS_SDRAM_BASE, CONFIG_SYS_SDRAM_BASE + dram_size - CONFIG_SYS_MEM_TOP_HIDE);
+ debug("Completed\n");
+ sync();
+ remove_tlb(CONFIG_SYS_SDRAM_BASE, dram_size);
+
+#if defined(CONFIG_DDR_ECC)
+ /*
+ * If ECC is enabled, clear and enable interrupts
+ */
+ if (is_ecc_enabled()) {
+ u32 val;
+
+ sync();
+ /* Clear error status */
+ mfsdram(DDR0_00, val);
+ mtsdram(DDR0_00, val | DDR0_00_INT_ACK_ALL);
+ /* Set 'int_mask' parameter to functionnal value */
+ mfsdram(DDR0_01, val);
+ mtsdram(DDR0_01, (val & ~DDR0_01_INT_MASK_MASK) |
+ DDR0_01_INT_MASK_ALL_OFF);
+#if defined(CONFIG_DDR_DATA_EYE)
+ /*
+ * Running denali_core_search_data_eye() when ECC is enabled
+ * causes non-ECC machine checks. This clears them.
+ */
+ print_mcsr();
+ mtspr(SPRN_MCSR, mfspr(SPRN_MCSR));
+ print_mcsr();
+#endif
+ sync();
+ }
+#endif /* defined(CONFIG_DDR_ECC) */
+#endif /* defined(CONFIG_ZERO_SDRAM) || defined(CONFIG_DDR_ECC) */
+
+ program_tlb(0, CONFIG_SYS_SDRAM_BASE, dram_size, MY_TLB_WORD2_I_ENABLE);
+ return dram_size;
+}
+
+void board_add_ram_info(int use_default)
+{
+ u32 val;
+
+ printf(" (ECC");
+ if (!is_ecc_enabled()) {
+ printf(" not");
+ }
+ printf(" enabled, %ld MHz", (2 * get_bus_freq(0)) / 1000000);
+
+ mfsdram(DDR0_03, val);
+ printf(", CL%d)", DDR0_03_CASLAT_LIN_DECODE(val) >> 1);
+}
+#endif /* CONFIG_SPD_EEPROM */
diff --git a/arch/powerpc/cpu/ppc4xx/ecc.c b/arch/powerpc/cpu/ppc4xx/ecc.c
new file mode 100644
index 0000000..7fe5dbb
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/ecc.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2008 Nuovation System Designs, LLC
+ * Grant Erickson <gerickson@nuovations.com>
+ *
+ * (C) Copyright 2005-2009
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * (C) Copyright 2002
+ * Jun Gu, Artesyn Technology, jung@artesyncp.com
+ *
+ * (C) Copyright 2001
+ * Bill Hunter, Wave 7 Optics, williamhunter@attbi.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will abe useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Description:
+ * This file implements generic DRAM ECC initialization for
+ * PowerPC processors using a SDRAM DDR/DDR2 controller,
+ * including the 405EX(r), 440GP/GX/EP/GR, 440SP(E), and
+ * 460EX/GT.
+ */
+
+#include <common.h>
+#include <asm/ppc4xx.h>
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/mmu.h>
+#include <asm/cache.h>
+
+#include "ecc.h"
+
+#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR) || \
+ defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
+#if defined(CONFIG_DDR_ECC) || defined(CONFIG_SDRAM_ECC)
+
+#if defined(CONFIG_405EX)
+/*
+ * Currently only 405EX uses 16bit data bus width as an alternative
+ * option to 32bit data width (SDRAM0_MCOPT1_WDTH)
+ */
+#define SDRAM_DATA_ALT_WIDTH 2
+#else
+#define SDRAM_DATA_ALT_WIDTH 8
+#endif
+
+static void wait_ddr_idle(void)
+{
+ u32 val;
+
+ do {
+ mfsdram(SDRAM_MCSTAT, val);
+ } while ((val & SDRAM_MCSTAT_IDLE_MASK) == SDRAM_MCSTAT_IDLE_NOT);
+}
+
+static void program_ecc_addr(unsigned long start_address,
+ unsigned long num_bytes,
+ unsigned long tlb_word2_i_value)
+{
+ unsigned long current_address;
+ unsigned long end_address;
+ unsigned long address_increment;
+ unsigned long mcopt1;
+ char str[] = "ECC generation -";
+ char slash[] = "\\|/-\\|/-";
+ int loop = 0;
+ int loopi = 0;
+
+ current_address = start_address;
+ mfsdram(SDRAM_MCOPT1, mcopt1);
+ if ((mcopt1 & SDRAM_MCOPT1_MCHK_MASK) != SDRAM_MCOPT1_MCHK_NON) {
+ mtsdram(SDRAM_MCOPT1,
+ (mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_GEN);
+ sync();
+ eieio();
+ wait_ddr_idle();
+
+ puts(str);
+
+#ifdef CONFIG_440
+ if (tlb_word2_i_value == TLB_WORD2_I_ENABLE) {
+#endif
+ /* ECC bit set method for non-cached memory */
+ if ((mcopt1 & SDRAM_MCOPT1_DMWD_MASK) == SDRAM_MCOPT1_DMWD_32)
+ address_increment = 4;
+ else
+ address_increment = SDRAM_DATA_ALT_WIDTH;
+ end_address = current_address + num_bytes;
+
+ while (current_address < end_address) {
+ *((unsigned long *)current_address) = 0;
+ current_address += address_increment;
+
+ if ((loop++ % (2 << 20)) == 0) {
+ putc('\b');
+ putc(slash[loopi++ % 8]);
+ }
+ }
+#ifdef CONFIG_440
+ } else {
+ /* ECC bit set method for cached memory */
+ dcbz_area(start_address, num_bytes);
+ /* Write modified dcache lines back to memory */
+ clean_dcache_range(start_address, start_address + num_bytes);
+ }
+#endif /* CONFIG_440 */
+
+ blank_string(strlen(str));
+
+ sync();
+ eieio();
+ wait_ddr_idle();
+
+ /* clear ECC error repoting registers */
+ mtsdram(SDRAM_ECCES, 0xffffffff);
+#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)
+ /*
+ * IBM DDR(1) core (440GX):
+ * Clear Mx bits in SDRAM0_BESR0/1
+ */
+ mtsdram(SDRAM0_BESR0, 0xffffffff);
+ mtsdram(SDRAM0_BESR1, 0xffffffff);
+#elif defined(CONFIG_440)
+ /*
+ * 440/460 DDR2 core:
+ * Clear EMID (Error PLB Master ID) in MQ0_ESL
+ */
+ mtdcr(SDRAM_ERRSTATLL, 0xfff00000);
+#else
+ /*
+ * 405EX(r) DDR2 core:
+ * Clear M0ID (Error PLB Master ID) in SDRAM_BESR
+ */
+ mtsdram(SDRAM_BESR, 0xf0000000);
+#endif
+
+ mtsdram(SDRAM_MCOPT1,
+ (mcopt1 & ~SDRAM_MCOPT1_MCHK_MASK) | SDRAM_MCOPT1_MCHK_CHK_REP);
+ sync();
+ eieio();
+ wait_ddr_idle();
+ }
+}
+
+#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)
+void ecc_init(unsigned long * const start, unsigned long size)
+{
+ /*
+ * Init ECC with cache disabled (on PPC's with IBM DDR
+ * controller (non DDR2), not tested with cache enabled yet
+ */
+ program_ecc_addr((u32)start, size, TLB_WORD2_I_ENABLE);
+}
+#endif
+
+#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
+void do_program_ecc(unsigned long tlb_word2_i_value)
+{
+ unsigned long mcopt1;
+ unsigned long mcopt2;
+ unsigned long mcstat;
+ phys_size_t memsize = sdram_memsize();
+
+ if (memsize > CONFIG_MAX_MEM_MAPPED) {
+ printf("\nWarning: Can't enable ECC on systems with more than 2GB of SDRAM!\n");
+ return;
+ }
+
+ mfsdram(SDRAM_MCOPT1, mcopt1);
+ mfsdram(SDRAM_MCOPT2, mcopt2);
+
+ if ((mcopt1 & SDRAM_MCOPT1_MCHK_MASK) != SDRAM_MCOPT1_MCHK_NON) {
+ /* DDR controller must be enabled and not in self-refresh. */
+ mfsdram(SDRAM_MCSTAT, mcstat);
+ if (((mcopt2 & SDRAM_MCOPT2_DCEN_MASK) == SDRAM_MCOPT2_DCEN_ENABLE)
+ && ((mcopt2 & SDRAM_MCOPT2_SREN_MASK) == SDRAM_MCOPT2_SREN_EXIT)
+ && ((mcstat & (SDRAM_MCSTAT_MIC_MASK | SDRAM_MCSTAT_SRMS_MASK))
+ == (SDRAM_MCSTAT_MIC_COMP | SDRAM_MCSTAT_SRMS_NOT_SF))) {
+
+ program_ecc_addr(0, memsize, tlb_word2_i_value);
+ }
+ }
+}
+#endif
+
+#endif /* defined(CONFIG_DDR_ECC) || defined(CONFIG_SDRAM_ECC) */
+#endif /* defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)... */
diff --git a/arch/powerpc/cpu/ppc4xx/ecc.h b/arch/powerpc/cpu/ppc4xx/ecc.h
new file mode 100644
index 0000000..b258891
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/ecc.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2008 Nuovation System Designs, LLC
+ * Grant Erickson <gerickson@nuovations.com>
+ *
+ * Copyright (c) 2007-2009 DENX Software Engineering, GmbH
+ * Stefan Roese <sr@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will abe useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Description:
+ * This file implements ECC initialization for PowerPC processors
+ * using the IBM SDRAM DDR1 & DDR2 controller.
+ *
+ */
+
+#ifndef _ECC_H_
+#define _ECC_H_
+
+/*
+ * Since the IBM DDR controller used on 440GP/GX/EP/GR is not register
+ * compatible to the IBM DDR/2 controller used on 405EX/440SP/SPe/460EX/GT
+ * we need to make some processor dependant defines used later on by the
+ * driver.
+ */
+
+/* For 440GP/GX/EP/GR */
+#if defined(CONFIG_SDRAM_PPC4xx_IBM_DDR)
+#define SDRAM_MCOPT1 SDRAM_CFG0
+#define SDRAM_MCOPT1_MCHK_MASK SDRAM_CFG0_MCHK_MASK
+#define SDRAM_MCOPT1_MCHK_NON SDRAM_CFG0_MCHK_NON
+#define SDRAM_MCOPT1_MCHK_GEN SDRAM_CFG0_MCHK_GEN
+#define SDRAM_MCOPT1_MCHK_CHK SDRAM_CFG0_MCHK_CHK
+#define SDRAM_MCOPT1_MCHK_CHK_REP SDRAM_CFG0_MCHK_CHK
+#define SDRAM_MCOPT1_DMWD_MASK SDRAM_CFG0_DMWD_MASK
+#define SDRAM_MCOPT1_DMWD_32 SDRAM_CFG0_DMWD_32
+
+#define SDRAM_MCSTAT SDRAM0_MCSTS
+#define SDRAM_MCSTAT_IDLE_MASK SDRAM_MCSTS_CIS
+#define SDRAM_MCSTAT_IDLE_NOT SDRAM_MCSTS_IDLE_NOT
+
+#define SDRAM_ECCES SDRAM0_ECCESR
+#endif
+
+void ecc_init(unsigned long * const start, unsigned long size);
+void do_program_ecc(unsigned long tlb_word2_i_value);
+
+static void inline blank_string(int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++)
+ putc('\b');
+ for (i = 0; i < size; i++)
+ putc(' ');
+ for (i = 0; i < size; i++)
+ putc('\b');
+}
+
+#endif /* _ECC_H_ */
diff --git a/arch/powerpc/cpu/ppc4xx/fdt.c b/arch/powerpc/cpu/ppc4xx/fdt.c
new file mode 100644
index 0000000..3cdd531
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/fdt.c
@@ -0,0 +1,176 @@
+/*
+ * (C) Copyright 2007-2008
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <asm/cache.h>
+#include <asm/ppc4xx.h>
+
+#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
+#include <libfdt.h>
+#include <fdt_support.h>
+#include <asm/4xx_pcie.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void __ft_board_setup(void *blob, bd_t *bd)
+{
+ int rc;
+ int i;
+ u32 bxcr;
+ u32 ranges[EBC_NUM_BANKS * 4];
+ u32 *p = ranges;
+ char ebc_path[] = "/plb/opb/ebc";
+
+ ft_cpu_setup(blob, bd);
+
+ /*
+ * Read 4xx EBC bus bridge registers to get mappings of the
+ * peripheral banks into the OPB/PLB address space
+ */
+ for (i = 0; i < EBC_NUM_BANKS; i++) {
+ mtdcr(EBC0_CFGADDR, EBC_BXCR(i));
+ bxcr = mfdcr(EBC0_CFGDATA);
+
+ if ((bxcr & EBC_BXCR_BU_MASK) != EBC_BXCR_BU_NONE) {
+ *p++ = i;
+ *p++ = 0;
+ *p++ = bxcr & EBC_BXCR_BAS_MASK;
+ *p++ = EBC_BXCR_BANK_SIZE(bxcr);
+ }
+ }
+
+
+#ifdef CONFIG_FDT_FIXUP_NOR_FLASH_SIZE
+ /* Update reg property in all nor flash nodes too */
+ fdt_fixup_nor_flash_size(blob);
+#endif
+
+ /* Some 405 PPC's have EBC as direct PLB child in the dts */
+ if (fdt_path_offset(blob, ebc_path) < 0)
+ strcpy(ebc_path, "/plb/ebc");
+ rc = fdt_find_and_setprop(blob, ebc_path, "ranges", ranges,
+ (p - ranges) * sizeof(u32), 1);
+ if (rc) {
+ printf("Unable to update property EBC mappings, err=%s\n",
+ fdt_strerror(rc));
+ }
+}
+void ft_board_setup(void *blob, bd_t *bd) __attribute__((weak, alias("__ft_board_setup")));
+
+/*
+ * Fixup all PCIe nodes by setting the device_type property
+ * to "pci-endpoint" instead is "pci" for endpoint ports.
+ * This property will get checked later by the Linux driver
+ * to properly configure the PCIe port in Linux (again).
+ */
+void fdt_pcie_setup(void *blob)
+{
+ const char *compat = "ibm,plb-pciex";
+ const char *prop = "device_type";
+ const char *prop_val = "pci-endpoint";
+ const u32 *port;
+ int no;
+ int rc;
+
+ /* Search first PCIe node */
+ no = fdt_node_offset_by_compatible(blob, -1, compat);
+ while (no != -FDT_ERR_NOTFOUND) {
+ port = fdt_getprop(blob, no, "port", NULL);
+ if (port == NULL) {
+ printf("WARNING: could not find port property\n");
+ } else {
+ if (is_end_point(*port)) {
+ rc = fdt_setprop(blob, no, prop, prop_val,
+ strlen(prop_val) + 1);
+ if (rc < 0)
+ printf("WARNING: could not set %s for %s: %s.\n",
+ prop, compat, fdt_strerror(rc));
+ }
+ }
+
+ /* Jump to next PCIe node */
+ no = fdt_node_offset_by_compatible(blob, no, compat);
+ }
+}
+
+void ft_cpu_setup(void *blob, bd_t *bd)
+{
+ sys_info_t sys_info;
+ int off, ndepth = 0;
+
+ get_sys_info(&sys_info);
+
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4, "timebase-frequency",
+ bd->bi_intfreq, 1);
+ do_fixup_by_prop_u32(blob, "device_type", "cpu", 4, "clock-frequency",
+ bd->bi_intfreq, 1);
+ do_fixup_by_path_u32(blob, "/plb", "clock-frequency", sys_info.freqPLB, 1);
+ do_fixup_by_path_u32(blob, "/plb/opb", "clock-frequency", sys_info.freqOPB, 1);
+
+ if (fdt_path_offset(blob, "/plb/opb/ebc") >= 0)
+ do_fixup_by_path_u32(blob, "/plb/opb/ebc", "clock-frequency",
+ sys_info.freqEBC, 1);
+ else
+ do_fixup_by_path_u32(blob, "/plb/ebc", "clock-frequency",
+ sys_info.freqEBC, 1);
+
+ fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
+
+ /*
+ * Fixup all UART clocks for CPU internal UARTs
+ * (only these UARTs are definitely clocked by gd->arch.uart_clk)
+ *
+ * These UARTs are direct childs of /plb/opb. This code
+ * does not touch any UARTs that are connected to the ebc.
+ */
+ off = fdt_path_offset(blob, "/plb/opb");
+ while ((off = fdt_next_node(blob, off, &ndepth)) >= 0) {
+ /*
+ * process all sub nodes and stop when we are back
+ * at the starting depth
+ */
+ if (ndepth <= 0)
+ break;
+
+ /* only update direct childs */
+ if ((ndepth == 1) &&
+ (fdt_node_check_compatible(blob, off, "ns16550") == 0))
+ fdt_setprop(blob, off,
+ "clock-frequency",
+ (void *)&gd->arch.uart_clk, 4);
+ }
+
+ /*
+ * Fixup all ethernet nodes
+ * Note: aliases in the dts are required for this
+ */
+ fdt_fixup_ethernet(blob);
+
+ /*
+ * Fixup all available PCIe nodes by setting the device_type property
+ */
+ fdt_pcie_setup(blob);
+}
+#endif /* CONFIG_OF_LIBFDT && CONFIG_OF_BOARD_SETUP */
diff --git a/arch/powerpc/cpu/ppc4xx/gpio.c b/arch/powerpc/cpu/ppc4xx/gpio.c
new file mode 100644
index 0000000..20f0572
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/gpio.c
@@ -0,0 +1,260 @@
+/*
+ * (C) Copyright 2007-2008
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/ppc4xx-gpio.h>
+
+/* Only compile this file for boards with GPIO support */
+#if defined(GPIO0_BASE)
+
+#if defined(CONFIG_SYS_4xx_GPIO_TABLE)
+gpio_param_s const gpio_tab[GPIO_GROUP_MAX][GPIO_MAX] = CONFIG_SYS_4xx_GPIO_TABLE;
+#endif
+
+#if defined(GPIO0_OSRL)
+/* Only some 4xx variants support alternate funtions on the GPIO's */
+void gpio_config(int pin, int in_out, int gpio_alt, int out_val)
+{
+ u32 mask;
+ u32 mask2;
+ u32 val;
+ u32 offs = 0;
+ u32 offs2 = 0;
+ int pin2 = pin << 1;
+
+ if (pin >= GPIO_MAX) {
+ offs = 0x100;
+ pin -= GPIO_MAX;
+ }
+
+ if (pin >= GPIO_MAX/2) {
+ offs2 = 0x4;
+ pin2 = (pin - GPIO_MAX/2) << 1;
+ }
+
+ mask = 0x80000000 >> pin;
+ mask2 = 0xc0000000 >> pin2;
+
+ /* first set TCR to 0 */
+ out_be32((void *)GPIO0_TCR + offs, in_be32((void *)GPIO0_TCR + offs) & ~mask);
+
+ if (in_out == GPIO_OUT) {
+ val = in_be32((void *)GPIO0_OSRL + offs + offs2) & ~mask2;
+ switch (gpio_alt) {
+ case GPIO_ALT1:
+ val |= GPIO_ALT1_SEL >> pin2;
+ break;
+ case GPIO_ALT2:
+ val |= GPIO_ALT2_SEL >> pin2;
+ break;
+ case GPIO_ALT3:
+ val |= GPIO_ALT3_SEL >> pin2;
+ break;
+ }
+ out_be32((void *)GPIO0_OSRL + offs + offs2, val);
+
+ /* setup requested output value */
+ if (out_val == GPIO_OUT_0)
+ out_be32((void *)GPIO0_OR + offs,
+ in_be32((void *)GPIO0_OR + offs) & ~mask);
+ else if (out_val == GPIO_OUT_1)
+ out_be32((void *)GPIO0_OR + offs,
+ in_be32((void *)GPIO0_OR + offs) | mask);
+
+ /* now configure TCR to drive output if selected */
+ out_be32((void *)GPIO0_TCR + offs,
+ in_be32((void *)GPIO0_TCR + offs) | mask);
+ } else {
+ val = in_be32((void *)GPIO0_ISR1L + offs + offs2) & ~mask2;
+ val |= GPIO_IN_SEL >> pin2;
+ out_be32((void *)GPIO0_ISR1L + offs + offs2, val);
+ }
+}
+#endif /* GPIO_OSRL */
+
+void gpio_write_bit(int pin, int val)
+{
+ u32 offs = 0;
+
+ if (pin >= GPIO_MAX) {
+ offs = 0x100;
+ pin -= GPIO_MAX;
+ }
+
+ if (val)
+ out_be32((void *)GPIO0_OR + offs,
+ in_be32((void *)GPIO0_OR + offs) | GPIO_VAL(pin));
+ else
+ out_be32((void *)GPIO0_OR + offs,
+ in_be32((void *)GPIO0_OR + offs) & ~GPIO_VAL(pin));
+}
+
+int gpio_read_out_bit(int pin)
+{
+ u32 offs = 0;
+
+ if (pin >= GPIO_MAX) {
+ offs = 0x100;
+ pin -= GPIO_MAX;
+ }
+
+ return (in_be32((void *)GPIO0_OR + offs) & GPIO_VAL(pin) ? 1 : 0);
+}
+
+int gpio_read_in_bit(int pin)
+{
+ u32 offs = 0;
+
+ if (pin >= GPIO_MAX) {
+ offs = 0x100;
+ pin -= GPIO_MAX;
+ }
+
+ return (in_be32((void *)GPIO0_IR + offs) & GPIO_VAL(pin) ? 1 : 0);
+}
+
+#if defined(CONFIG_SYS_4xx_GPIO_TABLE)
+void gpio_set_chip_configuration(void)
+{
+ unsigned char i=0, j=0, offs=0, gpio_core;
+ unsigned long reg, core_add;
+
+ for (gpio_core=0; gpio_core<GPIO_GROUP_MAX; gpio_core++) {
+ j = 0;
+ offs = 0;
+ /* GPIO config of the GPIOs 0 to 31 */
+ for (i=0; i<GPIO_MAX; i++, j++) {
+ if (i == GPIO_MAX/2) {
+ offs = 4;
+ j = i-16;
+ }
+
+ core_add = gpio_tab[gpio_core][i].add;
+
+ if ((gpio_tab[gpio_core][i].in_out == GPIO_IN) ||
+ (gpio_tab[gpio_core][i].in_out == GPIO_BI)) {
+
+ switch (gpio_tab[gpio_core][i].alt_nb) {
+ case GPIO_SEL:
+ break;
+
+ case GPIO_ALT1:
+ reg = in_be32((void *)GPIO_IS1(core_add+offs))
+ & ~(GPIO_MASK >> (j*2));
+ reg = reg | (GPIO_IN_SEL >> (j*2));
+ out_be32((void *)GPIO_IS1(core_add+offs), reg);
+ break;
+
+ case GPIO_ALT2:
+ reg = in_be32((void *)GPIO_IS2(core_add+offs))
+ & ~(GPIO_MASK >> (j*2));
+ reg = reg | (GPIO_IN_SEL >> (j*2));
+ out_be32((void *)GPIO_IS2(core_add+offs), reg);
+ break;
+
+ case GPIO_ALT3:
+ reg = in_be32((void *)GPIO_IS3(core_add+offs))
+ & ~(GPIO_MASK >> (j*2));
+ reg = reg | (GPIO_IN_SEL >> (j*2));
+ out_be32((void *)GPIO_IS3(core_add+offs), reg);
+ break;
+ }
+ }
+
+ if ((gpio_tab[gpio_core][i].in_out == GPIO_OUT) ||
+ (gpio_tab[gpio_core][i].in_out == GPIO_BI)) {
+
+ u32 gpio_alt_sel = 0;
+
+ switch (gpio_tab[gpio_core][i].alt_nb) {
+ case GPIO_SEL:
+ /*
+ * Setup output value
+ * 1 -> high level
+ * 0 -> low level
+ * else -> don't touch
+ */
+ reg = in_be32((void *)GPIO_OR(core_add));
+ if (gpio_tab[gpio_core][i].out_val == GPIO_OUT_1)
+ reg |= (0x80000000 >> (i));
+ else if (gpio_tab[gpio_core][i].out_val == GPIO_OUT_0)
+ reg &= ~(0x80000000 >> (i));
+ out_be32((void *)GPIO_OR(core_add), reg);
+
+ reg = in_be32((void *)GPIO_TCR(core_add)) |
+ (0x80000000 >> (i));
+ out_be32((void *)GPIO_TCR(core_add), reg);
+
+ reg = in_be32((void *)GPIO_OS(core_add+offs))
+ & ~(GPIO_MASK >> (j*2));
+ out_be32((void *)GPIO_OS(core_add+offs), reg);
+ reg = in_be32((void *)GPIO_TS(core_add+offs))
+ & ~(GPIO_MASK >> (j*2));
+ out_be32((void *)GPIO_TS(core_add+offs), reg);
+ break;
+
+ case GPIO_ALT1:
+ gpio_alt_sel = GPIO_ALT1_SEL;
+ break;
+
+ case GPIO_ALT2:
+ gpio_alt_sel = GPIO_ALT2_SEL;
+ break;
+
+ case GPIO_ALT3:
+ gpio_alt_sel = GPIO_ALT3_SEL;
+ break;
+ }
+
+ if (0 != gpio_alt_sel) {
+ reg = in_be32((void *)GPIO_OS(core_add+offs))
+ & ~(GPIO_MASK >> (j*2));
+ reg = reg | (gpio_alt_sel >> (j*2));
+ out_be32((void *)GPIO_OS(core_add+offs), reg);
+
+ if (gpio_tab[gpio_core][i].out_val == GPIO_OUT_1) {
+ reg = in_be32((void *)GPIO_TCR(core_add))
+ | (0x80000000 >> (i));
+ out_be32((void *)GPIO_TCR(core_add), reg);
+ reg = in_be32((void *)GPIO_TS(core_add+offs))
+ & ~(GPIO_MASK >> (j*2));
+ out_be32((void *)GPIO_TS(core_add+offs), reg);
+ } else {
+ reg = in_be32((void *)GPIO_TCR(core_add))
+ & ~(0x80000000 >> (i));
+ out_be32((void *)GPIO_TCR(core_add), reg);
+ reg = in_be32((void *)GPIO_TS(core_add+offs))
+ & ~(GPIO_MASK >> (j*2));
+ reg = reg | (gpio_alt_sel >> (j*2));
+ out_be32((void *)GPIO_TS(core_add+offs), reg);
+ }
+ }
+ }
+ }
+ }
+}
+
+#endif /* GPIO0_BASE */
+#endif /* CONFIG_SYS_4xx_GPIO_TABLE */
diff --git a/arch/powerpc/cpu/ppc4xx/interrupts.c b/arch/powerpc/cpu/ppc4xx/interrupts.c
new file mode 100644
index 0000000..d0bca92
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/interrupts.c
@@ -0,0 +1,209 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002 (440 port)
+ * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com
+ *
+ * (C) Copyright 2003 (440GX port)
+ * Travis B. Sawyer, Sandburst Corporation, tsawyer@sandburst.com
+ *
+ * (C) Copyright 2008 (PPC440X05 port for Virtex 5 FX)
+ * Ricardo Ribalda-Universidad Autonoma de Madrid-ricardo.ribalda@uam.es
+ * Work supported by Qtechnology (htpp://qtec.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <asm/interrupt.h>
+#include <asm/ppc4xx.h>
+#include <ppc_asm.tmpl>
+#include <commproc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * CPM interrupt vector functions.
+ */
+struct irq_action {
+ interrupt_handler_t *handler;
+ void *arg;
+ int count;
+};
+static struct irq_action irq_vecs[IRQ_MAX];
+
+#if defined(CONFIG_440)
+
+/* SPRN changed in 440 */
+static __inline__ void set_evpr(unsigned long val)
+{
+ asm volatile("mtspr 0x03f,%0" : : "r" (val));
+}
+
+#else /* !defined(CONFIG_440) */
+
+static __inline__ void set_pit(unsigned long val)
+{
+ asm volatile("mtpit %0" : : "r" (val));
+}
+
+static __inline__ void set_evpr(unsigned long val)
+{
+ asm volatile("mtevpr %0" : : "r" (val));
+}
+#endif /* defined(CONFIG_440 */
+
+int interrupt_init_cpu (unsigned *decrementer_count)
+{
+ int vec;
+ unsigned long val;
+
+ /* decrementer is automatically reloaded */
+ *decrementer_count = 0;
+
+ /*
+ * Mark all irqs as free
+ */
+ for (vec = 0; vec < IRQ_MAX; vec++) {
+ irq_vecs[vec].handler = NULL;
+ irq_vecs[vec].arg = NULL;
+ irq_vecs[vec].count = 0;
+ }
+
+#ifdef CONFIG_4xx
+ /*
+ * Init PIT
+ */
+#if defined(CONFIG_440)
+ val = mfspr( SPRN_TCR );
+ val &= (~0x04400000); /* clear DIS & ARE */
+ mtspr( SPRN_TCR, val );
+ mtspr( SPRN_DEC, 0 ); /* Prevent exception after TSR clear*/
+ mtspr( SPRN_DECAR, 0 ); /* clear reload */
+ mtspr( SPRN_TSR, 0x08000000 ); /* clear DEC status */
+ val = gd->bd->bi_intfreq/1000; /* 1 msec */
+ mtspr( SPRN_DECAR, val ); /* Set auto-reload value */
+ mtspr( SPRN_DEC, val ); /* Set inital val */
+#else
+ set_pit(gd->bd->bi_intfreq / 1000);
+#endif
+#endif /* CONFIG_4xx */
+
+#ifdef CONFIG_ADCIOP
+ /*
+ * Init PIT
+ */
+ set_pit(66000);
+#endif
+
+ /*
+ * Enable PIT
+ */
+ val = mfspr(SPRN_TCR);
+ val |= 0x04400000;
+ mtspr(SPRN_TCR, val);
+
+ /*
+ * Set EVPR to 0
+ */
+ set_evpr(0x00000000);
+
+ /*
+ * Call uic or xilinx_irq pic_enable
+ */
+ pic_enable();
+
+ return (0);
+}
+
+void timer_interrupt_cpu(struct pt_regs *regs)
+{
+ /* nothing to do here */
+ return;
+}
+
+void interrupt_run_handler(int vec)
+{
+ irq_vecs[vec].count++;
+
+ if (irq_vecs[vec].handler != NULL) {
+ /* call isr */
+ (*irq_vecs[vec].handler) (irq_vecs[vec].arg);
+ } else {
+ pic_irq_disable(vec);
+ printf("Masking bogus interrupt vector %d\n", vec);
+ }
+
+ pic_irq_ack(vec);
+ return;
+}
+
+void irq_install_handler(int vec, interrupt_handler_t * handler, void *arg)
+{
+ /*
+ * Print warning when replacing with a different irq vector
+ */
+ if ((irq_vecs[vec].handler != NULL) && (irq_vecs[vec].handler != handler)) {
+ printf("Interrupt vector %d: handler 0x%x replacing 0x%x\n",
+ vec, (uint) handler, (uint) irq_vecs[vec].handler);
+ }
+ irq_vecs[vec].handler = handler;
+ irq_vecs[vec].arg = arg;
+
+ pic_irq_enable(vec);
+ return;
+}
+
+void irq_free_handler(int vec)
+{
+ debug("Free interrupt for vector %d ==> %p\n",
+ vec, irq_vecs[vec].handler);
+
+ pic_irq_disable(vec);
+
+ irq_vecs[vec].handler = NULL;
+ irq_vecs[vec].arg = NULL;
+ return;
+}
+
+#if defined(CONFIG_CMD_IRQ)
+int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int vec;
+
+ printf ("Interrupt-Information:\n");
+ printf ("Nr Routine Arg Count\n");
+
+ for (vec = 0; vec < IRQ_MAX; vec++) {
+ if (irq_vecs[vec].handler != NULL) {
+ printf ("%02d %08lx %08lx %d\n",
+ vec,
+ (ulong)irq_vecs[vec].handler,
+ (ulong)irq_vecs[vec].arg,
+ irq_vecs[vec].count);
+ }
+ }
+
+ return 0;
+}
+#endif
diff --git a/arch/powerpc/cpu/ppc4xx/kgdb.S b/arch/powerpc/cpu/ppc4xx/kgdb.S
new file mode 100644
index 0000000..417ba62
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/kgdb.S
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2000 Murray Jensen <Murray.Jensen@cmst.csiro.au>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <command.h>
+#include <asm/ppc4xx.h>
+#include <version.h>
+
+#define CONFIG_405GP 1 /* needed for Linux kernel header files */
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+
+#if defined(CONFIG_CMD_KGDB)
+ /*
+ * cache flushing routines for kgdb
+ */
+
+ .globl kgdb_flush_cache_all
+kgdb_flush_cache_all:
+ /* icache */
+ iccci r0,r0 /* iccci invalidates the entire I cache */
+ /* dcache */
+ addi r6,0,0x0000 /* clear GPR 6 */
+ addi r7,r0, 128 /* do loop for # of dcache lines */
+ /* NOTE: dccci invalidates both */
+ mtctr r7 /* ways in the D cache */
+..dcloop:
+ dccci 0,r6 /* invalidate line */
+ addi r6,r6, 32 /* bump to next line */
+ bdnz ..dcloop
+ blr
+
+ .globl kgdb_flush_cache_range
+kgdb_flush_cache_range:
+ li r5,L1_CACHE_BYTES-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,L1_CACHE_SHIFT
+ beqlr
+ mtctr r4
+ mr r6,r3
+1: dcbst 0,r3
+ addi r3,r3,L1_CACHE_BYTES
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ mtctr r4
+2: icbi 0,r6
+ addi r6,r6,L1_CACHE_BYTES
+ bdnz 2b
+ SYNC
+ blr
+
+#endif
diff --git a/arch/powerpc/cpu/ppc4xx/miiphy.c b/arch/powerpc/cpu/ppc4xx/miiphy.c
new file mode 100644
index 0000000..297155f
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/miiphy.c
@@ -0,0 +1,365 @@
+/*-----------------------------------------------------------------------------+
+ | This source code is dual-licensed. You may use it under the terms of the
+ | GNU General Public License version 2, or under the license below.
+ |
+ | This source code has been made available to you by IBM on an AS-IS
+ | basis. Anyone receiving this source is licensed under IBM
+ | copyrights to use it in any way he or she deems fit, including
+ | copying it, modifying it, compiling it, and redistributing it either
+ | with or without modifications. No license under IBM patents or
+ | patent applications is to be implied by the copyright license.
+ |
+ | Any user of this software should understand that IBM cannot provide
+ | technical support for this software and will not be responsible for
+ | any consequences resulting from the use of this software.
+ |
+ | Any person who transfers this source code or any derivative work
+ | must include the IBM copyright notice, this paragraph, and the
+ | preceding two paragraphs in the transferred software.
+ |
+ | COPYRIGHT I B M CORPORATION 1995
+ | LICENSED MATERIAL - PROGRAM PROPERTY OF I B M
+ +-----------------------------------------------------------------------------*/
+/*-----------------------------------------------------------------------------+
+ |
+ | File Name: miiphy.c
+ |
+ | Function: This module has utilities for accessing the MII PHY through
+ | the EMAC3 macro.
+ |
+ | Author: Mark Wisner
+ |
+ +-----------------------------------------------------------------------------*/
+
+/* define DEBUG for debugging output (obviously ;-)) */
+#if 0
+#define DEBUG
+#endif
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <ppc_asm.tmpl>
+#include <commproc.h>
+#include <asm/ppc4xx-emac.h>
+#include <asm/ppc4xx-mal.h>
+#include <miiphy.h>
+
+#if !defined(CONFIG_PHY_CLK_FREQ)
+#define CONFIG_PHY_CLK_FREQ 0
+#endif
+
+/***********************************************************/
+/* Dump out to the screen PHY regs */
+/***********************************************************/
+
+void miiphy_dump (char *devname, unsigned char addr)
+{
+ unsigned long i;
+ unsigned short data;
+
+ for (i = 0; i < 0x1A; i++) {
+ if (miiphy_read (devname, addr, i, &data)) {
+ printf ("read error for reg %lx\n", i);
+ return;
+ }
+ printf ("Phy reg %lx ==> %4x\n", i, data);
+
+ /* jump to the next set of regs */
+ if (i == 0x07)
+ i = 0x0f;
+
+ } /* end for loop */
+} /* end dump */
+
+/***********************************************************/
+/* (Re)start autonegotiation */
+/***********************************************************/
+int phy_setup_aneg (char *devname, unsigned char addr)
+{
+ u16 bmcr;
+
+#if defined(CONFIG_PHY_DYNAMIC_ANEG)
+ /*
+ * Set up advertisement based on capablilities reported by the PHY.
+ * This should work for both copper and fiber.
+ */
+ u16 bmsr;
+#if defined(CONFIG_PHY_GIGE)
+ u16 exsr = 0x0000;
+#endif
+
+ miiphy_read (devname, addr, MII_BMSR, &bmsr);
+
+#if defined(CONFIG_PHY_GIGE)
+ if (bmsr & BMSR_ESTATEN)
+ miiphy_read (devname, addr, MII_ESTATUS, &exsr);
+
+ if (exsr & (ESTATUS_1000XF | ESTATUS_1000XH)) {
+ /* 1000BASE-X */
+ u16 anar = 0x0000;
+
+ if (exsr & ESTATUS_1000XF)
+ anar |= ADVERTISE_1000XFULL;
+
+ if (exsr & ESTATUS_1000XH)
+ anar |= ADVERTISE_1000XHALF;
+
+ miiphy_write (devname, addr, MII_ADVERTISE, anar);
+ } else
+#endif
+ {
+ u16 anar, btcr;
+
+ miiphy_read (devname, addr, MII_ADVERTISE, &anar);
+ anar &= ~(0x5000 | LPA_100BASE4 | LPA_100FULL |
+ LPA_100HALF | LPA_10FULL | LPA_10HALF);
+
+ miiphy_read (devname, addr, MII_CTRL1000, &btcr);
+ btcr &= ~(0x00FF | PHY_1000BTCR_1000FD | PHY_1000BTCR_1000HD);
+
+ if (bmsr & BMSR_100BASE4)
+ anar |= LPA_100BASE4;
+
+ if (bmsr & BMSR_100FULL)
+ anar |= LPA_100FULL;
+
+ if (bmsr & BMSR_100HALF)
+ anar |= LPA_100HALF;
+
+ if (bmsr & BMSR_10FULL)
+ anar |= LPA_10FULL;
+
+ if (bmsr & BMSR_10HALF)
+ anar |= LPA_10HALF;
+
+ miiphy_write (devname, addr, MII_ADVERTISE, anar);
+
+#if defined(CONFIG_PHY_GIGE)
+ if (exsr & ESTATUS_1000_TFULL)
+ btcr |= PHY_1000BTCR_1000FD;
+
+ if (exsr & ESTATUS_1000_THALF)
+ btcr |= PHY_1000BTCR_1000HD;
+
+ miiphy_write (devname, addr, MII_CTRL1000, btcr);
+#endif
+ }
+
+#else /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
+ /*
+ * Set up standard advertisement
+ */
+ u16 adv;
+
+ miiphy_read (devname, addr, MII_ADVERTISE, &adv);
+ adv |= (LPA_LPACK | LPA_100FULL | LPA_100HALF |
+ LPA_10FULL | LPA_10HALF);
+ miiphy_write (devname, addr, MII_ADVERTISE, adv);
+
+ miiphy_read (devname, addr, MII_CTRL1000, &adv);
+ adv |= (0x0300);
+ miiphy_write (devname, addr, MII_CTRL1000, adv);
+
+#endif /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
+
+ /* Start/Restart aneg */
+ miiphy_read (devname, addr, MII_BMCR, &bmcr);
+ bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ miiphy_write (devname, addr, MII_BMCR, bmcr);
+
+ return 0;
+}
+
+/***********************************************************/
+/* read a phy reg and return the value with a rc */
+/***********************************************************/
+/* AMCC_TODO:
+ * Find out of the choice for the emac for MDIO is from the bridges,
+ * i.e. ZMII or RGMII as approporiate. If the bridges are not used
+ * to determine the emac for MDIO, then is the SDR0_ETH_CFG[MDIO_SEL]
+ * used? If so, then this routine below does not apply to the 460EX/GT.
+ *
+ * sr: Currently on 460EX only EMAC0 works with MDIO, so we always
+ * return EMAC0 offset here
+ * vg: For 460EX/460GT if internal GPCS PHY address is specified
+ * return appropriate EMAC offset
+ */
+unsigned int miiphy_getemac_offset(u8 addr)
+{
+#if defined(CONFIG_440) && \
+ !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) && \
+ !defined(CONFIG_460EX) && !defined(CONFIG_460GT)
+ unsigned long zmii;
+ unsigned long eoffset;
+
+ /* Need to find out which mdi port we're using */
+ zmii = in_be32((void *)ZMII0_FER);
+
+ if (zmii & (ZMII_FER_MDI << ZMII_FER_V (0)))
+ /* using port 0 */
+ eoffset = 0;
+
+ else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (1)))
+ /* using port 1 */
+ eoffset = 0x100;
+
+ else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (2)))
+ /* using port 2 */
+ eoffset = 0x400;
+
+ else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (3)))
+ /* using port 3 */
+ eoffset = 0x600;
+
+ else {
+ /* None of the mdi ports are enabled! */
+ /* enable port 0 */
+ zmii |= ZMII_FER_MDI << ZMII_FER_V (0);
+ out_be32((void *)ZMII0_FER, zmii);
+ eoffset = 0;
+ /* need to soft reset port 0 */
+ zmii = in_be32((void *)EMAC0_MR0);
+ zmii |= EMAC_MR0_SRST;
+ out_be32((void *)EMAC0_MR0, zmii);
+ }
+
+ return (eoffset);
+#else
+
+#if defined(CONFIG_405EX)
+ unsigned long rgmii;
+ int devnum = 1;
+
+ rgmii = in_be32((void *)RGMII_FER);
+ if (rgmii & (1 << (19 - devnum)))
+ return 0x100;
+#endif
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ u32 eoffset = 0;
+
+ switch (addr) {
+#if defined(CONFIG_HAS_ETH1) && defined(CONFIG_GPCS_PHY1_ADDR)
+ case CONFIG_GPCS_PHY1_ADDR:
+ if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x100)))
+ eoffset = 0x100;
+ break;
+#endif
+#if defined(CONFIG_HAS_ETH2) && defined(CONFIG_GPCS_PHY2_ADDR)
+ case CONFIG_GPCS_PHY2_ADDR:
+ if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x300)))
+ eoffset = 0x300;
+ break;
+#endif
+#if defined(CONFIG_HAS_ETH3) && defined(CONFIG_GPCS_PHY3_ADDR)
+ case CONFIG_GPCS_PHY3_ADDR:
+ if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x400)))
+ eoffset = 0x400;
+ break;
+#endif
+ default:
+ eoffset = 0;
+ break;
+ }
+ return eoffset;
+#endif
+
+ return 0;
+#endif
+}
+
+static int emac_miiphy_wait(u32 emac_reg)
+{
+ u32 sta_reg;
+ int i;
+
+ /* wait for completion */
+ i = 0;
+ do {
+ sta_reg = in_be32((void *)EMAC0_STACR + emac_reg);
+ if (i++ > 5) {
+ debug("%s [%d]: Timeout! EMAC0_STACR=0x%0x\n", __func__,
+ __LINE__, sta_reg);
+ return -1;
+ }
+ udelay(10);
+ } while ((sta_reg & EMAC_STACR_OC) == EMAC_STACR_OC_MASK);
+
+ return 0;
+}
+
+static int emac_miiphy_command(u8 addr, u8 reg, int cmd, u16 value)
+{
+ u32 emac_reg;
+ u32 sta_reg;
+
+ emac_reg = miiphy_getemac_offset(addr);
+
+ /* wait for completion */
+ if (emac_miiphy_wait(emac_reg) != 0)
+ return -1;
+
+ sta_reg = reg; /* reg address */
+
+ /* set clock (50MHz) and read flags */
+#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_405EX)
+#if defined(CONFIG_IBM_EMAC4_V4) /* EMAC4 V4 changed bit setting */
+ sta_reg = (sta_reg & ~EMAC_STACR_OP_MASK) | cmd;
+#else
+ sta_reg |= cmd;
+#endif
+#else
+ sta_reg = (sta_reg | cmd) & ~EMAC_STACR_CLK_100MHZ;
+#endif
+
+ /* Some boards (mainly 405EP based) define the PHY clock freqency fixed */
+ sta_reg = sta_reg | CONFIG_PHY_CLK_FREQ;
+ sta_reg = sta_reg | ((u32)addr << 5); /* Phy address */
+ sta_reg = sta_reg | EMAC_STACR_OC_MASK; /* new IBM emac v4 */
+ if (cmd == EMAC_STACR_WRITE)
+ memcpy(&sta_reg, &value, 2); /* put in data */
+
+ out_be32((void *)EMAC0_STACR + emac_reg, sta_reg);
+ debug("%s [%d]: sta_reg=%08x\n", __func__, __LINE__, sta_reg);
+
+ /* wait for completion */
+ if (emac_miiphy_wait(emac_reg) != 0)
+ return -1;
+
+ debug("%s [%d]: sta_reg=%08x\n", __func__, __LINE__, sta_reg);
+ if ((sta_reg & EMAC_STACR_PHYE) != 0)
+ return -1;
+
+ return 0;
+}
+
+int emac4xx_miiphy_read (const char *devname, unsigned char addr, unsigned char reg,
+ unsigned short *value)
+{
+ unsigned long sta_reg;
+ unsigned long emac_reg;
+
+ emac_reg = miiphy_getemac_offset(addr);
+
+ if (emac_miiphy_command(addr, reg, EMAC_STACR_READ, 0) != 0)
+ return -1;
+
+ sta_reg = in_be32((void *)EMAC0_STACR + emac_reg);
+ *value = sta_reg >> 16;
+
+ return 0;
+}
+
+/***********************************************************/
+/* write a phy reg and return the value with a rc */
+/***********************************************************/
+
+int emac4xx_miiphy_write (const char *devname, unsigned char addr, unsigned char reg,
+ unsigned short value)
+{
+ return emac_miiphy_command(addr, reg, EMAC_STACR_WRITE, value);
+}
diff --git a/arch/powerpc/cpu/ppc4xx/reginfo.c b/arch/powerpc/cpu/ppc4xx/reginfo.c
new file mode 100644
index 0000000..2f1ab9e
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/reginfo.c
@@ -0,0 +1,370 @@
+/*
+ *(C) Copyright 2005-2009 Netstal Maschinen AG
+ * Bruno Hars (Bruno.Hars@netstal.com)
+ * Niklaus Giger (Niklaus.Giger@netstal.com)
+ *
+ * This source code is free software; you can redistribute it
+ * and/or modify it in source code form under the terms of the GNU
+ * General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/*
+ * reginfo.c - register dump of HW-configuratin register for PPC4xx based board
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/ppc4xx-uic.h>
+#include <asm/ppc4xx-emac.h>
+
+enum REGISTER_TYPE {
+ IDCR1, /* Indirectly Accessed DCR via SDRAM0_CFGADDR/SDRAM0_CFGDATA */
+ IDCR2, /* Indirectly Accessed DCR via EBC0_CFGADDR/EBC0_CFGDATA */
+ IDCR3, /* Indirectly Accessed DCR via EBM0_CFGADDR/EBM0_CFGDATA */
+ IDCR4, /* Indirectly Accessed DCR via PPM0_CFGADDR/PPM0_CFGDATA */
+ IDCR5, /* Indirectly Accessed DCR via CPR0_CFGADDR/CPR0_CFGDATA */
+ IDCR6, /* Indirectly Accessed DCR via SDR0_CFGADDR/SDR0_CFGDATA */
+ MM /* Directly Accessed MMIO Register */
+};
+
+struct cpu_register {
+ char *name;
+ enum REGISTER_TYPE type;
+ u32 address;
+};
+
+/*
+ * PPC440EPx registers ordered for output
+ * name type addr size
+ * -------------------------------------------
+ */
+
+const struct cpu_register ppc4xx_reg[] = {
+ {"PB0CR", IDCR2, PB0CR},
+ {"PB0AP", IDCR2, PB0AP},
+ {"PB1CR", IDCR2, PB1CR},
+ {"PB1AP", IDCR2, PB1AP},
+ {"PB2CR", IDCR2, PB2CR},
+ {"PB2AP", IDCR2, PB2AP},
+ {"PB3CR", IDCR2, PB3CR},
+ {"PB3AP", IDCR2, PB3AP},
+
+ {"PB4CR", IDCR2, PB4CR},
+ {"PB4AP", IDCR2, PB4AP},
+#if !defined(CONFIG_405EP)
+ {"PB5CR", IDCR2, PB5CR},
+ {"PB5AP", IDCR2, PB5AP},
+ {"PB6CR", IDCR2, PB6CR},
+ {"PB6AP", IDCR2, PB6AP},
+ {"PB7CR", IDCR2, PB7CR},
+ {"PB7AP", IDCR2, PB7AP},
+#endif
+
+ {"PBEAR", IDCR2, PBEAR},
+#if defined(CONFIG_405EP) || defined (CONFIG_405GP)
+ {"PBESR0", IDCR2, PBESR0},
+ {"PBESR1", IDCR2, PBESR1},
+#endif
+ {"EBC0_CFG", IDCR2, EBC0_CFG},
+
+#ifdef CONFIG_405GP
+ {"SDRAM0_BESR0", IDCR1, SDRAM0_BESR0},
+ {"SDRAM0_BESRS0", IDCR1, SDRAM0_BESRS0},
+ {"SDRAM0_BESR1", IDCR1, SDRAM0_BESR1},
+ {"SDRAM0_BESRS1", IDCR1, SDRAM0_BESRS1},
+ {"SDRAM0_BEAR", IDCR1, SDRAM0_BEAR},
+ {"SDRAM0_CFG", IDCR1, SDRAM0_CFG},
+ {"SDRAM0_RTR", IDCR1, SDRAM0_RTR},
+ {"SDRAM0_PMIT", IDCR1, SDRAM0_PMIT},
+
+ {"SDRAM0_B0CR", IDCR1, SDRAM0_B0CR},
+ {"SDRAM0_B1CR", IDCR1, SDRAM0_B1CR},
+ {"SDRAM0_B2CR", IDCR1, SDRAM0_B2CR},
+ {"SDRAM0_B3CR", IDCR1, SDRAM0_B1CR},
+ {"SDRAM0_TR", IDCR1, SDRAM0_TR},
+ {"SDRAM0_ECCCFG", IDCR1, SDRAM0_B1CR},
+ {"SDRAM0_ECCESR", IDCR1, SDRAM0_ECCESR},
+
+
+#endif
+
+#ifdef CONFIG_440EPX
+ {"SDR0_SDSTP0", IDCR6, SDR0_SDSTP0},
+ {"SDR0_SDSTP1", IDCR6, SDR0_SDSTP1},
+ {"SDR0_SDSTP2", IDCR6, SDR0_SDSTP2},
+ {"SDR0_SDSTP3", IDCR6, SDR0_SDSTP3},
+ {"SDR0_CUST0", IDCR6, SDR0_CUST0},
+ {"SDR0_CUST1", IDCR6, SDR0_CUST1},
+ {"SDR0_EBC", IDCR6, SDR0_EBC},
+ {"SDR0_AMP0", IDCR6, SDR0_AMP0},
+ {"SDR0_AMP1", IDCR6, SDR0_AMP1},
+ {"SDR0_CP440", IDCR6, SDR0_CP440},
+ {"SDR0_CRYP0", IDCR6, SDR0_CRYP0},
+ {"SDR0_DDRCFG", IDCR6, SDR0_DDRCFG},
+ {"SDR0_EMAC0RXST", IDCR6, SDR0_EMAC0RXST},
+ {"SDR0_EMAC0TXST", IDCR6, SDR0_EMAC0TXST},
+ {"SDR0_MFR", IDCR6, SDR0_MFR},
+ {"SDR0_PCI0", IDCR6, SDR0_PCI0},
+ {"SDR0_PFC0", IDCR6, SDR0_PFC0},
+ {"SDR0_PFC1", IDCR6, SDR0_PFC1},
+ {"SDR0_PFC2", IDCR6, SDR0_PFC2},
+ {"SDR0_PFC4", IDCR6, SDR0_PFC4},
+ {"SDR0_UART0", IDCR6, SDR0_UART0},
+ {"SDR0_UART1", IDCR6, SDR0_UART1},
+ {"SDR0_UART2", IDCR6, SDR0_UART2},
+ {"SDR0_UART3", IDCR6, SDR0_UART3},
+ {"DDR0_02", IDCR1, DDR0_02},
+ {"DDR0_00", IDCR1, DDR0_00},
+ {"DDR0_01", IDCR1, DDR0_01},
+ {"DDR0_03", IDCR1, DDR0_03},
+ {"DDR0_04", IDCR1, DDR0_04},
+ {"DDR0_05", IDCR1, DDR0_05},
+ {"DDR0_06", IDCR1, DDR0_06},
+ {"DDR0_07", IDCR1, DDR0_07},
+ {"DDR0_08", IDCR1, DDR0_08},
+ {"DDR0_09", IDCR1, DDR0_09},
+ {"DDR0_10", IDCR1, DDR0_10},
+ {"DDR0_11", IDCR1, DDR0_11},
+ {"DDR0_12", IDCR1, DDR0_12},
+ {"DDR0_14", IDCR1, DDR0_14},
+ {"DDR0_17", IDCR1, DDR0_17},
+ {"DDR0_18", IDCR1, DDR0_18},
+ {"DDR0_19", IDCR1, DDR0_19},
+ {"DDR0_20", IDCR1, DDR0_20},
+ {"DDR0_21", IDCR1, DDR0_21},
+ {"DDR0_22", IDCR1, DDR0_22},
+ {"DDR0_23", IDCR1, DDR0_23},
+ {"DDR0_24", IDCR1, DDR0_24},
+ {"DDR0_25", IDCR1, DDR0_25},
+ {"DDR0_26", IDCR1, DDR0_26},
+ {"DDR0_27", IDCR1, DDR0_27},
+ {"DDR0_28", IDCR1, DDR0_28},
+ {"DDR0_31", IDCR1, DDR0_31},
+ {"DDR0_32", IDCR1, DDR0_32},
+ {"DDR0_33", IDCR1, DDR0_33},
+ {"DDR0_34", IDCR1, DDR0_34},
+ {"DDR0_35", IDCR1, DDR0_35},
+ {"DDR0_36", IDCR1, DDR0_36},
+ {"DDR0_37", IDCR1, DDR0_37},
+ {"DDR0_38", IDCR1, DDR0_38},
+ {"DDR0_39", IDCR1, DDR0_39},
+ {"DDR0_40", IDCR1, DDR0_40},
+ {"DDR0_41", IDCR1, DDR0_41},
+ {"DDR0_42", IDCR1, DDR0_42},
+ {"DDR0_43", IDCR1, DDR0_43},
+ {"DDR0_44", IDCR1, DDR0_44},
+ {"CPR0_ICFG", IDCR5, CPR0_ICFG},
+ {"CPR0_MALD", IDCR5, CPR0_MALD},
+ {"CPR0_OPBD00", IDCR5, CPR0_OPBD0},
+ {"CPR0_PERD0", IDCR5, CPR0_PERD},
+ {"CPR0_PLLC0", IDCR5, CPR0_PLLC},
+ {"CPR0_PLLD0", IDCR5, CPR0_PLLD},
+ {"CPR0_PRIMAD0", IDCR5, CPR0_PRIMAD0},
+ {"CPR0_PRIMBD0", IDCR5, CPR0_PRIMBD0},
+ {"CPR0_SPCID", IDCR5, CPR0_SPCID},
+ {"SPI0_MODE", MM, SPI0_MODE},
+ {"IIC0_CLKDIV", MM, PCIL0_PMM1MA},
+ {"PCIL0_PMM0MA", MM, PCIL0_PMM0MA},
+ {"PCIL0_PMM1MA", MM, PCIL0_PMM1MA},
+ {"PCIL0_PTM1LA", MM, PCIL0_PMM1MA},
+ {"PCIL0_PTM1MS", MM, PCIL0_PTM1MS},
+ {"PCIL0_PTM2LA", MM, PCIL0_PMM1MA},
+ {"PCIL0_PTM2MS", MM, PCIL0_PTM2MS},
+ {"ZMII0_FER", MM, ZMII0_FER},
+ {"ZMII0_SSR", MM, ZMII0_SSR},
+ {"EMAC0_IPGVR", MM, EMAC0_IPGVR},
+ {"EMAC0_MR1", MM, EMAC0_MR1},
+ {"EMAC0_PTR", MM, EMAC0_PTR},
+ {"EMAC0_RWMR", MM, EMAC0_RWMR},
+ {"EMAC0_STACR", MM, EMAC0_STACR},
+ {"EMAC0_TMR0", MM, EMAC0_TMR0},
+ {"EMAC0_TMR1", MM, EMAC0_TMR1},
+ {"EMAC0_TRTR", MM, EMAC0_TRTR},
+ {"EMAC1_MR1", MM, EMAC1_MR1},
+ {"GPIO0_OR", MM, GPIO0_OR},
+ {"GPIO1_OR", MM, GPIO1_OR},
+ {"GPIO0_TCR", MM, GPIO0_TCR},
+ {"GPIO1_TCR", MM, GPIO1_TCR},
+ {"GPIO0_ODR", MM, GPIO0_ODR},
+ {"GPIO1_ODR", MM, GPIO1_ODR},
+ {"GPIO0_OSRL", MM, GPIO0_OSRL},
+ {"GPIO0_OSRH", MM, GPIO0_OSRH},
+ {"GPIO1_OSRL", MM, GPIO1_OSRL},
+ {"GPIO1_OSRH", MM, GPIO1_OSRH},
+ {"GPIO0_TSRL", MM, GPIO0_TSRL},
+ {"GPIO0_TSRH", MM, GPIO0_TSRH},
+ {"GPIO1_TSRL", MM, GPIO1_TSRL},
+ {"GPIO1_TSRH", MM, GPIO1_TSRH},
+ {"GPIO0_IR", MM, GPIO0_IR},
+ {"GPIO1_IR", MM, GPIO1_IR},
+ {"GPIO0_ISR1L", MM, GPIO0_ISR1L},
+ {"GPIO0_ISR1H", MM, GPIO0_ISR1H},
+ {"GPIO1_ISR1L", MM, GPIO1_ISR1L},
+ {"GPIO1_ISR1H", MM, GPIO1_ISR1H},
+ {"GPIO0_ISR2L", MM, GPIO0_ISR2L},
+ {"GPIO0_ISR2H", MM, GPIO0_ISR2H},
+ {"GPIO1_ISR2L", MM, GPIO1_ISR2L},
+ {"GPIO1_ISR2H", MM, GPIO1_ISR2H},
+ {"GPIO0_ISR3L", MM, GPIO0_ISR3L},
+ {"GPIO0_ISR3H", MM, GPIO0_ISR3H},
+ {"GPIO1_ISR3L", MM, GPIO1_ISR3L},
+ {"GPIO1_ISR3H", MM, GPIO1_ISR3H},
+ {"SDR0_USB2PHY0CR", IDCR6, SDR0_USB2PHY0CR},
+ {"SDR0_USB2H0CR", IDCR6, SDR0_USB2H0CR},
+ {"SDR0_USB2D0CR", IDCR6, SDR0_USB2D0CR},
+#endif
+};
+
+/*
+ * CPU Register dump of PPC4xx HW configuration registers
+ * Output: first all DCR-registers, then in order of struct ppc4xx_reg
+ */
+#define PRINT_DCR(dcr) printf("0x%08x %-16s: 0x%08x\n", dcr,#dcr, mfdcr(dcr));
+
+void ppc4xx_reginfo(void)
+{
+ unsigned int i;
+ unsigned int n;
+ u32 value;
+ enum REGISTER_TYPE type;
+#if defined (CONFIG_405EP)
+ printf("Dump PPC405EP HW configuration registers\n\n");
+#elif CONFIG_405GP
+ printf ("Dump 405GP HW configuration registers\n\n");
+#elif CONFIG_440EPX
+ printf("Dump PPC440EPx HW configuration registers\n\n");
+#endif
+ printf("MSR: 0x%08x\n", mfmsr());
+
+ printf ("\nUniversal Interrupt Controller Regs\n");
+ PRINT_DCR(UIC0SR);
+ PRINT_DCR(UIC0ER);
+ PRINT_DCR(UIC0CR);
+ PRINT_DCR(UIC0PR);
+ PRINT_DCR(UIC0TR);
+ PRINT_DCR(UIC0MSR);
+ PRINT_DCR(UIC0VR);
+ PRINT_DCR(UIC0VCR);
+
+#if (UIC_MAX > 1)
+ PRINT_DCR(UIC2SR);
+ PRINT_DCR(UIC2ER);
+ PRINT_DCR(UIC2CR);
+ PRINT_DCR(UIC2PR);
+ PRINT_DCR(UIC2TR);
+ PRINT_DCR(UIC2MSR);
+ PRINT_DCR(UIC2VR);
+ PRINT_DCR(UIC2VCR);
+#endif
+
+#if (UIC_MAX > 2)
+ PRINT_DCR(UIC2SR);
+ PRINT_DCR(UIC2ER);
+ PRINT_DCR(UIC2CR);
+ PRINT_DCR(UIC2PR);
+ PRINT_DCR(UIC2TR);
+ PRINT_DCR(UIC2MSR);
+ PRINT_DCR(UIC2VR);
+ PRINT_DCR(UIC2VCR);
+#endif
+
+#if (UIC_MAX > 3)
+ PRINT_DCR(UIC3SR);
+ PRINT_DCR(UIC3ER);
+ PRINT_DCR(UIC3CR);
+ PRINT_DCR(UIC3PR);
+ PRINT_DCR(UIC3TR);
+ PRINT_DCR(UIC3MSR);
+ PRINT_DCR(UIC3VR);
+ PRINT_DCR(UIC3VCR);
+#endif
+
+#if defined (CONFIG_405EP) || defined (CONFIG_405GP)
+ printf ("\n\nDMA Channels\n");
+ PRINT_DCR(DMASR);
+ PRINT_DCR(DMASGC);
+ PRINT_DCR(DMAADR);
+
+ PRINT_DCR(DMACR0);
+ PRINT_DCR(DMACT0);
+ PRINT_DCR(DMADA0);
+ PRINT_DCR(DMASA0);
+ PRINT_DCR(DMASB0);
+
+ PRINT_DCR(DMACR1);
+ PRINT_DCR(DMACT1);
+ PRINT_DCR(DMADA1);
+ PRINT_DCR(DMASA1);
+ PRINT_DCR(DMASB1);
+
+ PRINT_DCR(DMACR2);
+ PRINT_DCR(DMACT2);
+ PRINT_DCR(DMADA2);
+ PRINT_DCR(DMASA2);
+ PRINT_DCR(DMASB2);
+
+ PRINT_DCR(DMACR3);
+ PRINT_DCR(DMACT3);
+ PRINT_DCR(DMADA3);
+ PRINT_DCR(DMASA3);
+ PRINT_DCR(DMASB3);
+#endif
+
+ printf ("\n\nVarious HW-Configuration registers\n");
+#if defined (CONFIG_440EPX)
+ PRINT_DCR(MAL0_CFG);
+ PRINT_DCR(CPM0_ER);
+ PRINT_DCR(CPM1_ER);
+ PRINT_DCR(PLB4A0_ACR);
+ PRINT_DCR(PLB4A1_ACR);
+ PRINT_DCR(PLB3A0_ACR);
+ PRINT_DCR(OPB2PLB40_BCTRL);
+ PRINT_DCR(P4P3BO0_CFG);
+#endif
+ n = sizeof(ppc4xx_reg) / sizeof(ppc4xx_reg[0]);
+ for (i = 0; i < n; i++) {
+ value = 0;
+ type = ppc4xx_reg[i].type;
+ switch (type) {
+ case IDCR1: /* Indirect via SDRAM0_CFGADDR/DDR0_CFGDATA */
+ mtdcr(SDRAM0_CFGADDR, ppc4xx_reg[i].address);
+ value = mfdcr(SDRAM0_CFGDATA);
+ break;
+ case IDCR2: /* Indirect via EBC0_CFGADDR/EBC0_CFGDATA */
+ mtdcr(EBC0_CFGADDR, ppc4xx_reg[i].address);
+ value = mfdcr(EBC0_CFGDATA);
+ break;
+ case IDCR5: /* Indirect via CPR0_CFGADDR/CPR0_CFGDATA */
+ mtdcr(CPR0_CFGADDR, ppc4xx_reg[i].address);
+ value = mfdcr(CPR0_CFGDATA);
+ break;
+ case IDCR6: /* Indirect via SDR0_CFGADDR/SDR0_CFGDATA */
+ mtdcr(SDR0_CFGADDR, ppc4xx_reg[i].address);
+ value = mfdcr(SDR0_CFGDATA);
+ break;
+ case MM: /* Directly Accessed MMIO Register */
+ value = in_be32((const volatile unsigned __iomem *)
+ ppc4xx_reg[i].address);
+ break;
+ default:
+ printf("\nERROR: struct entry %d: unknown register"
+ "type\n", i);
+ break;
+ }
+ printf("0x%08x %-16s: 0x%08x\n",ppc4xx_reg[i].address,
+ ppc4xx_reg[i].name, value);
+ }
+}
diff --git a/arch/powerpc/cpu/ppc4xx/resetvec.S b/arch/powerpc/cpu/ppc4xx/resetvec.S
new file mode 100644
index 0000000..b3308bd
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/resetvec.S
@@ -0,0 +1,12 @@
+/* Copyright MontaVista Software Incorporated, 2000 */
+#include <config.h>
+ .section .resetvec,"ax"
+#if defined(CONFIG_440)
+ b _start_440
+#else
+#if defined(CONFIG_BOOT_PCI) && defined(CONFIG_MIP405)
+ b _start_pci
+#else
+ b _start
+#endif
+#endif
diff --git a/arch/powerpc/cpu/ppc4xx/sdram.c b/arch/powerpc/cpu/ppc4xx/sdram.c
new file mode 100644
index 0000000..b827daf
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/sdram.c
@@ -0,0 +1,468 @@
+/*
+ * (C) Copyright 2005-2007
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * (C) Copyright 2006
+ * DAVE Srl <www.dave-tech.it>
+ *
+ * (C) Copyright 2002-2004
+ * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/ppc4xx.h>
+#include <asm/processor.h>
+#include "sdram.h"
+#include "ecc.h"
+
+#ifdef CONFIG_SDRAM_BANK0
+
+#ifndef CONFIG_440
+
+#ifndef CONFIG_SYS_SDRAM_TABLE
+sdram_conf_t mb0cf[] = {
+ {(128 << 20), 13, 0x000A4001}, /* (0-128MB) Address Mode 3, 13x10(4) */
+ {(64 << 20), 13, 0x00084001}, /* (0-64MB) Address Mode 3, 13x9(4) */
+ {(32 << 20), 12, 0x00062001}, /* (0-32MB) Address Mode 2, 12x9(4) */
+ {(16 << 20), 12, 0x00046001}, /* (0-16MB) Address Mode 4, 12x8(4) */
+ {(4 << 20), 11, 0x00008001}, /* (0-4MB) Address Mode 5, 11x8(2) */
+};
+#else
+sdram_conf_t mb0cf[] = CONFIG_SYS_SDRAM_TABLE;
+#endif
+
+#define N_MB0CF (sizeof(mb0cf) / sizeof(mb0cf[0]))
+
+#ifdef CONFIG_SYS_SDRAM_CASL
+static ulong ns2clks(ulong ns)
+{
+ ulong bus_period_x_10 = ONE_BILLION / (get_bus_freq(0) / 10);
+
+ return ((ns * 10) + bus_period_x_10) / bus_period_x_10;
+}
+#endif /* CONFIG_SYS_SDRAM_CASL */
+
+static ulong compute_sdtr1(ulong speed)
+{
+#ifdef CONFIG_SYS_SDRAM_CASL
+ ulong tmp;
+ ulong sdtr1 = 0;
+
+ /* CASL */
+ if (CONFIG_SYS_SDRAM_CASL < 2)
+ sdtr1 |= (1 << SDRAM0_TR_CASL);
+ else
+ if (CONFIG_SYS_SDRAM_CASL > 4)
+ sdtr1 |= (3 << SDRAM0_TR_CASL);
+ else
+ sdtr1 |= ((CONFIG_SYS_SDRAM_CASL-1) << SDRAM0_TR_CASL);
+
+ /* PTA */
+ tmp = ns2clks(CONFIG_SYS_SDRAM_PTA);
+ if ((tmp >= 2) && (tmp <= 4))
+ sdtr1 |= ((tmp-1) << SDRAM0_TR_PTA);
+ else
+ sdtr1 |= ((4-1) << SDRAM0_TR_PTA);
+
+ /* CTP */
+ tmp = ns2clks(CONFIG_SYS_SDRAM_CTP);
+ if ((tmp >= 2) && (tmp <= 4))
+ sdtr1 |= ((tmp-1) << SDRAM0_TR_CTP);
+ else
+ sdtr1 |= ((4-1) << SDRAM0_TR_CTP);
+
+ /* LDF */
+ tmp = ns2clks(CONFIG_SYS_SDRAM_LDF);
+ if ((tmp >= 2) && (tmp <= 4))
+ sdtr1 |= ((tmp-1) << SDRAM0_TR_LDF);
+ else
+ sdtr1 |= ((2-1) << SDRAM0_TR_LDF);
+
+ /* RFTA */
+ tmp = ns2clks(CONFIG_SYS_SDRAM_RFTA);
+ if ((tmp >= 4) && (tmp <= 10))
+ sdtr1 |= ((tmp-4) << SDRAM0_TR_RFTA);
+ else
+ sdtr1 |= ((10-4) << SDRAM0_TR_RFTA);
+
+ /* RCD */
+ tmp = ns2clks(CONFIG_SYS_SDRAM_RCD);
+ if ((tmp >= 2) && (tmp <= 4))
+ sdtr1 |= ((tmp-1) << SDRAM0_TR_RCD);
+ else
+ sdtr1 |= ((4-1) << SDRAM0_TR_RCD);
+
+ return sdtr1;
+#else /* CONFIG_SYS_SDRAM_CASL */
+ /*
+ * If no values are configured in the board config file
+ * use the default values, which seem to be ok for most
+ * boards.
+ *
+ * REMARK:
+ * For new board ports we strongly recommend to define the
+ * correct values for the used SDRAM chips in your board
+ * config file (see PPChameleonEVB.h)
+ */
+ if (speed > 100000000) {
+ /*
+ * 133 MHz SDRAM
+ */
+ return 0x01074015;
+ } else {
+ /*
+ * default: 100 MHz SDRAM
+ */
+ return 0x0086400d;
+ }
+#endif /* CONFIG_SYS_SDRAM_CASL */
+}
+
+/* refresh is expressed in ms */
+static ulong compute_rtr(ulong speed, ulong rows, ulong refresh)
+{
+#ifdef CONFIG_SYS_SDRAM_CASL
+ ulong tmp;
+
+ tmp = ((refresh*1000*1000) / (1 << rows)) * (speed / 1000);
+ tmp /= 1000000;
+
+ return ((tmp & 0x00003FF8) << 16);
+#else /* CONFIG_SYS_SDRAM_CASL */
+ if (speed > 100000000) {
+ /*
+ * 133 MHz SDRAM
+ */
+ return 0x07f00000;
+ } else {
+ /*
+ * default: 100 MHz SDRAM
+ */
+ return 0x05f00000;
+ }
+#endif /* CONFIG_SYS_SDRAM_CASL */
+}
+
+/*
+ * Autodetect onboard SDRAM on 405 platforms
+ */
+phys_size_t initdram(int board_type)
+{
+ ulong speed;
+ ulong sdtr1;
+ int i;
+
+ /*
+ * Determine SDRAM speed
+ */
+ speed = get_bus_freq(0); /* parameter not used on ppc4xx */
+
+ /*
+ * sdtr1 (register SDRAM0_TR) must take into account timings listed
+ * in SDRAM chip datasheet. rtr (register SDRAM0_RTR) must take into
+ * account actual SDRAM size. So we can set up sdtr1 according to what
+ * is specified in board configuration file while rtr dependds on SDRAM
+ * size we are assuming before detection.
+ */
+ sdtr1 = compute_sdtr1(speed);
+
+ for (i=0; i<N_MB0CF; i++) {
+ /*
+ * Disable memory controller.
+ */
+ mtsdram(SDRAM0_CFG, 0x00000000);
+
+ /*
+ * Set MB0CF for bank 0.
+ */
+ mtsdram(SDRAM0_B0CR, mb0cf[i].reg);
+ mtsdram(SDRAM0_TR, sdtr1);
+ mtsdram(SDRAM0_RTR, compute_rtr(speed, mb0cf[i].rows, 64));
+
+ udelay(200);
+
+ /*
+ * Set memory controller options reg, MCOPT1.
+ * Set DC_EN to '1' and BRD_PRF to '01' for 16 byte PLB Burst
+ * read/prefetch.
+ */
+ mtsdram(SDRAM0_CFG, 0x80800000);
+
+ udelay(10000);
+
+ if (get_ram_size(0, mb0cf[i].size) == mb0cf[i].size) {
+ phys_size_t size = mb0cf[i].size;
+
+ /*
+ * OK, size detected. Enable second bank if
+ * defined (assumes same type as bank 0)
+ */
+#ifdef CONFIG_SDRAM_BANK1
+ mtsdram(SDRAM0_CFG, 0x00000000);
+ mtsdram(SDRAM0_B1CR, mb0cf[i].size | mb0cf[i].reg);
+ mtsdram(SDRAM0_CFG, 0x80800000);
+ udelay(10000);
+
+ /*
+ * Check if 2nd bank is really available.
+ * If the size not equal to the size of the first
+ * bank, then disable the 2nd bank completely.
+ */
+ if (get_ram_size((long *)mb0cf[i].size, mb0cf[i].size) !=
+ mb0cf[i].size) {
+ mtsdram(SDRAM0_B1CR, 0);
+ mtsdram(SDRAM0_CFG, 0);
+ } else {
+ /*
+ * We have two identical banks, so the size
+ * is twice the bank size
+ */
+ size = 2 * size;
+ }
+#endif
+
+ /*
+ * OK, size detected -> all done
+ */
+ return size;
+ }
+ }
+
+ return 0;
+}
+
+#else /* CONFIG_440 */
+
+/*
+ * Define some default values. Those can be overwritten in the
+ * board config file.
+ */
+
+#ifndef CONFIG_SYS_SDRAM_TABLE
+sdram_conf_t mb0cf[] = {
+ {(256 << 20), 13, 0x000C4001}, /* 256MB mode 3, 13x10(4) */
+ {(128 << 20), 13, 0x000A4001}, /* 128MB mode 3, 13x10(4) */
+ {(64 << 20), 12, 0x00082001} /* 64MB mode 2, 12x9(4) */
+};
+#else
+sdram_conf_t mb0cf[] = CONFIG_SYS_SDRAM_TABLE;
+#endif
+
+#ifndef CONFIG_SYS_SDRAM0_TR0
+#define CONFIG_SYS_SDRAM0_TR0 0x41094012
+#endif
+
+#ifndef CONFIG_SYS_SDRAM0_WDDCTR
+#define CONFIG_SYS_SDRAM0_WDDCTR 0x00000000 /* wrcp=0 dcd=0 */
+#endif
+
+#ifndef CONFIG_SYS_SDRAM0_RTR
+#define CONFIG_SYS_SDRAM0_RTR 0x04100000 /* 7.8us @ 133MHz PLB */
+#endif
+
+#ifndef CONFIG_SYS_SDRAM0_CFG0
+#define CONFIG_SYS_SDRAM0_CFG0 0x82000000 /* DCEN=1, PMUD=0, 64-bit */
+#endif
+
+#define N_MB0CF (sizeof(mb0cf) / sizeof(mb0cf[0]))
+
+#define NUM_TRIES 64
+#define NUM_READS 10
+
+static void sdram_tr1_set(int ram_address, int* tr1_value)
+{
+ int i;
+ int j, k;
+ volatile unsigned int* ram_pointer = (unsigned int *)ram_address;
+ int first_good = -1, last_bad = 0x1ff;
+
+ unsigned long test[NUM_TRIES] = {
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA,
+ 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+ 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A,
+ 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+ 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5,
+ 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+ 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA,
+ 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55,
+ 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55 };
+
+ /* go through all possible SDRAM0_TR1[RDCT] values */
+ for (i=0; i<=0x1ff; i++) {
+ /* set the current value for TR1 */
+ mtsdram(SDRAM0_TR1, (0x80800800 | i));
+
+ /* write values */
+ for (j=0; j<NUM_TRIES; j++) {
+ ram_pointer[j] = test[j];
+
+ /* clear any cache at ram location */
+ __asm__("dcbf 0,%0": :"r" (&ram_pointer[j]));
+ }
+
+ /* read values back */
+ for (j=0; j<NUM_TRIES; j++) {
+ for (k=0; k<NUM_READS; k++) {
+ /* clear any cache at ram location */
+ __asm__("dcbf 0,%0": :"r" (&ram_pointer[j]));
+
+ if (ram_pointer[j] != test[j])
+ break;
+ }
+
+ /* read error */
+ if (k != NUM_READS)
+ break;
+ }
+
+ /* we have a SDRAM0_TR1[RDCT] that is part of the window */
+ if (j == NUM_TRIES) {
+ if (first_good == -1)
+ first_good = i; /* found beginning of window */
+ } else { /* bad read */
+ /* if we have not had a good read then don't care */
+ if (first_good != -1) {
+ /* first failure after a good read */
+ last_bad = i-1;
+ break;
+ }
+ }
+ }
+
+ /* return the current value for TR1 */
+ *tr1_value = (first_good + last_bad) / 2;
+}
+
+/*
+ * Autodetect onboard DDR SDRAM on 440 platforms
+ *
+ * NOTE: Some of the hardcoded values are hardware dependant,
+ * so this should be extended for other future boards
+ * using this routine!
+ */
+phys_size_t initdram(int board_type)
+{
+ int i;
+ int tr1_bank1;
+
+#if defined(CONFIG_440GX) || defined(CONFIG_440EP) || \
+ defined(CONFIG_440GR) || defined(CONFIG_440SP)
+ /*
+ * Soft-reset SDRAM controller.
+ */
+ mtsdr(SDR0_SRST, SDR0_SRST_DMC);
+ mtsdr(SDR0_SRST, 0x00000000);
+#endif
+
+ for (i=0; i<N_MB0CF; i++) {
+ /*
+ * Disable memory controller.
+ */
+ mtsdram(SDRAM0_CFG0, 0x00000000);
+
+ /*
+ * Setup some default
+ */
+ mtsdram(SDRAM0_UABBA, 0x00000000); /* ubba=0 (default) */
+ mtsdram(SDRAM0_SLIO, 0x00000000); /* rdre=0 wrre=0 rarw=0 */
+ mtsdram(SDRAM0_DEVOPT, 0x00000000); /* dll=0 ds=0 (normal) */
+ mtsdram(SDRAM0_WDDCTR, CONFIG_SYS_SDRAM0_WDDCTR);
+ mtsdram(SDRAM0_CLKTR, 0x40000000); /* clkp=1 (90 deg wr) dcdt=0 */
+
+ /*
+ * Following for CAS Latency = 2.5 @ 133 MHz PLB
+ */
+ mtsdram(SDRAM0_B0CR, mb0cf[i].reg);
+ mtsdram(SDRAM0_TR0, CONFIG_SYS_SDRAM0_TR0);
+ mtsdram(SDRAM0_TR1, 0x80800800); /* SS=T2 SL=STAGE 3 CD=1 CT=0x00*/
+ mtsdram(SDRAM0_RTR, CONFIG_SYS_SDRAM0_RTR);
+ mtsdram(SDRAM0_CFG1, 0x00000000); /* Self-refresh exit, disable PM*/
+ udelay(400); /* Delay 200 usecs (min) */
+
+ /*
+ * Enable the controller, then wait for DCEN to complete
+ */
+ mtsdram(SDRAM0_CFG0, CONFIG_SYS_SDRAM0_CFG0);
+ udelay(10000);
+
+ if (get_ram_size(0, mb0cf[i].size) == mb0cf[i].size) {
+ phys_size_t size = mb0cf[i].size;
+ /*
+ * Optimize TR1 to current hardware environment
+ */
+ sdram_tr1_set(0x00000000, &tr1_bank1);
+ mtsdram(SDRAM0_TR1, (tr1_bank1 | 0x80800800));
+
+
+ /*
+ * OK, size detected. Enable second bank if
+ * defined (assumes same type as bank 0)
+ */
+#ifdef CONFIG_SDRAM_BANK1
+ mtsdram(SDRAM0_CFG0, 0);
+ mtsdram(SDRAM0_B1CR, mb0cf[i].size | mb0cf[i].reg);
+ mtsdram(SDRAM0_CFG0, CONFIG_SYS_SDRAM0_CFG0);
+ udelay(10000);
+
+ /*
+ * Check if 2nd bank is really available.
+ * If the size not equal to the size of the first
+ * bank, then disable the 2nd bank completely.
+ */
+ if (get_ram_size((long *)mb0cf[i].size, mb0cf[i].size)
+ != mb0cf[i].size) {
+ mtsdram(SDRAM0_CFG0, 0);
+ mtsdram(SDRAM0_B1CR, 0);
+ mtsdram(SDRAM0_CFG0, CONFIG_SYS_SDRAM0_CFG0);
+ udelay(10000);
+ } else {
+ /*
+ * We have two identical banks, so the size
+ * is twice the bank size
+ */
+ size = 2 * size;
+ }
+#endif
+
+#ifdef CONFIG_SDRAM_ECC
+ ecc_init(0, size);
+#endif
+
+ /*
+ * OK, size detected -> all done
+ */
+ return size;
+ }
+ }
+
+ return 0; /* nothing found ! */
+}
+
+#endif /* CONFIG_440 */
+
+#endif /* CONFIG_SDRAM_BANK0 */
diff --git a/arch/powerpc/cpu/ppc4xx/sdram.h b/arch/powerpc/cpu/ppc4xx/sdram.h
new file mode 100644
index 0000000..bea3376
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/sdram.h
@@ -0,0 +1,76 @@
+/*
+ * (C) Copyright 2006
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * (C) Copyright 2006
+ * DAVE Srl <www.dave-tech.it>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _SDRAM_H_
+#define _SDRAM_H_
+
+#include <config.h>
+
+#define ONE_BILLION 1000000000
+
+struct sdram_conf_s {
+ unsigned long size;
+ int rows;
+ unsigned long reg;
+};
+
+typedef struct sdram_conf_s sdram_conf_t;
+
+/* Bitfields offsets */
+#define SDRAM0_TR_CASL (31 - 8)
+#define SDRAM0_TR_PTA (31 - 13)
+#define SDRAM0_TR_CTP (31 - 15)
+#define SDRAM0_TR_LDF (31 - 17)
+#define SDRAM0_TR_RFTA (31 - 29)
+#define SDRAM0_TR_RCD (31 - 31)
+
+#ifdef CONFIG_SYS_SDRAM_CL
+/* SDRAM timings [ns] according to AMCC/IBM names (see SDRAM_faq.doc) */
+#define CONFIG_SYS_SDRAM_CASL CONFIG_SYS_SDRAM_CL
+#define CONFIG_SYS_SDRAM_PTA CONFIG_SYS_SDRAM_tRP
+#define CONFIG_SYS_SDRAM_CTP (CONFIG_SYS_SDRAM_tRC - CONFIG_SYS_SDRAM_tRCD - CONFIG_SYS_SDRAM_tRP)
+#define CONFIG_SYS_SDRAM_LDF 0
+#ifdef CONFIG_SYS_SDRAM_tRFC
+#define CONFIG_SYS_SDRAM_RFTA CONFIG_SYS_SDRAM_tRFC
+#else
+#define CONFIG_SYS_SDRAM_RFTA CONFIG_SYS_SDRAM_tRC
+#endif
+#define CONFIG_SYS_SDRAM_RCD CONFIG_SYS_SDRAM_tRCD
+#endif /* #ifdef CONFIG_SYS_SDRAM_CL */
+
+/*
+ * Some defines for the 440 DDR controller
+ */
+#define SDRAM_CFG0_DC_EN 0x80000000 /* SDRAM Controller Enable */
+#define SDRAM_CFG0_MEMCHK 0x30000000 /* Memory data error checking mask*/
+#define SDRAM_CFG0_MEMCHK_NON 0x00000000 /* No ECC generation */
+#define SDRAM_CFG0_MEMCHK_GEN 0x20000000 /* ECC generation */
+#define SDRAM_CFG0_MEMCHK_CHK 0x30000000 /* ECC generation and checking */
+#define SDRAM_CFG0_DRAMWDTH 0x02000000 /* DRAM width mask */
+#define SDRAM_CFG0_DRAMWDTH_32 0x00000000 /* 32 bits */
+#define SDRAM_CFG0_DRAMWDTH_64 0x02000000 /* 64 bits */
+
+#endif
diff --git a/arch/powerpc/cpu/ppc4xx/speed.c b/arch/powerpc/cpu/ppc4xx/speed.c
new file mode 100644
index 0000000..45ef035
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/speed.c
@@ -0,0 +1,1225 @@
+/*
+ * (C) Copyright 2000-2008
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <ppc_asm.tmpl>
+#include <asm/ppc4xx.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define ONE_BILLION 1000000000
+#ifdef DEBUG
+#define DEBUGF(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#endif
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR)
+
+void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
+{
+ unsigned long pllmr;
+ unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
+ uint pvr = get_pvr();
+ unsigned long psr;
+ unsigned long m;
+
+ /*
+ * Read PLL Mode register
+ */
+ pllmr = mfdcr (CPC0_PLLMR);
+
+ /*
+ * Read Pin Strapping register
+ */
+ psr = mfdcr (CPC0_PSR);
+
+ /*
+ * Determine FWD_DIV.
+ */
+ sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29);
+
+ /*
+ * Determine FBK_DIV.
+ */
+ sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25);
+ if (sysInfo->pllFbkDiv == 0) {
+ sysInfo->pllFbkDiv = 16;
+ }
+
+ /*
+ * Determine PLB_DIV.
+ */
+ sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1;
+
+ /*
+ * Determine PCI_DIV.
+ */
+ sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1;
+
+ /*
+ * Determine EXTBUS_DIV.
+ */
+ sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2;
+
+ /*
+ * Determine OPB_DIV.
+ */
+ sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1;
+
+ /*
+ * Check if PPC405GPr used (mask minor revision field)
+ */
+ if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
+ /*
+ * Determine FWD_DIV B (only PPC405GPr with new mode strapping).
+ */
+ sysInfo->pllFwdDivB = 8 - (pllmr & PLLMR_FWDB_DIV_MASK);
+
+ /*
+ * Determine factor m depending on PLL feedback clock source
+ */
+ if (!(psr & PSR_PCI_ASYNC_EN)) {
+ if (psr & PSR_NEW_MODE_EN) {
+ /*
+ * sync pci clock used as feedback (new mode)
+ */
+ m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllPciDiv;
+ } else {
+ /*
+ * sync pci clock used as feedback (legacy mode)
+ */
+ m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllPciDiv;
+ }
+ } else if (psr & PSR_NEW_MODE_EN) {
+ if (psr & PSR_PERCLK_SYNC_MODE_EN) {
+ /*
+ * PerClk used as feedback (new mode)
+ */
+ m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllExtBusDiv;
+ } else {
+ /*
+ * CPU clock used as feedback (new mode)
+ */
+ m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
+ }
+ } else if (sysInfo->pllExtBusDiv == sysInfo->pllFbkDiv) {
+ /*
+ * PerClk used as feedback (legacy mode)
+ */
+ m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllExtBusDiv;
+ } else {
+ /*
+ * PLB clock used as feedback (legacy mode)
+ */
+ m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv;
+ }
+
+ sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
+ (unsigned long long)sysClkPeriodPs;
+ sysInfo->freqProcessor = sysInfo->freqVCOHz / sysInfo->pllFwdDiv;
+ sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDivB * sysInfo->pllPlbDiv);
+ } else {
+ /*
+ * Check pllFwdDiv to see if running in bypass mode where the CPU speed
+ * is equal to the 405GP SYS_CLK_FREQ. If not in bypass mode, check VCO
+ * to make sure it is within the proper range.
+ * spec: VCO = SYS_CLOCK x FBKDIV x PLBDIV x FWDDIV
+ * Note freqVCO is calculated in MHz to avoid errors introduced by rounding.
+ */
+ if (sysInfo->pllFwdDiv == 1) {
+ sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
+ sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv;
+ } else {
+ sysInfo->freqVCOHz = ( 1000000000000LL *
+ (unsigned long long)sysInfo->pllFwdDiv *
+ (unsigned long long)sysInfo->pllFbkDiv *
+ (unsigned long long)sysInfo->pllPlbDiv
+ ) / (unsigned long long)sysClkPeriodPs;
+ sysInfo->freqPLB = (ONE_BILLION / ((sysClkPeriodPs * 10) /
+ sysInfo->pllFbkDiv)) * 10000;
+ sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv;
+ }
+ }
+
+ sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
+ sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
+ sysInfo->freqUART = sysInfo->freqProcessor;
+}
+
+
+/********************************************
+ * get_PCI_freq
+ * return PCI bus freq in Hz
+ *********************************************/
+ulong get_PCI_freq (void)
+{
+ ulong val;
+ PPC4xx_SYS_INFO sys_info;
+
+ get_sys_info (&sys_info);
+ val = sys_info.freqPLB / sys_info.pllPciDiv;
+ return val;
+}
+
+
+#elif defined(CONFIG_440)
+
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_460SX) || defined(CONFIG_APM821XX)
+static u8 pll_fwdv_multi_bits[] = {
+ /* values for: 1 - 16 */
+ 0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
+ 0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
+};
+
+u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
+{
+ u32 index;
+
+ for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
+ if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
+ return index + 1;
+
+ return 0;
+}
+
+static u8 pll_fbdv_multi_bits[] = {
+ /* values for: 1 - 100 */
+ 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
+ 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
+ 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
+ 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
+ 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
+ 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
+ 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
+ 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
+ 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
+ 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
+ /* values for: 101 - 200 */
+ 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
+ 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
+ 0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
+ 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
+ 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
+ 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
+ 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
+ 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
+ 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
+ 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
+ /* values for: 201 - 255 */
+ 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
+ 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
+ 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
+ 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
+ 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
+ 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
+};
+
+u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
+{
+ u32 index;
+
+ for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
+ if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
+ return index + 1;
+
+ return 0;
+}
+
+#if defined(CONFIG_APM821XX)
+
+void get_sys_info(sys_info_t *sysInfo)
+{
+ unsigned long plld;
+ unsigned long temp;
+ unsigned long mul;
+ unsigned long cpudv;
+ unsigned long plb2dv;
+ unsigned long ddr2dv;
+
+ /* Calculate Forward divisor A and Feeback divisor */
+ mfcpr(CPR0_PLLD, plld);
+
+ temp = CPR0_PLLD_FWDVA(plld);
+ sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
+
+ temp = CPR0_PLLD_FDV(plld);
+ sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
+
+ /* Calculate OPB clock divisor */
+ mfcpr(CPR0_OPBD, temp);
+ temp = CPR0_OPBD_OPBDV(temp);
+ sysInfo->pllOpbDiv = temp ? temp : 4;
+
+ /* Calculate Peripheral clock divisor */
+ mfcpr(CPR0_PERD, temp);
+ temp = CPR0_PERD_PERDV(temp);
+ sysInfo->pllExtBusDiv = temp ? temp : 4;
+
+ /* Calculate CPU clock divisor */
+ mfcpr(CPR0_CPUD, temp);
+ temp = CPR0_CPUD_CPUDV(temp);
+ cpudv = temp ? temp : 8;
+
+ /* Calculate PLB2 clock divisor */
+ mfcpr(CPR0_PLB2D, temp);
+ temp = CPR0_PLB2D_PLB2DV(temp);
+ plb2dv = temp ? temp : 4;
+
+ /* Calculate DDR2 clock divisor */
+ mfcpr(CPR0_DDR2D, temp);
+ temp = CPR0_DDR2D_DDR2DV(temp);
+ ddr2dv = temp ? temp : 4;
+
+ /* Calculate 'M' based on feedback source */
+ mfcpr(CPR0_PLLC, temp);
+ temp = CPR0_PLLC_SEL(temp);
+ if (temp == 0) {
+ /* PLL internal feedback */
+ mul = sysInfo->pllFbkDiv;
+ } else {
+ /* PLL PerClk feedback */
+ mul = sysInfo->pllFwdDivA * sysInfo->pllFbkDiv * cpudv
+ * plb2dv * 2 * sysInfo->pllOpbDiv *
+ sysInfo->pllExtBusDiv;
+ }
+
+ /* Now calculate the individual clocks */
+ sysInfo->freqVCOMhz = (mul * CONFIG_SYS_CLK_FREQ) + (mul >> 1);
+ sysInfo->freqProcessor = sysInfo->freqVCOMhz /
+ sysInfo->pllFwdDivA / cpudv;
+ sysInfo->freqPLB = sysInfo->freqVCOMhz /
+ sysInfo->pllFwdDivA / cpudv / plb2dv / 2;
+ sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
+ sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
+ sysInfo->freqDDR = sysInfo->freqVCOMhz /
+ sysInfo->pllFwdDivA / cpudv / ddr2dv / 2;
+ sysInfo->freqUART = sysInfo->freqPLB;
+}
+
+#else
+/*
+ * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
+ * with latest EAS
+ */
+void get_sys_info (sys_info_t * sysInfo)
+{
+ unsigned long strp0;
+ unsigned long strp1;
+ unsigned long temp;
+ unsigned long m;
+ unsigned long plbedv0;
+
+ /* Extract configured divisors */
+ mfsdr(SDR0_SDSTP0, strp0);
+ mfsdr(SDR0_SDSTP1, strp1);
+
+ temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
+ sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
+
+ temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
+ sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
+
+ temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
+ sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
+
+ temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
+ sysInfo->pllOpbDiv = temp ? temp : 4;
+
+ /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
+ temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
+ sysInfo->pllExtBusDiv = temp ? temp : 4;
+
+ temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
+ plbedv0 = temp ? temp: 8;
+
+ /* Calculate 'M' based on feedback source */
+ temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
+ if (temp == 0) {
+ /* PLL internal feedback */
+ m = sysInfo->pllFbkDiv;
+ } else {
+ /* PLL PerClk feedback */
+ m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
+ sysInfo->pllExtBusDiv;
+ }
+
+ /* Now calculate the individual clocks */
+ sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
+ sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
+ sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
+ sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
+ sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
+ sysInfo->freqDDR = sysInfo->freqPLB;
+ sysInfo->freqUART = sysInfo->freqPLB;
+
+ return;
+}
+#endif
+
+#elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+void get_sys_info (sys_info_t *sysInfo)
+{
+ unsigned long temp;
+ unsigned long reg;
+ unsigned long lfdiv;
+ unsigned long m;
+ unsigned long prbdv0;
+ /*
+ WARNING: ASSUMES the following:
+ ENG=1
+ PRADV0=1
+ PRBDV0=1
+ */
+
+ /* Decode CPR0_PLLD0 for divisors */
+ mfcpr(CPR0_PLLD, reg);
+ temp = (reg & PLLD_FWDVA_MASK) >> 16;
+ sysInfo->pllFwdDivA = temp ? temp : 16;
+ temp = (reg & PLLD_FWDVB_MASK) >> 8;
+ sysInfo->pllFwdDivB = temp ? temp: 8 ;
+ temp = (reg & PLLD_FBDV_MASK) >> 24;
+ sysInfo->pllFbkDiv = temp ? temp : 32;
+ lfdiv = reg & PLLD_LFBDV_MASK;
+
+ mfcpr(CPR0_OPBD0, reg);
+ temp = (reg & OPBDDV_MASK) >> 24;
+ sysInfo->pllOpbDiv = temp ? temp : 4;
+
+ mfcpr(CPR0_PERD, reg);
+ temp = (reg & PERDV_MASK) >> 24;
+ sysInfo->pllExtBusDiv = temp ? temp : 8;
+
+ mfcpr(CPR0_PRIMBD0, reg);
+ temp = (reg & PRBDV_MASK) >> 24;
+ prbdv0 = temp ? temp : 8;
+
+ mfcpr(CPR0_SPCID, reg);
+ temp = (reg & SPCID_MASK) >> 24;
+ sysInfo->pllPciDiv = temp ? temp : 4;
+
+ /* Calculate 'M' based on feedback source */
+ mfsdr(SDR0_SDSTP0, reg);
+ temp = (reg & PLLSYS0_SEL_MASK) >> 27;
+ if (temp == 0) { /* PLL output */
+ /* Figure which pll to use */
+ mfcpr(CPR0_PLLC, reg);
+ temp = (reg & PLLC_SRC_MASK) >> 29;
+ if (!temp) /* PLLOUTA */
+ m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
+ else /* PLLOUTB */
+ m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
+ }
+ else if (temp == 1) /* CPU output */
+ m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
+ else /* PerClk */
+ m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
+
+ /* Now calculate the individual clocks */
+ sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
+ sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
+ sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
+ sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
+ sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
+ sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
+ sysInfo->freqUART = sysInfo->freqPLB;
+
+ /* Figure which timer source to use */
+ if (mfspr(SPRN_CCR1) & 0x0080) {
+ /* External Clock, assume same as SYS_CLK */
+ temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
+ if (CONFIG_SYS_CLK_FREQ > temp)
+ sysInfo->freqTmrClk = temp;
+ else
+ sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
+ }
+ else /* Internal clock */
+ sysInfo->freqTmrClk = sysInfo->freqProcessor;
+}
+
+/********************************************
+ * get_PCI_freq
+ * return PCI bus freq in Hz
+ *********************************************/
+ulong get_PCI_freq (void)
+{
+ sys_info_t sys_info;
+ get_sys_info (&sys_info);
+ return sys_info.freqPCI;
+}
+
+#elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
+ && !defined(CONFIG_XILINX_440)
+void get_sys_info (sys_info_t * sysInfo)
+{
+ unsigned long strp0;
+ unsigned long temp;
+ unsigned long m;
+
+ /* Extract configured divisors */
+ strp0 = mfdcr( CPC0_STRP0 );
+ sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
+ sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
+ temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
+ sysInfo->pllFbkDiv = temp ? temp : 16;
+ sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
+ sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
+
+ /* Calculate 'M' based on feedback source */
+ if( strp0 & PLLSYS0_EXTSL_MASK )
+ m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
+ else
+ m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
+
+ /* Now calculate the individual clocks */
+ sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
+ sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
+ sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
+ if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
+ sysInfo->freqPLB >>= 1;
+ sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
+ sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
+ sysInfo->freqUART = sysInfo->freqPLB;
+}
+#else
+
+#if !defined(CONFIG_XILINX_440)
+void get_sys_info (sys_info_t * sysInfo)
+{
+ unsigned long strp0;
+ unsigned long strp1;
+ unsigned long temp;
+ unsigned long temp1;
+ unsigned long lfdiv;
+ unsigned long m;
+ unsigned long prbdv0;
+
+#if defined(CONFIG_YUCCA)
+ unsigned long sys_freq;
+ unsigned long sys_per=0;
+ unsigned long msr;
+ unsigned long pci_clock_per;
+ unsigned long sdr_ddrpll;
+
+ /*-------------------------------------------------------------------------+
+ | Get the system clock period.
+ +-------------------------------------------------------------------------*/
+ sys_per = determine_sysper();
+
+ msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
+
+ /*-------------------------------------------------------------------------+
+ | Calculate the system clock speed from the period.
+ +-------------------------------------------------------------------------*/
+ sys_freq = (ONE_BILLION / sys_per) * 1000;
+#endif
+
+ /* Extract configured divisors */
+ mfsdr( SDR0_SDSTP0,strp0 );
+ mfsdr( SDR0_SDSTP1,strp1 );
+
+ temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
+ sysInfo->pllFwdDivA = temp ? temp : 16 ;
+ temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
+ sysInfo->pllFwdDivB = temp ? temp: 8 ;
+ temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
+ sysInfo->pllFbkDiv = temp ? temp : 32;
+ temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
+ sysInfo->pllOpbDiv = temp ? temp : 4;
+ temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
+ sysInfo->pllExtBusDiv = temp ? temp : 4;
+ prbdv0 = (strp0 >> 2) & 0x7;
+
+ /* Calculate 'M' based on feedback source */
+ temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
+ temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
+ lfdiv = temp1 ? temp1 : 64;
+ if (temp == 0) { /* PLL output */
+ /* Figure which pll to use */
+ temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
+ if (!temp)
+ m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
+ else
+ m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
+ }
+ else if (temp == 1) /* CPU output */
+ m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
+ else /* PerClk */
+ m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
+
+ /* Now calculate the individual clocks */
+#if defined(CONFIG_YUCCA)
+ sysInfo->freqVCOMhz = (m * sys_freq) ;
+#else
+ sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
+#endif
+ sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
+ sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
+ sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
+ sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
+
+#if defined(CONFIG_YUCCA)
+ /* Determine PCI Clock Period */
+ pci_clock_per = determine_pci_clock_per();
+ sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
+ mfsdr(SDR0_DDR0, sdr_ddrpll);
+ sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
+#endif
+
+ sysInfo->freqUART = sysInfo->freqPLB;
+}
+
+#endif
+#endif /* CONFIG_XILINX_440 */
+
+#if defined(CONFIG_YUCCA)
+unsigned long determine_sysper(void)
+{
+ unsigned int fpga_clocking_reg;
+ unsigned int master_clock_selection;
+ unsigned long master_clock_per = 0;
+ unsigned long fb_div_selection;
+ unsigned int vco_div_reg_value;
+ unsigned long vco_div_selection;
+ unsigned long sys_per = 0;
+ int extClkVal;
+
+ /*-------------------------------------------------------------------------+
+ | Read FPGA reg 0 and reg 1 to get FPGA reg information
+ +-------------------------------------------------------------------------*/
+ fpga_clocking_reg = in16(FPGA_REG16);
+
+
+ /* Determine Master Clock Source Selection */
+ master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
+
+ switch(master_clock_selection) {
+ case FPGA_REG16_MASTER_CLK_66_66:
+ master_clock_per = PERIOD_66_66MHZ;
+ break;
+ case FPGA_REG16_MASTER_CLK_50:
+ master_clock_per = PERIOD_50_00MHZ;
+ break;
+ case FPGA_REG16_MASTER_CLK_33_33:
+ master_clock_per = PERIOD_33_33MHZ;
+ break;
+ case FPGA_REG16_MASTER_CLK_25:
+ master_clock_per = PERIOD_25_00MHZ;
+ break;
+ case FPGA_REG16_MASTER_CLK_EXT:
+ if ((extClkVal==EXTCLK_33_33)
+ && (extClkVal==EXTCLK_50)
+ && (extClkVal==EXTCLK_66_66)
+ && (extClkVal==EXTCLK_83)) {
+ /* calculate master clock period from external clock value */
+ master_clock_per=(ONE_BILLION/extClkVal) * 1000;
+ } else {
+ /* Unsupported */
+ DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
+ hang();
+ }
+ break;
+ default:
+ /* Unsupported */
+ DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
+ hang();
+ break;
+ }
+
+ /* Determine FB divisors values */
+ if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
+ if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
+ fb_div_selection = FPGA_FB_DIV_6;
+ else
+ fb_div_selection = FPGA_FB_DIV_12;
+ } else {
+ if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
+ fb_div_selection = FPGA_FB_DIV_10;
+ else
+ fb_div_selection = FPGA_FB_DIV_20;
+ }
+
+ /* Determine VCO divisors values */
+ vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
+
+ switch(vco_div_reg_value) {
+ case FPGA_REG16_VCO_DIV_4:
+ vco_div_selection = FPGA_VCO_DIV_4;
+ break;
+ case FPGA_REG16_VCO_DIV_6:
+ vco_div_selection = FPGA_VCO_DIV_6;
+ break;
+ case FPGA_REG16_VCO_DIV_8:
+ vco_div_selection = FPGA_VCO_DIV_8;
+ break;
+ case FPGA_REG16_VCO_DIV_10:
+ default:
+ vco_div_selection = FPGA_VCO_DIV_10;
+ break;
+ }
+
+ if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
+ switch(master_clock_per) {
+ case PERIOD_25_00MHZ:
+ if (fb_div_selection == FPGA_FB_DIV_12) {
+ if (vco_div_selection == FPGA_VCO_DIV_4)
+ sys_per = PERIOD_75_00MHZ;
+ if (vco_div_selection == FPGA_VCO_DIV_6)
+ sys_per = PERIOD_50_00MHZ;
+ }
+ break;
+ case PERIOD_33_33MHZ:
+ if (fb_div_selection == FPGA_FB_DIV_6) {
+ if (vco_div_selection == FPGA_VCO_DIV_4)
+ sys_per = PERIOD_50_00MHZ;
+ if (vco_div_selection == FPGA_VCO_DIV_6)
+ sys_per = PERIOD_33_33MHZ;
+ }
+ if (fb_div_selection == FPGA_FB_DIV_10) {
+ if (vco_div_selection == FPGA_VCO_DIV_4)
+ sys_per = PERIOD_83_33MHZ;
+ if (vco_div_selection == FPGA_VCO_DIV_10)
+ sys_per = PERIOD_33_33MHZ;
+ }
+ if (fb_div_selection == FPGA_FB_DIV_12) {
+ if (vco_div_selection == FPGA_VCO_DIV_4)
+ sys_per = PERIOD_100_00MHZ;
+ if (vco_div_selection == FPGA_VCO_DIV_6)
+ sys_per = PERIOD_66_66MHZ;
+ if (vco_div_selection == FPGA_VCO_DIV_8)
+ sys_per = PERIOD_50_00MHZ;
+ }
+ break;
+ case PERIOD_50_00MHZ:
+ if (fb_div_selection == FPGA_FB_DIV_6) {
+ if (vco_div_selection == FPGA_VCO_DIV_4)
+ sys_per = PERIOD_75_00MHZ;
+ if (vco_div_selection == FPGA_VCO_DIV_6)
+ sys_per = PERIOD_50_00MHZ;
+ }
+ if (fb_div_selection == FPGA_FB_DIV_10) {
+ if (vco_div_selection == FPGA_VCO_DIV_6)
+ sys_per = PERIOD_83_33MHZ;
+ if (vco_div_selection == FPGA_VCO_DIV_10)
+ sys_per = PERIOD_50_00MHZ;
+ }
+ if (fb_div_selection == FPGA_FB_DIV_12) {
+ if (vco_div_selection == FPGA_VCO_DIV_6)
+ sys_per = PERIOD_100_00MHZ;
+ if (vco_div_selection == FPGA_VCO_DIV_8)
+ sys_per = PERIOD_75_00MHZ;
+ }
+ break;
+ case PERIOD_66_66MHZ:
+ if (fb_div_selection == FPGA_FB_DIV_6) {
+ if (vco_div_selection == FPGA_VCO_DIV_4)
+ sys_per = PERIOD_100_00MHZ;
+ if (vco_div_selection == FPGA_VCO_DIV_6)
+ sys_per = PERIOD_66_66MHZ;
+ if (vco_div_selection == FPGA_VCO_DIV_8)
+ sys_per = PERIOD_50_00MHZ;
+ }
+ if (fb_div_selection == FPGA_FB_DIV_10) {
+ if (vco_div_selection == FPGA_VCO_DIV_8)
+ sys_per = PERIOD_83_33MHZ;
+ if (vco_div_selection == FPGA_VCO_DIV_10)
+ sys_per = PERIOD_66_66MHZ;
+ }
+ if (fb_div_selection == FPGA_FB_DIV_12) {
+ if (vco_div_selection == FPGA_VCO_DIV_8)
+ sys_per = PERIOD_100_00MHZ;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (sys_per == 0) {
+ /* Other combinations are not supported */
+ DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
+ hang();
+ }
+ } else {
+ /* calcul system clock without cheking */
+ /* if engineering option clock no check is selected */
+ /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
+ sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
+ }
+
+ return(sys_per);
+}
+
+/*-------------------------------------------------------------------------+
+| determine_pci_clock_per.
++-------------------------------------------------------------------------*/
+unsigned long determine_pci_clock_per(void)
+{
+ unsigned long pci_clock_selection, pci_period;
+
+ /*-------------------------------------------------------------------------+
+ | Read FPGA reg 6 to get PCI 0 FPGA reg information
+ +-------------------------------------------------------------------------*/
+ pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
+
+
+ pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
+
+ switch (pci_clock_selection) {
+ case FPGA_REG16_PCI0_CLK_133_33:
+ pci_period = PERIOD_133_33MHZ;
+ break;
+ case FPGA_REG16_PCI0_CLK_100:
+ pci_period = PERIOD_100_00MHZ;
+ break;
+ case FPGA_REG16_PCI0_CLK_66_66:
+ pci_period = PERIOD_66_66MHZ;
+ break;
+ default:
+ pci_period = PERIOD_33_33MHZ;;
+ break;
+ }
+
+ return(pci_period);
+}
+#endif
+
+#elif defined(CONFIG_XILINX_405)
+extern void get_sys_info (sys_info_t * sysInfo);
+extern ulong get_PCI_freq (void);
+
+#elif defined(CONFIG_405)
+
+void get_sys_info (sys_info_t * sysInfo)
+{
+ sysInfo->freqVCOMhz=3125000;
+ sysInfo->freqProcessor=12*1000*1000;
+ sysInfo->freqPLB=50*1000*1000;
+ sysInfo->freqPCI=66*1000*1000;
+}
+
+#elif defined(CONFIG_405EP)
+void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
+{
+ unsigned long pllmr0;
+ unsigned long pllmr1;
+ unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
+ unsigned long m;
+ unsigned long pllmr0_ccdv;
+
+ /*
+ * Read PLL Mode registers
+ */
+ pllmr0 = mfdcr (CPC0_PLLMR0);
+ pllmr1 = mfdcr (CPC0_PLLMR1);
+
+ /*
+ * Determine forward divider A
+ */
+ sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
+
+ /*
+ * Determine forward divider B (should be equal to A)
+ */
+ sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
+
+ /*
+ * Determine FBK_DIV.
+ */
+ sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
+ if (sysInfo->pllFbkDiv == 0)
+ sysInfo->pllFbkDiv = 16;
+
+ /*
+ * Determine PLB_DIV.
+ */
+ sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
+
+ /*
+ * Determine PCI_DIV.
+ */
+ sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
+
+ /*
+ * Determine EXTBUS_DIV.
+ */
+ sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
+
+ /*
+ * Determine OPB_DIV.
+ */
+ sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
+
+ /*
+ * Determine the M factor
+ */
+ m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
+
+ /*
+ * Determine VCO clock frequency
+ */
+ sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
+ (unsigned long long)sysClkPeriodPs;
+
+ /*
+ * Determine CPU clock frequency
+ */
+ pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
+ if (pllmr1 & PLLMR1_SSCS_MASK) {
+ /*
+ * This is true if FWDVA == FWDVB:
+ * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
+ * / pllmr0_ccdv;
+ */
+ sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
+ / sysInfo->pllFwdDiv / pllmr0_ccdv;
+ } else {
+ sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
+ }
+
+ /*
+ * Determine PLB clock frequency
+ */
+ sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
+
+ sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
+
+ sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
+
+ sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
+}
+
+
+/********************************************
+ * get_PCI_freq
+ * return PCI bus freq in Hz
+ *********************************************/
+ulong get_PCI_freq (void)
+{
+ ulong val;
+ PPC4xx_SYS_INFO sys_info;
+
+ get_sys_info (&sys_info);
+ val = sys_info.freqPLB / sys_info.pllPciDiv;
+ return val;
+}
+
+#elif defined(CONFIG_405EZ)
+void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
+{
+ unsigned long cpr_plld;
+ unsigned long cpr_pllc;
+ unsigned long cpr_primad;
+ unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
+ unsigned long primad_cpudv;
+ unsigned long m;
+ unsigned long plloutb;
+
+ /*
+ * Read PLL Mode registers
+ */
+ mfcpr(CPR0_PLLD, cpr_plld);
+ mfcpr(CPR0_PLLC, cpr_pllc);
+
+ /*
+ * Determine forward divider A
+ */
+ sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
+
+ /*
+ * Determine forward divider B
+ */
+ sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
+ if (sysInfo->pllFwdDivB == 0)
+ sysInfo->pllFwdDivB = 8;
+
+ /*
+ * Determine FBK_DIV.
+ */
+ sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
+ if (sysInfo->pllFbkDiv == 0)
+ sysInfo->pllFbkDiv = 256;
+
+ /*
+ * Read CPR_PRIMAD register
+ */
+ mfcpr(CPR0_PRIMAD, cpr_primad);
+
+ /*
+ * Determine PLB_DIV.
+ */
+ sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
+ if (sysInfo->pllPlbDiv == 0)
+ sysInfo->pllPlbDiv = 16;
+
+ /*
+ * Determine EXTBUS_DIV.
+ */
+ sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
+ if (sysInfo->pllExtBusDiv == 0)
+ sysInfo->pllExtBusDiv = 16;
+
+ /*
+ * Determine OPB_DIV.
+ */
+ sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
+ if (sysInfo->pllOpbDiv == 0)
+ sysInfo->pllOpbDiv = 16;
+
+ /*
+ * Determine the M factor
+ */
+ if (cpr_pllc & PLLC_SRC_MASK)
+ m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
+ else
+ m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
+
+ /*
+ * Determine VCO clock frequency
+ */
+ sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
+ (unsigned long long)sysClkPeriodPs;
+
+ /*
+ * Determine CPU clock frequency
+ */
+ primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
+ if (primad_cpudv == 0)
+ primad_cpudv = 16;
+
+ sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
+ sysInfo->pllFwdDiv / primad_cpudv;
+
+ /*
+ * Determine PLB clock frequency
+ */
+ sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
+ sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
+
+ sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
+ sysInfo->pllOpbDiv;
+
+ sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
+ sysInfo->pllExtBusDiv;
+
+ plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
+ sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
+ sysInfo->pllFwdDivB);
+ sysInfo->freqUART = plloutb;
+}
+
+#elif defined(CONFIG_405EX)
+
+/*
+ * TODO: We need to get the CPR registers and calculate these values correctly!!!!
+ * We need the specs!!!!
+ */
+static unsigned char get_fbdv(unsigned char index)
+{
+ unsigned char ret = 0;
+ /* This is table should be 256 bytes.
+ * Only take first 52 values.
+ */
+ unsigned char fbdv_tb[] = {
+ 0x00, 0xff, 0x7f, 0xfd,
+ 0x7a, 0xf5, 0x6a, 0xd5,
+ 0x2a, 0xd4, 0x29, 0xd3,
+ 0x26, 0xcc, 0x19, 0xb3,
+ 0x67, 0xce, 0x1d, 0xbb,
+ 0x77, 0xee, 0x5d, 0xba,
+ 0x74, 0xe9, 0x52, 0xa5,
+ 0x4b, 0x96, 0x2c, 0xd8,
+ 0x31, 0xe3, 0x46, 0x8d,
+ 0x1b, 0xb7, 0x6f, 0xde,
+ 0x3d, 0xfb, 0x76, 0xed,
+ 0x5a, 0xb5, 0x6b, 0xd6,
+ 0x2d, 0xdb, 0x36, 0xec,
+
+ };
+
+ if ((index & 0x7f) == 0)
+ return 1;
+ while (ret < sizeof (fbdv_tb)) {
+ if (fbdv_tb[ret] == index)
+ break;
+ ret++;
+ }
+ ret++;
+
+ return ret;
+}
+
+#define PLL_FBK_PLL_LOCAL 0
+#define PLL_FBK_CPU 1
+#define PLL_FBK_PERCLK 5
+
+void get_sys_info (sys_info_t * sysInfo)
+{
+ unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
+ unsigned long m = 1;
+ unsigned int tmp;
+ unsigned char fwdva[16] = {
+ 1, 2, 14, 9, 4, 11, 16, 13,
+ 12, 5, 6, 15, 10, 7, 8, 3,
+ };
+ unsigned char sel, cpudv0, plb2xDiv;
+
+ mfcpr(CPR0_PLLD, tmp);
+
+ /*
+ * Determine forward divider A
+ */
+ sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
+
+ /*
+ * Determine FBK_DIV.
+ */
+ sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
+
+ /*
+ * Determine PLBDV0
+ */
+ sysInfo->pllPlbDiv = 2;
+
+ /*
+ * Determine PERDV0
+ */
+ mfcpr(CPR0_PERD, tmp);
+ tmp = (tmp >> 24) & 0x03;
+ sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
+
+ /*
+ * Determine OPBDV0
+ */
+ mfcpr(CPR0_OPBD0, tmp);
+ tmp = (tmp >> 24) & 0x03;
+ sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
+
+ /* Determine PLB2XDV0 */
+ mfcpr(CPR0_PLBD, tmp);
+ tmp = (tmp >> 16) & 0x07;
+ plb2xDiv = (tmp == 0) ? 8 : tmp;
+
+ /* Determine CPUDV0 */
+ mfcpr(CPR0_CPUD, tmp);
+ tmp = (tmp >> 24) & 0x07;
+ cpudv0 = (tmp == 0) ? 8 : tmp;
+
+ /* Determine SEL(5:7) in CPR0_PLLC */
+ mfcpr(CPR0_PLLC, tmp);
+ sel = (tmp >> 24) & 0x07;
+
+ /*
+ * Determine the M factor
+ * PLL local: M = FBDV
+ * CPU clock: M = FBDV * FWDVA * CPUDV0
+ * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
+ *
+ */
+ switch (sel) {
+ case PLL_FBK_CPU:
+ m = sysInfo->pllFwdDiv * cpudv0;
+ break;
+ case PLL_FBK_PERCLK:
+ m = sysInfo->pllFwdDiv * plb2xDiv * 2
+ * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
+ break;
+ case PLL_FBK_PLL_LOCAL:
+ break;
+ default:
+ printf("%s unknown m\n", __FUNCTION__);
+ return;
+
+ }
+ m *= sysInfo->pllFbkDiv;
+
+ /*
+ * Determine VCO clock frequency
+ */
+ sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
+ (unsigned long long)sysClkPeriodPs;
+
+ /*
+ * Determine CPU clock frequency
+ */
+ sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
+
+ /*
+ * Determine PLB clock frequency, ddr1x should be the same
+ */
+ sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
+ sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
+ sysInfo->freqDDR = sysInfo->freqPLB;
+ sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
+ sysInfo->freqUART = sysInfo->freqPLB;
+}
+
+#endif
+
+int get_clocks (void)
+{
+ sys_info_t sys_info;
+
+ get_sys_info (&sys_info);
+ gd->cpu_clk = sys_info.freqProcessor;
+ gd->bus_clk = sys_info.freqPLB;
+
+ return (0);
+}
+
+
+/********************************************
+ * get_bus_freq
+ * return PLB bus freq in Hz
+ *********************************************/
+ulong get_bus_freq (ulong dummy)
+{
+ ulong val;
+
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
+ defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
+ defined(CONFIG_405EX) || defined(CONFIG_405) || \
+ defined(CONFIG_440)
+ sys_info_t sys_info;
+
+ get_sys_info (&sys_info);
+ val = sys_info.freqPLB;
+#else
+# error get_bus_freq() not implemented
+#endif
+
+ return val;
+}
+
+ulong get_OPB_freq (void)
+{
+ PPC4xx_SYS_INFO sys_info;
+
+ get_sys_info (&sys_info);
+
+ return sys_info.freqOPB;
+}
diff --git a/arch/powerpc/cpu/ppc4xx/spl_boot.c b/arch/powerpc/cpu/ppc4xx/spl_boot.c
new file mode 100644
index 0000000..80869f6
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/spl_boot.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2013 Stefan Roese <sr@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <spl.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Return selected boot device. On PPC4xx its only NOR flash right now.
+ */
+u32 spl_boot_device(void)
+{
+ return BOOT_DEVICE_NOR;
+}
+
+/*
+ * SPL version of board_init_f()
+ */
+void board_init_f(ulong bootflag)
+{
+ /*
+ * First we need to initialize the SDRAM, so that the real
+ * U-Boot or the OS (Linux) can be loaded
+ */
+ initdram(0);
+
+ /* Clear bss */
+ memset(__bss_start, '\0', __bss_end - __bss_start);
+
+ /*
+ * Init global_data pointer. Has to be done before calling
+ * get_clocks(), as it stores some clock values into gd needed
+ * later on in the serial driver.
+ */
+ /* Pointer is writable since we allocated a register for it */
+ gd = (gd_t *)(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
+ /* Clear initial global data */
+ memset((void *)gd, 0, sizeof(gd_t));
+
+ /*
+ * get_clocks() needs to be called so that the serial driver
+ * works correctly
+ */
+ get_clocks();
+
+ /*
+ * Do rudimental console / serial setup
+ */
+ preloader_console_init();
+
+ /*
+ * Call board_init_r() (SPL framework version) to load and boot
+ * real U-Boot or OS
+ */
+ board_init_r(NULL, 0);
+ /* Does not return!!! */
+}
diff --git a/arch/powerpc/cpu/ppc4xx/start.S b/arch/powerpc/cpu/ppc4xx/start.S
new file mode 100644
index 0000000..57ae1d3
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/start.S
@@ -0,0 +1,2096 @@
+/*
+ * Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
+ * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
+ * Copyright (C) 2000,2001,2002 Wolfgang Denk <wd@denx.de>
+ * Copyright (C) 2007 Stefan Roese <sr@denx.de>, DENX Software Engineering
+ * Copyright (c) 2008 Nuovation System Designs, LLC
+ * Grant Erickson <gerickson@nuovations.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+/*------------------------------------------------------------------------------+
+ * This source code is dual-licensed. You may use it under the terms of the
+ * GNU General Public License version 2, or under the license below.
+ *
+ * This source code has been made available to you by IBM on an AS-IS
+ * basis. Anyone receiving this source is licensed under IBM
+ * copyrights to use it in any way he or she deems fit, including
+ * copying it, modifying it, compiling it, and redistributing it either
+ * with or without modifications. No license under IBM patents or
+ * patent applications is to be implied by the copyright license.
+ *
+ * Any user of this software should understand that IBM cannot provide
+ * technical support for this software and will not be responsible for
+ * any consequences resulting from the use of this software.
+ *
+ * Any person who transfers this source code or any derivative work
+ * must include the IBM copyright notice, this paragraph, and the
+ * preceding two paragraphs in the transferred software.
+ *
+ * COPYRIGHT I B M CORPORATION 1995
+ * LICENSED MATERIAL - PROGRAM PROPERTY OF I B M
+ *-------------------------------------------------------------------------------
+ */
+
+/*
+ * Startup code for IBM/AMCC PowerPC 4xx (PPC4xx) based boards
+ *
+ * The following description only applies to the NOR flash style booting.
+ * NAND booting is different. For more details about NAND booting on 4xx
+ * take a look at doc/README.nand-boot-ppc440.
+ *
+ * The CPU starts at address 0xfffffffc (last word in the address space).
+ * The U-Boot image therefore has to be located in the "upper" area of the
+ * flash (e.g. 512MiB - 0xfff80000 ... 0xffffffff). The default value for
+ * the boot chip-select (CS0) is quite big and covers this area. On the
+ * 405EX this is for example 0xffe00000 ... 0xffffffff. U-Boot will
+ * reconfigure this CS0 (and other chip-selects as well when configured
+ * this way) in the boot process to the "correct" values matching the
+ * board layout.
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <asm/ppc4xx.h>
+#include <version.h>
+
+#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+
+#include <asm/cache.h>
+#include <asm/mmu.h>
+#include <asm/ppc4xx-isram.h>
+
+#ifdef CONFIG_SYS_INIT_DCACHE_CS
+# if (CONFIG_SYS_INIT_DCACHE_CS == 0)
+# define PBxAP PB1AP
+# define PBxCR PB0CR
+# if (defined(CONFIG_SYS_EBC_PB0AP) && defined(CONFIG_SYS_EBC_PB0CR))
+# define PBxAP_VAL CONFIG_SYS_EBC_PB0AP
+# define PBxCR_VAL CONFIG_SYS_EBC_PB0CR
+# endif
+# endif
+# if (CONFIG_SYS_INIT_DCACHE_CS == 1)
+# define PBxAP PB1AP
+# define PBxCR PB1CR
+# if (defined(CONFIG_SYS_EBC_PB1AP) && defined(CONFIG_SYS_EBC_PB1CR))
+# define PBxAP_VAL CONFIG_SYS_EBC_PB1AP
+# define PBxCR_VAL CONFIG_SYS_EBC_PB1CR
+# endif
+# endif
+# if (CONFIG_SYS_INIT_DCACHE_CS == 2)
+# define PBxAP PB2AP
+# define PBxCR PB2CR
+# if (defined(CONFIG_SYS_EBC_PB2AP) && defined(CONFIG_SYS_EBC_PB2CR))
+# define PBxAP_VAL CONFIG_SYS_EBC_PB2AP
+# define PBxCR_VAL CONFIG_SYS_EBC_PB2CR
+# endif
+# endif
+# if (CONFIG_SYS_INIT_DCACHE_CS == 3)
+# define PBxAP PB3AP
+# define PBxCR PB3CR
+# if (defined(CONFIG_SYS_EBC_PB3AP) && defined(CONFIG_SYS_EBC_PB3CR))
+# define PBxAP_VAL CONFIG_SYS_EBC_PB3AP
+# define PBxCR_VAL CONFIG_SYS_EBC_PB3CR
+# endif
+# endif
+# if (CONFIG_SYS_INIT_DCACHE_CS == 4)
+# define PBxAP PB4AP
+# define PBxCR PB4CR
+# if (defined(CONFIG_SYS_EBC_PB4AP) && defined(CONFIG_SYS_EBC_PB4CR))
+# define PBxAP_VAL CONFIG_SYS_EBC_PB4AP
+# define PBxCR_VAL CONFIG_SYS_EBC_PB4CR
+# endif
+# endif
+# if (CONFIG_SYS_INIT_DCACHE_CS == 5)
+# define PBxAP PB5AP
+# define PBxCR PB5CR
+# if (defined(CONFIG_SYS_EBC_PB5AP) && defined(CONFIG_SYS_EBC_PB5CR))
+# define PBxAP_VAL CONFIG_SYS_EBC_PB5AP
+# define PBxCR_VAL CONFIG_SYS_EBC_PB5CR
+# endif
+# endif
+# if (CONFIG_SYS_INIT_DCACHE_CS == 6)
+# define PBxAP PB6AP
+# define PBxCR PB6CR
+# if (defined(CONFIG_SYS_EBC_PB6AP) && defined(CONFIG_SYS_EBC_PB6CR))
+# define PBxAP_VAL CONFIG_SYS_EBC_PB6AP
+# define PBxCR_VAL CONFIG_SYS_EBC_PB6CR
+# endif
+# endif
+# if (CONFIG_SYS_INIT_DCACHE_CS == 7)
+# define PBxAP PB7AP
+# define PBxCR PB7CR
+# if (defined(CONFIG_SYS_EBC_PB7AP) && defined(CONFIG_SYS_EBC_PB7CR))
+# define PBxAP_VAL CONFIG_SYS_EBC_PB7AP
+# define PBxCR_VAL CONFIG_SYS_EBC_PB7CR
+# endif
+# endif
+# ifndef PBxAP_VAL
+# define PBxAP_VAL 0
+# endif
+# ifndef PBxCR_VAL
+# define PBxCR_VAL 0
+# endif
+/*
+ * Memory Bank x (nothingness) initialization CONFIG_SYS_INIT_RAM_ADDR + 64 MiB
+ * used as temporary stack pointer for the primordial stack
+ */
+# ifndef CONFIG_SYS_INIT_DCACHE_PBxAR
+# define CONFIG_SYS_INIT_DCACHE_PBxAR (EBC_BXAP_BME_DISABLED | \
+ EBC_BXAP_TWT_ENCODE(7) | \
+ EBC_BXAP_BCE_DISABLE | \
+ EBC_BXAP_BCT_2TRANS | \
+ EBC_BXAP_CSN_ENCODE(0) | \
+ EBC_BXAP_OEN_ENCODE(0) | \
+ EBC_BXAP_WBN_ENCODE(0) | \
+ EBC_BXAP_WBF_ENCODE(0) | \
+ EBC_BXAP_TH_ENCODE(2) | \
+ EBC_BXAP_RE_DISABLED | \
+ EBC_BXAP_SOR_NONDELAYED | \
+ EBC_BXAP_BEM_WRITEONLY | \
+ EBC_BXAP_PEN_DISABLED)
+# endif /* CONFIG_SYS_INIT_DCACHE_PBxAR */
+# ifndef CONFIG_SYS_INIT_DCACHE_PBxCR
+# define CONFIG_SYS_INIT_DCACHE_PBxCR (EBC_BXCR_BAS_ENCODE(CONFIG_SYS_INIT_RAM_ADDR) | \
+ EBC_BXCR_BS_64MB | \
+ EBC_BXCR_BU_RW | \
+ EBC_BXCR_BW_16BIT)
+# endif /* CONFIG_SYS_INIT_DCACHE_PBxCR */
+# ifndef CONFIG_SYS_INIT_RAM_PATTERN
+# define CONFIG_SYS_INIT_RAM_PATTERN 0xDEADDEAD
+# endif
+#endif /* CONFIG_SYS_INIT_DCACHE_CS */
+
+#if (defined(CONFIG_SYS_INIT_RAM_DCACHE) && (CONFIG_SYS_INIT_RAM_SIZE > (4 << 10)))
+#error Only 4k of init-ram is supported - please adjust CONFIG_SYS_INIT_RAM_SIZE!
+#endif
+
+/*
+ * Unless otherwise overriden, enable two 128MB cachable instruction regions
+ * at CONFIG_SYS_SDRAM_BASE and another 128MB cacheable instruction region covering
+ * NOR flash at CONFIG_SYS_FLASH_BASE. Disable all cacheable data regions.
+ */
+#if !defined(CONFIG_SYS_FLASH_BASE)
+/* If not already defined, set it to the "last" 128MByte region */
+# define CONFIG_SYS_FLASH_BASE 0xf8000000
+#endif
+#if !defined(CONFIG_SYS_ICACHE_SACR_VALUE)
+# define CONFIG_SYS_ICACHE_SACR_VALUE \
+ (PPC_128MB_SACR_VALUE(CONFIG_SYS_SDRAM_BASE + ( 0 << 20)) | \
+ PPC_128MB_SACR_VALUE(CONFIG_SYS_SDRAM_BASE + (128 << 20)) | \
+ PPC_128MB_SACR_VALUE(CONFIG_SYS_FLASH_BASE))
+#endif /* !defined(CONFIG_SYS_ICACHE_SACR_VALUE) */
+
+#if !defined(CONFIG_SYS_DCACHE_SACR_VALUE)
+# define CONFIG_SYS_DCACHE_SACR_VALUE \
+ (0x00000000)
+#endif /* !defined(CONFIG_SYS_DCACHE_SACR_VALUE) */
+
+#if !defined(CONFIG_SYS_TLB_FOR_BOOT_FLASH)
+#define CONFIG_SYS_TLB_FOR_BOOT_FLASH 0 /* use TLB 0 as default */
+#endif
+
+#define function_prolog(func_name) .text; \
+ .align 2; \
+ .globl func_name; \
+ func_name:
+#define function_epilog(func_name) .type func_name,@function; \
+ .size func_name,.-func_name
+
+/* We don't want the MMU yet.
+*/
+#undef MSR_KERNEL
+#define MSR_KERNEL ( MSR_ME ) /* Machine Check */
+
+
+ .extern ext_bus_cntlr_init
+#ifdef CONFIG_NAND_U_BOOT
+ .extern reconfig_tlb0
+#endif
+
+/*
+ * Set up GOT: Global Offset Table
+ *
+ * Use r12 to access the GOT
+ */
+#if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_SPL_BUILD)
+ START_GOT
+ GOT_ENTRY(_GOT2_TABLE_)
+ GOT_ENTRY(_FIXUP_TABLE_)
+
+ GOT_ENTRY(_start)
+ GOT_ENTRY(_start_of_vectors)
+ GOT_ENTRY(_end_of_vectors)
+ GOT_ENTRY(transfer_to_handler)
+
+ GOT_ENTRY(__init_end)
+ GOT_ENTRY(__bss_end)
+ GOT_ENTRY(__bss_start)
+ END_GOT
+#endif /* CONFIG_NAND_SPL */
+
+#if defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL) && \
+ !defined(CONFIG_SPL_BUILD)
+ /*
+ * NAND U-Boot image is started from offset 0
+ */
+ .text
+#if defined(CONFIG_440)
+ bl reconfig_tlb0
+#endif
+ GET_GOT
+ bl cpu_init_f /* run low-level CPU init code (from Flash) */
+ bl board_init_f
+ /* NOTREACHED - board_init_f() does not return */
+#endif
+
+#if defined(CONFIG_SYS_RAMBOOT) || defined(CONFIG_BOOT_FROM_XMD)
+ /*
+ * 4xx RAM-booting U-Boot image is started from offset 0
+ */
+ .text
+ bl _start_440
+#endif
+
+#if defined(CONFIG_SPL) && !defined(CONFIG_SPL_BUILD)
+ /*
+ * This is the entry of the real U-Boot from a board port
+ * that supports SPL booting on the PPC4xx. We only need
+ * to call board_init_f() here. Everything else has already
+ * been done in the SPL u-boot version.
+ */
+ GET_GOT /* initialize GOT access */
+ bl board_init_f /* run 1st part of board init code (in Flash)*/
+ /* NOTREACHED - board_init_f() does not return */
+#endif
+
+/*
+ * 440 Startup -- on reset only the top 4k of the effective
+ * address space is mapped in by an entry in the instruction
+ * and data shadow TLB. The .bootpg section is located in the
+ * top 4k & does only what's necessary to map in the the rest
+ * of the boot rom. Once the boot rom is mapped in we can
+ * proceed with normal startup.
+ *
+ * NOTE: CS0 only covers the top 2MB of the effective address
+ * space after reset.
+ */
+
+#if defined(CONFIG_440)
+#if !defined(CONFIG_NAND_SPL)
+ .section .bootpg,"ax"
+#endif
+ .globl _start_440
+
+/**************************************************************************/
+_start_440:
+ /*--------------------------------------------------------------------+
+ | 440EPX BUP Change - Hardware team request
+ +--------------------------------------------------------------------*/
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+ sync
+ nop
+ nop
+#endif
+ /*----------------------------------------------------------------+
+ | Core bug fix. Clear the esr
+ +-----------------------------------------------------------------*/
+ li r0,0
+ mtspr SPRN_ESR,r0
+ /*----------------------------------------------------------------*/
+ /* Clear and set up some registers. */
+ /*----------------------------------------------------------------*/
+ iccci r0,r0 /* NOTE: operands not used for 440 */
+ dccci r0,r0 /* NOTE: operands not used for 440 */
+ sync
+ li r0,0
+ mtspr SPRN_SRR0,r0
+ mtspr SPRN_SRR1,r0
+ mtspr SPRN_CSRR0,r0
+ mtspr SPRN_CSRR1,r0
+ /* NOTE: 440GX adds machine check status regs */
+#if defined(CONFIG_440) && !defined(CONFIG_440GP)
+ mtspr SPRN_MCSRR0,r0
+ mtspr SPRN_MCSRR1,r0
+ mfspr r1,SPRN_MCSR
+ mtspr SPRN_MCSR,r1
+#endif
+
+ /*----------------------------------------------------------------*/
+ /* CCR0 init */
+ /*----------------------------------------------------------------*/
+ /* Disable store gathering & broadcast, guarantee inst/data
+ * cache block touch, force load/store alignment
+ * (see errata 1.12: 440_33)
+ */
+ lis r1,0x0030 /* store gathering & broadcast disable */
+ ori r1,r1,0x6000 /* cache touch */
+ mtspr SPRN_CCR0,r1
+
+ /*----------------------------------------------------------------*/
+ /* Initialize debug */
+ /*----------------------------------------------------------------*/
+ mfspr r1,SPRN_DBCR0
+ andis. r1, r1, 0x8000 /* test DBCR0[EDM] bit */
+ bne skip_debug_init /* if set, don't clear debug register */
+ mfspr r1,SPRN_CCR0
+ ori r1,r1,CCR0_DTB@l /* Disable Trace Broadcast */
+ mtspr SPRN_CCR0,r1
+ mtspr SPRN_DBCR0,r0
+ mtspr SPRN_DBCR1,r0
+ mtspr SPRN_DBCR2,r0
+ mtspr SPRN_IAC1,r0
+ mtspr SPRN_IAC2,r0
+ mtspr SPRN_IAC3,r0
+ mtspr SPRN_DAC1,r0
+ mtspr SPRN_DAC2,r0
+ mtspr SPRN_DVC1,r0
+ mtspr SPRN_DVC2,r0
+
+ mfspr r1,SPRN_DBSR
+ mtspr SPRN_DBSR,r1 /* Clear all valid bits */
+skip_debug_init:
+
+#if defined (CONFIG_440SPE)
+ /*----------------------------------------------------------------+
+ | Initialize Core Configuration Reg1.
+ | a. ICDPEI: Record even parity. Normal operation.
+ | b. ICTPEI: Record even parity. Normal operation.
+ | c. DCTPEI: Record even parity. Normal operation.
+ | d. DCDPEI: Record even parity. Normal operation.
+ | e. DCUPEI: Record even parity. Normal operation.
+ | f. DCMPEI: Record even parity. Normal operation.
+ | g. FCOM: Normal operation
+ | h. MMUPEI: Record even parity. Normal operation.
+ | i. FFF: Flush only as much data as necessary.
+ | j. TCS: Timebase increments from CPU clock.
+ +-----------------------------------------------------------------*/
+ li r0,0
+ mtspr SPRN_CCR1, r0
+
+ /*----------------------------------------------------------------+
+ | Reset the timebase.
+ | The previous write to CCR1 sets the timebase source.
+ +-----------------------------------------------------------------*/
+ mtspr SPRN_TBWL, r0
+ mtspr SPRN_TBWU, r0
+#endif
+
+ /*----------------------------------------------------------------*/
+ /* Setup interrupt vectors */
+ /*----------------------------------------------------------------*/
+ mtspr SPRN_IVPR,r0 /* Vectors start at 0x0000_0000 */
+ li r1,0x0100
+ mtspr SPRN_IVOR0,r1 /* Critical input */
+ li r1,0x0200
+ mtspr SPRN_IVOR1,r1 /* Machine check */
+ li r1,0x0300
+ mtspr SPRN_IVOR2,r1 /* Data storage */
+ li r1,0x0400
+ mtspr SPRN_IVOR3,r1 /* Instruction storage */
+ li r1,0x0500
+ mtspr SPRN_IVOR4,r1 /* External interrupt */
+ li r1,0x0600
+ mtspr SPRN_IVOR5,r1 /* Alignment */
+ li r1,0x0700
+ mtspr SPRN_IVOR6,r1 /* Program check */
+ li r1,0x0800
+ mtspr SPRN_IVOR7,r1 /* Floating point unavailable */
+ li r1,0x0c00
+ mtspr SPRN_IVOR8,r1 /* System call */
+ li r1,0x0a00
+ mtspr SPRN_IVOR9,r1 /* Auxiliary Processor unavailable */
+ li r1,0x0900
+ mtspr SPRN_IVOR10,r1 /* Decrementer */
+ li r1,0x1300
+ mtspr SPRN_IVOR13,r1 /* Data TLB error */
+ li r1,0x1400
+ mtspr SPRN_IVOR14,r1 /* Instr TLB error */
+ li r1,0x2000
+ mtspr SPRN_IVOR15,r1 /* Debug */
+
+ /*----------------------------------------------------------------*/
+ /* Configure cache regions */
+ /*----------------------------------------------------------------*/
+ mtspr SPRN_INV0,r0
+ mtspr SPRN_INV1,r0
+ mtspr SPRN_INV2,r0
+ mtspr SPRN_INV3,r0
+ mtspr SPRN_DNV0,r0
+ mtspr SPRN_DNV1,r0
+ mtspr SPRN_DNV2,r0
+ mtspr SPRN_DNV3,r0
+ mtspr SPRN_ITV0,r0
+ mtspr SPRN_ITV1,r0
+ mtspr SPRN_ITV2,r0
+ mtspr SPRN_ITV3,r0
+ mtspr SPRN_DTV0,r0
+ mtspr SPRN_DTV1,r0
+ mtspr SPRN_DTV2,r0
+ mtspr SPRN_DTV3,r0
+
+ /*----------------------------------------------------------------*/
+ /* Cache victim limits */
+ /*----------------------------------------------------------------*/
+ /* floors 0, ceiling max to use the entire cache -- nothing locked
+ */
+ lis r1,0x0001
+ ori r1,r1,0xf800
+ mtspr SPRN_IVLIM,r1
+ mtspr SPRN_DVLIM,r1
+
+ /*----------------------------------------------------------------+
+ |Initialize MMUCR[STID] = 0.
+ +-----------------------------------------------------------------*/
+ mfspr r0,SPRN_MMUCR
+ addis r1,0,0xFFFF
+ ori r1,r1,0xFF00
+ and r0,r0,r1
+ mtspr SPRN_MMUCR,r0
+
+ /*----------------------------------------------------------------*/
+ /* Clear all TLB entries -- TID = 0, TS = 0 */
+ /*----------------------------------------------------------------*/
+ addis r0,0,0x0000
+#ifdef CONFIG_SYS_RAMBOOT
+ li r4,0 /* Start with TLB #0 */
+#else
+ li r4,1 /* Start with TLB #1 */
+#endif
+ li r1,64 /* 64 TLB entries */
+ sub r1,r1,r4 /* calculate last TLB # */
+ mtctr r1
+rsttlb:
+#ifdef CONFIG_SYS_RAMBOOT
+ tlbre r3,r4,0 /* Read contents from TLB word #0 to get EPN */
+ rlwinm. r3,r3,0,0xfffffc00 /* Mask EPN */
+ beq tlbnxt /* Skip EPN=0 TLB, this is the SDRAM TLB */
+#endif
+ tlbwe r0,r4,0 /* Invalidate all entries (V=0)*/
+ tlbwe r0,r4,1
+ tlbwe r0,r4,2
+tlbnxt: addi r4,r4,1 /* Next TLB */
+ bdnz rsttlb
+
+ /*----------------------------------------------------------------*/
+ /* TLB entry setup -- step thru tlbtab */
+ /*----------------------------------------------------------------*/
+#if defined(CONFIG_440SPE_REVA)
+ /*----------------------------------------------------------------*/
+ /* We have different TLB tables for revA and rev B of 440SPe */
+ /*----------------------------------------------------------------*/
+ mfspr r1, PVR
+ lis r0,0x5342
+ ori r0,r0,0x1891
+ cmpw r7,r1,r0
+ bne r7,..revA
+ bl tlbtabB
+ b ..goon
+..revA:
+ bl tlbtabA
+..goon:
+#else
+ bl tlbtab /* Get tlbtab pointer */
+#endif
+ mr r5,r0
+ li r1,0x003f /* 64 TLB entries max */
+ mtctr r1
+ li r4,0 /* TLB # */
+
+ addi r5,r5,-4
+1:
+#ifdef CONFIG_SYS_RAMBOOT
+ tlbre r3,r4,0 /* Read contents from TLB word #0 */
+ rlwinm. r3,r3,0,0x00000200 /* Mask V (valid) bit */
+ bne tlbnx2 /* Skip V=1 TLB, this is the SDRAM TLB */
+#endif
+ lwzu r0,4(r5)
+ cmpwi r0,0
+ beq 2f /* 0 marks end */
+ lwzu r1,4(r5)
+ lwzu r2,4(r5)
+ tlbwe r0,r4,0 /* TLB Word 0 */
+ tlbwe r1,r4,1 /* TLB Word 1 */
+ tlbwe r2,r4,2 /* TLB Word 2 */
+tlbnx2: addi r4,r4,1 /* Next TLB */
+ bdnz 1b
+
+ /*----------------------------------------------------------------*/
+ /* Continue from 'normal' start */
+ /*----------------------------------------------------------------*/
+2:
+ bl 3f
+ b _start
+
+3: li r0,0
+ mtspr SPRN_SRR1,r0 /* Keep things disabled for now */
+ mflr r1
+ mtspr SPRN_SRR0,r1
+ rfi
+#endif /* CONFIG_440 */
+
+/*
+ * r3 - 1st arg to board_init(): IMMP pointer
+ * r4 - 2nd arg to board_init(): boot flag
+ */
+#if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_SPL_BUILD)
+ .text
+ .long 0x27051956 /* U-Boot Magic Number */
+ .globl version_string
+version_string:
+ .ascii U_BOOT_VERSION_STRING, "\0"
+
+ . = EXC_OFF_SYS_RESET
+ .globl _start_of_vectors
+_start_of_vectors:
+
+/* Critical input. */
+ CRIT_EXCEPTION(0x100, CritcalInput, UnknownException)
+
+#ifdef CONFIG_440
+/* Machine check */
+ MCK_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+#else
+ CRIT_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+#endif /* CONFIG_440 */
+
+/* Data Storage exception. */
+ STD_EXCEPTION(0x300, DataStorage, UnknownException)
+
+/* Instruction Storage exception. */
+ STD_EXCEPTION(0x400, InstStorage, UnknownException)
+
+/* External Interrupt exception. */
+ STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
+
+/* Alignment exception. */
+ . = 0x600
+Alignment:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE)
+
+/* Program check exception */
+ . = 0x700
+ProgramCheck:
+ EXCEPTION_PROLOG(SRR0, SRR1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException,
+ MSR_KERNEL, COPY_EE)
+
+#ifdef CONFIG_440
+ STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+ STD_EXCEPTION(0x900, Decrementer, DecrementerPITException)
+ STD_EXCEPTION(0xa00, APU, UnknownException)
+#endif
+ STD_EXCEPTION(0xc00, SystemCall, UnknownException)
+
+#ifdef CONFIG_440
+ STD_EXCEPTION(0x1300, DataTLBError, UnknownException)
+ STD_EXCEPTION(0x1400, InstructionTLBError, UnknownException)
+#else
+ STD_EXCEPTION(0x1000, PIT, DecrementerPITException)
+ STD_EXCEPTION(0x1100, InstructionTLBMiss, UnknownException)
+ STD_EXCEPTION(0x1200, DataTLBMiss, UnknownException)
+#endif
+ CRIT_EXCEPTION(0x2000, DebugBreakpoint, DebugException )
+
+ .globl _end_of_vectors
+_end_of_vectors:
+ . = _START_OFFSET
+#endif
+ .globl _start
+_start:
+
+#if defined(CONFIG_SPL) && !defined(CONFIG_SPL_BUILD)
+ /*
+ * This is the entry of the real U-Boot from a board port
+ * that supports SPL booting on the PPC4xx. We only need
+ * to call board_init_f() here. Everything else has already
+ * been done in the SPL u-boot version.
+ */
+ GET_GOT /* initialize GOT access */
+ bl board_init_f /* run 1st part of board init code (in Flash)*/
+ /* NOTREACHED - board_init_f() does not return */
+#endif
+
+/*****************************************************************************/
+#if defined(CONFIG_440)
+
+ /*----------------------------------------------------------------*/
+ /* Clear and set up some registers. */
+ /*----------------------------------------------------------------*/
+ li r0,0x0000
+ lis r1,0xffff
+ mtspr SPRN_DEC,r0 /* prevent dec exceptions */
+ mtspr SPRN_TBWL,r0 /* prevent fit & wdt exceptions */
+ mtspr SPRN_TBWU,r0
+ mtspr SPRN_TSR,r1 /* clear all timer exception status */
+ mtspr SPRN_TCR,r0 /* disable all */
+ mtspr SPRN_ESR,r0 /* clear exception syndrome register */
+ mtxer r0 /* clear integer exception register */
+
+ /*----------------------------------------------------------------*/
+ /* Debug setup -- some (not very good) ice's need an event*/
+ /* to establish control :-( Define CONFIG_SYS_INIT_DBCR to the dbsr */
+ /* value you need in this case 0x8cff 0000 should do the trick */
+ /*----------------------------------------------------------------*/
+#if defined(CONFIG_SYS_INIT_DBCR)
+ lis r1,0xffff
+ ori r1,r1,0xffff
+ mtspr SPRN_DBSR,r1 /* Clear all status bits */
+ lis r0,CONFIG_SYS_INIT_DBCR@h
+ ori r0,r0,CONFIG_SYS_INIT_DBCR@l
+ mtspr SPRN_DBCR0,r0
+ isync
+#endif
+
+ /*----------------------------------------------------------------*/
+ /* Setup the internal SRAM */
+ /*----------------------------------------------------------------*/
+ li r0,0
+
+#ifdef CONFIG_SYS_INIT_RAM_DCACHE
+ /* Clear Dcache to use as RAM */
+ addis r3,r0,CONFIG_SYS_INIT_RAM_ADDR@h
+ ori r3,r3,CONFIG_SYS_INIT_RAM_ADDR@l
+ addis r4,r0,CONFIG_SYS_INIT_RAM_SIZE@h
+ ori r4,r4,CONFIG_SYS_INIT_RAM_SIZE@l
+ rlwinm. r5,r4,0,27,31
+ rlwinm r5,r4,27,5,31
+ beq ..d_ran
+ addi r5,r5,0x0001
+..d_ran:
+ mtctr r5
+..d_ag:
+ dcbz r0,r3
+ addi r3,r3,32
+ bdnz ..d_ag
+
+ /*
+ * Lock the init-ram/stack in d-cache, so that other regions
+ * may use d-cache as well
+ * Note, that this current implementation locks exactly 4k
+ * of d-cache, so please make sure that you don't define a
+ * bigger init-ram area. Take a look at the lwmon5 440EPx
+ * implementation as a reference.
+ */
+ msync
+ isync
+ /* 8. set TFLOOR/NFLOOR to 8 (-> 8*16*32 bytes locked -> 4k) */
+ lis r1,0x0201
+ ori r1,r1,0xf808
+ mtspr SPRN_DVLIM,r1
+ lis r1,0x0808
+ ori r1,r1,0x0808
+ mtspr SPRN_DNV0,r1
+ mtspr SPRN_DNV1,r1
+ mtspr SPRN_DNV2,r1
+ mtspr SPRN_DNV3,r1
+ mtspr SPRN_DTV0,r1
+ mtspr SPRN_DTV1,r1
+ mtspr SPRN_DTV2,r1
+ mtspr SPRN_DTV3,r1
+ msync
+ isync
+#endif /* CONFIG_SYS_INIT_RAM_DCACHE */
+
+ /* 440EP & 440GR are only 440er PPC's without internal SRAM */
+#if !defined(CONFIG_440EP) && !defined(CONFIG_440GR)
+ /* not all PPC's have internal SRAM usable as L2-cache */
+#if defined(CONFIG_440GX) || \
+ defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
+ defined(CONFIG_460SX)
+ mtdcr L2_CACHE_CFG,r0 /* Ensure L2 Cache is off */
+#elif defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_APM821XX)
+ lis r1, 0x0000
+ ori r1,r1,0x0008 /* Set L2_CACHE_CFG[RDBW]=1 */
+ mtdcr L2_CACHE_CFG,r1
+#endif
+
+ lis r2,0x7fff
+ ori r2,r2,0xffff
+ mfdcr r1,ISRAM0_DPC
+ and r1,r1,r2 /* Disable parity check */
+ mtdcr ISRAM0_DPC,r1
+ mfdcr r1,ISRAM0_PMEG
+ and r1,r1,r2 /* Disable pwr mgmt */
+ mtdcr ISRAM0_PMEG,r1
+
+ lis r1,0x8000 /* BAS = 8000_0000 */
+#if defined(CONFIG_440GX) || defined(CONFIG_440SP)
+ ori r1,r1,0x0980 /* first 64k */
+ mtdcr ISRAM0_SB0CR,r1
+ lis r1,0x8001
+ ori r1,r1,0x0980 /* second 64k */
+ mtdcr ISRAM0_SB1CR,r1
+ lis r1, 0x8002
+ ori r1,r1, 0x0980 /* third 64k */
+ mtdcr ISRAM0_SB2CR,r1
+ lis r1, 0x8003
+ ori r1,r1, 0x0980 /* fourth 64k */
+ mtdcr ISRAM0_SB3CR,r1
+#elif defined(CONFIG_440SPE) || defined(CONFIG_460EX) || \
+ defined(CONFIG_460GT) || defined(CONFIG_APM821XX)
+ lis r1,0x0000 /* BAS = X_0000_0000 */
+ ori r1,r1,0x0984 /* first 64k */
+ mtdcr ISRAM0_SB0CR,r1
+ lis r1,0x0001
+ ori r1,r1,0x0984 /* second 64k */
+ mtdcr ISRAM0_SB1CR,r1
+ lis r1, 0x0002
+ ori r1,r1, 0x0984 /* third 64k */
+ mtdcr ISRAM0_SB2CR,r1
+ lis r1, 0x0003
+ ori r1,r1, 0x0984 /* fourth 64k */
+ mtdcr ISRAM0_SB3CR,r1
+#if defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
+ defined(CONFIG_APM821XX)
+ lis r2,0x7fff
+ ori r2,r2,0xffff
+ mfdcr r1,ISRAM1_DPC
+ and r1,r1,r2 /* Disable parity check */
+ mtdcr ISRAM1_DPC,r1
+ mfdcr r1,ISRAM1_PMEG
+ and r1,r1,r2 /* Disable pwr mgmt */
+ mtdcr ISRAM1_PMEG,r1
+
+ lis r1,0x0004 /* BAS = 4_0004_0000 */
+ ori r1,r1,ISRAM1_SIZE /* ocm size */
+ mtdcr ISRAM1_SB0CR,r1
+#endif
+#elif defined(CONFIG_460SX)
+ lis r1,0x0000 /* BAS = 0000_0000 */
+ ori r1,r1,0x0B84 /* first 128k */
+ mtdcr ISRAM0_SB0CR,r1
+ lis r1,0x0001
+ ori r1,r1,0x0B84 /* second 128k */
+ mtdcr ISRAM0_SB1CR,r1
+ lis r1, 0x0002
+ ori r1,r1, 0x0B84 /* third 128k */
+ mtdcr ISRAM0_SB2CR,r1
+ lis r1, 0x0003
+ ori r1,r1, 0x0B84 /* fourth 128k */
+ mtdcr ISRAM0_SB3CR,r1
+#elif defined(CONFIG_440GP)
+ ori r1,r1,0x0380 /* 8k rw */
+ mtdcr ISRAM0_SB0CR,r1
+ mtdcr ISRAM0_SB1CR,r0 /* Disable bank 1 */
+#endif
+#endif /* #if !defined(CONFIG_440EP) && !defined(CONFIG_440GR) */
+
+ /*----------------------------------------------------------------*/
+ /* Setup the stack in internal SRAM */
+ /*----------------------------------------------------------------*/
+ lis r1,CONFIG_SYS_INIT_RAM_ADDR@h
+ ori r1,r1,CONFIG_SYS_INIT_SP_OFFSET@l
+ li r0,0
+ stwu r0,-4(r1)
+ stwu r0,-4(r1) /* Terminate call chain */
+
+ stwu r1,-8(r1) /* Save back chain and move SP */
+ lis r0,RESET_VECTOR@h /* Address of reset vector */
+ ori r0,r0, RESET_VECTOR@l
+ stwu r1,-8(r1) /* Save back chain and move SP */
+ stw r0,+12(r1) /* Save return addr (underflow vect) */
+
+#ifdef CONFIG_NAND_SPL
+ bl nand_boot_common /* will not return */
+#else
+#ifndef CONFIG_SPL_BUILD
+ GET_GOT
+#endif
+
+ bl cpu_init_f /* run low-level CPU init code (from Flash) */
+ bl board_init_f
+ /* NOTREACHED - board_init_f() does not return */
+#endif
+
+#endif /* CONFIG_440 */
+
+/*****************************************************************************/
+#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
+ defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
+ defined(CONFIG_405EX) || defined(CONFIG_405)
+ /*----------------------------------------------------------------------- */
+ /* Clear and set up some registers. */
+ /*----------------------------------------------------------------------- */
+ addi r4,r0,0x0000
+#if !defined(CONFIG_405EX)
+ mtspr SPRN_SGR,r4
+#else
+ /*
+ * On 405EX, completely clearing the SGR leads to PPC hangup
+ * upon PCIe configuration access. The PCIe memory regions
+ * need to be guarded!
+ */
+ lis r3,0x0000
+ ori r3,r3,0x7FFC
+ mtspr SPRN_SGR,r3
+#endif
+ mtspr SPRN_DCWR,r4
+ mtesr r4 /* clear Exception Syndrome Reg */
+ mttcr r4 /* clear Timer Control Reg */
+ mtxer r4 /* clear Fixed-Point Exception Reg */
+ mtevpr r4 /* clear Exception Vector Prefix Reg */
+ addi r4,r0,(0xFFFF-0x10000) /* set r4 to 0xFFFFFFFF (status in the */
+ /* dbsr is cleared by setting bits to 1) */
+ mtdbsr r4 /* clear/reset the dbsr */
+
+ /* Invalidate the i- and d-caches. */
+ bl invalidate_icache
+ bl invalidate_dcache
+
+ /* Set-up icache cacheability. */
+ lis r4, CONFIG_SYS_ICACHE_SACR_VALUE@h
+ ori r4, r4, CONFIG_SYS_ICACHE_SACR_VALUE@l
+ mticcr r4
+ isync
+
+ /* Set-up dcache cacheability. */
+ lis r4, CONFIG_SYS_DCACHE_SACR_VALUE@h
+ ori r4, r4, CONFIG_SYS_DCACHE_SACR_VALUE@l
+ mtdccr r4
+
+#if !(defined(CONFIG_SYS_EBC_PB0AP) && defined(CONFIG_SYS_EBC_PB0CR))\
+ && !defined (CONFIG_XILINX_405)
+ /*----------------------------------------------------------------------- */
+ /* Tune the speed and size for flash CS0 */
+ /*----------------------------------------------------------------------- */
+ bl ext_bus_cntlr_init
+#endif
+
+#if !(defined(CONFIG_SYS_INIT_DCACHE_CS) || defined(CONFIG_SYS_TEMP_STACK_OCM))
+ /*
+ * For boards that don't have OCM and can't use the data cache
+ * for their primordial stack, setup stack here directly after the
+ * SDRAM is initialized in ext_bus_cntlr_init.
+ */
+ lis r1, CONFIG_SYS_INIT_RAM_ADDR@h
+ ori r1,r1,CONFIG_SYS_INIT_SP_OFFSET /* set up the stack in SDRAM */
+
+ li r0, 0 /* Make room for stack frame header and */
+ stwu r0, -4(r1) /* clear final stack frame so that */
+ stwu r0, -4(r1) /* stack backtraces terminate cleanly */
+ /*
+ * Set up a dummy frame to store reset vector as return address.
+ * this causes stack underflow to reset board.
+ */
+ stwu r1, -8(r1) /* Save back chain and move SP */
+ lis r0, RESET_VECTOR@h /* Address of reset vector */
+ ori r0, r0, RESET_VECTOR@l
+ stwu r1, -8(r1) /* Save back chain and move SP */
+ stw r0, +12(r1) /* Save return addr (underflow vect) */
+#endif /* !(CONFIG_SYS_INIT_DCACHE_CS || !CONFIG_SYS_TEM_STACK_OCM) */
+
+#if defined(CONFIG_405EP)
+ /*----------------------------------------------------------------------- */
+ /* DMA Status, clear to come up clean */
+ /*----------------------------------------------------------------------- */
+ addis r3,r0, 0xFFFF /* Clear all existing DMA status */
+ ori r3,r3, 0xFFFF
+ mtdcr DMASR, r3
+
+ bl ppc405ep_init /* do ppc405ep specific init */
+#endif /* CONFIG_405EP */
+
+#if defined(CONFIG_SYS_OCM_DATA_ADDR) && defined(CONFIG_SYS_OCM_DATA_SIZE)
+#if defined(CONFIG_405EZ)
+ /********************************************************************
+ * Setup OCM - On Chip Memory - PPC405EZ uses OCM Controller V2
+ *******************************************************************/
+ /*
+ * We can map the OCM on the PLB3, so map it at
+ * CONFIG_SYS_OCM_DATA_ADDR + 0x8000
+ */
+ lis r3,CONFIG_SYS_OCM_DATA_ADDR@h /* OCM location */
+ ori r3,r3,CONFIG_SYS_OCM_DATA_ADDR@l
+ ori r3,r3,0x0270 /* 16K for Bank 1, R/W/Enable */
+ mtdcr OCM0_PLBCR1,r3 /* Set PLB Access */
+ ori r3,r3,0x4000 /* Add 0x4000 for bank 2 */
+ mtdcr OCM0_PLBCR2,r3 /* Set PLB Access */
+ isync
+
+ lis r3,CONFIG_SYS_OCM_DATA_ADDR@h /* OCM location */
+ ori r3,r3,CONFIG_SYS_OCM_DATA_ADDR@l
+ ori r3,r3,0x0270 /* 16K for Bank 1, R/W/Enable */
+ mtdcr OCM0_DSRC1, r3 /* Set Data Side */
+ mtdcr OCM0_ISRC1, r3 /* Set Instruction Side */
+ ori r3,r3,0x4000 /* Add 0x4000 for bank 2 */
+ mtdcr OCM0_DSRC2, r3 /* Set Data Side */
+ mtdcr OCM0_ISRC2, r3 /* Set Instruction Side */
+ addis r3,0,0x0800 /* OCM Data Parity Disable - 1 Wait State */
+ mtdcr OCM0_DISDPC,r3
+
+ isync
+#else /* CONFIG_405EZ */
+ /********************************************************************
+ * Setup OCM - On Chip Memory
+ *******************************************************************/
+ /* Setup OCM */
+ lis r0, 0x7FFF
+ ori r0, r0, 0xFFFF
+ mfdcr r3, OCM0_ISCNTL /* get instr-side IRAM config */
+ mfdcr r4, OCM0_DSCNTL /* get data-side IRAM config */
+ and r3, r3, r0 /* disable data-side IRAM */
+ and r4, r4, r0 /* disable data-side IRAM */
+ mtdcr OCM0_ISCNTL, r3 /* set instr-side IRAM config */
+ mtdcr OCM0_DSCNTL, r4 /* set data-side IRAM config */
+ isync
+
+ lis r3,CONFIG_SYS_OCM_DATA_ADDR@h /* OCM location */
+ ori r3,r3,CONFIG_SYS_OCM_DATA_ADDR@l
+ mtdcr OCM0_DSARC, r3
+ addis r4, 0, 0xC000 /* OCM data area enabled */
+ mtdcr OCM0_DSCNTL, r4
+ isync
+#endif /* CONFIG_405EZ */
+#endif
+
+ /*----------------------------------------------------------------------- */
+ /* Setup temporary stack in DCACHE or OCM if needed for SDRAM SPD. */
+ /*----------------------------------------------------------------------- */
+#ifdef CONFIG_SYS_INIT_DCACHE_CS
+ li r4, PBxAP
+ mtdcr EBC0_CFGADDR, r4
+ lis r4, CONFIG_SYS_INIT_DCACHE_PBxAR@h
+ ori r4, r4, CONFIG_SYS_INIT_DCACHE_PBxAR@l
+ mtdcr EBC0_CFGDATA, r4
+
+ addi r4, 0, PBxCR
+ mtdcr EBC0_CFGADDR, r4
+ lis r4, CONFIG_SYS_INIT_DCACHE_PBxCR@h
+ ori r4, r4, CONFIG_SYS_INIT_DCACHE_PBxCR@l
+ mtdcr EBC0_CFGDATA, r4
+
+ /*
+ * Enable the data cache for the 128MB storage access control region
+ * at CONFIG_SYS_INIT_RAM_ADDR.
+ */
+ mfdccr r4
+ oris r4, r4, PPC_128MB_SACR_VALUE(CONFIG_SYS_INIT_RAM_ADDR)@h
+ ori r4, r4, PPC_128MB_SACR_VALUE(CONFIG_SYS_INIT_RAM_ADDR)@l
+ mtdccr r4
+
+ /*
+ * Preallocate data cache lines to be used to avoid a subsequent
+ * cache miss and an ensuing machine check exception when exceptions
+ * are enabled.
+ */
+ li r0, 0
+
+ lis r3, CONFIG_SYS_INIT_RAM_ADDR@h
+ ori r3, r3, CONFIG_SYS_INIT_RAM_ADDR@l
+
+ lis r4, CONFIG_SYS_INIT_RAM_SIZE@h
+ ori r4, r4, CONFIG_SYS_INIT_RAM_SIZE@l
+
+ /*
+ * Convert the size, in bytes, to the number of cache lines/blocks
+ * to preallocate.
+ */
+ clrlwi. r5, r4, (32 - L1_CACHE_SHIFT)
+ srwi r5, r4, L1_CACHE_SHIFT
+ beq ..load_counter
+ addi r5, r5, 0x0001
+..load_counter:
+ mtctr r5
+
+ /* Preallocate the computed number of cache blocks. */
+..alloc_dcache_block:
+ dcba r0, r3
+ addi r3, r3, L1_CACHE_BYTES
+ bdnz ..alloc_dcache_block
+ sync
+
+ /*
+ * Load the initial stack pointer and data area and convert the size,
+ * in bytes, to the number of words to initialize to a known value.
+ */
+ lis r1, CONFIG_SYS_INIT_RAM_ADDR@h
+ ori r1, r1, CONFIG_SYS_INIT_SP_OFFSET@l
+
+ lis r4, (CONFIG_SYS_INIT_RAM_SIZE >> 2)@h
+ ori r4, r4, (CONFIG_SYS_INIT_RAM_SIZE >> 2)@l
+ mtctr r4
+
+ lis r2, CONFIG_SYS_INIT_RAM_ADDR@h
+ ori r2, r2, CONFIG_SYS_INIT_RAM_SIZE@l
+
+ lis r4, CONFIG_SYS_INIT_RAM_PATTERN@h
+ ori r4, r4, CONFIG_SYS_INIT_RAM_PATTERN@l
+
+..stackloop:
+ stwu r4, -4(r2)
+ bdnz ..stackloop
+
+ /*
+ * Make room for stack frame header and clear final stack frame so
+ * that stack backtraces terminate cleanly.
+ */
+ stwu r0, -4(r1)
+ stwu r0, -4(r1)
+
+ /*
+ * Set up a dummy frame to store reset vector as return address.
+ * this causes stack underflow to reset board.
+ */
+ stwu r1, -8(r1) /* Save back chain and move SP */
+ addis r0, 0, RESET_VECTOR@h /* Address of reset vector */
+ ori r0, r0, RESET_VECTOR@l
+ stwu r1, -8(r1) /* Save back chain and move SP */
+ stw r0, +12(r1) /* Save return addr (underflow vect) */
+
+#elif defined(CONFIG_SYS_TEMP_STACK_OCM) && \
+ (defined(CONFIG_SYS_OCM_DATA_ADDR) && defined(CONFIG_SYS_OCM_DATA_SIZE))
+ /*
+ * Stack in OCM.
+ */
+
+ /* Set up Stack at top of OCM */
+ lis r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)@h
+ ori r1, r1, (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)@l
+
+ /* Set up a zeroized stack frame so that backtrace works right */
+ li r0, 0
+ stwu r0, -4(r1)
+ stwu r0, -4(r1)
+
+ /*
+ * Set up a dummy frame to store reset vector as return address.
+ * this causes stack underflow to reset board.
+ */
+ stwu r1, -8(r1) /* Save back chain and move SP */
+ lis r0, RESET_VECTOR@h /* Address of reset vector */
+ ori r0, r0, RESET_VECTOR@l
+ stwu r1, -8(r1) /* Save back chain and move SP */
+ stw r0, +12(r1) /* Save return addr (underflow vect) */
+#endif /* CONFIG_SYS_INIT_DCACHE_CS */
+
+#ifdef CONFIG_NAND_SPL
+ bl nand_boot_common /* will not return */
+#else
+ GET_GOT /* initialize GOT access */
+
+ bl cpu_init_f /* run low-level CPU init code (from Flash) */
+
+ bl board_init_f /* run first part of init code (from Flash) */
+ /* NOTREACHED - board_init_f() does not return */
+
+#endif /* CONFIG_NAND_SPL */
+
+#endif /* CONFIG_405GP || CONFIG_405CR || CONFIG_405 || CONFIG_405EP */
+ /*----------------------------------------------------------------------- */
+
+
+#if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_SPL_BUILD)
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception.
+ * Register r21 is pointer into trap frame, r1 has new stack pointer.
+ */
+ .globl transfer_to_handler
+transfer_to_handler:
+ stw r22,_NIP(r21)
+ lis r22,MSR_POW@h
+ andc r23,r23,r22
+ stw r23,_MSR(r21)
+ SAVE_GPR(7, r21)
+ SAVE_4GPRS(8, r21)
+ SAVE_8GPRS(12, r21)
+ SAVE_8GPRS(24, r21)
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ mtspr SPRG2,r22 /* r1 is now kernel sp */
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
+
+int_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+
+crit_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SPRN_CSRR0,r2
+ mtspr SPRN_CSRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfci
+
+#ifdef CONFIG_440
+mck_return:
+ mfmsr r28 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r28,r28,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r28
+ SYNC
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SPRN_MCSRR0,r2
+ mtspr SPRN_MCSRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfmci
+#endif /* CONFIG_440 */
+
+
+ .globl get_pvr
+get_pvr:
+ mfspr r3, PVR
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: out16 */
+/* Description: Output 16 bits */
+/*------------------------------------------------------------------------------- */
+ .globl out16
+out16:
+ sth r4,0x0000(r3)
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: out16r */
+/* Description: Byte reverse and output 16 bits */
+/*------------------------------------------------------------------------------- */
+ .globl out16r
+out16r:
+ sthbrx r4,r0,r3
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: out32r */
+/* Description: Byte reverse and output 32 bits */
+/*------------------------------------------------------------------------------- */
+ .globl out32r
+out32r:
+ stwbrx r4,r0,r3
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: in16 */
+/* Description: Input 16 bits */
+/*------------------------------------------------------------------------------- */
+ .globl in16
+in16:
+ lhz r3,0x0000(r3)
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: in16r */
+/* Description: Input 16 bits and byte reverse */
+/*------------------------------------------------------------------------------- */
+ .globl in16r
+in16r:
+ lhbrx r3,r0,r3
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: in32r */
+/* Description: Input 32 bits and byte reverse */
+/*------------------------------------------------------------------------------- */
+ .globl in32r
+in32r:
+ lwbrx r3,r0,r3
+ blr
+
+#if !defined(CONFIG_SPL_BUILD)
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * r3 = Relocated stack pointer
+ * r4 = Relocated global data pointer
+ * r5 = Relocated text pointer
+ */
+ .globl relocate_code
+relocate_code:
+#if defined(CONFIG_4xx_DCACHE) || defined(CONFIG_SYS_INIT_DCACHE_CS)
+ /*
+ * We need to flush the initial global data (gd_t) and bd_info
+ * before the dcache will be invalidated.
+ */
+
+ /* Save registers */
+ mr r9, r3
+ mr r10, r4
+ mr r11, r5
+
+ /*
+ * Flush complete dcache, this is faster than flushing the
+ * ranges for global_data and bd_info instead.
+ */
+ bl flush_dcache
+
+#if defined(CONFIG_SYS_INIT_DCACHE_CS)
+ /*
+ * Undo the earlier data cache set-up for the primordial stack and
+ * data area. First, invalidate the data cache and then disable data
+ * cacheability for that area. Finally, restore the EBC values, if
+ * any.
+ */
+
+ /* Invalidate the primordial stack and data area in cache */
+ lis r3, CONFIG_SYS_INIT_RAM_ADDR@h
+ ori r3, r3, CONFIG_SYS_INIT_RAM_ADDR@l
+
+ lis r4, CONFIG_SYS_INIT_RAM_SIZE@h
+ ori r4, r4, CONFIG_SYS_INIT_RAM_SIZE@l
+ add r4, r4, r3
+
+ bl invalidate_dcache_range
+
+ /* Disable cacheability for the region */
+ mfdccr r3
+ lis r4, ~PPC_128MB_SACR_VALUE(CONFIG_SYS_INIT_RAM_ADDR)@h
+ ori r4, r4, ~PPC_128MB_SACR_VALUE(CONFIG_SYS_INIT_RAM_ADDR)@l
+ and r3, r3, r4
+ mtdccr r3
+
+ /* Restore the EBC parameters */
+ li r3, PBxAP
+ mtdcr EBC0_CFGADDR, r3
+ lis r3, PBxAP_VAL@h
+ ori r3, r3, PBxAP_VAL@l
+ mtdcr EBC0_CFGDATA, r3
+
+ li r3, PBxCR
+ mtdcr EBC0_CFGADDR, r3
+ lis r3, PBxCR_VAL@h
+ ori r3, r3, PBxCR_VAL@l
+ mtdcr EBC0_CFGDATA, r3
+#endif /* defined(CONFIG_SYS_INIT_DCACHE_CS) */
+
+ /* Restore registers */
+ mr r3, r9
+ mr r4, r10
+ mr r5, r11
+#endif /* defined(CONFIG_4xx_DCACHE) || defined(CONFIG_SYS_INIT_DCACHE_CS) */
+
+#ifdef CONFIG_SYS_INIT_RAM_DCACHE
+ /*
+ * Unlock the previously locked d-cache
+ */
+ msync
+ isync
+ /* set TFLOOR/NFLOOR to 0 again */
+ lis r6,0x0001
+ ori r6,r6,0xf800
+ mtspr SPRN_DVLIM,r6
+ lis r6,0x0000
+ ori r6,r6,0x0000
+ mtspr SPRN_DNV0,r6
+ mtspr SPRN_DNV1,r6
+ mtspr SPRN_DNV2,r6
+ mtspr SPRN_DNV3,r6
+ mtspr SPRN_DTV0,r6
+ mtspr SPRN_DTV1,r6
+ mtspr SPRN_DTV2,r6
+ mtspr SPRN_DTV3,r6
+ msync
+ isync
+
+ /* Invalidate data cache, now no longer our stack */
+ dccci 0,0
+ sync
+ isync
+#endif /* CONFIG_SYS_INIT_RAM_DCACHE */
+
+ /*
+ * On some 440er platforms the cache is enabled in the first TLB (Boot-CS)
+ * to speed up the boot process. Now this cache needs to be disabled.
+ */
+#if defined(CONFIG_440)
+ /* Clear all potential pending exceptions */
+ mfspr r1,SPRN_MCSR
+ mtspr SPRN_MCSR,r1
+ addi r1,r0,CONFIG_SYS_TLB_FOR_BOOT_FLASH /* Use defined TLB */
+ tlbre r0,r1,0x0002 /* Read contents */
+ ori r0,r0,0x0c00 /* Or in the inhibit, write through bit */
+ tlbwe r0,r1,0x0002 /* Save it out */
+ sync
+ isync
+#endif /* defined(CONFIG_440) */
+ mr r1, r3 /* Set new stack pointer */
+ mr r9, r4 /* Save copy of Init Data pointer */
+ mr r10, r5 /* Save copy of Destination Address */
+
+ GET_GOT
+ mr r3, r5 /* Destination Address */
+ lis r4, CONFIG_SYS_MONITOR_BASE@h /* Source Address */
+ ori r4, r4, CONFIG_SYS_MONITOR_BASE@l
+ lwz r5, GOT(__init_end)
+ sub r5, r5, r4
+ li r6, L1_CACHE_BYTES /* Cache Line Size */
+
+ /*
+ * Fix GOT pointer:
+ *
+ * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+ *
+ * Offset:
+ */
+ sub r15, r10, r4
+
+ /* First our own GOT */
+ add r12, r12, r15
+ /* then the one used by the C code */
+ add r30, r30, r15
+
+ /*
+ * Now relocate code
+ */
+
+ cmplw cr1,r3,r4
+ addi r0,r5,3
+ srwi. r0,r0,2
+ beq cr1,4f /* In place copy is not necessary */
+ beq 7f /* Protect against 0 count */
+ mtctr r0
+ bge cr1,2f
+
+ la r8,-4(r4)
+ la r7,-4(r3)
+1: lwzu r0,4(r8)
+ stwu r0,4(r7)
+ bdnz 1b
+ b 4f
+
+2: slwi r0,r0,2
+ add r8,r4,r0
+ add r7,r3,r0
+3: lwzu r0,-4(r8)
+ stwu r0,-4(r7)
+ bdnz 3b
+
+/*
+ * Now flush the cache: note that we must start from a cache aligned
+ * address. Otherwise we might miss one cache line.
+ */
+4: cmpwi r6,0
+ add r5,r3,r5
+ beq 7f /* Always flush prefetch queue in any case */
+ subi r0,r6,1
+ andc r3,r3,r0
+ mr r4,r3
+5: dcbst 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 5b
+ sync /* Wait for all dcbst to complete on bus */
+ mr r4,r3
+6: icbi 0,r4
+ add r4,r4,r6
+ cmplw r4,r5
+ blt 6b
+7: sync /* Wait for all icbi to complete on bus */
+ isync
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+
+ addi r0, r10, in_ram - _start + _START_OFFSET
+ mtlr r0
+ blr /* NEVER RETURNS! */
+
+in_ram:
+
+ /*
+ * Relocation Function, r12 point to got2+0x8000
+ *
+ * Adjust got2 pointers, no need to check for 0, this code
+ * already puts a few entries in the table.
+ */
+ li r0,__got2_entries@sectoff@l
+ la r3,GOT(_GOT2_TABLE_)
+ lwz r11,GOT(_GOT2_TABLE_)
+ mtctr r0
+ sub r11,r3,r11
+ addi r3,r3,-4
+1: lwzu r0,4(r3)
+ cmpwi r0,0
+ beq- 2f
+ add r0,r0,r11
+ stw r0,0(r3)
+2: bdnz 1b
+
+ /*
+ * Now adjust the fixups and the pointers to the fixups
+ * in case we need to move ourselves again.
+ */
+ li r0,__fixup_entries@sectoff@l
+ lwz r3,GOT(_FIXUP_TABLE_)
+ cmpwi r0,0
+ mtctr r0
+ addi r3,r3,-4
+ beq 4f
+3: lwzu r4,4(r3)
+ lwzux r0,r4,r11
+ cmpwi r0,0
+ add r0,r0,r11
+ stw r4,0(r3)
+ beq- 5f
+ stw r0,0(r4)
+5: bdnz 3b
+4:
+clear_bss:
+ /*
+ * Now clear BSS segment
+ */
+ lwz r3,GOT(__bss_start)
+ lwz r4,GOT(__bss_end)
+
+ cmplw 0, r3, r4
+ beq 7f
+
+ li r0, 0
+
+ andi. r5, r4, 3
+ beq 6f
+ sub r4, r4, r5
+ mtctr r5
+ mr r5, r4
+5: stb r0, 0(r5)
+ addi r5, r5, 1
+ bdnz 5b
+6:
+ stw r0, 0(r3)
+ addi r3, r3, 4
+ cmplw 0, r3, r4
+ bne 6b
+
+7:
+ mr r3, r9 /* Init Data pointer */
+ mr r4, r10 /* Destination Address */
+ bl board_init_r
+
+ /*
+ * Copy exception vector code to low memory
+ *
+ * r3: dest_addr
+ * r7: source address, r8: end address, r9: target address
+ */
+ .globl trap_init
+trap_init:
+ mflr r4 /* save link register */
+ GET_GOT
+ lwz r7, GOT(_start_of_vectors)
+ lwz r8, GOT(_end_of_vectors)
+
+ li r9, 0x100 /* reset vector always at 0x100 */
+
+ cmplw 0, r7, r8
+ bgelr /* return if r7>=r8 - just in case */
+1:
+ lwz r0, 0(r7)
+ stw r0, 0(r9)
+ addi r7, r7, 4
+ addi r9, r9, 4
+ cmplw 0, r7, r8
+ bne 1b
+
+ /*
+ * relocate `hdlr' and `int_return' entries
+ */
+ li r7, .L_MachineCheck - _start + _START_OFFSET
+ li r8, Alignment - _start + _START_OFFSET
+2:
+ bl trap_reloc
+ addi r7, r7, 0x100 /* next exception vector */
+ cmplw 0, r7, r8
+ blt 2b
+
+ li r7, .L_Alignment - _start + _START_OFFSET
+ bl trap_reloc
+
+ li r7, .L_ProgramCheck - _start + _START_OFFSET
+ bl trap_reloc
+
+#ifdef CONFIG_440
+ li r7, .L_FPUnavailable - _start + _START_OFFSET
+ bl trap_reloc
+
+ li r7, .L_Decrementer - _start + _START_OFFSET
+ bl trap_reloc
+
+ li r7, .L_APU - _start + _START_OFFSET
+ bl trap_reloc
+
+ li r7, .L_InstructionTLBError - _start + _START_OFFSET
+ bl trap_reloc
+
+ li r7, .L_DataTLBError - _start + _START_OFFSET
+ bl trap_reloc
+#else /* CONFIG_440 */
+ li r7, .L_PIT - _start + _START_OFFSET
+ bl trap_reloc
+
+ li r7, .L_InstructionTLBMiss - _start + _START_OFFSET
+ bl trap_reloc
+
+ li r7, .L_DataTLBMiss - _start + _START_OFFSET
+ bl trap_reloc
+#endif /* CONFIG_440 */
+
+ li r7, .L_DebugBreakpoint - _start + _START_OFFSET
+ bl trap_reloc
+
+#if !defined(CONFIG_440)
+ addi r7,r0,0x1000 /* set ME bit (Machine Exceptions) */
+ oris r7,r7,0x0002 /* set CE bit (Critical Exceptions) */
+ mtmsr r7 /* change MSR */
+#else
+ bl __440_msr_set
+ b __440_msr_continue
+
+__440_msr_set:
+ addi r7,r0,0x1000 /* set ME bit (Machine Exceptions) */
+ oris r7,r7,0x0002 /* set CE bit (Critical Exceptions) */
+ mtspr SPRN_SRR1,r7
+ mflr r7
+ mtspr SPRN_SRR0,r7
+ rfi
+__440_msr_continue:
+#endif
+
+ mtlr r4 /* restore link register */
+ blr
+#endif /* CONFIG_SPL_BUILD */
+
+#if defined(CONFIG_440)
+/*----------------------------------------------------------------------------+
+| dcbz_area.
++----------------------------------------------------------------------------*/
+ function_prolog(dcbz_area)
+ rlwinm. r5,r4,0,27,31
+ rlwinm r5,r4,27,5,31
+ beq ..d_ra2
+ addi r5,r5,0x0001
+..d_ra2:mtctr r5
+..d_ag2:dcbz r0,r3
+ addi r3,r3,32
+ bdnz ..d_ag2
+ sync
+ blr
+ function_epilog(dcbz_area)
+#endif /* CONFIG_440 */
+#endif /* CONFIG_NAND_SPL */
+
+/*------------------------------------------------------------------------------- */
+/* Function: in8 */
+/* Description: Input 8 bits */
+/*------------------------------------------------------------------------------- */
+ .globl in8
+in8:
+ lbz r3,0x0000(r3)
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: out8 */
+/* Description: Output 8 bits */
+/*------------------------------------------------------------------------------- */
+ .globl out8
+out8:
+ stb r4,0x0000(r3)
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: out32 */
+/* Description: Output 32 bits */
+/*------------------------------------------------------------------------------- */
+ .globl out32
+out32:
+ stw r4,0x0000(r3)
+ blr
+
+/*------------------------------------------------------------------------------- */
+/* Function: in32 */
+/* Description: Input 32 bits */
+/*------------------------------------------------------------------------------- */
+ .globl in32
+in32:
+ lwz 3,0x0000(3)
+ blr
+
+/**************************************************************************/
+/* PPC405EP specific stuff */
+/**************************************************************************/
+#ifdef CONFIG_405EP
+ppc405ep_init:
+
+#ifdef CONFIG_BUBINGA
+ /*
+ * Initialize EBC chip selects 1 & 4 and GPIO pins (for alternate
+ * function) to support FPGA and NVRAM accesses below.
+ */
+
+ lis r3,GPIO0_OSRH@h /* config GPIO output select */
+ ori r3,r3,GPIO0_OSRH@l
+ lis r4,CONFIG_SYS_GPIO0_OSRH@h
+ ori r4,r4,CONFIG_SYS_GPIO0_OSRH@l
+ stw r4,0(r3)
+ lis r3,GPIO0_OSRL@h
+ ori r3,r3,GPIO0_OSRL@l
+ lis r4,CONFIG_SYS_GPIO0_OSRL@h
+ ori r4,r4,CONFIG_SYS_GPIO0_OSRL@l
+ stw r4,0(r3)
+
+ lis r3,GPIO0_ISR1H@h /* config GPIO input select */
+ ori r3,r3,GPIO0_ISR1H@l
+ lis r4,CONFIG_SYS_GPIO0_ISR1H@h
+ ori r4,r4,CONFIG_SYS_GPIO0_ISR1H@l
+ stw r4,0(r3)
+ lis r3,GPIO0_ISR1L@h
+ ori r3,r3,GPIO0_ISR1L@l
+ lis r4,CONFIG_SYS_GPIO0_ISR1L@h
+ ori r4,r4,CONFIG_SYS_GPIO0_ISR1L@l
+ stw r4,0(r3)
+
+ lis r3,GPIO0_TSRH@h /* config GPIO three-state select */
+ ori r3,r3,GPIO0_TSRH@l
+ lis r4,CONFIG_SYS_GPIO0_TSRH@h
+ ori r4,r4,CONFIG_SYS_GPIO0_TSRH@l
+ stw r4,0(r3)
+ lis r3,GPIO0_TSRL@h
+ ori r3,r3,GPIO0_TSRL@l
+ lis r4,CONFIG_SYS_GPIO0_TSRL@h
+ ori r4,r4,CONFIG_SYS_GPIO0_TSRL@l
+ stw r4,0(r3)
+
+ lis r3,GPIO0_TCR@h /* config GPIO driver output enables */
+ ori r3,r3,GPIO0_TCR@l
+ lis r4,CONFIG_SYS_GPIO0_TCR@h
+ ori r4,r4,CONFIG_SYS_GPIO0_TCR@l
+ stw r4,0(r3)
+
+ li r3,PB1AP /* program EBC bank 1 for RTC access */
+ mtdcr EBC0_CFGADDR,r3
+ lis r3,CONFIG_SYS_EBC_PB1AP@h
+ ori r3,r3,CONFIG_SYS_EBC_PB1AP@l
+ mtdcr EBC0_CFGDATA,r3
+ li r3,PB1CR
+ mtdcr EBC0_CFGADDR,r3
+ lis r3,CONFIG_SYS_EBC_PB1CR@h
+ ori r3,r3,CONFIG_SYS_EBC_PB1CR@l
+ mtdcr EBC0_CFGDATA,r3
+
+ li r3,PB1AP /* program EBC bank 1 for RTC access */
+ mtdcr EBC0_CFGADDR,r3
+ lis r3,CONFIG_SYS_EBC_PB1AP@h
+ ori r3,r3,CONFIG_SYS_EBC_PB1AP@l
+ mtdcr EBC0_CFGDATA,r3
+ li r3,PB1CR
+ mtdcr EBC0_CFGADDR,r3
+ lis r3,CONFIG_SYS_EBC_PB1CR@h
+ ori r3,r3,CONFIG_SYS_EBC_PB1CR@l
+ mtdcr EBC0_CFGDATA,r3
+
+ li r3,PB4AP /* program EBC bank 4 for FPGA access */
+ mtdcr EBC0_CFGADDR,r3
+ lis r3,CONFIG_SYS_EBC_PB4AP@h
+ ori r3,r3,CONFIG_SYS_EBC_PB4AP@l
+ mtdcr EBC0_CFGDATA,r3
+ li r3,PB4CR
+ mtdcr EBC0_CFGADDR,r3
+ lis r3,CONFIG_SYS_EBC_PB4CR@h
+ ori r3,r3,CONFIG_SYS_EBC_PB4CR@l
+ mtdcr EBC0_CFGDATA,r3
+#endif
+
+ /*
+ !-----------------------------------------------------------------------
+ ! Check to see if chip is in bypass mode.
+ ! If so, write stored CPC0_PLLMR0 and CPC0_PLLMR1 values and perform a
+ ! CPU reset Otherwise, skip this step and keep going.
+ ! Note: Running BIOS in bypass mode is not supported since PLB speed
+ ! will not be fast enough for the SDRAM (min 66MHz)
+ !-----------------------------------------------------------------------
+ */
+ mfdcr r5, CPC0_PLLMR1
+ rlwinm r4,r5,1,0x1 /* get system clock source (SSCS) */
+ cmpi cr0,0,r4,0x1
+
+ beq pll_done /* if SSCS =b'1' then PLL has */
+ /* already been set */
+ /* and CPU has been reset */
+ /* so skip to next section */
+
+#ifdef CONFIG_BUBINGA
+ /*
+ !-----------------------------------------------------------------------
+ ! Read NVRAM to get value to write in PLLMR.
+ ! If value has not been correctly saved, write default value
+ ! Default config values (assuming on-board 33MHz SYS_CLK) are above.
+ ! See CPU_DEFAULT_200 and CPU_DEFAULT_266 above.
+ !
+ ! WARNING: This code assumes the first three words in the nvram_t
+ ! structure in openbios.h. Changing the beginning of
+ ! the structure will break this code.
+ !
+ !-----------------------------------------------------------------------
+ */
+ addis r3,0,NVRAM_BASE@h
+ addi r3,r3,NVRAM_BASE@l
+
+ lwz r4, 0(r3)
+ addis r5,0,NVRVFY1@h
+ addi r5,r5,NVRVFY1@l
+ cmp cr0,0,r4,r5 /* Compare 1st NVRAM Magic number*/
+ bne ..no_pllset
+ addi r3,r3,4
+ lwz r4, 0(r3)
+ addis r5,0,NVRVFY2@h
+ addi r5,r5,NVRVFY2@l
+ cmp cr0,0,r4,r5 /* Compare 2 NVRAM Magic number */
+ bne ..no_pllset
+ addi r3,r3,8 /* Skip over conf_size */
+ lwz r4, 4(r3) /* Load PLLMR1 value from NVRAM */
+ lwz r3, 0(r3) /* Load PLLMR0 value from NVRAM */
+ rlwinm r5,r4,1,0x1 /* get system clock source (SSCS) */
+ cmpi cr0,0,r5,1 /* See if PLL is locked */
+ beq pll_write
+..no_pllset:
+#endif /* CONFIG_BUBINGA */
+
+#ifdef CONFIG_TAIHU
+ mfdcr r4, CPC0_BOOT
+ andi. r5, r4, CPC0_BOOT_SEP@l
+ bne strap_1 /* serial eeprom present */
+ addis r5,0,CPLD_REG0_ADDR@h
+ ori r5,r5,CPLD_REG0_ADDR@l
+ andi. r5, r5, 0x10
+ bne _pci_66mhz
+#endif /* CONFIG_TAIHU */
+
+#if defined(CONFIG_ZEUS)
+ mfdcr r4, CPC0_BOOT
+ andi. r5, r4, CPC0_BOOT_SEP@l
+ bne strap_1 /* serial eeprom present */
+ lis r3,0x0000
+ addi r3,r3,0x3030
+ lis r4,0x8042
+ addi r4,r4,0x223e
+ b 1f
+strap_1:
+ mfdcr r3, CPC0_PLLMR0
+ mfdcr r4, CPC0_PLLMR1
+ b 1f
+#endif
+
+ addis r3,0,PLLMR0_DEFAULT@h /* PLLMR0 default value */
+ ori r3,r3,PLLMR0_DEFAULT@l /* */
+ addis r4,0,PLLMR1_DEFAULT@h /* PLLMR1 default value */
+ ori r4,r4,PLLMR1_DEFAULT@l /* */
+
+#ifdef CONFIG_TAIHU
+ b 1f
+_pci_66mhz:
+ addis r3,0,PLLMR0_DEFAULT_PCI66@h
+ ori r3,r3,PLLMR0_DEFAULT_PCI66@l
+ addis r4,0,PLLMR1_DEFAULT_PCI66@h
+ ori r4,r4,PLLMR1_DEFAULT_PCI66@l
+ b 1f
+strap_1:
+ mfdcr r3, CPC0_PLLMR0
+ mfdcr r4, CPC0_PLLMR1
+#endif /* CONFIG_TAIHU */
+
+1:
+ b pll_write /* Write the CPC0_PLLMR with new value */
+
+pll_done:
+ /*
+ !-----------------------------------------------------------------------
+ ! Clear Soft Reset Register
+ ! This is needed to enable PCI if not booting from serial EPROM
+ !-----------------------------------------------------------------------
+ */
+ addi r3, 0, 0x0
+ mtdcr CPC0_SRR, r3
+
+ addis r3,0,0x0010
+ mtctr r3
+pci_wait:
+ bdnz pci_wait
+
+ blr /* return to main code */
+
+/*
+!-----------------------------------------------------------------------------
+! Function: pll_write
+! Description: Updates the value of the CPC0_PLLMR according to CMOS27E documentation
+! That is:
+! 1. Pll is first disabled (de-activated by putting in bypass mode)
+! 2. PLL is reset
+! 3. Clock dividers are set while PLL is held in reset and bypassed
+! 4. PLL Reset is cleared
+! 5. Wait 100us for PLL to lock
+! 6. A core reset is performed
+! Input: r3 = Value to write to CPC0_PLLMR0
+! Input: r4 = Value to write to CPC0_PLLMR1
+! Output r3 = none
+!-----------------------------------------------------------------------------
+*/
+ .globl pll_write
+pll_write:
+ mfdcr r5, CPC0_UCR
+ andis. r5,r5,0xFFFF
+ ori r5,r5,0x0101 /* Stop the UART clocks */
+ mtdcr CPC0_UCR,r5 /* Before changing PLL */
+
+ mfdcr r5, CPC0_PLLMR1
+ rlwinm r5,r5,0,0x7FFFFFFF /* Disable PLL */
+ mtdcr CPC0_PLLMR1,r5
+ oris r5,r5,0x4000 /* Set PLL Reset */
+ mtdcr CPC0_PLLMR1,r5
+
+ mtdcr CPC0_PLLMR0,r3 /* Set clock dividers */
+ rlwinm r5,r4,0,0x3FFFFFFF /* Reset & Bypass new PLL dividers */
+ oris r5,r5,0x4000 /* Set PLL Reset */
+ mtdcr CPC0_PLLMR1,r5 /* Set clock dividers */
+ rlwinm r5,r5,0,0xBFFFFFFF /* Clear PLL Reset */
+ mtdcr CPC0_PLLMR1,r5
+
+ /*
+ ! Wait min of 100us for PLL to lock.
+ ! See CMOS 27E databook for more info.
+ ! At 200MHz, that means waiting 20,000 instructions
+ */
+ addi r3,0,20000 /* 2000 = 0x4e20 */
+ mtctr r3
+pll_wait:
+ bdnz pll_wait
+
+ oris r5,r5,0x8000 /* Enable PLL */
+ mtdcr CPC0_PLLMR1,r5 /* Engage */
+
+ /*
+ * Reset CPU to guarantee timings are OK
+ * Not sure if this is needed...
+ */
+ addis r3,0,0x1000
+ mtspr SPRN_DBCR0,r3 /* This will cause a CPU core reset, and */
+ /* execution will continue from the poweron */
+ /* vector of 0xfffffffc */
+#endif /* CONFIG_405EP */
+
+#if defined(CONFIG_440)
+/*----------------------------------------------------------------------------+
+| mttlb3.
++----------------------------------------------------------------------------*/
+ function_prolog(mttlb3)
+ TLBWE(4,3,2)
+ blr
+ function_epilog(mttlb3)
+
+/*----------------------------------------------------------------------------+
+| mftlb3.
++----------------------------------------------------------------------------*/
+ function_prolog(mftlb3)
+ TLBRE(3,3,2)
+ blr
+ function_epilog(mftlb3)
+
+/*----------------------------------------------------------------------------+
+| mttlb2.
++----------------------------------------------------------------------------*/
+ function_prolog(mttlb2)
+ TLBWE(4,3,1)
+ blr
+ function_epilog(mttlb2)
+
+/*----------------------------------------------------------------------------+
+| mftlb2.
++----------------------------------------------------------------------------*/
+ function_prolog(mftlb2)
+ TLBRE(3,3,1)
+ blr
+ function_epilog(mftlb2)
+
+/*----------------------------------------------------------------------------+
+| mttlb1.
++----------------------------------------------------------------------------*/
+ function_prolog(mttlb1)
+ TLBWE(4,3,0)
+ blr
+ function_epilog(mttlb1)
+
+/*----------------------------------------------------------------------------+
+| mftlb1.
++----------------------------------------------------------------------------*/
+ function_prolog(mftlb1)
+ TLBRE(3,3,0)
+ blr
+ function_epilog(mftlb1)
+#endif /* CONFIG_440 */
+
+#if defined(CONFIG_NAND_SPL)
+/*
+ * void nand_boot_relocate(dst, src, bytes)
+ *
+ * r3 = Destination address to copy code to (in SDRAM)
+ * r4 = Source address to copy code from
+ * r5 = size to copy in bytes
+ */
+nand_boot_relocate:
+ mr r6,r3
+ mr r7,r4
+ mflr r8
+
+ /*
+ * Copy SPL from icache into SDRAM
+ */
+ subi r3,r3,4
+ subi r4,r4,4
+ srwi r5,r5,2
+ mtctr r5
+..spl_loop:
+ lwzu r0,4(r4)
+ stwu r0,4(r3)
+ bdnz ..spl_loop
+
+ /*
+ * Calculate "corrected" link register, so that we "continue"
+ * in execution in destination range
+ */
+ sub r3,r7,r6 /* r3 = src - dst */
+ sub r8,r8,r3 /* r8 = link-reg - (src - dst) */
+ mtlr r8
+ blr
+
+nand_boot_common:
+ /*
+ * First initialize SDRAM. It has to be available *before* calling
+ * nand_boot().
+ */
+ lis r3,CONFIG_SYS_SDRAM_BASE@h
+ ori r3,r3,CONFIG_SYS_SDRAM_BASE@l
+ bl initdram
+
+ /*
+ * Now copy the 4k SPL code into SDRAM and continue execution
+ * from there.
+ */
+ lis r3,CONFIG_SYS_NAND_BOOT_SPL_DST@h
+ ori r3,r3,CONFIG_SYS_NAND_BOOT_SPL_DST@l
+ lis r4,CONFIG_SYS_NAND_BOOT_SPL_SRC@h
+ ori r4,r4,CONFIG_SYS_NAND_BOOT_SPL_SRC@l
+ lis r5,CONFIG_SYS_NAND_BOOT_SPL_SIZE@h
+ ori r5,r5,CONFIG_SYS_NAND_BOOT_SPL_SIZE@l
+ bl nand_boot_relocate
+
+ /*
+ * We're running from SDRAM now!!!
+ *
+ * It is necessary for 4xx systems to relocate from running at
+ * the original location (0xfffffxxx) to somewhere else (SDRAM
+ * preferably). This is because CS0 needs to be reconfigured for
+ * NAND access. And we can't reconfigure this CS when currently
+ * "running" from it.
+ */
+
+ /*
+ * Finally call nand_boot() to load main NAND U-Boot image from
+ * NAND and jump to it.
+ */
+ bl nand_boot /* will not return */
+#endif /* CONFIG_NAND_SPL */
diff --git a/arch/powerpc/cpu/ppc4xx/tlb.c b/arch/powerpc/cpu/ppc4xx/tlb.c
new file mode 100644
index 0000000..684da92
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/tlb.c
@@ -0,0 +1,352 @@
+/*
+ * (C) Copyright 2007
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_440)
+
+#include <asm/ppc440.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <asm/mmu.h>
+
+typedef struct region {
+ u64 base;
+ u32 size;
+ u32 tlb_word2_i_value;
+} region_t;
+
+void remove_tlb(u32 vaddr, u32 size)
+{
+ int i;
+ u32 tlb_word0_value;
+ u32 tlb_vaddr;
+ u32 tlb_size = 0;
+
+ for (i=0; i<PPC4XX_TLB_SIZE; i++) {
+ tlb_word0_value = mftlb1(i);
+ tlb_vaddr = TLB_WORD0_EPN_DECODE(tlb_word0_value);
+ if (((tlb_word0_value & TLB_WORD0_V_MASK) == TLB_WORD0_V_ENABLE) &&
+ (tlb_vaddr >= vaddr)) {
+ /*
+ * TLB is enabled and start address is lower or equal
+ * than the area we are looking for. Now we only have
+ * to check the size/end address for a match.
+ */
+ switch (tlb_word0_value & TLB_WORD0_SIZE_MASK) {
+ case TLB_WORD0_SIZE_1KB:
+ tlb_size = 1 << 10;
+ break;
+ case TLB_WORD0_SIZE_4KB:
+ tlb_size = 4 << 10;
+ break;
+ case TLB_WORD0_SIZE_16KB:
+ tlb_size = 16 << 10;
+ break;
+ case TLB_WORD0_SIZE_64KB:
+ tlb_size = 64 << 10;
+ break;
+ case TLB_WORD0_SIZE_256KB:
+ tlb_size = 256 << 10;
+ break;
+ case TLB_WORD0_SIZE_1MB:
+ tlb_size = 1 << 20;
+ break;
+ case TLB_WORD0_SIZE_16MB:
+ tlb_size = 16 << 20;
+ break;
+ case TLB_WORD0_SIZE_256MB:
+ tlb_size = 256 << 20;
+ break;
+ }
+
+ /*
+ * Now check the end-address if it's in the range
+ */
+ if ((tlb_vaddr + tlb_size - 1) <= (vaddr + size - 1))
+ /*
+ * Found a TLB in the range.
+ * Disable it by writing 0 to tlb0 word.
+ */
+ mttlb1(i, 0);
+ }
+ }
+
+ /* Execute an ISYNC instruction so that the new TLB entry takes effect */
+ asm("isync");
+}
+
+/*
+ * Change the I attribute (cache inhibited) of a TLB or multiple TLB's.
+ * This function is used to either turn cache on or off in a specific
+ * memory area.
+ */
+void change_tlb(u32 vaddr, u32 size, u32 tlb_word2_i_value)
+{
+ int i;
+ u32 tlb_word0_value;
+ u32 tlb_word2_value;
+ u32 tlb_vaddr;
+ u32 tlb_size = 0;
+
+ for (i=0; i<PPC4XX_TLB_SIZE; i++) {
+ tlb_word0_value = mftlb1(i);
+ tlb_vaddr = TLB_WORD0_EPN_DECODE(tlb_word0_value);
+ if (((tlb_word0_value & TLB_WORD0_V_MASK) == TLB_WORD0_V_ENABLE) &&
+ (tlb_vaddr >= vaddr)) {
+ /*
+ * TLB is enabled and start address is lower or equal
+ * than the area we are looking for. Now we only have
+ * to check the size/end address for a match.
+ */
+ switch (tlb_word0_value & TLB_WORD0_SIZE_MASK) {
+ case TLB_WORD0_SIZE_1KB:
+ tlb_size = 1 << 10;
+ break;
+ case TLB_WORD0_SIZE_4KB:
+ tlb_size = 4 << 10;
+ break;
+ case TLB_WORD0_SIZE_16KB:
+ tlb_size = 16 << 10;
+ break;
+ case TLB_WORD0_SIZE_64KB:
+ tlb_size = 64 << 10;
+ break;
+ case TLB_WORD0_SIZE_256KB:
+ tlb_size = 256 << 10;
+ break;
+ case TLB_WORD0_SIZE_1MB:
+ tlb_size = 1 << 20;
+ break;
+ case TLB_WORD0_SIZE_16MB:
+ tlb_size = 16 << 20;
+ break;
+ case TLB_WORD0_SIZE_256MB:
+ tlb_size = 256 << 20;
+ break;
+ }
+
+ /*
+ * Now check the end-address if it's in the range
+ */
+ if (((tlb_vaddr + tlb_size - 1) <= (vaddr + size - 1)) ||
+ ((tlb_vaddr < (vaddr + size - 1)) &&
+ ((tlb_vaddr + tlb_size - 1) > (vaddr + size - 1)))) {
+ /*
+ * Found a TLB in the range.
+ * Change cache attribute in tlb2 word.
+ */
+ tlb_word2_value =
+ TLB_WORD2_U0_DISABLE | TLB_WORD2_U1_DISABLE |
+ TLB_WORD2_U2_DISABLE | TLB_WORD2_U3_DISABLE |
+ TLB_WORD2_W_DISABLE | tlb_word2_i_value |
+ TLB_WORD2_M_DISABLE | TLB_WORD2_G_DISABLE |
+ TLB_WORD2_E_DISABLE | TLB_WORD2_UX_ENABLE |
+ TLB_WORD2_UW_ENABLE | TLB_WORD2_UR_ENABLE |
+ TLB_WORD2_SX_ENABLE | TLB_WORD2_SW_ENABLE |
+ TLB_WORD2_SR_ENABLE;
+
+ /*
+ * Now either flush or invalidate the dcache
+ */
+ if (tlb_word2_i_value)
+ flush_dcache();
+ else
+ invalidate_dcache();
+
+ mttlb3(i, tlb_word2_value);
+ asm("iccci 0,0");
+ }
+ }
+ }
+
+ /* Execute an ISYNC instruction so that the new TLB entry takes effect */
+ asm("isync");
+}
+
+static int add_tlb_entry(u64 phys_addr,
+ u32 virt_addr,
+ u32 tlb_word0_size_value,
+ u32 tlb_word2_i_value)
+{
+ int i;
+ unsigned long tlb_word0_value;
+ unsigned long tlb_word1_value;
+ unsigned long tlb_word2_value;
+
+ /* First, find the index of a TLB entry not being used */
+ for (i=0; i<PPC4XX_TLB_SIZE; i++) {
+ tlb_word0_value = mftlb1(i);
+ if ((tlb_word0_value & TLB_WORD0_V_MASK) == TLB_WORD0_V_DISABLE)
+ break;
+ }
+ if (i >= PPC4XX_TLB_SIZE)
+ return -1;
+
+ /* Second, create the TLB entry */
+ tlb_word0_value = TLB_WORD0_EPN_ENCODE(virt_addr) | TLB_WORD0_V_ENABLE |
+ TLB_WORD0_TS_0 | tlb_word0_size_value;
+ tlb_word1_value = TLB_WORD1_RPN_ENCODE((u32)phys_addr) |
+ TLB_WORD1_ERPN_ENCODE(phys_addr >> 32);
+ tlb_word2_value = TLB_WORD2_U0_DISABLE | TLB_WORD2_U1_DISABLE |
+ TLB_WORD2_U2_DISABLE | TLB_WORD2_U3_DISABLE |
+ TLB_WORD2_W_DISABLE | tlb_word2_i_value |
+ TLB_WORD2_M_DISABLE | TLB_WORD2_G_DISABLE |
+ TLB_WORD2_E_DISABLE | TLB_WORD2_UX_ENABLE |
+ TLB_WORD2_UW_ENABLE | TLB_WORD2_UR_ENABLE |
+ TLB_WORD2_SX_ENABLE | TLB_WORD2_SW_ENABLE |
+ TLB_WORD2_SR_ENABLE;
+
+ /* Wait for all memory accesses to complete */
+ sync();
+
+ /* Third, add the TLB entries */
+ mttlb1(i, tlb_word0_value);
+ mttlb2(i, tlb_word1_value);
+ mttlb3(i, tlb_word2_value);
+
+ /* Execute an ISYNC instruction so that the new TLB entry takes effect */
+ asm("isync");
+
+ return 0;
+}
+
+static void program_tlb_addr(u64 phys_addr,
+ u32 virt_addr,
+ u32 mem_size,
+ u32 tlb_word2_i_value)
+{
+ int rc;
+ int tlb_i;
+
+ tlb_i = tlb_word2_i_value;
+ while (mem_size != 0) {
+ rc = 0;
+ /* Add the TLB entries in to map the region. */
+ if (((phys_addr & TLB_256MB_ALIGN_MASK) == phys_addr) &&
+ (mem_size >= TLB_256MB_SIZE)) {
+ /* Add a 256MB TLB entry */
+ if ((rc = add_tlb_entry(phys_addr, virt_addr,
+ TLB_WORD0_SIZE_256MB, tlb_i)) == 0) {
+ mem_size -= TLB_256MB_SIZE;
+ phys_addr += TLB_256MB_SIZE;
+ virt_addr += TLB_256MB_SIZE;
+ }
+ } else if (((phys_addr & TLB_16MB_ALIGN_MASK) == phys_addr) &&
+ (mem_size >= TLB_16MB_SIZE)) {
+ /* Add a 16MB TLB entry */
+ if ((rc = add_tlb_entry(phys_addr, virt_addr,
+ TLB_WORD0_SIZE_16MB, tlb_i)) == 0) {
+ mem_size -= TLB_16MB_SIZE;
+ phys_addr += TLB_16MB_SIZE;
+ virt_addr += TLB_16MB_SIZE;
+ }
+ } else if (((phys_addr & TLB_1MB_ALIGN_MASK) == phys_addr) &&
+ (mem_size >= TLB_1MB_SIZE)) {
+ /* Add a 1MB TLB entry */
+ if ((rc = add_tlb_entry(phys_addr, virt_addr,
+ TLB_WORD0_SIZE_1MB, tlb_i)) == 0) {
+ mem_size -= TLB_1MB_SIZE;
+ phys_addr += TLB_1MB_SIZE;
+ virt_addr += TLB_1MB_SIZE;
+ }
+ } else if (((phys_addr & TLB_256KB_ALIGN_MASK) == phys_addr) &&
+ (mem_size >= TLB_256KB_SIZE)) {
+ /* Add a 256KB TLB entry */
+ if ((rc = add_tlb_entry(phys_addr, virt_addr,
+ TLB_WORD0_SIZE_256KB, tlb_i)) == 0) {
+ mem_size -= TLB_256KB_SIZE;
+ phys_addr += TLB_256KB_SIZE;
+ virt_addr += TLB_256KB_SIZE;
+ }
+ } else if (((phys_addr & TLB_64KB_ALIGN_MASK) == phys_addr) &&
+ (mem_size >= TLB_64KB_SIZE)) {
+ /* Add a 64KB TLB entry */
+ if ((rc = add_tlb_entry(phys_addr, virt_addr,
+ TLB_WORD0_SIZE_64KB, tlb_i)) == 0) {
+ mem_size -= TLB_64KB_SIZE;
+ phys_addr += TLB_64KB_SIZE;
+ virt_addr += TLB_64KB_SIZE;
+ }
+ } else if (((phys_addr & TLB_16KB_ALIGN_MASK) == phys_addr) &&
+ (mem_size >= TLB_16KB_SIZE)) {
+ /* Add a 16KB TLB entry */
+ if ((rc = add_tlb_entry(phys_addr, virt_addr,
+ TLB_WORD0_SIZE_16KB, tlb_i)) == 0) {
+ mem_size -= TLB_16KB_SIZE;
+ phys_addr += TLB_16KB_SIZE;
+ virt_addr += TLB_16KB_SIZE;
+ }
+ } else if (((phys_addr & TLB_4KB_ALIGN_MASK) == phys_addr) &&
+ (mem_size >= TLB_4KB_SIZE)) {
+ /* Add a 4KB TLB entry */
+ if ((rc = add_tlb_entry(phys_addr, virt_addr,
+ TLB_WORD0_SIZE_4KB, tlb_i)) == 0) {
+ mem_size -= TLB_4KB_SIZE;
+ phys_addr += TLB_4KB_SIZE;
+ virt_addr += TLB_4KB_SIZE;
+ }
+ } else if (((phys_addr & TLB_1KB_ALIGN_MASK) == phys_addr) &&
+ (mem_size >= TLB_1KB_SIZE)) {
+ /* Add a 1KB TLB entry */
+ if ((rc = add_tlb_entry(phys_addr, virt_addr,
+ TLB_WORD0_SIZE_1KB, tlb_i)) == 0) {
+ mem_size -= TLB_1KB_SIZE;
+ phys_addr += TLB_1KB_SIZE;
+ virt_addr += TLB_1KB_SIZE;
+ }
+ } else {
+ printf("ERROR: no TLB size exists for the base address 0x%llx.\n",
+ phys_addr);
+ }
+
+ if (rc != 0)
+ printf("ERROR: no TLB entries available for the base addr 0x%llx.\n",
+ phys_addr);
+ }
+
+ return;
+}
+
+/*
+ * Program one (or multiple) TLB entries for one memory region
+ *
+ * Common usage for boards with SDRAM DIMM modules to dynamically
+ * configure the TLB's for the SDRAM
+ */
+void program_tlb(u64 phys_addr, u32 virt_addr, u32 size, u32 tlb_word2_i_value)
+{
+ region_t region_array;
+
+ region_array.base = phys_addr;
+ region_array.size = size;
+ region_array.tlb_word2_i_value = tlb_word2_i_value; /* en-/disable cache */
+
+ /* Call the routine to add in the tlb entries for the memory regions */
+ program_tlb_addr(region_array.base, virt_addr, region_array.size,
+ region_array.tlb_word2_i_value);
+
+ return;
+}
+
+#endif /* CONFIG_440 */
diff --git a/arch/powerpc/cpu/ppc4xx/traps.c b/arch/powerpc/cpu/ppc4xx/traps.c
new file mode 100644
index 0000000..dae19cb
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/traps.c
@@ -0,0 +1,408 @@
+/*
+ * linux/arch/powerpc/kernel/traps.c
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#include <common.h>
+#include <command.h>
+#include <kgdb.h>
+#include <asm/processor.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+/* THIS NEEDS CHANGING to use the board info structure.
+ */
+#define END_OF_MEM (gd->bd->bi_memstart + gd->bd->bi_memsize)
+
+static __inline__ unsigned long get_esr(void)
+{
+ unsigned long val;
+
+#if defined(CONFIG_440)
+ asm volatile("mfspr %0, 0x03e" : "=r" (val) :);
+#else
+ asm volatile("mfesr %0" : "=r" (val) :);
+#endif
+ return val;
+}
+
+#define ESR_MCI 0x80000000
+#define ESR_PIL 0x08000000
+#define ESR_PPR 0x04000000
+#define ESR_PTR 0x02000000
+#define ESR_DST 0x00800000
+#define ESR_DIZ 0x00400000
+#define ESR_U0F 0x00008000
+
+#if defined(CONFIG_CMD_BEDBUG)
+extern void do_bedbug_breakpoint(struct pt_regs *);
+#endif
+
+/*
+ * Trap & Exception support
+ */
+
+static void print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ unsigned long i;
+
+ printf("Call backtrace: ");
+ while (sp) {
+ if ((uint)sp > END_OF_MEM)
+ break;
+
+ i = sp[1];
+ if (cnt++ % 7 == 0)
+ printf("\n");
+ printf("%08lX ", i);
+ if (cnt > 32) break;
+ sp = (unsigned long *)*sp;
+ }
+ printf("\n");
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ int i;
+
+ printf("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DEAR: %08lX\n",
+ regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar);
+ printf("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+ regs->msr&MSR_IR ? 1 : 0,
+ regs->msr&MSR_DR ? 1 : 0);
+
+ printf("\n");
+ for (i = 0; i < 32; i++) {
+ if ((i % 8) == 0) {
+ printf("GPR%02d: ", i);
+ }
+
+ printf("%08lX ", regs->gpr[i]);
+ if ((i % 8) == 7) {
+ printf("\n");
+ }
+ }
+}
+
+
+static void _exception(int signr, struct pt_regs *regs)
+{
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Exception");
+}
+
+void MachineCheckException(struct pt_regs *regs)
+{
+ unsigned long fixup, val;
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+ u32 value2;
+ int corr_ecc = 0;
+ int uncorr_ecc = 0;
+#endif
+
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ regs->nip = fixup;
+ val = mfspr(MCSR);
+ /* Clear MCSR */
+ mtspr(SPRN_MCSR, val);
+ return;
+ }
+
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ printf("Machine Check Exception.\n");
+ printf("Caused by (from msr): ");
+ printf("regs %p ", regs);
+
+ val = get_esr();
+
+#if !defined(CONFIG_440) && !defined(CONFIG_405EX)
+ if (val& ESR_IMCP) {
+ printf("Instruction");
+ mtspr(ESR, val & ~ESR_IMCP);
+ } else {
+ printf("Data");
+ }
+ printf(" machine check.\n");
+
+#elif defined(CONFIG_440) || defined(CONFIG_405EX)
+ if (val& ESR_IMCP){
+ printf("Instruction Synchronous Machine Check exception\n");
+ mtspr(SPRN_ESR, val & ~ESR_IMCP);
+ } else {
+ val = mfspr(MCSR);
+ if (val & MCSR_IB)
+ printf("Instruction Read PLB Error\n");
+#if defined(CONFIG_440)
+ if (val & MCSR_DRB)
+ printf("Data Read PLB Error\n");
+ if (val & MCSR_DWB)
+ printf("Data Write PLB Error\n");
+#else
+ if (val & MCSR_DB)
+ printf("Data PLB Error\n");
+#endif
+ if (val & MCSR_TLBP)
+ printf("TLB Parity Error\n");
+ if (val & MCSR_ICP){
+ /*flush_instruction_cache(); */
+ printf("I-Cache Parity Error\n");
+ }
+ if (val & MCSR_DCSP)
+ printf("D-Cache Search Parity Error\n");
+ if (val & MCSR_DCFP)
+ printf("D-Cache Flush Parity Error\n");
+ if (val & MCSR_IMPE)
+ printf("Machine Check exception is imprecise\n");
+
+ /* Clear MCSR */
+ mtspr(SPRN_MCSR, val);
+ }
+
+#if defined(CONFIG_DDR_ECC) && defined(CONFIG_SDRAM_PPC4xx_IBM_DDR2)
+ /*
+ * Read and print ECC status register/info:
+ * The faulting address is only known upon uncorrectable ECC
+ * errors.
+ */
+ mfsdram(SDRAM_ECCES, val);
+ if (val & SDRAM_ECCES_CE)
+ printf("ECC: Correctable error\n");
+ if (val & SDRAM_ECCES_UE) {
+ printf("ECC: Uncorrectable error at 0x%02x%08x\n",
+ mfdcr(SDRAM_ERRADDULL), mfdcr(SDRAM_ERRADDLLL));
+ }
+#endif /* CONFIG_DDR_ECC ... */
+
+#if defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
+ mfsdram(DDR0_00, val) ;
+ printf("DDR0: DDR0_00 %lx\n", val);
+ val = (val >> 16) & 0xff;
+ if (val & 0x80)
+ printf("DDR0: At least one interrupt active\n");
+ if (val & 0x40)
+ printf("DDR0: DRAM initialization complete.\n");
+ if (val & 0x20) {
+ printf("DDR0: Multiple uncorrectable ECC events.\n");
+ uncorr_ecc = 1;
+ }
+ if (val & 0x10) {
+ printf("DDR0: Single uncorrectable ECC event.\n");
+ uncorr_ecc = 1;
+ }
+ if (val & 0x08) {
+ printf("DDR0: Multiple correctable ECC events.\n");
+ corr_ecc = 1;
+ }
+ if (val & 0x04) {
+ printf("DDR0: Single correctable ECC event.\n");
+ corr_ecc = 1;
+ }
+ if (val & 0x02)
+ printf("Multiple accesses outside the defined"
+ " physical memory space detected\n");
+ if (val & 0x01)
+ printf("DDR0: Single access outside the defined"
+ " physical memory space detected.\n");
+
+ mfsdram(DDR0_01, val);
+ val = (val >> 8) & 0x7;
+ switch (val ) {
+ case 0:
+ printf("DDR0: Write Out-of-Range command\n");
+ break;
+ case 1:
+ printf("DDR0: Read Out-of-Range command\n");
+ break;
+ case 2:
+ printf("DDR0: Masked write Out-of-Range command\n");
+ break;
+ case 4:
+ printf("DDR0: Wrap write Out-of-Range command\n");
+ break;
+ case 5:
+ printf("DDR0: Wrap read Out-of-Range command\n");
+ break;
+ default:
+ mfsdram(DDR0_01, value2);
+ printf("DDR0: No DDR0 error know 0x%lx %x\n", val, value2);
+ }
+ mfsdram(DDR0_23, val);
+ if (((val >> 16) & 0xff) && corr_ecc)
+ printf("DDR0: Syndrome for correctable ECC event 0x%lx\n",
+ (val >> 16) & 0xff);
+ mfsdram(DDR0_23, val);
+ if (((val >> 8) & 0xff) && uncorr_ecc)
+ printf("DDR0: Syndrome for uncorrectable ECC event 0x%lx\n",
+ (val >> 8) & 0xff);
+ mfsdram(DDR0_33, val);
+ if (val)
+ printf("DDR0: Address of command that caused an "
+ "Out-of-Range interrupt %lx\n", val);
+ mfsdram(DDR0_34, val);
+ if (val && uncorr_ecc)
+ printf("DDR0: Address of uncorrectable ECC event %lx\n", val);
+ mfsdram(DDR0_35, val);
+ if (val && uncorr_ecc)
+ printf("DDR0: Address of uncorrectable ECC event %lx\n", val);
+ mfsdram(DDR0_36, val);
+ if (val && uncorr_ecc)
+ printf("DDR0: Data of uncorrectable ECC event 0x%08lx\n", val);
+ mfsdram(DDR0_37, val);
+ if (val && uncorr_ecc)
+ printf("DDR0: Data of uncorrectable ECC event 0x%08lx\n", val);
+ mfsdram(DDR0_38, val);
+ if (val && corr_ecc)
+ printf("DDR0: Address of correctable ECC event %lx\n", val);
+ mfsdram(DDR0_39, val);
+ if (val && corr_ecc)
+ printf("DDR0: Address of correctable ECC event %lx\n", val);
+ mfsdram(DDR0_40, val);
+ if (val && corr_ecc)
+ printf("DDR0: Data of correctable ECC event 0x%08lx\n", val);
+ mfsdram(DDR0_41, val);
+ if (val && corr_ecc)
+ printf("DDR0: Data of correctable ECC event 0x%08lx\n", val);
+#endif /* CONFIG_440EPX */
+#endif /* CONFIG_440 */
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("machine check");
+}
+
+void AlignmentException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ show_regs(regs);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Alignment Exception");
+}
+
+void ProgramCheckException(struct pt_regs *regs)
+{
+ long esr_val;
+
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ show_regs(regs);
+
+ esr_val = get_esr();
+ if( esr_val & ESR_PIL )
+ printf( "** Illegal Instruction **\n" );
+ else if( esr_val & ESR_PPR )
+ printf( "** Privileged Instruction **\n" );
+ else if( esr_val & ESR_PTR )
+ printf( "** Trap Instruction **\n" );
+
+ print_backtrace((unsigned long *)regs->gpr[1]);
+ panic("Program Check Exception");
+}
+
+void DecrementerPITException(struct pt_regs *regs)
+{
+ /*
+ * Reset PIT interrupt
+ */
+ mtspr(SPRN_TSR, 0x08000000);
+
+ /*
+ * Call timer_interrupt routine in interrupts.c
+ */
+ timer_interrupt(NULL);
+}
+
+
+void UnknownException(struct pt_regs *regs)
+{
+#if defined(CONFIG_CMD_KGDB)
+ if (debugger_exception_handler && (*debugger_exception_handler)(regs))
+ return;
+#endif
+
+ printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+ _exception(0, regs);
+}
+
+void DebugException(struct pt_regs *regs)
+{
+ printf("Debugger trap at @ %lx\n", regs->nip );
+ show_regs(regs);
+#if defined(CONFIG_CMD_BEDBUG)
+ do_bedbug_breakpoint( regs );
+#endif
+}
+
+/* Probe an address by reading. If not present, return -1, otherwise
+ * return 0.
+ */
+int
+addr_probe(uint *addr)
+{
+#if 0
+ int retval;
+
+ __asm__ __volatile__( \
+ "1: lwz %0,0(%1)\n" \
+ " eieio\n" \
+ " li %0,0\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,-1\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r" (retval) : "r"(addr));
+
+ return (retval);
+#endif
+ return 0;
+}
diff --git a/arch/powerpc/cpu/ppc4xx/u-boot-spl.lds b/arch/powerpc/cpu/ppc4xx/u-boot-spl.lds
new file mode 100644
index 0000000..ae1df17
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/u-boot-spl.lds
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2012-2013 Stefan Roese <sr@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+MEMORY
+{
+ sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR,
+ LENGTH = CONFIG_SPL_BSS_MAX_SIZE
+ flash : ORIGIN = CONFIG_SPL_TEXT_BASE,
+ LENGTH = CONFIG_SYS_SPL_MAX_LEN
+}
+
+OUTPUT_ARCH(powerpc)
+ENTRY(_start)
+SECTIONS
+{
+#ifdef CONFIG_440
+ .bootpg 0xfffff000 :
+ {
+ arch/powerpc/cpu/ppc4xx/start.o (.bootpg)
+
+ /*
+ * PPC440 board need a board specific object with the
+ * TLB definitions. This needs to get included right after
+ * start.o, since the first shadow TLB only covers 4k
+ * of address space.
+ */
+ CONFIG_BOARDDIR/init.o (.bootpg)
+ } > flash
+#endif
+
+ .resetvec 0xFFFFFFFC :
+ {
+ KEEP(*(.resetvec))
+ } > flash
+
+ .text :
+ {
+ __start = .;
+ arch/powerpc/cpu/ppc4xx/start.o (.text)
+ CONFIG_BOARDDIR/init.o (.text)
+ *(.text*)
+ } > flash
+
+ . = ALIGN(4);
+ .data : { *(SORT_BY_ALIGNMENT(.data*)) } > flash
+
+ . = ALIGN(4);
+ .rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } > flash
+
+ .bss :
+ {
+ . = ALIGN(4);
+ __bss_start = .;
+ *(.bss*)
+ . = ALIGN(4);
+ __bss_end = .;
+ } > sdram
+}
diff --git a/arch/powerpc/cpu/ppc4xx/u-boot.lds b/arch/powerpc/cpu/ppc4xx/u-boot.lds
new file mode 100644
index 0000000..e994f02
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/u-boot.lds
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2007-2009 Freescale Semiconductor, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "config.h" /* CONFIG_BOARDDIR */
+
+#ifndef RESET_VECTOR_ADDRESS
+#ifdef CONFIG_RESET_VECTOR_ADDRESS
+#define RESET_VECTOR_ADDRESS CONFIG_RESET_VECTOR_ADDRESS
+#else
+#define RESET_VECTOR_ADDRESS 0xfffffffc
+#endif
+#endif
+
+OUTPUT_ARCH(powerpc)
+
+PHDRS
+{
+ text PT_LOAD;
+ bss PT_LOAD;
+}
+
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = + SIZEOF_HEADERS;
+ .text :
+ {
+ *(.text*)
+ } :text
+ _etext = .;
+ PROVIDE (etext = .);
+ .rodata :
+ {
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ } :text
+
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x00FF) & 0xFFFFFF00;
+ _erotext = .;
+ PROVIDE (erotext = .);
+ .reloc :
+ {
+ _GOT2_TABLE_ = .;
+ KEEP(*(.got2))
+ KEEP(*(.got))
+ PROVIDE(_GLOBAL_OFFSET_TABLE_ = . + 4);
+ _FIXUP_TABLE_ = .;
+ KEEP(*(.fixup))
+ }
+ __got2_entries = ((_GLOBAL_OFFSET_TABLE_ - _GOT2_TABLE_) >> 2) - 1;
+ __fixup_entries = (. - _FIXUP_TABLE_) >> 2;
+
+ .data :
+ {
+ *(.data*)
+ *(.sdata*)
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+
+ . = .;
+
+ . = ALIGN(4);
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+ . = .;
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ . = ALIGN(256);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(256);
+ __init_end = .;
+
+#ifndef CONFIG_SPL
+#ifdef CONFIG_440
+ .bootpg RESET_VECTOR_ADDRESS - 0xffc :
+ {
+ arch/powerpc/cpu/ppc4xx/start.o (.bootpg)
+
+ /*
+ * PPC440 board need a board specific object with the
+ * TLB definitions. This needs to get included right after
+ * start.o, since the first shadow TLB only covers 4k
+ * of address space.
+ */
+#ifdef CONFIG_INIT_TLB
+ CONFIG_INIT_TLB (.bootpg)
+#else
+ CONFIG_BOARDDIR/init.o (.bootpg)
+#endif
+ } :text = 0xffff
+#endif
+
+ .resetvec RESET_VECTOR_ADDRESS :
+ {
+ KEEP(*(.resetvec))
+ } :text = 0xffff
+
+ . = RESET_VECTOR_ADDRESS + 0x4;
+
+ /*
+ * Make sure that the bss segment isn't linked at 0x0, otherwise its
+ * address won't be updated during relocation fixups. Note that
+ * this is a temporary fix. Code to dynamically the fixup the bss
+ * location will be added in the future. When the bss relocation
+ * fixup code is present this workaround should be removed.
+ */
+#if (RESET_VECTOR_ADDRESS == 0xfffffffc)
+ . |= 0x10;
+#endif
+#endif /* CONFIG_SPL */
+
+ __bss_start = .;
+ .bss (NOLOAD) :
+ {
+ *(.bss*)
+ *(.sbss*)
+ *(COMMON)
+ } :bss
+
+ . = ALIGN(4);
+ __bss_end = . ;
+ PROVIDE (end = .);
+}
diff --git a/arch/powerpc/cpu/ppc4xx/uic.c b/arch/powerpc/cpu/ppc4xx/uic.c
new file mode 100644
index 0000000..324f0e9
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/uic.c
@@ -0,0 +1,180 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002 (440 port)
+ * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com
+ *
+ * (C) Copyright 2003 (440GX port)
+ * Travis B. Sawyer, Sandburst Corporation, tsawyer@sandburst.com
+ *
+ * (C) Copyright 2008 (PPC440X05 port for Virtex 5 FX)
+ * Ricardo Ribalda-Universidad Autonoma de Madrid-ricardo.ribalda@uam.es
+ * Work supported by Qtechnology (htpp://qtec.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <asm/interrupt.h>
+#include <asm/ppc4xx.h>
+#include <ppc_asm.tmpl>
+#include <commproc.h>
+
+#if (UIC_MAX > 3)
+#define UICB0_ALL (UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI) | \
+ UIC_MASK(VECNUM_UIC2CI) | UIC_MASK(VECNUM_UIC2NCI) | \
+ UIC_MASK(VECNUM_UIC3CI) | UIC_MASK(VECNUM_UIC3NCI))
+#elif (UIC_MAX > 2)
+#define UICB0_ALL (UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI) | \
+ UIC_MASK(VECNUM_UIC2CI) | UIC_MASK(VECNUM_UIC2NCI))
+#elif (UIC_MAX > 1)
+#define UICB0_ALL (UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI))
+#else
+#define UICB0_ALL 0
+#endif
+
+u32 get_dcr(u16);
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void pic_enable(void)
+{
+#if (UIC_MAX > 1)
+ /* Install the UIC1 handlers */
+ irq_install_handler(VECNUM_UIC1NCI, (void *)(void *)external_interrupt, 0);
+ irq_install_handler(VECNUM_UIC1CI, (void *)(void *)external_interrupt, 0);
+#endif
+#if (UIC_MAX > 2)
+ irq_install_handler(VECNUM_UIC2NCI, (void *)(void *)external_interrupt, 0);
+ irq_install_handler(VECNUM_UIC2CI, (void *)(void *)external_interrupt, 0);
+#endif
+#if (UIC_MAX > 3)
+ irq_install_handler(VECNUM_UIC3NCI, (void *)(void *)external_interrupt, 0);
+ irq_install_handler(VECNUM_UIC3CI, (void *)(void *)external_interrupt, 0);
+#endif
+}
+
+/* Handler for UIC interrupt */
+static void uic_interrupt(u32 uic_base, int vec_base)
+{
+ u32 uic_msr;
+ u32 msr_shift;
+ int vec;
+
+ /*
+ * Read masked interrupt status register to determine interrupt source
+ */
+ uic_msr = get_dcr(uic_base + UIC_MSR);
+ msr_shift = uic_msr;
+ vec = vec_base;
+
+ while (msr_shift != 0) {
+ if (msr_shift & 0x80000000)
+ interrupt_run_handler(vec);
+ /*
+ * Shift msr to next position and increment vector
+ */
+ msr_shift <<= 1;
+ vec++;
+ }
+}
+
+/*
+ * Handle external interrupts
+ */
+void external_interrupt(struct pt_regs *regs)
+{
+ u32 uic_msr;
+
+ /*
+ * Read masked interrupt status register to determine interrupt source
+ */
+ uic_msr = mfdcr(UIC0MSR);
+
+#if (UIC_MAX > 1)
+ if ((UIC_MASK(VECNUM_UIC1CI) & uic_msr) ||
+ (UIC_MASK(VECNUM_UIC1NCI) & uic_msr))
+ uic_interrupt(UIC1_DCR_BASE, 32);
+#endif
+
+#if (UIC_MAX > 2)
+ if ((UIC_MASK(VECNUM_UIC2CI) & uic_msr) ||
+ (UIC_MASK(VECNUM_UIC2NCI) & uic_msr))
+ uic_interrupt(UIC2_DCR_BASE, 64);
+#endif
+
+#if (UIC_MAX > 3)
+ if ((UIC_MASK(VECNUM_UIC3CI) & uic_msr) ||
+ (UIC_MASK(VECNUM_UIC3NCI) & uic_msr))
+ uic_interrupt(UIC3_DCR_BASE, 96);
+#endif
+
+ mtdcr(UIC0SR, (uic_msr & UICB0_ALL));
+
+ if (uic_msr & ~(UICB0_ALL))
+ uic_interrupt(UIC0_DCR_BASE, 0);
+
+ return;
+}
+
+void pic_irq_ack(unsigned int vec)
+{
+ if ((vec >= 0) && (vec < 32))
+ mtdcr(UIC0SR, UIC_MASK(vec));
+ else if ((vec >= 32) && (vec < 64))
+ mtdcr(UIC1SR, UIC_MASK(vec));
+ else if ((vec >= 64) && (vec < 96))
+ mtdcr(UIC2SR, UIC_MASK(vec));
+ else if (vec >= 96)
+ mtdcr(UIC3SR, UIC_MASK(vec));
+}
+
+/*
+ * Install and free a interrupt handler.
+ */
+void pic_irq_enable(unsigned int vec)
+{
+
+ if ((vec >= 0) && (vec < 32))
+ mtdcr(UIC0ER, mfdcr(UIC0ER) | UIC_MASK(vec));
+ else if ((vec >= 32) && (vec < 64))
+ mtdcr(UIC1ER, mfdcr(UIC1ER) | UIC_MASK(vec));
+ else if ((vec >= 64) && (vec < 96))
+ mtdcr(UIC2ER, mfdcr(UIC2ER) | UIC_MASK(vec));
+ else if (vec >= 96)
+ mtdcr(UIC3ER, mfdcr(UIC3ER) | UIC_MASK(vec));
+
+ debug("Install interrupt vector %d\n", vec);
+}
+
+void pic_irq_disable(unsigned int vec)
+{
+ if ((vec >= 0) && (vec < 32))
+ mtdcr(UIC0ER, mfdcr(UIC0ER) & ~UIC_MASK(vec));
+ else if ((vec >= 32) && (vec < 64))
+ mtdcr(UIC1ER, mfdcr(UIC1ER) & ~UIC_MASK(vec));
+ else if ((vec >= 64) && (vec < 96))
+ mtdcr(UIC2ER, mfdcr(UIC2ER) & ~UIC_MASK(vec));
+ else if (vec >= 96)
+ mtdcr(UIC3ER, mfdcr(UIC3ER) & ~UIC_MASK(vec));
+}
diff --git a/arch/powerpc/cpu/ppc4xx/usb.c b/arch/powerpc/cpu/ppc4xx/usb.c
new file mode 100644
index 0000000..8c71f75
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/usb.c
@@ -0,0 +1,61 @@
+/*
+ * (C) Copyright 2007
+ * Markus Klotzbuecher, DENX Software Engineering <mk@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT)
+
+#ifdef CONFIG_4xx_DCACHE
+#include <asm/mmu.h>
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+int usb_cpu_init(void)
+{
+#ifdef CONFIG_4xx_DCACHE
+ /* disable cache */
+ change_tlb(gd->bd->bi_memstart, gd->bd->bi_memsize, TLB_WORD2_I_ENABLE);
+#endif
+
+ return 0;
+}
+
+int usb_cpu_stop(void)
+{
+#ifdef CONFIG_4xx_DCACHE
+ /* enable cache */
+ change_tlb(gd->bd->bi_memstart, gd->bd->bi_memsize, 0);
+#endif
+ return 0;
+}
+
+int usb_cpu_init_fail(void)
+{
+#ifdef CONFIG_4xx_DCACHE
+ /* enable cache */
+ change_tlb(gd->bd->bi_memstart, gd->bd->bi_memsize, 0);
+#endif
+ return 0;
+}
+
+#endif /* defined(CONFIG_USB_OHCI) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT) */
diff --git a/arch/powerpc/cpu/ppc4xx/usb_ohci.c b/arch/powerpc/cpu/ppc4xx/usb_ohci.c
new file mode 100644
index 0000000..f820c37
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/usb_ohci.c
@@ -0,0 +1,1639 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB on the PPC440EP.
+ *
+ * (C) Copyright 2003-2004
+ * Gary Jennejohn, DENX Software Engineering <garyj@denx.de>
+ *
+ * (C) Copyright 2004
+ * Pierre Aubert, Staubli Faverges <p.aubert@staubli.com>
+ *
+ * Note: Much of this code has been derived from Linux 2.4
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+/*
+ * IMPORTANT NOTES
+ * 1 - this driver is intended for use with USB Mass Storage Devices
+ * (BBB) ONLY. There is NO support for Interrupt or Isochronous pipes!
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_USB_OHCI
+
+#include <malloc.h>
+#include <usb.h>
+#include "usb_ohci.h"
+
+#define OHCI_USE_NPS /* force NoPowerSwitching mode */
+#undef OHCI_VERBOSE_DEBUG /* not always helpful */
+#undef DEBUG
+#undef SHOW_INFO
+#undef OHCI_FILL_TRACE
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define OHCI_CONTROL_INIT \
+ (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
+#define readl(a) (*((volatile u32 *)(a)))
+#define writel(a, b) (*((volatile u32 *)(b)) = ((volatile u32)a))
+
+#define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+
+#ifdef DEBUG
+#define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg)
+#else
+#define dbg(format, arg...) do {} while(0)
+#endif /* DEBUG */
+#define err(format, arg...) printf("ERROR: " format "\n", ## arg)
+#ifdef SHOW_INFO
+#define info(format, arg...) printf("INFO: " format "\n", ## arg)
+#else
+#define info(format, arg...) do {} while(0)
+#endif
+
+#define m16_swap(x) swap_16(x)
+#define m32_swap(x) swap_32(x)
+
+#if defined(CONFIG_405EZ) || defined(CONFIG_440EP) || defined(CONFIG_440EPX)
+#define ohci_cpu_to_le16(x) (x)
+#define ohci_cpu_to_le32(x) (x)
+#else
+#define ohci_cpu_to_le16(x) swap_16(x)
+#define ohci_cpu_to_le32(x) swap_32(x)
+#endif
+
+/* global ohci_t */
+static ohci_t gohci;
+/* this must be aligned to a 256 byte boundary */
+struct ohci_hcca ghcca[1];
+/* a pointer to the aligned storage */
+struct ohci_hcca *phcca;
+/* this allocates EDs for all possible endpoints */
+struct ohci_device ohci_dev;
+/* urb_priv */
+urb_priv_t urb_priv;
+/* RHSC flag */
+int got_rhsc;
+/* device which was disconnected */
+struct usb_device *devgone;
+/* flag guarding URB transation */
+int urb_finished = 0;
+
+/*-------------------------------------------------------------------------*/
+
+/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
+ * The erratum (#4) description is incorrect. AMD's workaround waits
+ * till some bits (mostly reserved) are clear; ok for all revs.
+ */
+#define OHCI_QUIRK_AMD756 0xabcd
+#define read_roothub(hc, register, mask) ({ \
+ u32 temp = readl (&hc->regs->roothub.register); \
+ if (hc->flags & OHCI_QUIRK_AMD756) \
+ while (temp & mask) \
+ temp = readl (&hc->regs->roothub.register); \
+ temp; })
+
+static u32 roothub_a (struct ohci *hc)
+ { return read_roothub (hc, a, 0xfc0fe000); }
+static inline u32 roothub_b (struct ohci *hc)
+ { return readl (&hc->regs->roothub.b); }
+static inline u32 roothub_status (struct ohci *hc)
+ { return readl (&hc->regs->roothub.status); }
+static u32 roothub_portstatus (struct ohci *hc, int i)
+ { return read_roothub (hc, portstatus [i], 0xffe0fce0); }
+
+
+/* forward declaration */
+static int hc_interrupt (void);
+static void
+td_submit_job (struct usb_device * dev, unsigned long pipe, void * buffer,
+ int transfer_len, struct devrequest * setup, urb_priv_t * urb, int interval);
+
+/*-------------------------------------------------------------------------*
+ * URB support functions
+ *-------------------------------------------------------------------------*/
+
+/* free HCD-private data associated with this URB */
+
+static void urb_free_priv (urb_priv_t * urb)
+{
+ int i;
+ int last;
+ struct td * td;
+
+ last = urb->length - 1;
+ if (last >= 0) {
+ for (i = 0; i <= last; i++) {
+ td = urb->td[i];
+ if (td) {
+ td->usb_dev = NULL;
+ urb->td[i] = NULL;
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+static int sohci_get_current_frame_number (struct usb_device * dev);
+
+/* debug| print the main components of an URB
+ * small: 0) header + data packets 1) just header */
+
+static void pkt_print (struct usb_device * dev, unsigned long pipe, void * buffer,
+ int transfer_len, struct devrequest * setup, char * str, int small)
+{
+ urb_priv_t * purb = &urb_priv;
+
+ dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d/%d stat:%#lx",
+ str,
+ sohci_get_current_frame_number (dev),
+ usb_pipedevice (pipe),
+ usb_pipeendpoint (pipe),
+ usb_pipeout (pipe)? 'O': 'I',
+ usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
+ (usb_pipecontrol (pipe)? "CTRL": "BULK"),
+ purb->actual_length,
+ transfer_len, dev->status);
+#ifdef OHCI_VERBOSE_DEBUG
+ if (!small) {
+ int i, len;
+
+ if (usb_pipecontrol (pipe)) {
+ printf (__FILE__ ": cmd(8):");
+ for (i = 0; i < 8 ; i++)
+ printf (" %02x", ((__u8 *) setup) [i]);
+ printf ("\n");
+ }
+ if (transfer_len > 0 && buffer) {
+ printf (__FILE__ ": data(%d/%d):",
+ purb->actual_length,
+ transfer_len);
+ len = usb_pipeout (pipe)?
+ transfer_len: purb->actual_length;
+ for (i = 0; i < 16 && i < len; i++)
+ printf (" %02x", ((__u8 *) buffer) [i]);
+ printf ("%s\n", i < len? "...": "");
+ }
+ }
+#endif
+}
+
+/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
+void ep_print_int_eds (ohci_t *ohci, char * str) {
+ int i, j;
+ __u32 * ed_p;
+ for (i= 0; i < 32; i++) {
+ j = 5;
+ ed_p = &(ohci->hcca->int_table [i]);
+ if (*ed_p == 0)
+ continue;
+ printf (__FILE__ ": %s branch int %2d(%2x):", str, i, i);
+ while (*ed_p != 0 && j--) {
+ ed_t *ed = (ed_t *)ohci_cpu_to_le32(ed_p);
+ printf (" ed: %4x;", ed->hwINFO);
+ ed_p = &ed->hwNextED;
+ }
+ printf ("\n");
+ }
+}
+
+static void ohci_dump_intr_mask (char *label, __u32 mask)
+{
+ dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+ label,
+ mask,
+ (mask & OHCI_INTR_MIE) ? " MIE" : "",
+ (mask & OHCI_INTR_OC) ? " OC" : "",
+ (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+ (mask & OHCI_INTR_FNO) ? " FNO" : "",
+ (mask & OHCI_INTR_UE) ? " UE" : "",
+ (mask & OHCI_INTR_RD) ? " RD" : "",
+ (mask & OHCI_INTR_SF) ? " SF" : "",
+ (mask & OHCI_INTR_WDH) ? " WDH" : "",
+ (mask & OHCI_INTR_SO) ? " SO" : ""
+ );
+}
+
+static void maybe_print_eds (char *label, __u32 value)
+{
+ ed_t *edp = (ed_t *)value;
+
+ if (value) {
+ dbg ("%s %08x", label, value);
+ dbg ("%08x", edp->hwINFO);
+ dbg ("%08x", edp->hwTailP);
+ dbg ("%08x", edp->hwHeadP);
+ dbg ("%08x", edp->hwNextED);
+ }
+}
+
+static char * hcfs2string (int state)
+{
+ switch (state) {
+ case OHCI_USB_RESET: return "reset";
+ case OHCI_USB_RESUME: return "resume";
+ case OHCI_USB_OPER: return "operational";
+ case OHCI_USB_SUSPEND: return "suspend";
+ }
+ return "?";
+}
+
+/* dump control and status registers */
+static void ohci_dump_status (ohci_t *controller)
+{
+ struct ohci_regs *regs = controller->regs;
+ __u32 temp;
+
+ temp = readl (&regs->revision) & 0xff;
+ if (temp != 0x10)
+ dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+ temp = readl (&regs->control);
+ dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+ (temp & OHCI_CTRL_RWE) ? " RWE" : "",
+ (temp & OHCI_CTRL_RWC) ? " RWC" : "",
+ (temp & OHCI_CTRL_IR) ? " IR" : "",
+ hcfs2string (temp & OHCI_CTRL_HCFS),
+ (temp & OHCI_CTRL_BLE) ? " BLE" : "",
+ (temp & OHCI_CTRL_CLE) ? " CLE" : "",
+ (temp & OHCI_CTRL_IE) ? " IE" : "",
+ (temp & OHCI_CTRL_PLE) ? " PLE" : "",
+ temp & OHCI_CTRL_CBSR
+ );
+
+ temp = readl (&regs->cmdstatus);
+ dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+ (temp & OHCI_SOC) >> 16,
+ (temp & OHCI_OCR) ? " OCR" : "",
+ (temp & OHCI_BLF) ? " BLF" : "",
+ (temp & OHCI_CLF) ? " CLF" : "",
+ (temp & OHCI_HCR) ? " HCR" : ""
+ );
+
+ ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
+ ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
+
+ maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
+
+ maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
+ maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
+
+ maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
+ maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+
+ maybe_print_eds ("donehead", readl (&regs->donehead));
+}
+
+static void ohci_dump_roothub (ohci_t *controller, int verbose)
+{
+ __u32 temp, ndp, i;
+
+ temp = roothub_a (controller);
+ ndp = (temp & RH_A_NDP);
+
+ if (verbose) {
+ dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+ ((temp & RH_A_POTPGT) >> 24) & 0xff,
+ (temp & RH_A_NOCP) ? " NOCP" : "",
+ (temp & RH_A_OCPM) ? " OCPM" : "",
+ (temp & RH_A_DT) ? " DT" : "",
+ (temp & RH_A_NPS) ? " NPS" : "",
+ (temp & RH_A_PSM) ? " PSM" : "",
+ ndp
+ );
+ temp = roothub_b (controller);
+ dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+ temp,
+ (temp & RH_B_PPCM) >> 16,
+ (temp & RH_B_DR)
+ );
+ temp = roothub_status (controller);
+ dbg ("roothub.status: %08x%s%s%s%s%s%s",
+ temp,
+ (temp & RH_HS_CRWE) ? " CRWE" : "",
+ (temp & RH_HS_OCIC) ? " OCIC" : "",
+ (temp & RH_HS_LPSC) ? " LPSC" : "",
+ (temp & RH_HS_DRWE) ? " DRWE" : "",
+ (temp & RH_HS_OCI) ? " OCI" : "",
+ (temp & RH_HS_LPS) ? " LPS" : ""
+ );
+ }
+
+ for (i = 0; i < ndp; i++) {
+ temp = roothub_portstatus (controller, i);
+ dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+ i,
+ temp,
+ (temp & RH_PS_PRSC) ? " PRSC" : "",
+ (temp & RH_PS_OCIC) ? " OCIC" : "",
+ (temp & RH_PS_PSSC) ? " PSSC" : "",
+ (temp & RH_PS_PESC) ? " PESC" : "",
+ (temp & RH_PS_CSC) ? " CSC" : "",
+
+ (temp & RH_PS_LSDA) ? " LSDA" : "",
+ (temp & RH_PS_PPS) ? " PPS" : "",
+ (temp & RH_PS_PRS) ? " PRS" : "",
+ (temp & RH_PS_POCI) ? " POCI" : "",
+ (temp & RH_PS_PSS) ? " PSS" : "",
+
+ (temp & RH_PS_PES) ? " PES" : "",
+ (temp & RH_PS_CCS) ? " CCS" : ""
+ );
+ }
+}
+
+static void ohci_dump (ohci_t *controller, int verbose)
+{
+ dbg ("OHCI controller usb-%s state", controller->slot_name);
+
+ /* dumps some of the state we know about */
+ ohci_dump_status (controller);
+ if (verbose)
+ ep_print_int_eds (controller, "hcca");
+ dbg ("hcca frame #%04x", controller->hcca->frame_no);
+ ohci_dump_roothub (controller, 1);
+}
+
+
+#endif /* DEBUG */
+
+/*-------------------------------------------------------------------------*
+ * Interface functions (URB)
+ *-------------------------------------------------------------------------*/
+
+/* get a transfer request */
+
+int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup, int interval)
+{
+ ohci_t *ohci;
+ ed_t * ed;
+ urb_priv_t *purb_priv;
+ int i, size = 0;
+
+ ohci = &gohci;
+
+ /* when controller's hung, permit only roothub cleanup attempts
+ * such as powering down ports */
+ if (ohci->disabled) {
+ err("sohci_submit_job: EPIPE");
+ return -1;
+ }
+
+ /* if we have an unfinished URB from previous transaction let's
+ * fail and scream as quickly as possible so as not to corrupt
+ * further communication */
+ if (!urb_finished) {
+ err("sohci_submit_job: URB NOT FINISHED");
+ return -1;
+ }
+ /* we're about to begin a new transaction here so mark the URB unfinished */
+ urb_finished = 0;
+
+ /* every endpoint has a ed, locate and fill it */
+ if (!(ed = ep_add_ed (dev, pipe))) {
+ err("sohci_submit_job: ENOMEM");
+ return -1;
+ }
+
+ /* for the private part of the URB we need the number of TDs (size) */
+ switch (usb_pipetype (pipe)) {
+ case PIPE_BULK: /* one TD for every 4096 Byte */
+ size = (transfer_len - 1) / 4096 + 1;
+ break;
+ case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
+ size = (transfer_len == 0)? 2:
+ (transfer_len - 1) / 4096 + 3;
+ break;
+ }
+
+ if (size >= (N_URB_TD - 1)) {
+ err("need %d TDs, only have %d", size, N_URB_TD);
+ return -1;
+ }
+ purb_priv = &urb_priv;
+ purb_priv->pipe = pipe;
+
+ /* fill the private part of the URB */
+ purb_priv->length = size;
+ purb_priv->ed = ed;
+ purb_priv->actual_length = 0;
+
+ /* allocate the TDs */
+ /* note that td[0] was allocated in ep_add_ed */
+ for (i = 0; i < size; i++) {
+ purb_priv->td[i] = td_alloc (dev);
+ if (!purb_priv->td[i]) {
+ purb_priv->length = i;
+ urb_free_priv (purb_priv);
+ err("sohci_submit_job: ENOMEM");
+ return -1;
+ }
+ }
+
+ if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
+ urb_free_priv (purb_priv);
+ err("sohci_submit_job: EINVAL");
+ return -1;
+ }
+
+ /* link the ed into a chain if is not already */
+ if (ed->state != ED_OPER)
+ ep_link (ohci, ed);
+
+ /* fill the TDs and link it to the ed */
+ td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv, interval);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+/* tell us the current USB frame number */
+
+static int sohci_get_current_frame_number (struct usb_device *usb_dev)
+{
+ ohci_t *ohci = &gohci;
+
+ return ohci_cpu_to_le16 (ohci->hcca->frame_no);
+}
+#endif
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/
+
+/* link an ed into one of the HC chains */
+
+static int ep_link (ohci_t *ohci, ed_t *edi)
+{
+ volatile ed_t *ed = edi;
+
+ ed->state = ED_OPER;
+
+ switch (ed->type) {
+ case PIPE_CONTROL:
+ ed->hwNextED = 0;
+ if (ohci->ed_controltail == NULL) {
+ writel (ed, &ohci->regs->ed_controlhead);
+ } else {
+ ohci->ed_controltail->hwNextED = ohci_cpu_to_le32 ((unsigned long)ed);
+ }
+ ed->ed_prev = ohci->ed_controltail;
+ if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
+ !ohci->ed_rm_list[1] && !ohci->sleeping) {
+ ohci->hc_control |= OHCI_CTRL_CLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ ohci->ed_controltail = edi;
+ break;
+
+ case PIPE_BULK:
+ ed->hwNextED = 0;
+ if (ohci->ed_bulktail == NULL) {
+ writel (ed, &ohci->regs->ed_bulkhead);
+ } else {
+ ohci->ed_bulktail->hwNextED = ohci_cpu_to_le32 ((unsigned long)ed);
+ }
+ ed->ed_prev = ohci->ed_bulktail;
+ if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
+ !ohci->ed_rm_list[1] && !ohci->sleeping) {
+ ohci->hc_control |= OHCI_CTRL_BLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ ohci->ed_bulktail = edi;
+ break;
+ }
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* unlink an ed from one of the HC chains.
+ * just the link to the ed is unlinked.
+ * the link from the ed still points to another operational ed or 0
+ * so the HC can eventually finish the processing of the unlinked ed */
+
+static int ep_unlink (ohci_t *ohci, ed_t *edi)
+{
+ volatile ed_t *ed = edi;
+
+ ed->hwINFO |= ohci_cpu_to_le32 (OHCI_ED_SKIP);
+
+ switch (ed->type) {
+ case PIPE_CONTROL:
+ if (ed->ed_prev == NULL) {
+ if (!ed->hwNextED) {
+ ohci->hc_control &= ~OHCI_CTRL_CLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ writel (ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_controlhead);
+ } else {
+ ed->ed_prev->hwNextED = ed->hwNextED;
+ }
+ if (ohci->ed_controltail == ed) {
+ ohci->ed_controltail = ed->ed_prev;
+ } else {
+ ((ed_t *)ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+ }
+ break;
+
+ case PIPE_BULK:
+ if (ed->ed_prev == NULL) {
+ if (!ed->hwNextED) {
+ ohci->hc_control &= ~OHCI_CTRL_BLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ writel (ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_bulkhead);
+ } else {
+ ed->ed_prev->hwNextED = ed->hwNextED;
+ }
+ if (ohci->ed_bulktail == ed) {
+ ohci->ed_bulktail = ed->ed_prev;
+ } else {
+ ((ed_t *)ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+ }
+ break;
+ }
+ ed->state = ED_UNLINK;
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
+ * but the USB stack is a little bit stateless so we do it at every transaction
+ * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK
+ * in all other cases the state is left unchanged
+ * the ed info fields are setted anyway even though most of them should not change */
+
+static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe)
+{
+ td_t *td;
+ ed_t *ed_ret;
+ volatile ed_t *ed;
+
+ ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) |
+ (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))];
+
+ if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
+ err("ep_add_ed: pending delete");
+ /* pending delete request */
+ return NULL;
+ }
+
+ if (ed->state == ED_NEW) {
+ ed->hwINFO = ohci_cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */
+ /* dummy td; end of td list for ed */
+ td = td_alloc (usb_dev);
+ ed->hwTailP = ohci_cpu_to_le32 ((unsigned long)td);
+ ed->hwHeadP = ed->hwTailP;
+ ed->state = ED_UNLINK;
+ ed->type = usb_pipetype (pipe);
+ ohci_dev.ed_cnt++;
+ }
+
+ ed->hwINFO = ohci_cpu_to_le32 (usb_pipedevice (pipe)
+ | usb_pipeendpoint (pipe) << 7
+ | (usb_pipeisoc (pipe)? 0x8000: 0)
+ | (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
+ | (usb_dev->speed == USB_SPEED_LOW) << 13
+ | usb_maxpacket (usb_dev, pipe) << 16);
+
+ return ed_ret;
+}
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
+
+static void td_fill (ohci_t *ohci, unsigned int info,
+ void *data, int len,
+ struct usb_device *dev, int index, urb_priv_t *urb_priv)
+{
+ volatile td_t *td, *td_pt;
+#ifdef OHCI_FILL_TRACE
+ int i;
+#endif
+
+ if (index > urb_priv->length) {
+ err("index > length");
+ return;
+ }
+ /* use this td as the next dummy */
+ td_pt = urb_priv->td [index];
+ td_pt->hwNextTD = 0;
+
+ /* fill the old dummy TD */
+ td = urb_priv->td [index] = (td_t *)(ohci_cpu_to_le32 (urb_priv->ed->hwTailP) & ~0xf);
+
+ td->ed = urb_priv->ed;
+ td->next_dl_td = NULL;
+ td->index = index;
+ td->data = (__u32)data;
+#ifdef OHCI_FILL_TRACE
+ if (usb_pipebulk(urb_priv->pipe) && usb_pipeout(urb_priv->pipe)) {
+ for (i = 0; i < len; i++)
+ printf("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]);
+ printf("\n");
+ }
+#endif
+ if (!len)
+ data = 0;
+
+ td->hwINFO = ohci_cpu_to_le32 (info);
+ td->hwCBP = ohci_cpu_to_le32 ((unsigned long)data);
+ if (data)
+ td->hwBE = ohci_cpu_to_le32 ((unsigned long)(data + len - 1));
+ else
+ td->hwBE = 0;
+ td->hwNextTD = ohci_cpu_to_le32 ((unsigned long)td_pt);
+
+ /* append to queue */
+ td->ed->hwTailP = td->hwNextTD;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* prepare all TDs of a transfer */
+static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval)
+{
+ ohci_t *ohci = &gohci;
+ int data_len = transfer_len;
+ void *data;
+ int cnt = 0;
+ __u32 info = 0;
+ unsigned int toggle = 0;
+
+ /* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
+ if(usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
+ toggle = TD_T_TOGGLE;
+ } else {
+ toggle = TD_T_DATA0;
+ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1);
+ }
+ urb->td_cnt = 0;
+ if (data_len)
+ data = buffer;
+ else
+ data = 0;
+
+ switch (usb_pipetype (pipe)) {
+ case PIPE_BULK:
+ info = usb_pipeout (pipe)?
+ TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
+ while(data_len > 4096) {
+ td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, dev, cnt, urb);
+ data += 4096; data_len -= 4096; cnt++;
+ }
+ info = usb_pipeout (pipe)?
+ TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+ td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, dev, cnt, urb);
+ cnt++;
+
+ if (!ohci->sleeping)
+ writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+ break;
+
+ case PIPE_CONTROL:
+ info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+ td_fill (ohci, info, setup, 8, dev, cnt++, urb);
+ if (data_len > 0) {
+ info = usb_pipeout (pipe)?
+ TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
+ /* NOTE: mishandles transfers >8K, some >4K */
+ td_fill (ohci, info, data, data_len, dev, cnt++, urb);
+ }
+ info = usb_pipeout (pipe)?
+ TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
+ td_fill (ohci, info, data, 0, dev, cnt++, urb);
+ if (!ohci->sleeping)
+ writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+ break;
+ }
+ if (urb->length != cnt)
+ dbg("TD LENGTH %d != CNT %d", urb->length, cnt);
+}
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+
+
+/* calculate the transfer length and update the urb */
+
+static void dl_transfer_length(td_t * td)
+{
+ __u32 tdBE, tdCBP;
+ urb_priv_t *lurb_priv = &urb_priv;
+
+ tdBE = ohci_cpu_to_le32 (td->hwBE);
+ tdCBP = ohci_cpu_to_le32 (td->hwCBP);
+
+
+ if (!(usb_pipecontrol(lurb_priv->pipe) &&
+ ((td->index == 0) || (td->index == lurb_priv->length - 1)))) {
+ if (tdBE != 0) {
+ if (td->hwCBP == 0)
+ lurb_priv->actual_length += tdBE - td->data + 1;
+ else
+ lurb_priv->actual_length += tdCBP - td->data;
+ }
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+
+static td_t * dl_reverse_done_list (ohci_t *ohci)
+{
+ __u32 td_list_hc;
+ td_t *td_rev = NULL;
+ td_t *td_list = NULL;
+ urb_priv_t *lurb_priv = NULL;
+
+ td_list_hc = ohci_cpu_to_le32 (ohci->hcca->done_head) & 0xfffffff0;
+ ohci->hcca->done_head = 0;
+
+ while (td_list_hc) {
+ td_list = (td_t *)td_list_hc;
+
+ if (TD_CC_GET (ohci_cpu_to_le32 (td_list->hwINFO))) {
+ lurb_priv = &urb_priv;
+ dbg(" USB-error/status: %x : %p",
+ TD_CC_GET (ohci_cpu_to_le32 (td_list->hwINFO)), td_list);
+ if (td_list->ed->hwHeadP & ohci_cpu_to_le32 (0x1)) {
+ if (lurb_priv && ((td_list->index + 1) < lurb_priv->length)) {
+ td_list->ed->hwHeadP =
+ (lurb_priv->td[lurb_priv->length - 1]->hwNextTD & ohci_cpu_to_le32 (0xfffffff0)) |
+ (td_list->ed->hwHeadP & ohci_cpu_to_le32 (0x2));
+ lurb_priv->td_cnt += lurb_priv->length - td_list->index - 1;
+ } else
+ td_list->ed->hwHeadP &= ohci_cpu_to_le32 (0xfffffff2);
+ }
+#ifdef CONFIG_MPC5200
+ td_list->hwNextTD = 0;
+#endif
+ }
+
+ td_list->next_dl_td = td_rev;
+ td_rev = td_list;
+ td_list_hc = ohci_cpu_to_le32 (td_list->hwNextTD) & 0xfffffff0;
+ }
+ return td_list;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* td done list */
+static int dl_done_list (ohci_t *ohci, td_t *td_list)
+{
+ td_t *td_list_next = NULL;
+ ed_t *ed;
+ int cc = 0;
+ int stat = 0;
+ /* urb_t *urb; */
+ urb_priv_t *lurb_priv;
+ __u32 tdINFO, edHeadP, edTailP;
+
+ while (td_list) {
+ td_list_next = td_list->next_dl_td;
+
+ lurb_priv = &urb_priv;
+ tdINFO = ohci_cpu_to_le32 (td_list->hwINFO);
+
+ ed = td_list->ed;
+
+ dl_transfer_length(td_list);
+
+ /* error code of transfer */
+ cc = TD_CC_GET (tdINFO);
+ if (++(lurb_priv->td_cnt) == lurb_priv->length) {
+ if ((ed->state & (ED_OPER | ED_UNLINK))
+ && (lurb_priv->state != URB_DEL)) {
+ dbg("ConditionCode %#x", cc);
+ stat = cc_to_error[cc];
+ urb_finished = 1;
+ }
+ }
+
+ if (ed->state != ED_NEW) {
+ edHeadP = ohci_cpu_to_le32 (ed->hwHeadP) & 0xfffffff0;
+ edTailP = ohci_cpu_to_le32 (ed->hwTailP);
+
+ /* unlink eds if they are not busy */
+ if ((edHeadP == edTailP) && (ed->state == ED_OPER))
+ ep_unlink (ohci, ed);
+ }
+
+ td_list = td_list_next;
+ }
+ return stat;
+}
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub
+ *-------------------------------------------------------------------------*/
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] =
+{
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __u8 bDescriptorType; Device */
+ 0x10, /* __u16 bcdUSB; v1.1 */
+ 0x01,
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; */
+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
+ 0x00, /* __u16 idVendor; */
+ 0x00,
+ 0x00, /* __u16 idProduct; */
+ 0x00,
+ 0x00, /* __u16 bcdDevice; */
+ 0x00,
+ 0x00, /* __u8 iManufacturer; */
+ 0x01, /* __u8 iProduct; */
+ 0x00, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, /* __u16 wTotalLength; */
+ 0x00,
+ 0x01, /* __u8 bNumInterfaces; */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes;
+ Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* endpoint */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+ 0x00,
+ 0xff /* __u8 ep_bInterval; 255 ms */
+};
+
+static unsigned char root_hub_str_index0[] =
+{
+ 0x04, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 0x09, /* __u8 lang ID */
+ 0x04, /* __u8 lang ID */
+};
+
+static unsigned char root_hub_str_index1[] =
+{
+ 28, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 'O', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'C', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'I', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'R', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 't', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'u', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'b', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+};
+
+/* Hub class-specific descriptor is constructed dynamically */
+
+
+/*-------------------------------------------------------------------------*/
+
+#define OK(x) len = (x); break
+#ifdef DEBUG
+#define WR_RH_STAT(x) {info("WR:status %#8x", (x));writel((x), &gohci.regs->roothub.status);}
+#define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, (x));writel((x), &gohci.regs->roothub.portstatus[wIndex-1]);}
+#else
+#define WR_RH_STAT(x) writel((x), &gohci.regs->roothub.status)
+#define WR_RH_PORTSTAT(x) writel((x), &gohci.regs->roothub.portstatus[wIndex-1])
+#endif
+#define RD_RH_STAT roothub_status(&gohci)
+#define RD_RH_PORTSTAT roothub_portstatus(&gohci,wIndex-1)
+
+/* request to virtual root hub */
+
+int rh_check_port_status(ohci_t *controller)
+{
+ __u32 temp, ndp, i;
+ int res;
+
+ res = -1;
+ temp = roothub_a (controller);
+ ndp = (temp & RH_A_NDP);
+ for (i = 0; i < ndp; i++) {
+ temp = roothub_portstatus (controller, i);
+ /* check for a device disconnect */
+ if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
+ (RH_PS_PESC | RH_PS_CSC)) &&
+ ((temp & RH_PS_CCS) == 0)) {
+ res = i;
+ break;
+ }
+ }
+ return res;
+}
+
+static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len, struct devrequest *cmd)
+{
+ void * data = buffer;
+ int leni = transfer_len;
+ int len = 0;
+ int stat = 0;
+ __u32 datab[4];
+ __u8 *data_buf = (__u8 *)datab;
+ __u16 bmRType_bReq;
+ __u16 wValue;
+ __u16 wIndex;
+ __u16 wLength;
+
+#ifdef DEBUG
+urb_priv.actual_length = 0;
+pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));
+#endif
+ if (usb_pipeint(pipe)) {
+ info("Root-Hub submit IRQ: NOT implemented");
+ return 0;
+ }
+
+ bmRType_bReq = cmd->requesttype | (cmd->request << 8);
+ wValue = m16_swap (cmd->value);
+ wIndex = m16_swap (cmd->index);
+ wLength = m16_swap (cmd->length);
+
+ info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x",
+ dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
+
+ switch (bmRType_bReq) {
+ /* Request Destination:
+ without flags: Device,
+ RH_INTERFACE: interface,
+ RH_ENDPOINT: endpoint,
+ RH_CLASS means HUB here,
+ RH_OTHER | RH_CLASS almost ever means HUB_PORT here
+ */
+
+ case RH_GET_STATUS:
+ *(__u16 *) data_buf = m16_swap (1); OK (2);
+ case RH_GET_STATUS | RH_INTERFACE:
+ *(__u16 *) data_buf = m16_swap (0); OK (2);
+ case RH_GET_STATUS | RH_ENDPOINT:
+ *(__u16 *) data_buf = m16_swap (0); OK (2);
+ case RH_GET_STATUS | RH_CLASS:
+ *(__u32 *) data_buf = m32_swap (
+ RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
+ OK (4);
+ case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+ *(__u32 *) data_buf = m32_swap (RD_RH_PORTSTAT); OK (4);
+
+ case RH_CLEAR_FEATURE | RH_ENDPOINT:
+ switch (wValue) {
+ case (RH_ENDPOINT_STALL): OK (0);
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_CLASS:
+ switch (wValue) {
+ case RH_C_HUB_LOCAL_POWER:
+ OK(0);
+ case (RH_C_HUB_OVER_CURRENT):
+ WR_RH_STAT(RH_HS_OCIC); OK (0);
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case (RH_PORT_ENABLE):
+ WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
+ case (RH_PORT_SUSPEND):
+ WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
+ case (RH_PORT_POWER):
+ WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
+ case (RH_C_PORT_CONNECTION):
+ WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
+ case (RH_C_PORT_ENABLE):
+ WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
+ case (RH_C_PORT_SUSPEND):
+ WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
+ case (RH_C_PORT_OVER_CURRENT):
+ WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
+ case (RH_C_PORT_RESET):
+ WR_RH_PORTSTAT (RH_PS_PRSC); OK (0);
+ }
+ break;
+
+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case (RH_PORT_SUSPEND):
+ WR_RH_PORTSTAT (RH_PS_PSS ); OK (0);
+ case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT (RH_PS_PRS);
+ OK (0);
+ case (RH_PORT_POWER):
+ WR_RH_PORTSTAT (RH_PS_PPS ); OK (0);
+ case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT (RH_PS_PES );
+ OK (0);
+ }
+ break;
+
+ case RH_SET_ADDRESS: gohci.rh.devnum = wValue; OK(0);
+
+ case RH_GET_DESCRIPTOR:
+ switch ((wValue & 0xff00) >> 8) {
+ case (0x01): /* device descriptor */
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof (root_hub_dev_des),
+ wLength));
+ data_buf = root_hub_dev_des; OK(len);
+ case (0x02): /* configuration descriptor */
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof (root_hub_config_des),
+ wLength));
+ data_buf = root_hub_config_des; OK(len);
+ case (0x03): /* string descriptors */
+ if(wValue==0x0300) {
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof (root_hub_str_index0),
+ wLength));
+ data_buf = root_hub_str_index0;
+ OK(len);
+ }
+ if(wValue==0x0301) {
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof (root_hub_str_index1),
+ wLength));
+ data_buf = root_hub_str_index1;
+ OK(len);
+ }
+ default:
+ stat = USB_ST_STALLED;
+ }
+ break;
+
+ case RH_GET_DESCRIPTOR | RH_CLASS:
+ {
+ __u32 temp = roothub_a (&gohci);
+
+ data_buf [0] = 9; /* min length; */
+ data_buf [1] = 0x29;
+ data_buf [2] = temp & RH_A_NDP;
+ data_buf [3] = 0;
+ if (temp & RH_A_PSM) /* per-port power switching? */
+ data_buf [3] |= 0x1;
+ if (temp & RH_A_NOCP) /* no overcurrent reporting? */
+ data_buf [3] |= 0x10;
+ else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */
+ data_buf [3] |= 0x8;
+
+ /* corresponds to data_buf[4-7] */
+ datab [1] = 0;
+ data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+ temp = roothub_b (&gohci);
+ data_buf [7] = temp & RH_B_DR;
+ if (data_buf [2] < 7) {
+ data_buf [8] = 0xff;
+ } else {
+ data_buf [0] += 2;
+ data_buf [8] = (temp & RH_B_DR) >> 8;
+ data_buf [10] = data_buf [9] = 0xff;
+ }
+
+ len = min_t(unsigned int, leni,
+ min_t(unsigned int, data_buf [0], wLength));
+ OK (len);
+ }
+
+ case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1);
+
+ case RH_SET_CONFIGURATION: WR_RH_STAT (0x10000); OK (0);
+
+ default:
+ dbg ("unsupported root hub command");
+ stat = USB_ST_STALLED;
+ }
+
+#ifdef DEBUG
+ ohci_dump_roothub (&gohci, 1);
+#endif
+
+ len = min_t(int, len, leni);
+ if (data != data_buf)
+ memcpy (data, data_buf, len);
+ dev->act_len = len;
+ dev->status = stat;
+
+#ifdef DEBUG
+ if (transfer_len)
+ urb_priv.actual_length = transfer_len;
+ pkt_print(dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
+#endif
+
+ return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* common code for handling submit messages - used for all but root hub */
+/* accesses. */
+int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup, int interval)
+{
+ int stat = 0;
+ int maxsize = usb_maxpacket(dev, pipe);
+ int timeout;
+
+ /* device pulled? Shortcut the action. */
+ if (devgone == dev) {
+ dev->status = USB_ST_CRC_ERR;
+ return 0;
+ }
+
+#ifdef DEBUG
+ urb_priv.actual_length = 0;
+ pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+#endif
+ if (!maxsize) {
+ err("submit_common_message: pipesize for pipe %lx is zero",
+ pipe);
+ return -1;
+ }
+
+ if (sohci_submit_job(dev, pipe, buffer, transfer_len, setup, interval) < 0) {
+ err("sohci_submit_job failed");
+ return -1;
+ }
+
+ /* allow more time for a BULK device to react - some are slow */
+#define BULK_TO 5000 /* timeout in milliseconds */
+ if (usb_pipebulk(pipe))
+ timeout = BULK_TO;
+ else
+ timeout = 100;
+
+ /* wait for it to complete */
+ for (;;) {
+ /* check whether the controller is done */
+ stat = hc_interrupt();
+ if (stat < 0) {
+ stat = USB_ST_CRC_ERR;
+ break;
+ }
+
+ /* NOTE: since we are not interrupt driven in U-Boot and always
+ * handle only one URB at a time, we cannot assume the
+ * transaction finished on the first successful return from
+ * hc_interrupt().. unless the flag for current URB is set,
+ * meaning that all TD's to/from device got actually
+ * transferred and processed. If the current URB is not
+ * finished we need to re-iterate this loop so as
+ * hc_interrupt() gets called again as there needs to be some
+ * more TD's to process still */
+ if ((stat >= 0) && (stat != 0xff) && (urb_finished)) {
+ /* 0xff is returned for an SF-interrupt */
+ break;
+ }
+
+ if (--timeout) {
+ mdelay(1);
+ if (!urb_finished)
+ dbg("\%");
+
+ } else {
+ err("CTL:TIMEOUT ");
+ dbg("submit_common_msg: TO status %x\n", stat);
+ stat = USB_ST_CRC_ERR;
+ urb_finished = 1;
+ break;
+ }
+ }
+#if 0
+ /* we got an Root Hub Status Change interrupt */
+ if (got_rhsc) {
+#ifdef DEBUG
+ ohci_dump_roothub (&gohci, 1);
+#endif
+ got_rhsc = 0;
+ /* abuse timeout */
+ timeout = rh_check_port_status(&gohci);
+ if (timeout >= 0) {
+#if 0 /* this does nothing useful, but leave it here in case that changes */
+ /* the called routine adds 1 to the passed value */
+ usb_hub_port_connect_change(gohci.rh.dev, timeout - 1);
+#endif
+ /*
+ * XXX
+ * This is potentially dangerous because it assumes
+ * that only one device is ever plugged in!
+ */
+ devgone = dev;
+ }
+ }
+#endif
+
+ dev->status = stat;
+ dev->act_len = transfer_len;
+
+#ifdef DEBUG
+ pkt_print(dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe));
+#endif
+
+ /* free TDs in urb_priv */
+ urb_free_priv (&urb_priv);
+ return 0;
+}
+
+/* submit routines called from usb.c */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len)
+{
+ info("submit_bulk_msg");
+ return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0);
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup)
+{
+ int maxsize = usb_maxpacket(dev, pipe);
+
+ info("submit_control_msg");
+#ifdef DEBUG
+ urb_priv.actual_length = 0;
+ pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+#endif
+ if (!maxsize) {
+ err("submit_control_message: pipesize for pipe %lx is zero",
+ pipe);
+ return -1;
+ }
+ if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) {
+ gohci.rh.dev = dev;
+ /* root hub - redirect */
+ return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len,
+ setup);
+ }
+
+ return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, int interval)
+{
+ info("submit_int_msg");
+ return -1;
+}
+
+/*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+
+/* reset the HC and BUS */
+
+static int hc_reset (ohci_t *ohci)
+{
+ int timeout = 30;
+ int smm_timeout = 50; /* 0,5 sec */
+
+ if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
+ writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
+ info("USB HC TakeOver from SMM");
+ while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
+ mdelay (10);
+ if (--smm_timeout == 0) {
+ err("USB HC TakeOver failed!");
+ return -1;
+ }
+ }
+ }
+
+ /* Disable HC interrupts */
+ writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
+ dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;",
+ ohci->slot_name,
+ readl (&ohci->regs->control));
+
+ /* Reset USB (needed by some controllers) */
+ ohci->hc_control = 0;
+ writel (ohci->hc_control, &ohci->regs->control);
+
+ /* HC Reset requires max 10 us delay */
+ writel (OHCI_HCR, &ohci->regs->cmdstatus);
+ while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+ if (--timeout == 0) {
+ err("USB HC reset timed out!");
+ return -1;
+ }
+ udelay (1);
+ }
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Start an OHCI controller, set the BUS operational
+ * enable interrupts
+ * connect the virtual root hub */
+
+static int hc_start (ohci_t * ohci)
+{
+ __u32 mask;
+ unsigned int fminterval;
+
+ ohci->disabled = 1;
+
+ /* Tell the controller where the control and bulk lists are
+ * The lists are empty now. */
+
+ writel (0, &ohci->regs->ed_controlhead);
+ writel (0, &ohci->regs->ed_bulkhead);
+
+ writel ((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */
+
+ fminterval = 0x2edf;
+ writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
+ fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
+ writel (fminterval, &ohci->regs->fminterval);
+ writel (0x628, &ohci->regs->lsthresh);
+
+ /* start controller operations */
+ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ ohci->disabled = 0;
+ writel (ohci->hc_control, &ohci->regs->control);
+
+ /* disable all interrupts */
+ mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD |
+ OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC |
+ OHCI_INTR_OC | OHCI_INTR_MIE);
+ writel (mask, &ohci->regs->intrdisable);
+ /* clear all interrupts */
+ mask &= ~OHCI_INTR_MIE;
+ writel (mask, &ohci->regs->intrstatus);
+ /* Choose the interrupts we care about now - but w/o MIE */
+ mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
+ writel (mask, &ohci->regs->intrenable);
+
+#ifdef OHCI_USE_NPS
+ /* required for AMD-756 and some Mac platforms */
+ writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
+ &ohci->regs->roothub.a);
+ writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+#endif /* OHCI_USE_NPS */
+
+ /* POTPGT delay is bits 24-31, in 2 ms units. */
+ mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
+
+ /* connect the virtual root hub */
+ ohci->rh.devnum = 0;
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* an interrupt happens */
+
+static int
+hc_interrupt (void)
+{
+ ohci_t *ohci = &gohci;
+ struct ohci_regs *regs = ohci->regs;
+ int ints;
+ int stat = -1;
+
+ if ((ohci->hcca->done_head != 0) &&
+ !(ohci_cpu_to_le32(ohci->hcca->done_head) & 0x01)) {
+
+ ints = OHCI_INTR_WDH;
+
+ } else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+ ohci->disabled++;
+ err ("%s device removed!", ohci->slot_name);
+ return -1;
+
+ } else if ((ints &= readl (&regs->intrenable)) == 0) {
+ dbg("hc_interrupt: returning..\n");
+ return 0xff;
+ }
+
+ /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */
+
+ if (ints & OHCI_INTR_RHSC) {
+ got_rhsc = 1;
+ stat = 0xff;
+ }
+
+ if (ints & OHCI_INTR_UE) {
+ ohci->disabled++;
+ err ("OHCI Unrecoverable Error, controller usb-%s disabled",
+ ohci->slot_name);
+ /* e.g. due to PCI Master/Target Abort */
+
+#ifdef DEBUG
+ ohci_dump (ohci, 1);
+#endif
+ /* FIXME: be optimistic, hope that bug won't repeat often. */
+ /* Make some non-interrupt context restart the controller. */
+ /* Count and limit the retries though; either hardware or */
+ /* software errors can go forever... */
+ hc_reset (ohci);
+ return -1;
+ }
+
+ if (ints & OHCI_INTR_WDH) {
+ writel (OHCI_INTR_WDH, &regs->intrdisable);
+ stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci));
+ writel (OHCI_INTR_WDH, &regs->intrenable);
+ }
+
+ if (ints & OHCI_INTR_SO) {
+ dbg("USB Schedule overrun\n");
+ writel (OHCI_INTR_SO, &regs->intrenable);
+ stat = -1;
+ }
+
+ /* FIXME: this assumes SOF (1/ms) interrupts don't get lost... */
+ if (ints & OHCI_INTR_SF) {
+ unsigned int frame = ohci_cpu_to_le16 (ohci->hcca->frame_no) & 1;
+ mdelay(1);
+ writel (OHCI_INTR_SF, &regs->intrdisable);
+ if (ohci->ed_rm_list[frame] != NULL)
+ writel (OHCI_INTR_SF, &regs->intrenable);
+ stat = 0xff;
+ }
+
+ writel (ints, &regs->intrstatus);
+ return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+
+/* De-allocate all resources.. */
+
+static void hc_release_ohci (ohci_t *ohci)
+{
+ dbg ("USB HC release ohci usb-%s", ohci->slot_name);
+
+ if (!ohci->disabled)
+ hc_reset (ohci);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * low level initalisation routine, called from usb.c
+ */
+static char ohci_inited = 0;
+
+int usb_lowlevel_init(int index, void **controller)
+{
+ memset (&gohci, 0, sizeof (ohci_t));
+ memset (&urb_priv, 0, sizeof (urb_priv_t));
+
+ /* align the storage */
+ if ((__u32)&ghcca[0] & 0xff) {
+ err("HCCA not aligned!!");
+ return -1;
+ }
+ phcca = &ghcca[0];
+ info("aligned ghcca %p", phcca);
+ memset(&ohci_dev, 0, sizeof(struct ohci_device));
+ if ((__u32)&ohci_dev.ed[0] & 0x7) {
+ err("EDs not aligned!!");
+ return -1;
+ }
+ memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1));
+ if ((__u32)gtd & 0x7) {
+ err("TDs not aligned!!");
+ return -1;
+ }
+ ptd = gtd;
+ gohci.hcca = phcca;
+ memset (phcca, 0, sizeof (struct ohci_hcca));
+
+ gohci.disabled = 1;
+ gohci.sleeping = 0;
+ gohci.irq = -1;
+#if defined(CONFIG_440EP)
+ gohci.regs = (struct ohci_regs *)(CONFIG_SYS_PERIPHERAL_BASE | 0x1000);
+#elif defined(CONFIG_440EPX) || defined(CONFIG_SYS_USB_HOST)
+ gohci.regs = (struct ohci_regs *)(CONFIG_SYS_USB_HOST);
+#endif
+
+ gohci.flags = 0;
+ gohci.slot_name = "ppc440";
+
+ if (hc_reset (&gohci) < 0) {
+ hc_release_ohci (&gohci);
+ return -1;
+ }
+
+ if (hc_start (&gohci) < 0) {
+ err ("can't start usb-%s", gohci.slot_name);
+ hc_release_ohci (&gohci);
+ return -1;
+ }
+
+#ifdef DEBUG
+ ohci_dump (&gohci, 1);
+#endif
+ ohci_inited = 1;
+ urb_finished = 1;
+
+ return 0;
+}
+
+int usb_lowlevel_stop(int index)
+{
+ /* this gets called really early - before the controller has */
+ /* even been initialized! */
+ if (!ohci_inited)
+ return 0;
+ /* TODO release any interrupts, etc. */
+ /* call hc_release_ohci() here ? */
+ hc_reset (&gohci);
+ return 0;
+}
+
+#endif /* CONFIG_USB_OHCI */
diff --git a/arch/powerpc/cpu/ppc4xx/usb_ohci.h b/arch/powerpc/cpu/ppc4xx/usb_ohci.h
new file mode 100644
index 0000000..2c3dc4f
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/usb_ohci.h
@@ -0,0 +1,410 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * usb-ohci.h
+ */
+
+static int cc_to_error[16] = {
+
+/* mapping of the OHCI CC status to error codes */
+ /* No Error */ 0,
+ /* CRC Error */ USB_ST_CRC_ERR,
+ /* Bit Stuff */ USB_ST_BIT_ERR,
+ /* Data Togg */ USB_ST_CRC_ERR,
+ /* Stall */ USB_ST_STALLED,
+ /* DevNotResp */ -1,
+ /* PIDCheck */ USB_ST_BIT_ERR,
+ /* UnExpPID */ USB_ST_BIT_ERR,
+ /* DataOver */ USB_ST_BUF_ERR,
+ /* DataUnder */ USB_ST_BUF_ERR,
+ /* reservd */ -1,
+ /* reservd */ -1,
+ /* BufferOver */ USB_ST_BUF_ERR,
+ /* BuffUnder */ USB_ST_BUF_ERR,
+ /* Not Access */ -1,
+ /* Not Access */ -1
+};
+
+/* ED States */
+
+#define ED_NEW 0x00
+#define ED_UNLINK 0x01
+#define ED_OPER 0x02
+#define ED_DEL 0x04
+#define ED_URB_DEL 0x08
+
+/* usb_ohci_ed */
+struct ed {
+ __u32 hwINFO;
+ __u32 hwTailP;
+ __u32 hwHeadP;
+ __u32 hwNextED;
+
+ struct ed *ed_prev;
+ __u8 int_period;
+ __u8 int_branch;
+ __u8 int_load;
+ __u8 int_interval;
+ __u8 state;
+ __u8 type;
+ __u16 last_iso;
+ struct ed *ed_rm_list;
+
+ struct usb_device *usb_dev;
+ __u32 unused[3];
+} __attribute__((aligned(16)));
+typedef struct ed ed_t;
+
+/* TD info field */
+#define TD_CC 0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC 0x0C000000
+#define TD_T 0x03000000
+#define TD_T_DATA0 0x02000000
+#define TD_T_DATA1 0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R 0x00040000
+#define TD_DI 0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP 0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN 0x00100000
+#define TD_DP_OUT 0x00080000
+
+#define TD_ISO 0x00010000
+#define TD_DEL 0x00020000
+
+/* CC Codes */
+#define TD_CC_NOERROR 0x00
+#define TD_CC_CRC 0x01
+#define TD_CC_BITSTUFFING 0x02
+#define TD_CC_DATATOGGLEM 0x03
+#define TD_CC_STALL 0x04
+#define TD_DEVNOTRESP 0x05
+#define TD_PIDCHECKFAIL 0x06
+#define TD_UNEXPECTEDPID 0x07
+#define TD_DATAOVERRUN 0x08
+#define TD_DATAUNDERRUN 0x09
+#define TD_BUFFEROVERRUN 0x0C
+#define TD_BUFFERUNDERRUN 0x0D
+#define TD_NOTACCESSED 0x0F
+
+#define MAXPSW 1
+
+struct td {
+ __u32 hwINFO;
+ __u32 hwCBP; /* Current Buffer Pointer */
+ __u32 hwNextTD; /* Next TD Pointer */
+ __u32 hwBE; /* Memory Buffer End Pointer */
+
+ __u16 hwPSW[MAXPSW];
+ __u8 unused;
+ __u8 index;
+ struct ed *ed;
+ struct td *next_dl_td;
+ struct usb_device *usb_dev;
+ int transfer_len;
+ __u32 data;
+
+ __u32 unused2[2];
+} __attribute__((aligned(32)));
+typedef struct td td_t;
+
+#define OHCI_ED_SKIP (1 << 14)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of. It must be 256-byte aligned.
+ */
+
+#define NUM_INTS 32 /* part of the OHCI standard */
+struct ohci_hcca {
+ __u32 int_table[NUM_INTS]; /* Interrupt ED table */
+#if defined(CONFIG_MPC5200)
+ __u16 pad1; /* set to 0 on each frame_no change */
+ __u16 frame_no; /* current frame number */
+#else
+ __u16 frame_no; /* current frame number */
+ __u16 pad1; /* set to 0 on each frame_no change */
+#endif
+ __u32 done_head; /* info returned for an interrupt */
+ u8 reserved_for_hc[116];
+} __attribute__((aligned(256)));
+
+/*
+ * Maximum number of root hub ports.
+ */
+#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region. This is Memory Mapped I/O. You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+ /* control and status registers */
+ __u32 revision;
+ __u32 control;
+ __u32 cmdstatus;
+ __u32 intrstatus;
+ __u32 intrenable;
+ __u32 intrdisable;
+ /* memory pointers */
+ __u32 hcca;
+ __u32 ed_periodcurrent;
+ __u32 ed_controlhead;
+ __u32 ed_controlcurrent;
+ __u32 ed_bulkhead;
+ __u32 ed_bulkcurrent;
+ __u32 donehead;
+ /* frame counters */
+ __u32 fminterval;
+ __u32 fmremaining;
+ __u32 fmnumber;
+ __u32 periodicstart;
+ __u32 lsthresh;
+ /* Root hub ports */
+ struct ohci_roothub_regs {
+ __u32 a;
+ __u32 b;
+ __u32 status;
+ __u32 portstatus[MAX_ROOT_PORTS];
+ } roothub;
+} __attribute__((aligned(32)));
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */
+#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */
+#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */
+#define OHCI_CTRL_CLE (1 << 4) /* control list enable */
+#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */
+#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */
+#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
+#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
+#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+# define OHCI_USB_RESET (0 << 6)
+# define OHCI_USB_RESUME (1 << 6)
+# define OHCI_USB_OPER (2 << 6)
+# define OHCI_USB_SUSPEND (3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR (1 << 0) /* host controller reset */
+#define OHCI_CLF (1 << 1) /* control list filled */
+#define OHCI_BLF (1 << 2) /* bulk list filled */
+#define OHCI_OCR (1 << 3) /* ownership change request */
+#define OHCI_SOC (3 << 16) /* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */
+#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */
+#define OHCI_INTR_SF (1 << 2) /* start frame */
+#define OHCI_INTR_RD (1 << 3) /* resume detect */
+#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */
+#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */
+#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */
+#define OHCI_INTR_OC (1 << 30) /* ownership change */
+#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */
+
+/* Virtual Root HUB */
+struct virt_root_hub {
+ int devnum; /* Address of Root Hub endpoint */
+ void *dev; /* was urb */
+ void *int_addr;
+ int send;
+ int interval;
+};
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
+
+/* destination of request */
+#define RH_INTERFACE 0x01
+#define RH_ENDPOINT 0x02
+#define RH_OTHER 0x03
+
+#define RH_CLASS 0x20
+#define RH_VENDOR 0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS 0x0080
+#define RH_CLEAR_FEATURE 0x0100
+#define RH_SET_FEATURE 0x0300
+#define RH_SET_ADDRESS 0x0500
+#define RH_GET_DESCRIPTOR 0x0680
+#define RH_SET_DESCRIPTOR 0x0700
+#define RH_GET_CONFIGURATION 0x0880
+#define RH_SET_CONFIGURATION 0x0900
+#define RH_GET_STATE 0x0280
+#define RH_GET_INTERFACE 0x0A80
+#define RH_SET_INTERFACE 0x0B00
+#define RH_SYNC_FRAME 0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP 0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION 0x00
+#define RH_PORT_ENABLE 0x01
+#define RH_PORT_SUSPEND 0x02
+#define RH_PORT_OVER_CURRENT 0x03
+#define RH_PORT_RESET 0x04
+#define RH_PORT_POWER 0x08
+#define RH_PORT_LOW_SPEED 0x09
+
+#define RH_C_PORT_CONNECTION 0x10
+#define RH_C_PORT_ENABLE 0x11
+#define RH_C_PORT_SUSPEND 0x12
+#define RH_C_PORT_OVER_CURRENT 0x13
+#define RH_C_PORT_RESET 0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER 0x00
+#define RH_C_HUB_OVER_CURRENT 0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP 0x00
+#define RH_ENDPOINT_STALL 0x01
+
+#define RH_ACK 0x01
+#define RH_REQ_ERR -1
+#define RH_NACK 0x00
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS 0x00000001 /* current connect status */
+#define RH_PS_PES 0x00000002 /* port enable status */
+#define RH_PS_PSS 0x00000004 /* port suspend status */
+#define RH_PS_POCI 0x00000008 /* port over current indicator */
+#define RH_PS_PRS 0x00000010 /* port reset status */
+#define RH_PS_PPS 0x00000100 /* port power status */
+#define RH_PS_LSDA 0x00000200 /* low speed device attached */
+#define RH_PS_CSC 0x00010000 /* connect status change */
+#define RH_PS_PESC 0x00020000 /* port enable status change */
+#define RH_PS_PSSC 0x00040000 /* port suspend status change */
+#define RH_PS_OCIC 0x00080000 /* over current indicator change */
+#define RH_PS_PRSC 0x00100000 /* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS 0x00000001 /* local power status */
+#define RH_HS_OCI 0x00000002 /* over current indicator */
+#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
+#define RH_HS_LPSC 0x00010000 /* local power status change */
+#define RH_HS_OCIC 0x00020000 /* over current indicator change */
+#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR 0x0000ffff /* device removable flags */
+#define RH_B_PPCM 0xffff0000 /* port power control mask */
+
+/* roothub.a masks */
+#define RH_A_NDP (0xff << 0) /* number of downstream ports */
+#define RH_A_PSM (1 << 8) /* power switching mode */
+#define RH_A_NPS (1 << 9) /* no power switching */
+#define RH_A_DT (1 << 10) /* device type (mbz) */
+#define RH_A_OCPM (1 << 11) /* over current protection mode */
+#define RH_A_NOCP (1 << 12) /* no over current protection */
+#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
+
+/* urb */
+#define N_URB_TD 48
+typedef struct {
+ ed_t *ed;
+ __u16 length; /* number of tds associated with this request */
+ __u16 td_cnt; /* number of tds already serviced */
+ int state;
+ unsigned long pipe;
+ int actual_length;
+ td_t *td[N_URB_TD]; /* list pointer to all corresponding TDs associated with this request */
+} urb_priv_t;
+#define URB_DEL 1
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+typedef struct ohci {
+ struct ohci_hcca *hcca; /* hcca */
+ /*dma_addr_t hcca_dma; */
+
+ int irq;
+ int disabled; /* e.g. got a UE, we're hung */
+ int sleeping;
+ unsigned long flags; /* for HC bugs */
+
+ struct ohci_regs *regs; /* OHCI controller's memory */
+
+ ed_t *ed_rm_list[2]; /* lists of all endpoints to be removed */
+ ed_t *ed_bulktail; /* last endpoint of bulk list */
+ ed_t *ed_controltail; /* last endpoint of control list */
+ int intrstatus;
+ __u32 hc_control; /* copy of the hc control reg */
+ struct usb_device *dev[32];
+ struct virt_root_hub rh;
+
+ const char *slot_name;
+} ohci_t;
+
+#define NUM_EDS 8 /* num of preallocated endpoint descriptors */
+
+struct ohci_device {
+ ed_t ed[NUM_EDS];
+ int ed_cnt;
+};
+
+/* hcd */
+/* endpoint */
+static int ep_link(ohci_t * ohci, ed_t * ed);
+static int ep_unlink(ohci_t * ohci, ed_t * ed);
+static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe);
+
+/*-------------------------------------------------------------------------*/
+
+/* we need more TDs than EDs */
+#define NUM_TD 64
+
+/* +1 so we can align the storage */
+td_t gtd[NUM_TD + 1];
+/* pointers to aligned storage */
+td_t *ptd;
+
+/* TDs ... */
+static inline struct td *td_alloc(struct usb_device *usb_dev)
+{
+ int i;
+ struct td *td;
+
+ td = NULL;
+ for (i = 0; i < NUM_TD; i++) {
+ if (ptd[i].usb_dev == NULL) {
+ td = &ptd[i];
+ td->usb_dev = usb_dev;
+ break;
+ }
+ }
+
+ return td;
+}
+
+static inline void ed_free(struct ed *ed)
+{
+ ed->usb_dev = NULL;
+}
diff --git a/arch/powerpc/cpu/ppc4xx/xilinx_irq.c b/arch/powerpc/cpu/ppc4xx/xilinx_irq.c
new file mode 100644
index 0000000..eaa3de2
--- /dev/null
+++ b/arch/powerpc/cpu/ppc4xx/xilinx_irq.c
@@ -0,0 +1,100 @@
+/*
+ * (C) Copyright 2008
+ * Ricado Ribalda-Universidad Autonoma de Madrid-ricardo.ribalda@uam.es
+ * This work has been supported by: QTechnology http://qtec.com/
+ * Based on interrupts.c Wolfgang Denk-DENX Software Engineering-wd@denx.de
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <asm/interrupt.h>
+#include <asm/ppc4xx.h>
+#include <ppc_asm.tmpl>
+#include <commproc.h>
+#include <asm/io.h>
+#include <asm/xilinx_irq.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void pic_enable(void)
+{
+ debug("Xilinx PIC at 0x%8x\n", intc);
+
+ /*
+ * Disable all external interrupts until they are
+ * explicitly requested.
+ */
+ out_be32((u32 *) IER, 0);
+
+ /* Acknowledge any pending interrupts just in case. */
+ out_be32((u32 *) IAR, 0xffffffff);
+
+ /* Turn on the Master Enable. */
+ out_be32((u32 *) MER, 0x3UL);
+
+ return;
+}
+
+int xilinx_pic_irq_get(void)
+{
+ u32 irq;
+ irq = in_be32((u32 *) IVR);
+
+ /* If no interrupt is pending then all bits of the IVR are set to 1. As
+ * the IVR is as many bits wide as numbers of inputs are available.
+ * Therefore, if all bits of the IVR are set to one, its content will
+ * be bigger than XPAR_INTC_MAX_NUM_INTR_INPUTS.
+ */
+ if (irq >= XPAR_INTC_MAX_NUM_INTR_INPUTS)
+ irq = -1; /* report no pending interrupt. */
+
+ debug("get_irq: %d\n", irq);
+ return (irq);
+}
+
+void pic_irq_enable(unsigned int irq)
+{
+ u32 mask = IRQ_MASK(irq);
+ debug("enable: %d\n", irq);
+ out_be32((u32 *) SIE, mask);
+}
+
+void pic_irq_disable(unsigned int irq)
+{
+ u32 mask = IRQ_MASK(irq);
+ debug("disable: %d\n", irq);
+ out_be32((u32 *) CIE, mask);
+}
+
+void pic_irq_ack(unsigned int irq)
+{
+ u32 mask = IRQ_MASK(irq);
+ debug("ack: %d\n", irq);
+ out_be32((u32 *) IAR, mask);
+}
+
+void external_interrupt(struct pt_regs *regs)
+{
+ int irq;
+
+ irq = xilinx_pic_irq_get();
+ if (irq < 0)
+ return;
+
+ interrupt_run_handler(irq);
+
+ return;
+}
OpenPOWER on IntegriCloud