From e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb Mon Sep 17 00:00:00 2001 From: Yang Zhang Date: Fri, 28 Aug 2015 09:58:54 +0800 Subject: Add qemu 2.4.0 Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5 Signed-off-by: Yang Zhang --- .../roms/u-boot/arch/powerpc/cpu/74xx_7xx/Makefile | 13 + qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/cache.S | 404 +++ .../u-boot/arch/powerpc/cpu/74xx_7xx/config.mk | 8 + qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/cpu.c | 300 ++ .../u-boot/arch/powerpc/cpu/74xx_7xx/cpu_init.c | 47 + .../u-boot/arch/powerpc/cpu/74xx_7xx/interrupts.c | 88 + qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/io.S | 112 + qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/kgdb.S | 61 + qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/speed.c | 165 ++ qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/start.S | 840 ++++++ qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/traps.c | 218 ++ .../u-boot/arch/powerpc/cpu/74xx_7xx/u-boot.lds | 78 + qemu/roms/u-boot/arch/powerpc/cpu/Makefile | 3 + qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/Makefile | 22 + .../u-boot/arch/powerpc/cpu/mpc512x/asm-offsets.h | 15 + qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/cache.c | 17 + .../roms/u-boot/arch/powerpc/cpu/mpc512x/config.mk | 7 + qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/cpu.c | 200 ++ .../u-boot/arch/powerpc/cpu/mpc512x/cpu_init.c | 195 ++ qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/diu.c | 44 + .../u-boot/arch/powerpc/cpu/mpc512x/fixed_sdram.c | 155 + qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/i2c.c | 386 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/ide.c | 111 + .../u-boot/arch/powerpc/cpu/mpc512x/interrupts.c | 45 + qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/iopin.c | 87 + qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/pci.c | 209 ++ qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/serial.c | 443 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/speed.c | 137 + qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/start.S | 692 +++++ qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/traps.c | 190 ++ .../u-boot/arch/powerpc/cpu/mpc512x/u-boot.lds | 74 + qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/Makefile | 20 + qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/config.mk | 8 + qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/cpu.c | 156 + .../roms/u-boot/arch/powerpc/cpu/mpc5xx/cpu_init.c | 108 + .../u-boot/arch/powerpc/cpu/mpc5xx/interrupts.c | 192 ++ qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/serial.c | 168 ++ qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/speed.c | 52 + qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/spi.c | 396 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/start.S | 541 ++++ qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/traps.c | 211 ++ .../roms/u-boot/arch/powerpc/cpu/mpc5xx/u-boot.lds | 87 + qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/Makefile | 26 + .../roms/u-boot/arch/powerpc/cpu/mpc5xxx/config.mk | 9 + qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/cpu.c | 168 ++ .../u-boot/arch/powerpc/cpu/mpc5xxx/cpu_init.c | 231 ++ .../cpu/mpc5xxx/firmware_sc_task_bestcomm.impl.S | 359 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/i2c.c | 456 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/ide.c | 83 + .../u-boot/arch/powerpc/cpu/mpc5xxx/interrupts.c | 330 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/io.S | 112 + .../u-boot/arch/powerpc/cpu/mpc5xxx/loadtask.c | 76 + .../u-boot/arch/powerpc/cpu/mpc5xxx/pci_mpc5200.c | 171 ++ qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/serial.c | 276 ++ qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/speed.c | 84 + .../u-boot/arch/powerpc/cpu/mpc5xxx/spl_boot.c | 76 + qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/start.S | 764 +++++ qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/traps.c | 220 ++ .../powerpc/cpu/mpc5xxx/u-boot-customlayout.lds | 80 + .../u-boot/arch/powerpc/cpu/mpc5xxx/u-boot-spl.lds | 44 + .../u-boot/arch/powerpc/cpu/mpc5xxx/u-boot.lds | 76 + qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/usb.c | 42 + .../u-boot/arch/powerpc/cpu/mpc5xxx/usb_ohci.c | 1530 ++++++++++ .../u-boot/arch/powerpc/cpu/mpc5xxx/usb_ohci.h | 418 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/Makefile | 11 + .../roms/u-boot/arch/powerpc/cpu/mpc824x/config.mk | 8 + qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/cpu.c | 262 ++ .../u-boot/arch/powerpc/cpu/mpc824x/cpu_init.c | 311 ++ .../u-boot/arch/powerpc/cpu/mpc824x/drivers/epic.h | 1 + .../arch/powerpc/cpu/mpc824x/drivers/epic/README | 102 + .../arch/powerpc/cpu/mpc824x/drivers/epic/epic.h | 163 + .../arch/powerpc/cpu/mpc824x/drivers/epic/epic1.c | 517 ++++ .../arch/powerpc/cpu/mpc824x/drivers/epic/epic2.S | 196 ++ .../powerpc/cpu/mpc824x/drivers/epic/epicutil.S | 57 + .../arch/powerpc/cpu/mpc824x/drivers/errors.h | 212 ++ .../arch/powerpc/cpu/mpc824x/drivers/i2c/i2c.c | 254 ++ .../u-boot/arch/powerpc/cpu/mpc824x/interrupts.c | 77 + qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/pci.c | 75 + qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/speed.c | 102 + qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/start.S | 727 +++++ qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/traps.c | 194 ++ .../u-boot/arch/powerpc/cpu/mpc824x/u-boot.lds | 76 + qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/Makefile | 13 + .../u-boot/arch/powerpc/cpu/mpc8260/bedbug_603e.c | 236 ++ .../u-boot/arch/powerpc/cpu/mpc8260/commproc.c | 178 ++ .../roms/u-boot/arch/powerpc/cpu/mpc8260/config.mk | 9 + qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/cpu.c | 321 ++ .../u-boot/arch/powerpc/cpu/mpc8260/cpu_init.c | 276 ++ .../u-boot/arch/powerpc/cpu/mpc8260/ether_fcc.c | 1172 ++++++++ .../u-boot/arch/powerpc/cpu/mpc8260/ether_scc.c | 367 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/i2c.c | 740 +++++ .../u-boot/arch/powerpc/cpu/mpc8260/interrupts.c | 263 ++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/kgdb.S | 53 + qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/pci.c | 450 +++ .../u-boot/arch/powerpc/cpu/mpc8260/serial_scc.c | 492 +++ .../u-boot/arch/powerpc/cpu/mpc8260/serial_smc.c | 461 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/speed.c | 228 ++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/spi.c | 415 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/start.S | 989 +++++++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/traps.c | 248 ++ .../u-boot/arch/powerpc/cpu/mpc8260/u-boot.lds | 75 + qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/Makefile | 46 + qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/cache.c | 17 + .../roms/u-boot/arch/powerpc/cpu/mpc83xx/config.mk | 7 + qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/cpu.c | 226 ++ .../u-boot/arch/powerpc/cpu/mpc83xx/cpu_init.c | 508 ++++ qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/ecc.c | 389 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/fdt.c | 131 + .../u-boot/arch/powerpc/cpu/mpc83xx/interrupts.c | 81 + qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/law.c | 61 + qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/pci.c | 225 ++ qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/pcie.c | 335 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/qe_io.c | 69 + qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/serdes.c | 151 + .../u-boot/arch/powerpc/cpu/mpc83xx/spd_sdram.c | 927 ++++++ qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/speed.c | 593 ++++ .../u-boot/arch/powerpc/cpu/mpc83xx/spl_minimal.c | 96 + qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/start.S | 1199 ++++++++ qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/traps.c | 244 ++ .../u-boot/arch/powerpc/cpu/mpc83xx/u-boot-spl.lds | 39 + .../u-boot/arch/powerpc/cpu/mpc83xx/u-boot.lds | 75 + qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/Makefile | 116 + .../u-boot/arch/powerpc/cpu/mpc85xx/b4860_ids.c | 131 + .../u-boot/arch/powerpc/cpu/mpc85xx/b4860_serdes.c | 267 ++ .../arch/powerpc/cpu/mpc85xx/bsc9132_serdes.c | 93 + .../u-boot/arch/powerpc/cpu/mpc85xx/c29x_serdes.c | 62 + qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cache.c | 17 + .../u-boot/arch/powerpc/cpu/mpc85xx/cmd_errata.c | 310 ++ .../u-boot/arch/powerpc/cpu/mpc85xx/commproc.c | 186 ++ .../roms/u-boot/arch/powerpc/cpu/mpc85xx/config.mk | 14 + qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cpu.c | 648 ++++ .../u-boot/arch/powerpc/cpu/mpc85xx/cpu_init.c | 940 ++++++ .../arch/powerpc/cpu/mpc85xx/cpu_init_early.c | 185 ++ .../u-boot/arch/powerpc/cpu/mpc85xx/ether_fcc.c | 452 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fdt.c | 857 ++++++ .../arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c | 226 ++ .../arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.h | 12 + .../arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c | 877 ++++++ .../arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.h | 28 + .../u-boot/arch/powerpc/cpu/mpc85xx/interrupts.c | 110 + qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/liodn.c | 359 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mp.c | 472 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mp.h | 21 + .../arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c | 233 ++ .../arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c | 79 + .../arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c | 49 + .../arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c | 49 + .../arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c | 58 + .../arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c | 65 + .../u-boot/arch/powerpc/cpu/mpc85xx/p1010_serdes.c | 72 + .../u-boot/arch/powerpc/cpu/mpc85xx/p1021_serdes.c | 95 + .../u-boot/arch/powerpc/cpu/mpc85xx/p1022_serdes.c | 111 + .../u-boot/arch/powerpc/cpu/mpc85xx/p1023_serdes.c | 50 + .../u-boot/arch/powerpc/cpu/mpc85xx/p2020_serdes.c | 57 + .../u-boot/arch/powerpc/cpu/mpc85xx/p2041_ids.c | 113 + .../u-boot/arch/powerpc/cpu/mpc85xx/p2041_serdes.c | 90 + .../u-boot/arch/powerpc/cpu/mpc85xx/p3041_ids.c | 112 + .../u-boot/arch/powerpc/cpu/mpc85xx/p3041_serdes.c | 135 + .../u-boot/arch/powerpc/cpu/mpc85xx/p4080_ids.c | 112 + .../u-boot/arch/powerpc/cpu/mpc85xx/p4080_serdes.c | 82 + .../u-boot/arch/powerpc/cpu/mpc85xx/p5020_ids.c | 125 + .../u-boot/arch/powerpc/cpu/mpc85xx/p5020_serdes.c | 135 + .../u-boot/arch/powerpc/cpu/mpc85xx/p5040_ids.c | 111 + .../u-boot/arch/powerpc/cpu/mpc85xx/p5040_serdes.c | 101 + qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/pci.c | 214 ++ .../roms/u-boot/arch/powerpc/cpu/mpc85xx/portals.c | 308 ++ qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/qe_io.c | 72 + .../roms/u-boot/arch/powerpc/cpu/mpc85xx/release.S | 487 +++ .../u-boot/arch/powerpc/cpu/mpc85xx/resetvec.S | 2 + .../u-boot/arch/powerpc/cpu/mpc85xx/serial_scc.c | 262 ++ qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/speed.c | 532 ++++ .../u-boot/arch/powerpc/cpu/mpc85xx/spl_minimal.c | 45 + qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/start.S | 1978 +++++++++++++ .../u-boot/arch/powerpc/cpu/mpc85xx/t1040_ids.c | 84 + .../u-boot/arch/powerpc/cpu/mpc85xx/t1040_serdes.c | 68 + .../u-boot/arch/powerpc/cpu/mpc85xx/t2080_ids.c | 144 + .../u-boot/arch/powerpc/cpu/mpc85xx/t2080_serdes.c | 207 ++ .../u-boot/arch/powerpc/cpu/mpc85xx/t4240_ids.c | 189 ++ .../u-boot/arch/powerpc/cpu/mpc85xx/t4240_serdes.c | 353 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/tlb.c | 346 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/traps.c | 296 ++ .../arch/powerpc/cpu/mpc85xx/u-boot-nand.lds | 98 + .../arch/powerpc/cpu/mpc85xx/u-boot-nand_spl.lds | 69 + .../u-boot/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds | 115 + .../u-boot/arch/powerpc/cpu/mpc85xx/u-boot.lds | 129 + qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/Makefile | 24 + qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/cache.S | 378 +++ .../roms/u-boot/arch/powerpc/cpu/mpc86xx/config.mk | 8 + qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/cpu.c | 202 ++ .../u-boot/arch/powerpc/cpu/mpc86xx/cpu_init.c | 102 + qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/fdt.c | 66 + .../u-boot/arch/powerpc/cpu/mpc86xx/interrupts.c | 115 + qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/mp.c | 129 + .../arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c | 69 + .../arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c | 78 + .../roms/u-boot/arch/powerpc/cpu/mpc86xx/release.S | 151 + qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/speed.c | 146 + qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/start.S | 993 +++++++ qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/traps.c | 207 ++ .../u-boot/arch/powerpc/cpu/mpc86xx/u-boot.lds | 79 + qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/Makefile | 27 + .../u-boot/arch/powerpc/cpu/mpc8xx/bedbug_860.c | 314 ++ .../roms/u-boot/arch/powerpc/cpu/mpc8xx/commproc.c | 69 + qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/config.mk | 8 + qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu.c | 641 ++++ .../roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu_init.c | 246 ++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/fdt.c | 30 + qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/fec.c | 1013 +++++++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/fec.h | 12 + qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/i2c.c | 688 +++++ .../u-boot/arch/powerpc/cpu/mpc8xx/interrupts.c | 278 ++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/kgdb.S | 55 + .../u-boot/arch/powerpc/cpu/mpc8xx/plprcr_write.S | 119 + qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/scc.c | 535 ++++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/serial.c | 746 +++++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/speed.c | 400 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/spi.c | 540 ++++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/start.S | 650 ++++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/traps.c | 216 ++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/upatch.c | 194 ++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/video.c | 1318 +++++++++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/Makefile | 30 + qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/cpu.c | 271 ++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/fdt.c | 428 +++ .../roms/u-boot/arch/powerpc/cpu/mpc8xxx/fsl_lbc.c | 153 + qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/law.c | 354 +++ qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/srio.c | 446 +++ .../u-boot/arch/powerpc/cpu/ppc4xx/40x_spd_sdram.c | 444 +++ .../u-boot/arch/powerpc/cpu/ppc4xx/44x_spd_ddr.c | 1224 ++++++++ .../u-boot/arch/powerpc/cpu/ppc4xx/44x_spd_ddr2.c | 3129 ++++++++++++++++++++ .../powerpc/cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c | 1227 ++++++++ qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_pci.c | 864 ++++++ .../roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_pcie.c | 1280 ++++++++ .../roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_uart.c | 268 ++ qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/Makefile | 49 + .../u-boot/arch/powerpc/cpu/ppc4xx/bedbug_405.c | 308 ++ qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cache.S | 231 ++ .../arch/powerpc/cpu/ppc4xx/cmd_chip_config.c | 131 + .../u-boot/arch/powerpc/cpu/ppc4xx/cmd_ecctest.c | 262 ++ qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/config.mk | 17 + qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cpu.c | 719 +++++ .../roms/u-boot/arch/powerpc/cpu/ppc4xx/cpu_init.c | 543 ++++ qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/dcr.S | 180 ++ .../arch/powerpc/cpu/ppc4xx/denali_data_eye.c | 376 +++ .../arch/powerpc/cpu/ppc4xx/denali_spd_ddr2.c | 1231 ++++++++ qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/ecc.c | 188 ++ qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/ecc.h | 58 + qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/fdt.c | 160 + qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/gpio.c | 244 ++ .../u-boot/arch/powerpc/cpu/ppc4xx/interrupts.c | 193 ++ qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/kgdb.S | 61 + qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/miiphy.c | 346 +++ qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/reginfo.c | 357 +++ .../roms/u-boot/arch/powerpc/cpu/ppc4xx/resetvec.S | 12 + qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/sdram.c | 452 +++ qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/sdram.h | 60 + qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/speed.c | 1209 ++++++++ .../roms/u-boot/arch/powerpc/cpu/ppc4xx/spl_boot.c | 61 + qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/start.S | 1954 ++++++++++++ qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/tlb.c | 336 +++ qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/traps.c | 392 +++ .../u-boot/arch/powerpc/cpu/ppc4xx/u-boot-spl.lds | 61 + .../roms/u-boot/arch/powerpc/cpu/ppc4xx/u-boot.lds | 133 + qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/uic.c | 164 + qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/usb.c | 45 + .../roms/u-boot/arch/powerpc/cpu/ppc4xx/usb_ohci.c | 1525 ++++++++++ .../roms/u-boot/arch/powerpc/cpu/ppc4xx/usb_ohci.h | 410 +++ .../u-boot/arch/powerpc/cpu/ppc4xx/xilinx_irq.c | 89 + 268 files changed, 76622 insertions(+) create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/Makefile create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/cache.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/config.mk create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/cpu.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/cpu_init.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/interrupts.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/io.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/kgdb.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/speed.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/start.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/traps.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/u-boot.lds create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/Makefile create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/Makefile create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/asm-offsets.h create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/cache.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/config.mk create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/cpu.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/cpu_init.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/diu.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/fixed_sdram.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/i2c.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/ide.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/interrupts.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/iopin.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/pci.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/serial.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/speed.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/start.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/traps.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/u-boot.lds create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/Makefile create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/config.mk create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/cpu.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/cpu_init.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/interrupts.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/serial.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/speed.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/spi.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/start.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/traps.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/u-boot.lds create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/Makefile create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/config.mk create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/cpu.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/cpu_init.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/firmware_sc_task_bestcomm.impl.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/i2c.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/ide.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/interrupts.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/io.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/loadtask.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/pci_mpc5200.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/serial.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/speed.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/spl_boot.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/start.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/traps.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/u-boot-customlayout.lds create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/u-boot-spl.lds create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/u-boot.lds create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/usb.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/usb_ohci.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/usb_ohci.h create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/Makefile create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/config.mk create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/cpu.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/cpu_init.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic.h create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic/README create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic/epic.h create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic/epic1.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic/epic2.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic/epicutil.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/errors.h create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/i2c/i2c.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/interrupts.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/pci.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/speed.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/start.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/traps.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/u-boot.lds create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/Makefile create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/bedbug_603e.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/commproc.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/config.mk create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/cpu.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/cpu_init.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/ether_fcc.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/ether_scc.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/i2c.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/interrupts.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/kgdb.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/pci.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/serial_scc.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/serial_smc.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/speed.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/spi.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/start.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/traps.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/u-boot.lds create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/Makefile create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/cache.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/config.mk create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/cpu.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/cpu_init.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/ecc.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/fdt.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/interrupts.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/law.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/pci.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/pcie.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/qe_io.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/spd_sdram.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/speed.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/spl_minimal.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/start.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/traps.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/u-boot-spl.lds create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/u-boot.lds create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/Makefile create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/b4860_ids.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/b4860_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/bsc9132_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/c29x_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cache.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cmd_errata.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/commproc.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/config.mk create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cpu.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cpu_init.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cpu_init_early.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/ether_fcc.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fdt.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.h create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.h create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/interrupts.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/liodn.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mp.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mp.h create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p1010_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p1021_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p1022_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p1023_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p2020_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p2041_ids.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p2041_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p3041_ids.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p3041_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p4080_ids.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p4080_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p5020_ids.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p5020_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p5040_ids.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p5040_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/pci.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/portals.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/qe_io.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/release.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/resetvec.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/serial_scc.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/speed.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/spl_minimal.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/start.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t1040_ids.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t1040_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t2080_ids.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t2080_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t4240_ids.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t4240_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/tlb.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/traps.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/u-boot-nand.lds create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/u-boot-nand_spl.lds create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/u-boot.lds create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/Makefile create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/cache.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/config.mk create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/cpu.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/cpu_init.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/fdt.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/interrupts.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/mp.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/release.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/speed.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/start.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/traps.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/u-boot.lds create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/Makefile create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/bedbug_860.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/commproc.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/config.mk create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu_init.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/fdt.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/fec.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/fec.h create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/i2c.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/interrupts.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/kgdb.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/plprcr_write.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/scc.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/serial.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/speed.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/spi.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/start.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/traps.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/upatch.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/video.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/Makefile create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/cpu.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/fdt.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/fsl_lbc.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/law.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/srio.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/40x_spd_sdram.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/44x_spd_ddr.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/44x_spd_ddr2.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_pci.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_pcie.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_uart.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/Makefile create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/bedbug_405.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cache.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cmd_chip_config.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cmd_ecctest.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/config.mk create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cpu.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cpu_init.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/dcr.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/denali_data_eye.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/denali_spd_ddr2.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/ecc.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/ecc.h create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/fdt.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/gpio.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/interrupts.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/kgdb.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/miiphy.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/reginfo.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/resetvec.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/sdram.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/sdram.h create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/speed.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/spl_boot.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/start.S create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/tlb.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/traps.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/u-boot-spl.lds create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/u-boot.lds create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/uic.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/usb.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/usb_ohci.c create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/usb_ohci.h create mode 100644 qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/xilinx_irq.c (limited to 'qemu/roms/u-boot/arch/powerpc/cpu') diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/Makefile b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/Makefile new file mode 100644 index 000000000..f31fe756e --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/Makefile @@ -0,0 +1,13 @@ +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# (C) Copyright 2001 +# Josh Huber , Mission Critical Linux, Inc. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +extra-y = start.o +obj-y = cache.o kgdb.o io.o +obj-y += traps.o cpu.o cpu_init.o speed.o interrupts.o diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/cache.S b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/cache.S new file mode 100644 index 000000000..66c72983d --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/cache.S @@ -0,0 +1,404 @@ +#include +#include <74xx_7xx.h> +#include + +#include +#include + +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/config.mk b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/config.mk new file mode 100644 index 000000000..96812a02d --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/config.mk @@ -0,0 +1,8 @@ +# +# (C) Copyright 2001 +# Josh Huber , Mission Critical Linux, Inc. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +PLATFORM_CPPFLAGS += -DCONFIG_74xx_7xx -mstring diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/cpu.c b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/cpu.c new file mode 100644 index 000000000..6cd54bf92 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/cpu.c @@ -0,0 +1,300 @@ +/* + * (C) Copyright 2001 + * Josh Huber , Mission Critical Linux, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * cpu.c + * + * CPU specific code + * + * written or collected and sometimes rewritten by + * Magnus Damm + * + * minor modifications by + * Wolfgang Denk + * + * more modifications by + * Josh Huber + * 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 +#include +#include <74xx_7xx.h> +#include + +#if defined(CONFIG_OF_LIBFDT) +#include +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/cpu_init.c b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/cpu_init.c new file mode 100644 index 000000000..a6a878843 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/cpu_init.c @@ -0,0 +1,47 @@ +/* + * (C) Copyright 2001 + * Josh Huber , Mission Critical Linux, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * cpu_init.c - low level cpu init + * + * there's really nothing going on here yet. future work area? + */ + +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/interrupts.c b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/interrupts.c new file mode 100644 index 000000000..a9062435d --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/interrupts.c @@ -0,0 +1,88 @@ +/* + * (C) Copyright 2001 + * Josh Huber , Mission Critical Linux, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * interrupts.c - just enough support for the decrementer/timer + */ + +#include +#include +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/io.S b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/io.S new file mode 100644 index 000000000..3b4b08a88 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/io.S @@ -0,0 +1,112 @@ +/* + * Copyright (C) 1998 Dan Malek + * Copyright (C) 1999 Magnus Damm + * Copyright (C) 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * Copyright (C) 2002 Wolfgang Denk + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +/* ------------------------------------------------------------------------------- */ +/* 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/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/kgdb.S b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/kgdb.S new file mode 100644 index 000000000..42b3a7600 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/kgdb.S @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2000 Murray Jensen + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include <74xx_7xx.h> +#include + +#include +#include + +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/speed.c b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/speed.c new file mode 100644 index 000000000..5ffa41cfc --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/speed.c @@ -0,0 +1,165 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include <74xx_7xx.h> +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/start.S b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/start.S new file mode 100644 index 000000000..b0e102c66 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/start.S @@ -0,0 +1,840 @@ +/* + * Copyright (C) 1998 Dan Malek + * Copyright (C) 1999 Magnus Damm + * Copyright (C) 2000,2001,2002 Wolfgang Denk + * Copyright (C) 2001 Josh Huber + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* 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 +#include +#include <74xx_7xx.h> +#include + +#include +#include + +#include +#include +#include + +#if !defined(CONFIG_DB64360) && \ + !defined(CONFIG_DB64460) && \ + !defined(CONFIG_CPCI750) && \ + !defined(CONFIG_P3Mx) +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/traps.c b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/traps.c new file mode 100644 index 000000000..111c86cc1 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/traps.c @@ -0,0 +1,218 @@ +/* + * 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. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include +#include +#include +#include + +/* 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/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/u-boot.lds b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/u-boot.lds new file mode 100644 index 000000000..c09984908 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/74xx_7xx/u-boot.lds @@ -0,0 +1,78 @@ +/* + * (C) Copyright 2010 Wolfgang Denk + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +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/qemu/roms/u-boot/arch/powerpc/cpu/Makefile b/qemu/roms/u-boot/arch/powerpc/cpu/Makefile new file mode 100644 index 000000000..88b5298be --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_MPC83xx) += mpc8xxx/ +obj-$(CONFIG_MPC85xx) += mpc8xxx/ +obj-$(CONFIG_MPC86xx) += mpc8xxx/ diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/Makefile b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/Makefile new file mode 100644 index 000000000..a4934ef78 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/Makefile @@ -0,0 +1,22 @@ +# +# (C) Copyright 2007-2009 DENX Software Engineering +# +# SPDX-License-Identifier: GPL-2.0+ +# + +extra-y = start.o +obj-y := cpu.o +obj-y += traps.o +obj-y += cpu_init.o +obj-y += fixed_sdram.o +obj-y += i2c.o +obj-y += interrupts.o +obj-y += iopin.o +obj-y += serial.o +obj-y += speed.o +obj-$(CONFIG_FSL_DIU_FB) += diu.o +obj-$(CONFIG_CMD_IDE) += ide.o +obj-$(CONFIG_PCI) += pci.o + +# Stub implementations of cache management functions for USB +obj-$(CONFIG_USB_EHCI) += cache.o diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/asm-offsets.h b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/asm-offsets.h new file mode 100644 index 000000000..957d4be2d --- /dev/null +++ b/qemu/roms/u-boot/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/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/cache.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/cache.c new file mode 100644 index 000000000..66384f988 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/cache.c @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2012 Marek Vasut + * + * This file contains stub implementation of + * invalidate_dcache_range() + * flush_dcache_range() + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +void invalidate_dcache_range(unsigned long start, unsigned long stop) +{ +} + +void flush_dcache_range(unsigned long start, unsigned long stop) +{ +} diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/config.mk b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/config.mk new file mode 100644 index 000000000..03759e662 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/config.mk @@ -0,0 +1,7 @@ +# +# (C) Copyright 2007-2010 DENX Software Engineering +# +# SPDX-License-Identifier: GPL-2.0+ +# + +PLATFORM_CPPFLAGS += -DCONFIG_MPC512X -DCONFIG_E300 -msoft-float -mcpu=603e diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/cpu.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/cpu.c new file mode 100644 index 000000000..8508e8db4 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/cpu.c @@ -0,0 +1,200 @@ +/* + * (C) Copyright 2007-2010 DENX Software Engineering + * Copyright (C) 2004-2006 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * CPU specific code for the MPC512x family. + * + * Derived from the MPC83xx code. + */ + +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_OF_LIBFDT) +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/cpu_init.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/cpu_init.c new file mode 100644 index 000000000..48a5e4f8b --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/cpu_init.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2004-2006 Freescale Semiconductor, Inc. + * Copyright (C) 2007-2009 DENX Software Engineering + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Derived from the MPC83xx code. + */ + +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/diu.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/diu.c new file mode 100644 index 000000000..36e1f9cff --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/diu.c @@ -0,0 +1,44 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * York Sun + * + * FSL DIU Framebuffer driver + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/fixed_sdram.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/fixed_sdram.c new file mode 100644 index 000000000..6451ea9a4 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/fixed_sdram.c @@ -0,0 +1,155 @@ +/* + * (C) Copyright 2007-2009 DENX Software Engineering + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +/* + * 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/i2c.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/i2c.c new file mode 100644 index 000000000..15d519a11 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/i2c.c @@ -0,0 +1,386 @@ +/* + * (C) Copyright 2003 - 2009 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Based on the MPC5xxx code. + */ + +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_HARD_I2C + +#include + +/* 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 (®s->msr); + + while (timeout-- && (status & I2C_BB)) { + mpc_reg_out (®s->mcr, I2C_STA, I2C_STA); + (void)mpc_reg_in(®s->mdr); + mpc_reg_out (®s->mcr, 0, I2C_STA); + mpc_reg_out (®s->mcr, 0, 0); + mpc_reg_out (®s->mcr, I2C_EN, 0); + + udelay (1000); + status = mpc_reg_in (®s->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 (®s->msr); + + while (timeout-- && !(*status & I2C_IF)) { + udelay (1000); + *status = mpc_reg_in (®s->msr); + } + + if (!(*status & I2C_IF)) { + return -1; + } + + mpc_reg_out (®s->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 (®s->mcr, I2C_TX, I2C_TX); + mpc_reg_out (®s->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 (®s->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 (®s->mcr, 0, I2C_TX); + + for (i = 0; i < len; ++i) { + buf[rdcount] = mpc_reg_in (®s->mdr); + + if (dummy) { + dummy = 0; + } else { + rdcount++; + } + + if (wait_for_pin (&status)) { + return -4; + } + } + + mpc_reg_out (®s->mcr, I2C_TXAK, I2C_TXAK); + buf[rdcount++] = mpc_reg_in (®s->mdr); + + if (wait_for_pin (&status)) { + return -5; + } + + mpc_reg_out (®s->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 (®s->mcr, 0, 0); + + /* Set clock */ + mpc_reg_out (®s->mfdr, mpc_get_fdr (speed), 0); + mpc_reg_out (®s->madr, saddr << 1, 0); + + /* Enable module */ + mpc_reg_out (®s->mcr, I2C_EN, I2C_INIT_MASK); + mpc_reg_out (®s->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 (®s->mcr, I2C_STA, I2C_STA); + + if (! do_address (chip, 0)) { + mpc_reg_out (®s->mcr, 0, I2C_STA); + udelay (500); + break; + } + + mpc_reg_out (®s->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 (®s->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 (®s->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 (®s->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 (®s->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 (®s->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/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/ide.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/ide.c new file mode 100644 index 000000000..dd1130694 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/ide.c @@ -0,0 +1,111 @@ +/* + * (C) Copyright 2007-2009 DENX Software Engineering + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/interrupts.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/interrupts.c new file mode 100644 index 000000000..3385aed1c --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/interrupts.c @@ -0,0 +1,45 @@ +/* + * (C) Copyright 2000-2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright 2004 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Derived from the MPC83xx code. + */ + +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/iopin.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/iopin.c new file mode 100644 index 000000000..0b53c7b98 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/iopin.c @@ -0,0 +1,87 @@ +/* + * (C) Copyright 2008 + * Martha J Marx, Silicon Turnkey Express, mmarx@silicontkx.com + * mpc512x I/O pin/pad initialization for the ADS5121 board + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/pci.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/pci.c new file mode 100644 index 000000000..7ea5df296 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/pci.c @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2009-2010 DENX Software Engineering + * Copyright (C) Freescale Semiconductor, Inc. 2006, 2007. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +#include +#include +#include +#include +#if defined(CONFIG_OF_LIBFDT) +#include +#include +#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, ®16); + 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/serial.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/serial.c new file mode 100644 index 000000000..42e0dc96f --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/serial.c @@ -0,0 +1,443 @@ +/* + * (C) Copyright 2000 - 2010 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Based ont the MPC5200 PSC driver. + * Adapted for MPC512x by Jan Wrobel + */ + +/* + * Minimal serial functions needed to use one of the PSC ports + * as serial console interface. + */ + +#include +#include +#include +#include +#include + +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 +/* + * 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/speed.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/speed.c new file mode 100644 index 000000000..95069cad8 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/speed.c @@ -0,0 +1,137 @@ +/* + * (C) Copyright 2000-2009 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright (C) 2004-2006 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Based on the MPC83xx code. + */ + +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/start.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/start.S new file mode 100644 index 000000000..6c331d103 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/start.S @@ -0,0 +1,692 @@ +/* + * Copyright (C) 1998 Dan Malek + * Copyright (C) 1999 Magnus Damm + * Copyright (C) 2000-2009 Wolfgang Denk + * Copyright Freescale Semiconductor, Inc. 2004, 2006. + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Based on the MPC83xx code. + */ + +/* + * U-Boot - Startup Code for MPC512x based Embedded Boards + */ + +#include +#include +#ifndef CONFIG_IDENT_STRING +#define CONFIG_IDENT_STRING "MPC512X" +#endif +#include + +#define CONFIG_521X 1 /* needed for Linux kernel header files*/ + +#include +#include "asm-offsets.h" + +#include +#include + +#include +#include +#include + +/* + * 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/traps.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/traps.c new file mode 100644 index 000000000..9f5bcd7fc --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/traps.c @@ -0,0 +1,190 @@ +/* + * (C) Copyright 2000 - 2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Derived from the MPC83xx code. + */ + +/* + * This file handles the architecture-dependent parts of hardware + * exceptions + */ + +#include +#include +#include + +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. + */ +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/u-boot.lds b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/u-boot.lds new file mode 100644 index 000000000..9658b2195 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc512x/u-boot.lds @@ -0,0 +1,74 @@ +/* + * (C) Copyright 2007-2010 DENX Software Engineering. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/Makefile b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/Makefile new file mode 100644 index 000000000..7b8826a64 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/Makefile @@ -0,0 +1,20 @@ +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# (C) Copyright 2003 +# Martin Winistoerfer, martinwinistoerfer@gmx.ch. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +# +# 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 +# + +extra-y = start.o +obj-y = serial.o cpu.o cpu_init.o interrupts.o traps.o speed.o spi.o diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/config.mk b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/config.mk new file mode 100644 index 000000000..31e2dc987 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/config.mk @@ -0,0 +1,8 @@ +# +# (C) Copyright 2003 +# Martin Winistoerfer, martinwinistoerfer@gmx.ch. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +PLATFORM_CPPFLAGS += -DCONFIG_5xx -mpowerpc -msoft-float diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/cpu.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/cpu.c new file mode 100644 index 000000000..cfcf63336 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/cpu.c @@ -0,0 +1,156 @@ +/* + * (C) Copyright 2003 + * Martin Winistoerfer, martinwinistoerfer@gmx.ch. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * File: cpu.c + * + * Discription: Some cpu specific function for watchdog, + * cpu version test, clock setting ... + * + */ + + +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/cpu_init.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/cpu_init.c new file mode 100644 index 000000000..0f62c13f8 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/cpu_init.c @@ -0,0 +1,108 @@ +/* + * (C) Copyright 2003 Martin Winistoerfer, martinwinistoerfer@gmx.ch. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * File: cpu_init.c + * + * Discription: Contains initialisation functions to setup + * the cpu properly + * + */ + +#include +#include +#include + +/* + * 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/interrupts.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/interrupts.c new file mode 100644 index 000000000..35dddf598 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/interrupts.c @@ -0,0 +1,192 @@ +/* + * (C) Copyright 2000-2002 Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * (C) Copyright 2003 Martin Winistoerfer, martinwinistoerfer@gmx.ch. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * File: interrupt.c + * + * Discription: Contains interrupt routines needed by U-Boot + * + */ + +#include +#include +#include +#include + +#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; vecim_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 +#include +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/speed.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/speed.c new file mode 100644 index 000000000..24b9026f5 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/speed.c @@ -0,0 +1,52 @@ +/* + * (C) Copyright 2003 + * Martin Winistoerfer, martinwinistoerfer@gmx.ch. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * File: speed.c + * + * Discription: Provides cpu speed calculation + * + */ + +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/spi.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/spi.c new file mode 100644 index 000000000..ef8b55f5f --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/spi.c @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2001 Navin Boppuri / Prashant Patel + * , + * + * Copyright (c) 2001 Gerd Mennchen + * Copyright (c) 2001 Wolfgang Denk, DENX Software Engineering, . + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * 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 +#include +#include +#include +#include +#include +#include + +#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;dlenqsmcm_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;iqsmcm_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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/start.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/start.S new file mode 100644 index 000000000..6b196de35 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/start.S @@ -0,0 +1,541 @@ +/* + * Copyright (C) 1998 Dan Malek + * Copyright (C) 1999 Magnus Damm + * Copyright (C) 2000, 2001, 2002 Wolfgang Denk + * Copyright (C) 2003 Martin Winistoerfer, martinwinistoerfer@gmx.ch. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * File: start.S + * + * Discription: startup code + * + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +/* 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/traps.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/traps.c new file mode 100644 index 000000000..6f31d8149 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/traps.c @@ -0,0 +1,211 @@ +/* + * 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. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/u-boot.lds b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/u-boot.lds new file mode 100644 index 000000000..719846526 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xx/u-boot.lds @@ -0,0 +1,87 @@ +/* + * (C) Copyright 2001-2010 Wolfgang Denk, DENX Software Engineering, wd@denx.de + * (C) Copyright 2003 Martin Winistoerfer, martinwinistoerfer@gmx.ch + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/Makefile b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/Makefile new file mode 100644 index 000000000..5c67e1d37 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/Makefile @@ -0,0 +1,26 @@ +# +# (C) Copyright 2003-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +extra-y = start.o +extra-y += traps.o +obj-y += io.o +obj-y += firmware_sc_task_bestcomm.impl.o +obj-y += i2c.o +obj-y += cpu.o +obj-y += cpu_init.o +obj-y += ide.o +obj-y += interrupts.o +obj-y += loadtask.o +obj-y += pci_mpc5200.o +obj-y += serial.o +obj-y += speed.o +obj-$(CONFIG_CMD_USB) += usb_ohci.o +obj-$(CONFIG_CMD_USB) += usb.o + +ifdef CONFIG_SPL_BUILD +obj-y += spl_boot.o +endif diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/config.mk b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/config.mk new file mode 100644 index 000000000..3384f6ffc --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/config.mk @@ -0,0 +1,9 @@ +# +# (C) Copyright 2003-2010 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +PLATFORM_CPPFLAGS += -DCONFIG_MPC5xxx \ + -mstring -mcpu=603e -mmultiple diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/cpu.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/cpu.c new file mode 100644 index 000000000..7a463b5e0 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/cpu.c @@ -0,0 +1,168 @@ +/* + * (C) Copyright 2000-2010 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * CPU specific code for the MPC5xxx CPUs + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_OF_LIBFDT) +#include +#include +#endif + +#if defined(CONFIG_OF_IDE_FIXUP) +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/cpu_init.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/cpu_init.c new file mode 100644 index 000000000..f9b57baf6 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/cpu_init.c @@ -0,0 +1,231 @@ +/* + * (C) Copyright 2000-2010 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/firmware_sc_task_bestcomm.impl.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/firmware_sc_task_bestcomm.impl.S new file mode 100644 index 000000000..00c23121a --- /dev/null +++ b/qemu/roms/u-boot/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 + +/* 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/i2c.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/i2c.c new file mode 100644 index 000000000..73601ae18 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/i2c.c @@ -0,0 +1,456 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_HARD_I2C + +#include +#include + +#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(®s->msr); + + while (timeout-- && (status & I2C_BB)) { + mpc_reg_out(®s->mcr, I2C_STA, I2C_STA); + (void)mpc_reg_in(®s->mdr); + mpc_reg_out(®s->mcr, 0, I2C_STA); + mpc_reg_out(®s->mcr, 0, 0); + mpc_reg_out(®s->mcr, I2C_EN, 0); + udelay(15); + status = mpc_reg_in(®s->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(®s->msr); + + while (timeout-- && !(*status & I2C_IF)) { + udelay(15); + *status = mpc_reg_in(®s->msr); + } + + if (!(*status & I2C_IF)) { + return -1; + } + + mpc_reg_out(®s->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(®s->mcr, I2C_TX, I2C_TX); + mpc_reg_out(®s->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(®s->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(®s->mcr, 0, I2C_TX); + + for (i = 0; i < len; ++i) { + buf[rdcount] = mpc_reg_in(®s->mdr); + + if (dummy) { + dummy = 0; + } else { + rdcount++; + } + + + if (wait_for_pin(&status)) { + return -4; + } + } + + mpc_reg_out(®s->mcr, I2C_TXAK, I2C_TXAK); + buf[rdcount++] = mpc_reg_in(®s->mdr); + + if (wait_for_pin(&status)) { + return -5; + } + + mpc_reg_out(®s->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(®s->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(®s->mcr, I2C_EN|I2C_STA|I2C_TX, I2C_INIT_MASK); + udelay(delay); + mpc_reg_out(®s->mcr, 0, I2C_INIT_MASK); + udelay(delay); + } + + mpc_reg_out(®s->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(®s->mcr, 0, 0); + mpc_reg_out(®s->madr, saddr << 1, 0); + + /* Set clock + */ + mpc_reg_out(®s->mfdr, mpc_get_fdr(speed), 0); + + /* Enable module + */ + mpc_reg_out(®s->mcr, I2C_EN, I2C_INIT_MASK); + mpc_reg_out(®s->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(®s->mcr, I2C_STA, I2C_STA); + + if (! do_address(chip, 0)) { + mpc_reg_out(®s->mcr, 0, I2C_STA); + udelay(500); + break; + } + + mpc_reg_out(®s->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(®s->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(®s->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(®s->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(®s->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(®s->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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/ide.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/ide.c new file mode 100644 index 000000000..03cd7fd4e --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/ide.c @@ -0,0 +1,83 @@ +/* + * (C) Copyright 2004 + * Pierre AUBERT, Staubli Faverges, + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Init is derived from Linux code. + */ +#include + +#if defined(CONFIG_CMD_IDE) +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/interrupts.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/interrupts.c new file mode 100644 index 000000000..9121fa0cd --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/interrupts.c @@ -0,0 +1,330 @@ +/* + * (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 , Mission Critical Linux, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* 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 and Kent Borg. + * + * Copyright (C) 2004 Sylvain Munaut + * Copyright (C) 2003 Montavista Software, Inc + */ + +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/io.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/io.S new file mode 100644 index 000000000..32641ed67 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/io.S @@ -0,0 +1,112 @@ +/* + * Copyright (C) 1998 Dan Malek + * Copyright (C) 1999 Magnus Damm + * Copyright (C) 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * Copyright (C) 2003 Wolfgang Denk + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +/* ------------------------------------------------------------------------------- */ +/* 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/loadtask.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/loadtask.c new file mode 100644 index 000000000..47e7b596a --- /dev/null +++ b/qemu/roms/u-boot/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 +#include + +/* 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/pci_mpc5200.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/pci_mpc5200.c new file mode 100644 index 000000000..a89d5fd7a --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/pci_mpc5200.c @@ -0,0 +1,171 @@ +/* + * (C) Copyright 2000-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +#if defined(CONFIG_PCI) + +#include +#include +#include +#include + +/* 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/serial.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/serial.c new file mode 100644 index 000000000..cb5b0bfe9 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/serial.c @@ -0,0 +1,276 @@ +/* + * (C) Copyright 2000 - 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + * + * 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 +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/speed.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/speed.c new file mode 100644 index 000000000..30a0a358d --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/speed.c @@ -0,0 +1,84 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/spl_boot.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/spl_boot.c new file mode 100644 index 000000000..e182dfbd4 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/spl_boot.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2012 Stefan Roese + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/start.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/start.S new file mode 100644 index 000000000..02c706ec6 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/start.S @@ -0,0 +1,764 @@ +/* + * Copyright (C) 1998 Dan Malek + * Copyright (C) 1999 Magnus Damm + * Copyright (C) 2000 - 2003 Wolfgang Denk + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * U-Boot - Startup Code for MPC5xxx CPUs + */ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +/* 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/traps.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/traps.c new file mode 100644 index 000000000..5498b7e69 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/traps.c @@ -0,0 +1,220 @@ +/* + * 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. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include +#include +#include +#include + +/* 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/u-boot-customlayout.lds b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/u-boot-customlayout.lds new file mode 100644 index 000000000..5354172af --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/u-boot-customlayout.lds @@ -0,0 +1,80 @@ +/* + * (C) Copyright 2003-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/u-boot-spl.lds b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/u-boot-spl.lds new file mode 100644 index 000000000..1aa925e93 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/u-boot-spl.lds @@ -0,0 +1,44 @@ +/* + * Copyright 2012 Stefan Roese + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/u-boot.lds b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/u-boot.lds new file mode 100644 index 000000000..cd9e23fbb --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/u-boot.lds @@ -0,0 +1,76 @@ +/* + * (C) Copyright 2003-2010 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/usb.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/usb.c new file mode 100644 index 000000000..bdf1484e2 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/usb.c @@ -0,0 +1,42 @@ +/* + * (C) Copyright 2007 + * Markus Klotzbuecher, DENX Software Engineering + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT) + +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/usb_ohci.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/usb_ohci.c new file mode 100644 index 000000000..3c8b2d904 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/usb_ohci.c @@ -0,0 +1,1530 @@ +/* + * URB OHCI HCD (Host Controller Driver) for USB on the MPC5200. + * + * (C) Copyright 2003-2004 + * Gary Jennejohn, DENX Software Engineering + * + * (C) Copyright 2004 + * Pierre Aubert, Staubli Faverges + * + * Note: Much of this code has been derived from Linux 2.4 + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * + * SPDX-License-Identifier: GPL-2.0+ + */ +/* + * 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 + +#ifdef CONFIG_USB_OHCI + +#include +#include +#include "usb_ohci.h" + +#include + +#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 (®s->revision) & 0xff; + if (temp != 0x10) + dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f)); + + temp = readl (®s->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 (®s->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 (®s->intrstatus)); + ohci_dump_intr_mask ("intrenable", readl (®s->intrenable)); + + maybe_print_eds ("ed_periodcurrent", readl (®s->ed_periodcurrent)); + + maybe_print_eds ("ed_controlhead", readl (®s->ed_controlhead)); + maybe_print_eds ("ed_controlcurrent", readl (®s->ed_controlcurrent)); + + maybe_print_eds ("ed_bulkhead", readl (®s->ed_bulkhead)); + maybe_print_eds ("ed_bulkcurrent", readl (®s->ed_bulkcurrent)); + + maybe_print_eds ("donehead", readl (®s->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 + *-------------------------------------------------------------------------*/ + +#include + +/* 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 (®s->intrstatus)) == ~(u32)0) { + ohci->disabled++; + err ("%s device removed!", ohci->slot_name); + return -1; + + } else if ((ints &= readl (®s->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, ®s->intrdisable); + stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci)); + writel (OHCI_INTR_WDH, ®s->intrenable); + } + + if (ints & OHCI_INTR_SO) { + dbg("USB Schedule overrun\n"); + writel (OHCI_INTR_SO, ®s->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, ®s->intrdisable); + if (ohci->ed_rm_list[frame] != NULL) + writel (OHCI_INTR_SF, ®s->intrenable); + stat = 0xff; + } + + writel (ints, ®s->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, enum usb_init_type init, 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/usb_ohci.h b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/usb_ohci.h new file mode 100644 index 000000000..629b529a6 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc5xxx/usb_ohci.h @@ -0,0 +1,418 @@ +/* + * URB OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2001 David Brownell + * + * 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/Makefile b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/Makefile new file mode 100644 index 000000000..2c8be9257 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/Makefile @@ -0,0 +1,11 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +extra-y = start.o +obj-y = traps.o cpu.o cpu_init.o interrupts.o speed.o \ + drivers/epic/epic1.o drivers/i2c/i2c.o pci.o +obj-y += ../mpc8260/bedbug_603e.o diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/config.mk b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/config.mk new file mode 100644 index 000000000..a224bc8e7 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/config.mk @@ -0,0 +1,8 @@ +# +# (C) Copyright 2000-2010 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +PLATFORM_CPPFLAGS += -DCONFIG_MPC824X -mstring -mcpu=603e -msoft-float diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/cpu.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/cpu.c new file mode 100644 index 000000000..eaa4e8707 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/cpu.c @@ -0,0 +1,262 @@ +/* + * (C) Copyright 2000 - 2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +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)); + + print_size(checkicache(), " I-Cache "); + print_size(checkdcache(), " D-Cache\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/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/cpu_init.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/cpu_init.c new file mode 100644 index 000000000..68d88e910 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/cpu_init.c @@ -0,0 +1,311 @@ +/* + * (C) Copyright 2000 + * Rob Taylor. Flying Pig Systems. robt@flyingpig.com. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#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) +{ + 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) +/* 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*/ + val |= PICR2_CF_SNOOP_WS_1WS | PICR2_CF_APHASE_WS_1WS; /*1 wait state*/ + 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) + 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) <> 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) <> 6) <> 6) <> 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"); +} + +/* + * initialize higher level parts of CPU like time base and timers + */ +int cpu_init_r (void) +{ + return (0); +} diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic.h b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic.h new file mode 100644 index 000000000..2803f631c --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic.h @@ -0,0 +1 @@ +#include "epic/epic.h" diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic/README b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic/README new file mode 100644 index 000000000..57989969b --- /dev/null +++ b/qemu/roms/u-boot/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/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic/epic.h b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic/epic.h new file mode 100644 index 000000000..58f81c5df --- /dev/null +++ b/qemu/roms/u-boot/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/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic/epic1.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic/epic1.c new file mode 100644 index 000000000..ecbb42d0d --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic/epic1.c @@ -0,0 +1,517 @@ +/************************************************** + * + * copyright @ motorola, 1999 + * + *************************************************/ +#include +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic/epic2.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic/epic2.S new file mode 100644 index 000000000..52d19aae8 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic/epic2.S @@ -0,0 +1,196 @@ +/************************************** + * + * copyright @ Motorola, 1999 + * + **************************************/ + +#include +#include +#include + +/********************************************* + * 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic/epicutil.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/epic/epicutil.S new file mode 100644 index 000000000..4877050ba --- /dev/null +++ b/qemu/roms/u-boot/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 +#include + +/********************************************************** + * 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/errors.h b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/errors.h new file mode 100644 index 000000000..20794a2e8 --- /dev/null +++ b/qemu/roms/u-boot/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/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/i2c/i2c.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/i2c/i2c.c new file mode 100644 index 000000000..3638ab0f8 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/drivers/i2c/i2c.c @@ -0,0 +1,254 @@ +/* + * (C) Copyright 2003 + * Gleb Natapov + * Some bits are taken from linux driver writen by adrian@humboldt.co.uk + * + * Hardware I2C driver for MPC107 PCI bridge. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +#undef I2CDBG + +#ifdef CONFIG_HARD_I2C +#include + +#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 back. + */ + udelay (10000); + return i2c_read (chip, 0, 1, (uchar *) &tmp, 1); +} + +#endif /* CONFIG_HARD_I2C */ diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/interrupts.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/interrupts.c new file mode 100644 index 000000000..fad103fc6 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/interrupts.c @@ -0,0 +1,77 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Rob Taylor, Flying Pig Systems. robt@flyingpig.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/pci.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/pci.c new file mode 100644 index 000000000..1257b086f --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/pci.c @@ -0,0 +1,75 @@ +/* + * 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. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +#ifdef CONFIG_PCI + +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/speed.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/speed.c new file mode 100644 index 000000000..e6064a181 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/speed.c @@ -0,0 +1,102 @@ +/* + * (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 + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +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 (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/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/start.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/start.S new file mode 100644 index 000000000..b1fb062a0 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/start.S @@ -0,0 +1,727 @@ +/* + * Copyright (C) 1998 Dan Malek + * Copyright (C) 1999 Magnus Damm + * Copyright (C) 2000,2001,2002 Wolfgang Denk + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* 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 +#include +#include +#include + +#include +#include + +#include +#include +#include + +/* 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/traps.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/traps.c new file mode 100644 index 000000000..6abf41d37 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/traps.c @@ -0,0 +1,194 @@ +/* + * 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. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include +#include + +/* 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/u-boot.lds b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/u-boot.lds new file mode 100644 index 000000000..04aba84a0 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc824x/u-boot.lds @@ -0,0 +1,76 @@ +/* + * (C) Copyright 2001-2010 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/Makefile b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/Makefile new file mode 100644 index 000000000..83adc4c43 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/Makefile @@ -0,0 +1,13 @@ +# +# (C) Copyright 2000-2008 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +extra-y = start.o +obj-y = 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 kgdb.o + +obj-$(CONFIG_ETHER_ON_SCC) += ether_scc.o diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/bedbug_603e.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/bedbug_603e.c new file mode 100644 index 000000000..92f89578b --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/bedbug_603e.c @@ -0,0 +1,236 @@ +/* + * Bedbug Functions specific to the MPC603e core + */ + +#include +#include +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/commproc.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/commproc.c new file mode 100644 index 000000000..484bd1774 --- /dev/null +++ b/qemu/roms/u-boot/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 +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/config.mk b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/config.mk new file mode 100644 index 000000000..59f152df7 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/config.mk @@ -0,0 +1,9 @@ +# +# (C) Copyright 2000-2010 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +PLATFORM_CPPFLAGS += -DCONFIG_MPC8260 -DCONFIG_CPM2 \ + -mstring -mcpu=603e -mmultiple diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/cpu.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/cpu.c new file mode 100644 index 000000000..6eed6f53a --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/cpu.c @@ -0,0 +1,321 @@ +/* + * (C) Copyright 2000-2006 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * CPU specific code for the MPC825x / MPC826x / MPC827x / MPC828x + * + * written or collected and sometimes rewritten by + * Magnus Damm + * + * modified by + * Wolfgang Denk + * + * modified for 8260 by + * Murray Jensen + * + * added 8260 masks by + * Marius Groeger + * + * added HiP7 (824x/827x/8280) processors support by + * Yuli Barcohen + */ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_OF_LIBFDT) +#include +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/cpu_init.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/cpu_init.c new file mode 100644 index 000000000..f46a9c0a7 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/cpu_init.c @@ -0,0 +1,276 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/ether_fcc.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/ether_fcc.c new file mode 100644 index 000000000..d93a99109 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/ether_fcc.c @@ -0,0 +1,1172 @@ +/* + * MPC8260 FCC Fast Ethernet + * + * Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net) + * + * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH + * Marius Groeger + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * 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 +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +#include +#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 = ðer_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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/ether_scc.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/ether_scc.c new file mode 100644 index 000000000..c988def9b --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/ether_scc.c @@ -0,0 +1,367 @@ +/* + * MPC8260 SCC Ethernet + * + * Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net) + * + * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH + * Marius Groeger + * + * (C) Copyright (c) 2001 + * Advent Networks, Inc. + * Jay Monkman + * + * 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 + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/i2c.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/i2c.c new file mode 100644 index 000000000..8658ebdad --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/i2c.c @@ -0,0 +1,740 @@ +/* + * (C) Copyright 2000 + * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it + * + * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH + * Marius Groeger + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +#if defined(CONFIG_HARD_I2C) + +#include +#include + +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 (bus >= CONFIG_SYS_MAX_I2C_BUS) + return -1; + i2c_bus_num = bus; + return 0; +} + +#endif /* CONFIG_I2C_MULTI_BUS */ +#endif /* CONFIG_HARD_I2C */ diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/interrupts.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/interrupts.c new file mode 100644 index 000000000..30125a7a7 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/interrupts.c @@ -0,0 +1,263 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 22-Oct-00 + */ + +#include +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/kgdb.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/kgdb.S new file mode 100644 index 000000000..1432344bc --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/kgdb.S @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2000 Murray Jensen + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/pci.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/pci.c new file mode 100644 index 000000000..2c013bbe5 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/pci.c @@ -0,0 +1,450 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright (c) 2005 MontaVista Software, Inc. + * Vitaly Bordug + * Added support for PCI bridge on MPC8272ADS + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +#ifdef CONFIG_PCI + +#include +#include +#include +#include +#ifdef CONFIG_OF_LIBFDT +#include +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/serial_scc.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/serial_scc.c new file mode 100644 index 000000000..8bfb3dedc --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/serial_scc.c @@ -0,0 +1,492 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + * + * 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 +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/serial_smc.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/serial_smc.c new file mode 100644 index 000000000..594c5ebf1 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/serial_smc.c @@ -0,0 +1,461 @@ +/* + * (C) Copyright 2000, 2001, 2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + * + * 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 +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/speed.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/speed.c new file mode 100644 index 000000000..0a06c4862 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/speed.c @@ -0,0 +1,228 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/spi.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/spi.c new file mode 100644 index 000000000..8c91a713b --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/spi.c @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2001 Navin Boppuri / Prashant Patel + * , + * + * Copyright (c) 2001 Gerd Mennchen + * Copyright (c) 2001-2003 Wolfgang Denk, DENX Software Engineering, . + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * 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 +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/start.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/start.S new file mode 100644 index 000000000..324f132ba --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/start.S @@ -0,0 +1,989 @@ +/* + * Copyright (C) 1998 Dan Malek + * Copyright (C) 1999 Magnus Damm + * Copyright (C) 2000, 2001,2002 Wolfgang Denk + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * U-Boot - Startup Code for MPC8260 PowerPC based Embedded Boards + */ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +/* 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/traps.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/traps.c new file mode 100644 index 000000000..cbcf53364 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/traps.c @@ -0,0 +1,248 @@ +/* + * 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. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include +#include +#include +#include +#include + +/* 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/u-boot.lds b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/u-boot.lds new file mode 100644 index 000000000..50cbf85d2 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8260/u-boot.lds @@ -0,0 +1,75 @@ +/* + * (C) Copyright 2001-2010 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/Makefile b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/Makefile new file mode 100644 index 000000000..cf9116274 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/Makefile @@ -0,0 +1,46 @@ +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# Copyright 2004 Freescale Semiconductor, Inc. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +MINIMAL= + +ifdef CONFIG_SPL_BUILD +ifdef CONFIG_SPL_INIT_MINIMAL +MINIMAL=y +endif +endif + +extra-y = start.o + +ifdef MINIMAL + +obj-y += spl_minimal.o + +else + +obj-y += traps.o +obj-y += cpu.o +obj-y += cpu_init.o +obj-y += speed.o +obj-y += interrupts.o +obj-y += ecc.o +obj-$(CONFIG_QE) += qe_io.o +obj-$(CONFIG_FSL_SERDES) += serdes.o +obj-$(CONFIG_PCI) += pci.o +obj-$(CONFIG_PCIE) += pcie.o +obj-$(CONFIG_OF_LIBFDT) += fdt.o + +# Stub implementations of cache management functions for USB +obj-y += cache.o + +ifndef CONFIG_SYS_FSL_DDRC_GEN2 +obj-y += spd_sdram.o +endif +obj-$(CONFIG_SYS_FSL_DDR2) += law.o + +endif # not minimal diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/cache.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/cache.c new file mode 100644 index 000000000..66384f988 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/cache.c @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2012 Marek Vasut + * + * This file contains stub implementation of + * invalidate_dcache_range() + * flush_dcache_range() + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +void invalidate_dcache_range(unsigned long start, unsigned long stop) +{ +} + +void flush_dcache_range(unsigned long start, unsigned long stop) +{ +} diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/config.mk b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/config.mk new file mode 100644 index 000000000..dfce4d53b --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/config.mk @@ -0,0 +1,7 @@ +# +# Copyright 2004 Freescale Semiconductor, Inc. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +PLATFORM_CPPFLAGS += -DCONFIG_MPC83xx -DCONFIG_E300 -msoft-float diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/cpu.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/cpu.c new file mode 100644 index 000000000..e41988d5f --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/cpu.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * CPU specific code for the MPC83xx family. + * + * Derived from the MPC8260 and MPC85xx. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_BOOTCOUNT_LIMIT) && !defined(CONFIG_MPC831x) +#include +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/cpu_init.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/cpu_init.c new file mode 100644 index 000000000..00572de12 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/cpu_init.c @@ -0,0 +1,508 @@ +/* + * Copyright (C) 2004-2009 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#ifdef CONFIG_USB_EHCI_FSL +#include +#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<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_USB1_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/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/ecc.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/ecc.c new file mode 100644 index 000000000..985a02442 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/ecc.c @@ -0,0 +1,389 @@ +/* + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. + * + * Dave Liu + * based on the contribution of Marian Balakowicz + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#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_SYS_FSL_DDR2 + struct ccsr_ddr __iomem *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_SYS_FSL_DDR2 + struct ccsr_ddr __iomem *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 - set Single-Bit Error counter\n" + "ecc sbethr - set Single-Bit Threshold\n" + "ecc errdisable - 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 - 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 - set Memory Data Path Error Injection Mask High\n" + "ecc injectdatalo - set Memory Data Path Error Injection Mask Low\n" + "ecc injectecc - set ECC Error Injection Mask\n" + "ecc inject - enable/disable error injection\n" + "ecc mirror - enable/disable mirror byte\n" + "ecc testdw - 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 - 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/fdt.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/fdt.c new file mode 100644 index 000000000..450a9704e --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/fdt.c @@ -0,0 +1,131 @@ +/* + * Copyright 2007 Freescale Semiconductor, Inc. + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +extern void ft_qe_setup(void *blob); + +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_BOOTCOUNT_LIMIT) && \ + (defined(CONFIG_QE) && !defined(CONFIG_MPC831x)) +#include + +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) && \ + (defined(CONFIG_QE) && !defined(CONFIG_MPC831x)) + fdt_fixup_muram (blob); +#endif +} diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/interrupts.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/interrupts.c new file mode 100644 index 000000000..668aa0208 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/interrupts.c @@ -0,0 +1,81 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright 2004 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/law.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/law.c new file mode 100644 index 000000000..66c88b697 --- /dev/null +++ b/qemu/roms/u-boot/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 +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/pci.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/pci.c new file mode 100644 index 000000000..30606fbe5 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/pci.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) Freescale Semiconductor, Inc. 2007 + * + * Author: Scott Wood , + * with some bits from older board-specific PCI initialization. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +#if defined(CONFIG_OF_LIBFDT) +#include +#include +#endif + +#include + +#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, ®16); + 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, ®16); + 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/pcie.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/pcie.c new file mode 100644 index 000000000..28c25e5fe --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/pcie.c @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2007-2009 Freescale Semiconductor, Inc. + * Copyright (C) 2008-2009 MontaVista Software, Inc. + * + * Authors: Tony Li + * Anton Vorontsov + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +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); + +#define PCI_LTSSM 0x404 /* PCIe Link Training, Status State Machine */ +#define PCI_LTSSM_L0 0x16 /* L0 state */ + 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/qe_io.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/qe_io.c new file mode 100644 index 000000000..4fae19c73 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/qe_io.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2006 Freescale Semiconductor, Inc. + * + * Dave Liu + * based on source code of Shlomi Gridish + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/serdes.c new file mode 100644 index 000000000..a0bc477dc --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/serdes.c @@ -0,0 +1,151 @@ +/* + * Freescale SerDes initialization routine + * + * Copyright 2007,2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008 MontaVista Software, Inc. + * + * Author: Li Yang + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +/* 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/spd_sdram.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/spd_sdram.c new file mode 100644 index 000000000..f62e1b79d --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/spd_sdram.c @@ -0,0 +1,927 @@ +/* + * (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) + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/speed.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/speed.c new file mode 100644 index 000000000..1865626c2 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/speed.c @@ -0,0 +1,593 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/spl_minimal.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/spl_minimal.c new file mode 100644 index 000000000..784f4ab8b --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/spl_minimal.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2004-2008 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/start.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/start.S new file mode 100644 index 000000000..36724e5aa --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/start.S @@ -0,0 +1,1199 @@ +/* + * Copyright (C) 1998 Dan Malek + * Copyright (C) 1999 Magnus Damm + * Copyright (C) 2000, 2001,2002 Wolfgang Denk + * Copyright Freescale Semiconductor, Inc. 2004, 2006, 2008. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * U-Boot - Startup Code for MPC83xx PowerPC based Embedded Boards + */ + +#include +#include +#include +#ifndef CONFIG_IDENT_STRING +#define CONFIG_IDENT_STRING "MPC83XX" +#endif +#include + +#define CONFIG_83XX 1 /* needed for Linux kernel header files*/ + +#include +#include + +#include +#include +#include + +/* 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_svr +get_svr: + mfspr r3, SVR + blr + + .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/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/traps.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/traps.c new file mode 100644 index 000000000..3dd6900c8 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/traps.c @@ -0,0 +1,244 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * This file handles the architecture-dependent parts of hardware + * exceptions + */ + +#include +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/u-boot-spl.lds b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/u-boot-spl.lds new file mode 100644 index 000000000..774772bea --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/u-boot-spl.lds @@ -0,0 +1,39 @@ +/* + * (C) Copyright 2006 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright 2008 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/u-boot.lds b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/u-boot.lds new file mode 100644 index 000000000..3c177fa29 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc83xx/u-boot.lds @@ -0,0 +1,75 @@ +/* + * (C) Copyright 2006-2010 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/Makefile b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/Makefile new file mode 100644 index 000000000..ad26b432f --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/Makefile @@ -0,0 +1,116 @@ +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# (C) Copyright 2002,2003 Motorola Inc. +# Xianghua Xiao,X.Xiao@motorola.com +# +# SPDX-License-Identifier: GPL-2.0+ +# + +MINIMAL= + +ifdef CONFIG_SPL_BUILD +ifdef CONFIG_SPL_INIT_MINIMAL +MINIMAL=y +endif +endif + +extra-y = start.o resetvec.o + +ifdef MINIMAL + +obj-y += cpu_init_early.o tlb.o spl_minimal.o + +else + +obj-$(CONFIG_MP) += release.o + +obj-$(CONFIG_CMD_ERRATA) += cmd_errata.o +obj-$(CONFIG_CPM2) += commproc.o + +obj-$(CONFIG_CPM2) += ether_fcc.o +obj-$(CONFIG_OF_LIBFDT) += fdt.o +obj-$(CONFIG_FSL_CORENET) += liodn.o +obj-$(CONFIG_MP) += mp.o +obj-$(CONFIG_PCI) += pci.o +obj-$(CONFIG_SYS_DPAA_QBMAN) += portals.o + +# various SoC specific assignments +obj-$(CONFIG_PPC_P2041) += p2041_ids.o +obj-$(CONFIG_PPC_P3041) += p3041_ids.o +obj-$(CONFIG_PPC_P4080) += p4080_ids.o +obj-$(CONFIG_PPC_P5020) += p5020_ids.o +obj-$(CONFIG_PPC_P5040) += p5040_ids.o +obj-$(CONFIG_PPC_T4240) += t4240_ids.o +obj-$(CONFIG_PPC_T4160) += t4240_ids.o +obj-$(CONFIG_PPC_T4080) += t4240_ids.o +obj-$(CONFIG_PPC_B4420) += b4860_ids.o +obj-$(CONFIG_PPC_B4860) += b4860_ids.o +obj-$(CONFIG_PPC_T1040) += t1040_ids.o +obj-$(CONFIG_PPC_T1042) += t1040_ids.o +obj-$(CONFIG_PPC_T1020) += t1040_ids.o +obj-$(CONFIG_PPC_T1022) += t1040_ids.o +obj-$(CONFIG_PPC_T2080) += t2080_ids.o +obj-$(CONFIG_PPC_T2081) += t2080_ids.o + + +obj-$(CONFIG_QE) += qe_io.o +obj-$(CONFIG_CPM2) += serial_scc.o +obj-$(CONFIG_SYS_FSL_QORIQ_CHASSIS1) += fsl_corenet_serdes.o +obj-$(CONFIG_SYS_FSL_QORIQ_CHASSIS2) += fsl_corenet2_serdes.o + +# SoC specific SERDES support +obj-$(CONFIG_PPC_C29X) += c29x_serdes.o +obj-$(CONFIG_MPC8536) += mpc8536_serdes.o +obj-$(CONFIG_MPC8544) += mpc8544_serdes.o +obj-$(CONFIG_MPC8548) += mpc8548_serdes.o +obj-$(CONFIG_MPC8568) += mpc8568_serdes.o +obj-$(CONFIG_MPC8569) += mpc8569_serdes.o +obj-$(CONFIG_MPC8572) += mpc8572_serdes.o +obj-$(CONFIG_P1010) += p1010_serdes.o +obj-$(CONFIG_P1011) += p1021_serdes.o +obj-$(CONFIG_P1012) += p1021_serdes.o +obj-$(CONFIG_P1013) += p1022_serdes.o +obj-$(CONFIG_P1014) += p1010_serdes.o +obj-$(CONFIG_P1017) += p1023_serdes.o +obj-$(CONFIG_P1020) += p1021_serdes.o +obj-$(CONFIG_P1021) += p1021_serdes.o +obj-$(CONFIG_P1022) += p1022_serdes.o +obj-$(CONFIG_P1023) += p1023_serdes.o +obj-$(CONFIG_P1024) += p1021_serdes.o +obj-$(CONFIG_P1025) += p1021_serdes.o +obj-$(CONFIG_P2010) += p2020_serdes.o +obj-$(CONFIG_P2020) += p2020_serdes.o +obj-$(CONFIG_PPC_P2041) += p2041_serdes.o +obj-$(CONFIG_PPC_P3041) += p3041_serdes.o +obj-$(CONFIG_PPC_P4080) += p4080_serdes.o +obj-$(CONFIG_PPC_P5020) += p5020_serdes.o +obj-$(CONFIG_PPC_P5040) += p5040_serdes.o +obj-$(CONFIG_PPC_T4240) += t4240_serdes.o +obj-$(CONFIG_PPC_T4160) += t4240_serdes.o +obj-$(CONFIG_PPC_T4080) += t4240_serdes.o +obj-$(CONFIG_PPC_B4420) += b4860_serdes.o +obj-$(CONFIG_PPC_B4860) += b4860_serdes.o +obj-$(CONFIG_BSC9132) += bsc9132_serdes.o +obj-$(CONFIG_PPC_T1040) += t1040_serdes.o +obj-$(CONFIG_PPC_T1042) += t1040_serdes.o +obj-$(CONFIG_PPC_T1020) += t1040_serdes.o +obj-$(CONFIG_PPC_T1022) += t1040_serdes.o +obj-$(CONFIG_PPC_T2080) += t2080_serdes.o +obj-$(CONFIG_PPC_T2081) += t2080_serdes.o + +obj-y += cpu.o +obj-y += cpu_init.o +obj-y += cpu_init_early.o +obj-y += interrupts.o +ifneq ($(CONFIG_QEMU_E500),y) +obj-y += speed.o +endif +obj-y += tlb.o +obj-y += traps.o + +# Stub implementations of cache management functions for USB +obj-y += cache.o + +endif # not minimal diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/b4860_ids.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/b4860_ids.c new file mode 100644 index 000000000..39b8e3ecc --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/b4860_ids.c @@ -0,0 +1,131 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#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_BASE(1, 307), + SET_SRIO_LIODN_BASE(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, 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(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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/b4860_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/b4860_serdes.c new file mode 100644 index 000000000..cf18be552 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/b4860_serdes.c @@ -0,0 +1,267 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#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 */ + {0x02, {AURORA, AURORA, CPRI6, CPRI5, + CPRI4, CPRI3, CPRI2, CPRI1} }, + {0x04, {AURORA, AURORA, CPRI6, CPRI5, + CPRI4, CPRI3, CPRI2, CPRI1} }, + {0x05, {AURORA, AURORA, CPRI6, CPRI5, + CPRI4, CPRI3, CPRI2, CPRI1} }, + {0x06, {AURORA, AURORA, CPRI6, CPRI5, + CPRI4, CPRI3, CPRI2, CPRI1} }, + {0x08, {AURORA, AURORA, CPRI6, CPRI5, + CPRI4, CPRI3, CPRI2, CPRI1} }, + {0x09, {AURORA, AURORA, CPRI6, CPRI5, + CPRI4, CPRI3, CPRI2, CPRI1} }, + {0x0A, {AURORA, AURORA, CPRI6, CPRI5, + CPRI4, CPRI3, CPRI2, CPRI1} }, + {0x0B, {AURORA, AURORA, CPRI6, CPRI5, + CPRI4, CPRI3, CPRI2, CPRI1} }, + {0x0C, {AURORA, AURORA, CPRI6, CPRI5, + CPRI4, CPRI3, CPRI2, CPRI1} }, + {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}}, + {0x29, {SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6, + 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}}, + {0x2F, {AURORA, AURORA, + SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, + 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}}, + {0x39, {AURORA, AURORA, CPRI6, CPRI5, + CPRI4, CPRI3, CPRI2, CPRI1} }, + {0x3A, {AURORA, AURORA, CPRI6, CPRI5, + CPRI4, CPRI3, CPRI2, CPRI1} }, + {0x3C, {AURORA, AURORA, CPRI6, CPRI5, + CPRI4, CPRI3, CPRI2, CPRI1} }, + {0x3D, {AURORA, AURORA, CPRI6, CPRI5, + CPRI4, CPRI3, CPRI2, CPRI1} }, + {0x3E, {CPRI8, CPRI7, CPRI6, CPRI5, + CPRI4, CPRI3, CPRI2, CPRI1}}, + {0x5C, {AURORA, AURORA, + SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, + CPRI4, CPRI3, CPRI2, CPRI1} }, + {0x5D, {AURORA, AURORA, + SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, + CPRI4, CPRI3, CPRI2, CPRI1} }, + {} +}; +static struct serdes_config serdes2_cfg_tbl[] = { + /* SerDes 2 */ + {0x17, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, + AURORA, AURORA, SRIO1, SRIO1} }, + {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}}, + {0x2A, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + SRIO2, SRIO2, + 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}}, + {0x48, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + SGMII_FM1_DTSEC3, AURORA, + SRIO1, SRIO1, 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}}, + {0x79, {SRIO2, SRIO2, SRIO2, SRIO2, + SRIO1, SRIO1, SRIO1, SRIO1} }, + {0x7A, {SRIO2, SRIO2, SRIO2, SRIO2, + SRIO1, SRIO1, SRIO1, SRIO1}}, + {0x83, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + SRIO2, SRIO2, AURORA, AURORA, + XFI_FM1_MAC9, XFI_FM1_MAC10} }, + {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}}, + {0x86, {SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + SRIO2, SRIO2, + SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, + 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}}, + {0x8C, {SRIO2, SRIO2, 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}}, + {0xB1, {PCIE1, PCIE1, PCIE1, PCIE1, + SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, + XFI_FM1_MAC9, XFI_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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/bsc9132_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/bsc9132_serdes.c new file mode 100644 index 000000000..399b20889 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/bsc9132_serdes.c @@ -0,0 +1,93 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * Author: Prabhakar Kushwaha + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/c29x_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/c29x_serdes.c new file mode 100644 index 000000000..51972cb7c --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/c29x_serdes.c @@ -0,0 +1,62 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#define SRDS1_MAX_LANES 4 + +static u32 serdes1_prtcl_map; + +struct serdes_config { + u32 protocol; + u8 lanes[SRDS1_MAX_LANES]; +}; + +static const struct serdes_config serdes1_cfg_tbl[] = { + /* SerDes 1 */ + {1, {PCIE1, PCIE1, PCIE1, PCIE1} }, + {2, {PCIE1, PCIE1, PCIE1, PCIE1} }, + {3, {PCIE1, PCIE1, NONE, NONE} }, + {4, {PCIE1, PCIE1, NONE, NONE} }, + {5, {PCIE1, NONE, NONE, NONE} }, + {6, {PCIE1, NONE, NONE, NONE} }, + {} +}; + +int is_serdes_configured(enum srds_prtcl device) +{ + return (1 << device) & 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; + const struct serdes_config *ptr; + 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; + } + + ptr = &serdes1_cfg_tbl[srds_cfg]; + if (!ptr->protocol) + return; + + for (lane = 0; lane < SRDS1_MAX_LANES; lane++) { + enum srds_prtcl lane_prtcl = ptr->lanes[lane]; + serdes1_prtcl_map |= (1 << lane_prtcl); + } +} diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cache.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cache.c new file mode 100644 index 000000000..66384f988 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cache.c @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2012 Marek Vasut + * + * This file contains stub implementation of + * invalidate_dcache_range() + * flush_dcache_range() + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +void invalidate_dcache_range(unsigned long start, unsigned long stop) +{ +} + +void flush_dcache_range(unsigned long start, unsigned long stop) +{ +} diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cmd_errata.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cmd_errata.c new file mode 100644 index 000000000..9d8acd0aa --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cmd_errata.c @@ -0,0 +1,310 @@ +/* + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#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 + +#ifdef CONFIG_SYS_FSL_ERRATUM_A007212 +/* + * This workaround can be implemented in PBI, or by u-boot. + */ +static void check_erratum_a007212(void) +{ + u32 __iomem *plldgdcr = (void *)(CONFIG_SYS_DCSRBAR + 0x21c20); + + if (in_be32(plldgdcr) & 0x1fe) { + /* check if PLL ratio is set by workaround */ + puts("Work-around for Erratum A007212 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-A003474 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_A006475 + if (SVR_MAJ(get_svr()) == 1) + puts("Work-around for Erratum A006475 enabled\n"); +#endif +#ifdef CONFIG_SYS_FSL_ERRATUM_A006384 + if (SVR_MAJ(get_svr()) == 1) + puts("Work-around for Erratum A006384 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 +#ifdef CONFIG_SYS_FSL_ERRATUM_A006379 + if (has_erratum_a006379()) + puts("Work-around for Erratum A006379 enabled\n"); +#endif +#ifdef CONFIG_SYS_FSL_ERRATUM_SEC_A003571 + if (IS_SVR_REV(svr, 1, 0)) + puts("Work-around for Erratum A003571 enabled\n"); +#endif +#ifdef CONFIG_SYS_FSL_ERRATUM_A005812 + puts("Work-around for Erratum A-005812 enabled\n"); +#endif +#ifdef CONFIG_SYS_FSL_ERRATUM_A005125 + puts("Work-around for Erratum A005125 enabled\n"); +#endif +#ifdef CONFIG_SYS_FSL_ERRATUM_A007075 + if (has_erratum_a007075()) + puts("Work-around for Erratum A007075 enabled\n"); +#endif +#ifdef CONFIG_SYS_FSL_ERRATUM_I2C_A004447 + if ((SVR_SOC_VER(svr) == SVR_8548 && IS_SVR_REV(svr, 3, 1)) || + (SVR_REV(svr) <= CONFIG_SYS_FSL_A004447_SVR_REV)) + puts("Work-around for Erratum I2C-A004447 enabled\n"); +#endif +#ifdef CONFIG_SYS_FSL_ERRATUM_A006261 + if (has_erratum_a006261()) + puts("Work-around for Erratum A006261 enabled\n"); +#endif +#ifdef CONFIG_SYS_FSL_ERRATUM_A007212 + check_erratum_a007212(); +#endif + + return 0; +} + +U_BOOT_CMD( + errata, 1, 0, do_errata, + "Report errata workarounds", + "" +); diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/commproc.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/commproc.c new file mode 100644 index 000000000..37e706238 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/commproc.c @@ -0,0 +1,186 @@ +/* + * Adapted for Motorola MPC8560 chips + * Xianghua Xiao + * + * 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 +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/config.mk b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/config.mk new file mode 100644 index 000000000..1470f95ff --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/config.mk @@ -0,0 +1,14 @@ +# +# (C) Copyright 2002,2003 Motorola Inc. +# Xianghua Xiao, X.Xiao@motorola.com +# +# SPDX-License-Identifier: GPL-2.0+ +# + +PLATFORM_CPPFLAGS += -DCONFIG_MPC85xx -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 +PLATFORM_CPPFLAGS += $(call cc-option,-mspe=yes) \ + $(call cc-option,-mno-spe) diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cpu.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cpu.c new file mode 100644 index 000000000..684d4007e --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cpu.c @@ -0,0 +1,648 @@ +/* + * 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. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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) + ccsr_gur_t __iomem *gur = + (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); +#endif + + /* + * 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 defined(CONFIG_SYS_FSL_QORIQ_CHASSIS2) && defined(CONFIG_E6500) + if (SVR_SOC_VER(svr) == SVR_T4080) { + ccsr_rcpm_t *rcpm = + (void __iomem *)(CONFIG_SYS_FSL_CORENET_RCPM_ADDR); + + setbits_be32(&gur->devdisr2, FSL_CORENET_DEVDISR2_DTSEC1_6 || + FSL_CORENET_DEVDISR2_DTSEC1_9); + setbits_be32(&gur->devdisr3, FSL_CORENET_DEVDISR3_PCIE3); + setbits_be32(&gur->devdisr5, FSL_CORENET_DEVDISR5_DDR3); + + /* It needs SW to disable core4~7 as HW design sake on T4080 */ + for (i = 4; i < 8; i++) + cpu_disable(i); + + /* request core4~7 into PH20 state, prior to entering PCL10 + * state, all cores in cluster should be placed in PH20 state. + */ + setbits_be32(&rcpm->pcph20setr, 0xf0); + + /* put the 2nd cluster into PCL10 state */ + setbits_be32(&rcpm->clpcl10setr, 1 << 1); + } +#endif + + 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); + +#ifdef CONFIG_SYS_FSL_SINGLE_SOURCE_CLK + if (sysinfo.diff_sysclk == 1) + puts("Single Source Clock Configuration\n"); +#endif + + 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.freq_processor[core])); + } + printf("\n CCB:%-4s MHz,", strmhz(buf1, sysinfo.freq_systembus)); + printf("\n"); + +#ifdef CONFIG_FSL_CORENET + if (ddr_sync == 1) { + printf(" DDR:%-4s MHz (%s MT/s data rate) " + "(Synchronous), ", + strmhz(buf1, sysinfo.freq_ddrbus/2), + strmhz(buf2, sysinfo.freq_ddrbus)); + } else { + printf(" DDR:%-4s MHz (%s MT/s data rate) " + "(Asynchronous), ", + strmhz(buf1, sysinfo.freq_ddrbus/2), + strmhz(buf2, sysinfo.freq_ddrbus)); + } +#else + switch (ddr_ratio) { + case 0x0: + printf(" DDR:%-4s MHz (%s MT/s data rate), ", + strmhz(buf1, sysinfo.freq_ddrbus/2), + strmhz(buf2, sysinfo.freq_ddrbus)); + break; + case 0x7: + printf(" DDR:%-4s MHz (%s MT/s data rate) " + "(Synchronous), ", + strmhz(buf1, sysinfo.freq_ddrbus/2), + strmhz(buf2, sysinfo.freq_ddrbus)); + break; + default: + printf(" DDR:%-4s MHz (%s MT/s data rate) " + "(Asynchronous), ", + strmhz(buf1, sysinfo.freq_ddrbus/2), + strmhz(buf2, sysinfo.freq_ddrbus)); + break; + } +#endif + +#if defined(CONFIG_FSL_LBC) + if (sysinfo.freq_localbus > LCRR_CLKDIV) { + printf("LBC:%-4s MHz\n", strmhz(buf1, sysinfo.freq_localbus)); + } else { + printf("LBC: unknown (LCRR[CLKDIV] = 0x%02lx)\n", + sysinfo.freq_localbus); + } +#endif + +#if defined(CONFIG_FSL_IFC) + printf("IFC:%-4s MHz\n", strmhz(buf1, sysinfo.freq_localbus)); +#endif + +#ifdef CONFIG_CPM2 + printf("CPM: %s MHz\n", strmhz(buf1, sysinfo.freq_systembus)); +#endif + +#ifdef CONFIG_QE + printf(" QE:%-4s MHz\n", strmhz(buf1, sysinfo.freq_qe)); +#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.freq_fman[i])); + } +#endif + +#ifdef CONFIG_SYS_DPAA_QBMAN + printf(" QMAN: %s MHz\n", strmhz(buf1, sysinfo.freq_qman)); +#endif + +#ifdef CONFIG_SYS_DPAA_PME + printf(" PME: %s MHz\n", strmhz(buf1, sysinfo.freq_pme)); +#endif + + puts("L1: D-cache 32 KiB enabled\n I-cache 32 KiB enabled\n"); + +#ifdef CONFIG_FSL_CORENET + /* Display the RCW, so that no one gets confused as to what RCW + * we're actually using for this boot. + */ + puts("Reset Configuration Word (RCW):"); + for (i = 0; i < ARRAY_SIZE(gur->rcwsr); i++) { + u32 rcw = in_be32(&gur->rcwsr[i]); + + if ((i % 4) == 0) + printf("\n %08x:", i * 4); + printf(" %08x", rcw); + } + puts("\n"); +#endif + + 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 +__weak 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) || \ + defined(CONFIG_QEMU_E500) + 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; + struct ccsr_ddr __iomem *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_FSL_DDR_ADDR; + break; +#if defined(CONFIG_SYS_FSL_DDR2_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 1) + case 1: + ddr[i] = (void *)CONFIG_SYS_FSL_DDR2_ADDR; + break; +#endif +#if defined(CONFIG_SYS_FSL_DDR3_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 2) + case 2: + ddr[i] = (void *)CONFIG_SYS_FSL_DDR3_ADDR; + break; +#endif +#if defined(CONFIG_SYS_FSL_DDR4_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 3) + case 3: + ddr[i] = (void *)CONFIG_SYS_FSL_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(struct ccsr_ddr)/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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cpu_init.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cpu_init.c new file mode 100644 index 000000000..d6cf88555 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cpu_init.c @@ -0,0 +1,940 @@ +/* + * 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. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mp.h" +#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NAND +#include +#include +#endif + +#include "../../../../drivers/block/fsl_sata.h" +#ifdef CONFIG_U_QE +#include "../../../../drivers/qe/qe.h" +#endif + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_SYS_FSL_SINGLE_SOURCE_CLK +/* + * For deriving usb clock from 100MHz sysclk, reference divisor is set + * to a value of 5, which gives an intermediate value 20(100/5). The + * multiplication factor integer is set to 24, which when multiplied to + * above intermediate value provides clock for usb ip. + */ +void usb_single_source_clk_configure(struct ccsr_usb_phy *usb_phy) +{ + sys_info_t sysinfo; + + get_sys_info(&sysinfo); + if (sysinfo.diff_sysclk == 1) { + clrbits_be32(&usb_phy->pllprg[1], + CONFIG_SYS_FSL_USB_PLLPRG2_MFI); + setbits_be32(&usb_phy->pllprg[1], + CONFIG_SYS_FSL_USB_PLLPRG2_REF_DIV_INTERNAL_CLK | + CONFIG_SYS_FSL_USB_PLLPRG2_MFI_INTERNAL_CLK | + CONFIG_SYS_FSL_USB_INTERNAL_SOC_CLK_EN); + } +} +#endif + +#ifdef CONFIG_SYS_FSL_ERRATUM_A006261 +void fsl_erratum_a006261_workaround(struct ccsr_usb_phy __iomem *usb_phy) +{ +#ifdef CONFIG_SYS_FSL_USB_DUAL_PHY_ENABLE + u32 xcvrprg = in_be32(&usb_phy->port1.xcvrprg); + + /* Increase Disconnect Threshold by 50mV */ + xcvrprg &= ~CONFIG_SYS_FSL_USB_XCVRPRG_HS_DCNT_PROG_MASK | + INC_DCNT_THRESHOLD_50MV; + /* Enable programming of USB High speed Disconnect threshold */ + xcvrprg |= CONFIG_SYS_FSL_USB_XCVRPRG_HS_DCNT_PROG_EN; + out_be32(&usb_phy->port1.xcvrprg, xcvrprg); + + xcvrprg = in_be32(&usb_phy->port2.xcvrprg); + /* Increase Disconnect Threshold by 50mV */ + xcvrprg &= ~CONFIG_SYS_FSL_USB_XCVRPRG_HS_DCNT_PROG_MASK | + INC_DCNT_THRESHOLD_50MV; + /* Enable programming of USB High speed Disconnect threshold */ + xcvrprg |= CONFIG_SYS_FSL_USB_XCVRPRG_HS_DCNT_PROG_EN; + out_be32(&usb_phy->port2.xcvrprg, xcvrprg); +#else + + u32 temp = 0; + u32 status = in_be32(&usb_phy->status1); + + u32 squelch_prog_rd_0_2 = + (status >> CONFIG_SYS_FSL_USB_SQUELCH_PROG_RD_0) + & CONFIG_SYS_FSL_USB_SQUELCH_PROG_MASK; + + u32 squelch_prog_rd_3_5 = + (status >> CONFIG_SYS_FSL_USB_SQUELCH_PROG_RD_3) + & CONFIG_SYS_FSL_USB_SQUELCH_PROG_MASK; + + setbits_be32(&usb_phy->config1, + CONFIG_SYS_FSL_USB_HS_DISCNCT_INC); + setbits_be32(&usb_phy->config2, + CONFIG_SYS_FSL_USB_RX_AUTO_CAL_RD_WR_SEL); + + temp = squelch_prog_rd_0_2 << CONFIG_SYS_FSL_USB_SQUELCH_PROG_WR_0; + out_be32(&usb_phy->config2, in_be32(&usb_phy->config2) | temp); + + temp = squelch_prog_rd_3_5 << CONFIG_SYS_FSL_USB_SQUELCH_PROG_WR_3; + out_be32(&usb_phy->config2, in_be32(&usb_phy->config2) | temp); +#endif +} +#endif + + +#if defined(CONFIG_QE) && !defined(CONFIG_U_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 +#if defined(CONFIG_RAMBOOT_PBL) || defined(CONFIG_SYS_CPC_REINIT_F) +static void disable_cpc_sram(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++) { + 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 + +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_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 +#ifdef CONFIG_SYS_FSL_ERRATUM_A006379 + if (has_erratum_a006379()) { + setbits_be32(&cpc->cpchdbcr0, + CPC_HDBCR0_SPLRU_LEVEL_EN); + } +#endif + + out_be32(&cpc->cpccsr0, CPC_CSR0_CE | CPC_CSR0_PE); + /* Read back to sync write */ + in_be32(&cpc->cpccsr0); + + } + + puts("Corenet Platform Cache: "); + print_size(size * 1024, " enabled\n"); +} + +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 + +#ifdef CONFIG_SYS_FSL_ERRATUM_A007212 +void fsl_erratum_a007212_workaround(void) +{ + ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); + u32 ddr_pll_ratio; + u32 __iomem *plldgdcr1 = (void *)(CONFIG_SYS_DCSRBAR + 0x21c20); + u32 __iomem *plldadcr1 = (void *)(CONFIG_SYS_DCSRBAR + 0x21c28); + u32 __iomem *dpdovrcr4 = (void *)(CONFIG_SYS_DCSRBAR + 0x21e80); +#if (CONFIG_NUM_DDR_CONTROLLERS >= 2) + u32 __iomem *plldgdcr2 = (void *)(CONFIG_SYS_DCSRBAR + 0x21c40); + u32 __iomem *plldadcr2 = (void *)(CONFIG_SYS_DCSRBAR + 0x21c48); +#if (CONFIG_NUM_DDR_CONTROLLERS >= 3) + u32 __iomem *plldgdcr3 = (void *)(CONFIG_SYS_DCSRBAR + 0x21c60); + u32 __iomem *plldadcr3 = (void *)(CONFIG_SYS_DCSRBAR + 0x21c68); +#endif +#endif + /* + * Even this workaround applies to selected version of SoCs, it is + * safe to apply to all versions, with the limitation of odd ratios. + * If RCW has disabled DDR PLL, we have to apply this workaround, + * otherwise DDR will not work. + */ + ddr_pll_ratio = (in_be32(&gur->rcwsr[0]) >> + FSL_CORENET_RCWSR0_MEM_PLL_RAT_SHIFT) & + FSL_CORENET_RCWSR0_MEM_PLL_RAT_MASK; + /* check if RCW sets ratio to 0, required by this workaround */ + if (ddr_pll_ratio != 0) + return; + ddr_pll_ratio = (in_be32(&gur->rcwsr[0]) >> + FSL_CORENET_RCWSR0_MEM_PLL_RAT_RESV_SHIFT) & + FSL_CORENET_RCWSR0_MEM_PLL_RAT_MASK; + /* check if reserved bits have the desired ratio */ + if (ddr_pll_ratio == 0) { + printf("Error: Unknown DDR PLL ratio!\n"); + return; + } + ddr_pll_ratio >>= 1; + + setbits_be32(plldadcr1, 0x02000001); +#if (CONFIG_NUM_DDR_CONTROLLERS >= 2) + setbits_be32(plldadcr2, 0x02000001); +#if (CONFIG_NUM_DDR_CONTROLLERS >= 3) + setbits_be32(plldadcr3, 0x02000001); +#endif +#endif + setbits_be32(dpdovrcr4, 0xe0000000); + out_be32(plldgdcr1, 0x08000001 | (ddr_pll_ratio << 1)); +#if (CONFIG_NUM_DDR_CONTROLLERS >= 2) + out_be32(plldgdcr2, 0x08000001 | (ddr_pll_ratio << 1)); +#if (CONFIG_NUM_DDR_CONTROLLERS >= 3) + out_be32(plldgdcr3, 0x08000001 | (ddr_pll_ratio << 1)); +#endif +#endif + udelay(100); + clrbits_be32(plldadcr1, 0x02000001); +#if (CONFIG_NUM_DDR_CONTROLLERS >= 2) + clrbits_be32(plldadcr2, 0x02000001); +#if (CONFIG_NUM_DDR_CONTROLLERS >= 3) + clrbits_be32(plldadcr3, 0x02000001); +#endif +#endif + clrbits_be32(dpdovrcr4, 0xe0000000); +} +#endif + +ulong cpu_init_f(void) +{ + ulong flag = 0; + 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); + +#if defined(CONFIG_SYS_CPC_REINIT_F) + disable_cpc_sram(); +#endif +#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 + +#if defined(CONFIG_QE) && !defined(CONFIG_U_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 + +#ifdef CONFIG_SYS_DCSRBAR_PHYS +#ifdef CONFIG_DEEP_SLEEP + /* disable the console if boot from deep sleep */ + if (in_be32(&gur->scrtsr[0]) & (1 << 3)) + flag = GD_FLG_SILENT | GD_FLG_DISABLE_CONSOLE; +#endif +#endif +#ifdef CONFIG_SYS_FSL_ERRATUM_A007212 + fsl_erratum_a007212_workaround(); +#endif + + return flag; +} + +/* 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); + +#if defined(CONFIG_SYS_FSL_QORIQ_CHASSIS2) && defined(CONFIG_E6500) +int enable_cluster_l2(void) +{ + int i = 0; + u32 cluster, svr = get_svr(); + ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); + struct ccsr_cluster_l2 __iomem *l2cache; + + /* only the L2 of first cluster should be enabled as expected on T4080, + * but there is no EOC in the first cluster as HW sake, so return here + * to skip enabling L2 cache of the 2nd cluster. + */ + if (SVR_SOC_VER(svr) == SVR_T4080) + return 0; + + 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) && defined(CONFIG_E6500) + 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 +#ifdef CONFIG_SYS_FSL_ERRATUM_SEC_A003571 + ccsr_sec_t __iomem *sec = (void *)CONFIG_SYS_FSL_SEC_ADDR; +#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 +#ifdef CONFIG_SYS_FSL_ERRATUM_A005812 + /* + * A-005812 workaround sets bit 32 of SPR 976 for SoCs running + * in write shadow mode. Checking DCWS before setting SPR 976. + */ + if (mfspr(L1CSR2) & L1CSR2_DCWS) + mtspr(SPRN_HDBCR0, (mfspr(SPRN_HDBCR0) | 0x80000000)); +#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 KiB "); + /* set L2E=1, L2I=1, & L2BLKSZ=1 (128 KiBibyte) */ + cache_ctl = 0xc4000000; + } else { + puts("256 KiB "); + 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 KiB "); + /* set L2E=1, L2I=1, & L2BLKSZ=2 (256 KiBibyte) */ + cache_ctl = 0xc8000000; + } else { + puts("512 KiB "); + /* set L2E=1, L2I=1, & L2SRAM=0 */ + cache_ctl = 0xc0000000; + } + break; + case 0x3: + puts("1024 KiB "); + /* 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)) + ; + print_size((l2cfg0 & 0x3fff) * 64 * 1024, " enabled\n"); + } + +skip_l2: +#elif defined(CONFIG_SYS_FSL_QORIQ_CHASSIS2) && defined(CONFIG_E6500) + if (l2cache->l2csr0 & L2CSR0_L2E) + print_size((l2cache->l2cfg0 & 0x3fff) * 64 * 1024, + " enabled\n"); + + enable_cluster_l2(); +#else + puts("disabled\n"); +#endif + +#if defined(CONFIG_RAMBOOT_PBL) + disable_cpc_sram(); +#endif + enable_cpc(); + +#ifndef CONFIG_SYS_FSL_NO_SERDES + /* needs to be in ram since code uses global static vars */ + fsl_serdes_init(); +#endif + +#ifdef CONFIG_SYS_FSL_ERRATUM_SEC_A003571 +#define MCFGR_AXIPIPE 0x000000f0 + if (IS_SVR_REV(svr, 1, 0)) + clrbits_be32(&sec->mcfgr, MCFGR_AXIPIPE); +#endif + +#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 + { + struct ccsr_usb_phy __iomem *usb_phy1 = + (void *)CONFIG_SYS_MPC85xx_USB1_PHY_ADDR; +#ifdef CONFIG_SYS_FSL_ERRATUM_A006261 + if (has_erratum_a006261()) + fsl_erratum_a006261_workaround(usb_phy1); +#endif + out_be32(&usb_phy1->usb_enable_override, + CONFIG_SYS_FSL_USB_ENABLE_OVERRIDE); + } +#endif +#ifdef CONFIG_SYS_FSL_USB2_PHY_ENABLE + { + struct ccsr_usb_phy __iomem *usb_phy2 = + (void *)CONFIG_SYS_MPC85xx_USB2_PHY_ADDR; +#ifdef CONFIG_SYS_FSL_ERRATUM_A006261 + if (has_erratum_a006261()) + fsl_erratum_a006261_workaround(usb_phy2); +#endif + 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) + struct ccsr_usb_phy __iomem *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); +#ifdef CONFIG_SYS_FSL_SINGLE_SOURCE_CLK + usb_single_source_clk_configure(usb_phy); +#endif + 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); + +#ifdef CONFIG_SYS_FSL_ERRATUM_A006261 + if (has_erratum_a006261()) + fsl_erratum_a006261_workaround(usb_phy); +#endif + +#endif /* CONFIG_SYS_FSL_USB_DUAL_PHY_ENABLE */ + +#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(®->hcontrol, HCONTROL_ENTERPRISE_EN); + + /* second SATA controller */ + reg = (void *)CONFIG_SYS_MPC85xx_SATA2_ADDR; + clrbits_le32(®->hcontrol, HCONTROL_ENTERPRISE_EN); + } +#endif + + init_used_tlb_cams(); + + return 0; +} + +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); +} + +#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_U_QE + uint qe_base = CONFIG_SYS_IMMR + 0x00140000; /* QE immr base */ +#elif defined CONFIG_QE + uint qe_base = CONFIG_SYS_IMMR + 0x00080000; /* QE immr base */ +#endif + +#ifdef CONFIG_QE + qe_init(qe_base); + qe_reset(); +#endif +} diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cpu_init_early.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cpu_init_early.c new file mode 100644 index 000000000..47b712d56 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/cpu_init_early.c @@ -0,0 +1,185 @@ +/* + * Copyright 2009-2012 Freescale Semiconductor, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +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 *fdt) +{ + 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; + +#ifdef CONFIG_QEMU_E500 + /* + * CONFIG_SYS_CCSRBAR_PHYS below may use gd->fdt_blob on ePAPR systems, + * so we need to populate it before it accesses it. + */ + gd->fdt_blob = fdt; +#endif + + 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/ether_fcc.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/ether_fcc.c new file mode 100644 index 000000000..166dc9ed1 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/ether_fcc.c @@ -0,0 +1,452 @@ +/* + * 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 + * Marius Groeger + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * 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 +#include +#include +#include +#include +#include + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +#include +#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 = ðer_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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fdt.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fdt.c new file mode 100644 index 000000000..ed80a8418 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fdt.c @@ -0,0 +1,857 @@ +/* + * Copyright 2007-2011 Freescale Semiconductor, Inc. + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_FSL_ESDHC +#include +#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); +#if defined(CONFIG_SYS_FSL_QORIQ_CHASSIS2) && defined(CONFIG_E6500) + /* Only initialize every eighth thread */ + if (reg && !((*reg) % 8)) { + fdt_setprop_cell(blob, l2_off, "cache-stash-id", + (*reg / 4) + 32 + 1); + } +#else + if (reg) { + fdt_setprop_cell(blob, l2_off, "cache-stash-id", + (*reg * 2) + 32 + 1); + } +#endif +#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.freq_fman[0]); + +#if (CONFIG_SYS_NUM_FMAN == 2) + ft_fixup_clks(blob, "fsl,fman", CONFIG_SYS_FSL_FM2_OFFSET, + sysinfo.freq_fman[1]); +#endif +#endif + +#ifdef CONFIG_SYS_DPAA_QBMAN + do_fixup_by_compat_u32(blob, "fsl,qman", + "clock-frequency", sysinfo.freq_qman, 1); +#endif + +#ifdef CONFIG_SYS_DPAA_PME + do_fixup_by_compat_u32(blob, "fsl,pme", + "clock-frequency", sysinfo.freq_pme, 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, 16); + 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 + +#if defined(CONFIG_PPC_T1040) +static void fdt_fixup_l2_switch(void *blob) +{ + uchar l2swaddr[6]; + int node; + + /* The l2switch node from device-tree has + * compatible string "vitesse-9953" */ + node = fdt_node_offset_by_compatible(blob, -1, "vitesse-9953"); + if (node == -FDT_ERR_NOTFOUND) + /* no l2switch node has been found */ + return; + + /* Get MAC address for the l2switch from "l2switchaddr"*/ + if (!eth_getenv_enetaddr("l2switchaddr", l2swaddr)) { + printf("Warning: MAC address for l2switch not found\n"); + memset(l2swaddr, 0, sizeof(l2swaddr)); + } + + /* Add MAC address to l2switch node */ + fdt_setprop(blob, node, "local-mac-address", l2swaddr, + sizeof(l2swaddr)); +} +#else +#define fdt_fixup_l2_switch(x) +#endif + +void ft_cpu_setup(void *blob, bd_t *bd) +{ + int off; + int val; + int len; + 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); + +#ifndef CONFIG_FSL_TBCLK_EXTRA_DIV +#define CONFIG_FSL_TBCLK_EXTRA_DIV 1 +#endif + do_fixup_by_prop_u32(blob, "device_type", "cpu", 4, + "timebase-frequency", get_tbclk() / CONFIG_FSL_TBCLK_EXTRA_DIV, + 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", &len); + val = cpu_to_fdt32(sysinfo.freq_processor[(*reg) / (len / 4)]); + 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", gd->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); + + fdt_fixup_l2_switch(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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c new file mode 100644 index 000000000..70e09eaed --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.c @@ -0,0 +1,226 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include "fsl_corenet2_serdes.h" + +#ifdef CONFIG_SYS_FSL_SRDS_1 +static u64 serdes1_prtcl_map; +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 +static u64 serdes2_prtcl_map; +#endif +#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", + [QSGMII_SW1_A] = "QSGMII_SW1_A", + [QSGMII_SW1_B] = "QSGMII_SW1_B", +}; +#endif + +int is_serdes_configured(enum srds_prtcl device) +{ + u64 ret = 0; + +#ifdef CONFIG_SYS_FSL_SRDS_1 + ret |= (1ULL << device) & serdes1_prtcl_map; +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + ret |= (1ULL << device) & serdes2_prtcl_map; +#endif +#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) { +#ifdef CONFIG_SYS_FSL_SRDS_1 + case FSL_SRDS_1: + cfg &= FSL_CORENET2_RCWSR4_SRDS1_PRTCL; + cfg >>= FSL_CORENET2_RCWSR4_SRDS1_PRTCL_SHIFT; + break; +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + case FSL_SRDS_2: + cfg &= FSL_CORENET2_RCWSR4_SRDS2_PRTCL; + cfg >>= FSL_CORENET2_RCWSR4_SRDS2_PRTCL_SHIFT; + break; +#endif +#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) +{ + +#ifdef CONFIG_SYS_FSL_SRDS_1 + 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); +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + 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); +#endif +#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 + +} + +const char *serdes_clock_to_string(u32 clock) +{ + switch (clock) { + case SRDS_PLLCR0_RFCK_SEL_100: + return "100"; + case SRDS_PLLCR0_RFCK_SEL_125: + return "125"; + case SRDS_PLLCR0_RFCK_SEL_156_25: + return "156.25"; + case SRDS_PLLCR0_RFCK_SEL_161_13: + return "161.1328123"; + default: +#if defined(CONFIG_T4240QDS) + return "???"; +#else + return "122.88"; +#endif + } +} + diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.h b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.h new file mode 100644 index 000000000..d515b234a --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fsl_corenet2_serdes.h @@ -0,0 +1,12 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#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); +#endif /* __FSL_CORENET2_SERDES_H */ diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c new file mode 100644 index 000000000..ba22f90a6 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c @@ -0,0 +1,877 @@ +/* + * Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#ifdef CONFIG_SYS_P4080_ERRATUM_SERDES8 +#include +#endif +#include +#include +#include +#include +#include +#include +#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(®s->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(®s->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(®s->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(®s->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(®s->bank[FSL_SRDS_BANK_3].pllcr0, + SRDS_PLLCR0_RFCK_SEL_MASK, rfck_sel); + + clrsetbits_be32(®s->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(®s->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(®s->bank[FSL_SRDS_BANK_1].pllcr1, + SRDS_PLLCR1_PLL_BWSEL); + setbits_be32(®s->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(®s->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 _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 +} + +const char *serdes_clock_to_string(u32 clock) +{ + switch (clock) { + case SRDS_PLLCR0_RFCK_SEL_100: + return "100"; + case SRDS_PLLCR0_RFCK_SEL_125: + return "125"; + case SRDS_PLLCR0_RFCK_SEL_156_25: + return "156.25"; + case SRDS_PLLCR0_RFCK_SEL_161_13: + return "161.1328123"; + default: + return "150"; + } +} + diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.h b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.h new file mode 100644 index 000000000..c02dd20af --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.h @@ -0,0 +1,28 @@ +/* + * Copyright 2009-2010 Freescale Semiconductor, Inc. + * + * Author: Roy Zang + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/interrupts.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/interrupts.c new file mode 100644 index 000000000..a36a4af9d --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/interrupts.c @@ -0,0 +1,110 @@ +/* + * (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) + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#ifdef CONFIG_POST +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/liodn.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/liodn.c new file mode 100644 index 000000000..19e130e87 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/liodn.c @@ -0,0 +1,359 @@ +/* + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +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 + +static void fdt_fixup_pci_liodn_offsets(void *fdt, const char *compat, + int ep_liodn_start) +{ + 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] = 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 + + ccsr_pcix_t *pcix = (ccsr_pcix_t *)CONFIG_SYS_PCIE1_ADDR; + int pci_ver = pcix->ipver1 & 0xffff, liodn_base = 0; + + if (pci_ver >= 0x0204) { + if (pci_ver >= 0x0300) + liodn_base = 1024; + else + liodn_base = 256; + } + + if (liodn_base) { + char compat[32]; + + sprintf(compat, "fsl,qoriq-pcie-v%d.%d", + (pci_ver & 0xff00) >> 8, pci_ver & 0xff); + fdt_fixup_pci_liodn_offsets(blob, compat, liodn_base); + fdt_fixup_pci_liodn_offsets(blob, "fsl,qoriq-pcie", liodn_base); + } +} diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mp.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mp.c new file mode 100644 index 000000000..88c8e6593 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mp.c @@ -0,0 +1,472 @@ +/* + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mp.h b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mp.h new file mode 100644 index 000000000..ad9950bcf --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mp.h @@ -0,0 +1,21 @@ +#ifndef __MPC85XX_MP_H_ +#define __MPC85XX_MP_H_ + +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c new file mode 100644 index 000000000..baf52d549 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c @@ -0,0 +1,233 @@ +/* + * Copyright 2008,2010 Freescale Semiconductor, Inc. + * Dave Liu + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +/* 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c new file mode 100644 index 000000000..ed78a66f5 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c @@ -0,0 +1,79 @@ +/* + * Copyright 2010 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c new file mode 100644 index 000000000..d14695506 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c @@ -0,0 +1,49 @@ +/* + * Copyright 2010 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c new file mode 100644 index 000000000..9199f01b9 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c @@ -0,0 +1,49 @@ +/* + * Copyright 2010 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c new file mode 100644 index 000000000..6c80b5e4b --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c @@ -0,0 +1,58 @@ +/* + * Copyright 2010 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c new file mode 100644 index 000000000..3632eb557 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c @@ -0,0 +1,65 @@ +/* + * Copyright 2010 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p1010_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p1010_serdes.c new file mode 100644 index 000000000..4b965f7a0 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p1010_serdes.c @@ -0,0 +1,72 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Author: Prabhakar Kushwaha + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p1021_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p1021_serdes.c new file mode 100644 index 000000000..99a77bd2b --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p1021_serdes.c @@ -0,0 +1,95 @@ +/* + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p1022_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p1022_serdes.c new file mode 100644 index 000000000..14d17eb51 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p1022_serdes.c @@ -0,0 +1,111 @@ +/* + * Copyright 2010 Freescale Semiconductor, Inc. + * Author: Timur Tabi + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p1023_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p1023_serdes.c new file mode 100644 index 000000000..e83b0a335 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p1023_serdes.c @@ -0,0 +1,50 @@ +/* + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * Author: Roy Zang + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p2020_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p2020_serdes.c new file mode 100644 index 000000000..59d402c96 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p2020_serdes.c @@ -0,0 +1,57 @@ +/* + * Copyright 2010 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p2041_ids.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p2041_ids.c new file mode 100644 index 000000000..488e07846 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p2041_ids.c @@ -0,0 +1,113 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p2041_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p2041_serdes.c new file mode 100644 index 000000000..f278549cb --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p2041_serdes.c @@ -0,0 +1,90 @@ +/* + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p3041_ids.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p3041_ids.c new file mode 100644 index 000000000..7d98870e3 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p3041_ids.c @@ -0,0 +1,112 @@ +/* + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p3041_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p3041_serdes.c new file mode 100644 index 000000000..c88c78c4e --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p3041_serdes.c @@ -0,0 +1,135 @@ +/* + * Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p4080_ids.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p4080_ids.c new file mode 100644 index 000000000..b2a23c0c9 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p4080_ids.c @@ -0,0 +1,112 @@ +/* + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p4080_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p4080_serdes.c new file mode 100644 index 000000000..e719d322e --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p4080_serdes.c @@ -0,0 +1,82 @@ +/* + * Copyright 2009-2010 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p5020_ids.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p5020_ids.c new file mode 100644 index 000000000..b5d787c8e --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p5020_ids.c @@ -0,0 +1,125 @@ +/* + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p5020_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p5020_serdes.c new file mode 100644 index 000000000..c88c78c4e --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p5020_serdes.c @@ -0,0 +1,135 @@ +/* + * Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p5040_ids.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p5040_ids.c new file mode 100644 index 000000000..990f17949 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p5040_ids.c @@ -0,0 +1,111 @@ +/* + * Copyright 2010-2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p5040_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p5040_serdes.c new file mode 100644 index 000000000..2655974a4 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/p5040_serdes.c @@ -0,0 +1,101 @@ +/* + * Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/pci.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/pci.c new file mode 100644 index 000000000..c6d2fda5d --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/pci.c @@ -0,0 +1,214 @@ +/* + * Copyright 2004 Freescale Semiconductor. + * Copyright (C) 2003 Motorola Inc. + * Xianghua Xiao (x.xiao@motorola.com) + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * PCI Configuration space access support for MPC85xx PCI Bridge + */ +#include +#include +#include + +#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, ®16); + 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, ®16); + 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/portals.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/portals.c new file mode 100644 index 000000000..98815f8e1 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/portals.c @@ -0,0 +1,308 @@ +/* + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#include +#include + +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/qe_io.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/qe_io.c new file mode 100644 index 000000000..d2825ec36 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/qe_io.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2006 Freescale Semiconductor, Inc. + * + * Dave Liu + * based on source code of Shlomi Gridish + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "common.h" +#include "asm/errno.h" +#include "asm/io.h" +#include "asm/immap_85xx.h" + +#if defined(CONFIG_QE) && !defined(CONFIG_U_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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/release.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/release.S new file mode 100644 index 000000000..a2c0ad424 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/release.S @@ -0,0 +1,487 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor, Inc. + * Kumar Gala + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +/* 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_SYS_FSL_ERRATUM_A005812 + /* + * A-005812 workaround sets bit 32 of SPR 976 for SoCs running in + * write shadow mode. This code should run after other code setting + * DCWS. + */ + mfspr r3,L1CSR2 + andis. r3,r3,(L1CSR2_DCWS)@h + beq 1f + mfspr r3, SPRN_HDBCR0 + oris r3, r3, 0x8000 + mtspr SPRN_HDBCR0, r3 +1: +#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 + + /* 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/resetvec.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/resetvec.S new file mode 100644 index 000000000..29555d4a0 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/resetvec.S @@ -0,0 +1,2 @@ + .section .resetvec,"ax" + b _start_e500 diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/serial_scc.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/serial_scc.c new file mode 100644 index 000000000..faba6421f --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/serial_scc.c @@ -0,0 +1,262 @@ +/* + * (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. + * + * SPDX-License-Identifier: GPL-2.0+ + * + * 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 +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/speed.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/speed.c new file mode 100644 index 000000000..3236f6a5d --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/speed.c @@ -0,0 +1,532 @@ +/* + * 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. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + + +#ifndef CONFIG_SYS_FSL_NUM_CC_PLLS +#define CONFIG_SYS_FSL_NUM_CC_PLLS 6 +#endif +/* --------------------------------------------------------------- */ + +void get_sys_info(sys_info_t *sys_info) +{ + 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; +#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2 + int cc_group[12] = CONFIG_SYS_FSL_CLUSTER_CLOCKS; +#endif + + 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, freq_c_pll[CONFIG_SYS_FSL_NUM_CC_PLLS]; +#if !defined(CONFIG_FM_PLAT_CLK_DIV) || !defined(CONFIG_PME_PLAT_CLK_DIV) + uint rcw_tmp; +#endif + uint ratio[CONFIG_SYS_FSL_NUM_CC_PLLS]; + unsigned long sysclk = CONFIG_SYS_CLK_FREQ; + uint mem_pll_rat; + + sys_info->freq_systembus = sysclk; +#ifdef CONFIG_SYS_FSL_SINGLE_SOURCE_CLK + uint ddr_refclk_sel; + unsigned int porsr1_sys_clk; + porsr1_sys_clk = in_be32(&gur->porsr1) >> FSL_DCFG_PORSR1_SYSCLK_SHIFT + & FSL_DCFG_PORSR1_SYSCLK_MASK; + if (porsr1_sys_clk == FSL_DCFG_PORSR1_SYSCLK_DIFF) + sys_info->diff_sysclk = 1; + else + sys_info->diff_sysclk = 0; + + /* + * DDR_REFCLK_SEL rcw bit is used to determine if DDR PLLS + * are driven by separate DDR Refclock or single source + * differential clock. + */ + ddr_refclk_sel = (in_be32(&gur->rcwsr[5]) >> + FSL_CORENET2_RCWSR5_DDR_REFCLK_SEL_SHIFT) & + FSL_CORENET2_RCWSR5_DDR_REFCLK_SEL_MASK; + /* + * For single source clocking, both ddrclock and sysclock + * are driven by differential sysclock. + */ + if (ddr_refclk_sel == FSL_CORENET2_RCWSR5_DDR_REFCLK_SINGLE_CLK) + sys_info->freq_ddrbus = CONFIG_SYS_CLK_FREQ; + else +#endif +#ifdef CONFIG_DDR_CLK_FREQ + sys_info->freq_ddrbus = CONFIG_DDR_CLK_FREQ; +#else + sys_info->freq_ddrbus = sysclk; +#endif + + sys_info->freq_systembus *= (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; +#ifdef CONFIG_SYS_FSL_ERRATUM_A007212 + if (mem_pll_rat == 0) { + mem_pll_rat = (in_be32(&gur->rcwsr[0]) >> + FSL_CORENET_RCWSR0_MEM_PLL_RAT_RESV_SHIFT) & + FSL_CORENET_RCWSR0_MEM_PLL_RAT_MASK; + } +#endif + /* T4240/T4160 Rev2.0 MEM_PLL_RAT uses a value which is half of + * T4240/T4160 Rev1.0. eg. It's 12 in Rev1.0, however, for Rev2.0 + * it uses 6. + */ +#if defined(CONFIG_PPC_T4240) || defined(CONFIG_PPC_T4160) || \ + defined(CONFIG_PPC_T4080) + if (SVR_MAJ(get_svr()) >= 2) + mem_pll_rat *= 2; +#endif + if (mem_pll_rat > 2) + sys_info->freq_ddrbus *= mem_pll_rat; + else + sys_info->freq_ddrbus = sys_info->freq_systembus * mem_pll_rat; + + for (i = 0; i < CONFIG_SYS_FSL_NUM_CC_PLLS; i++) { + ratio[i] = (in_be32(&clk->pllcgsr[i].pllcngsr) >> 1) & 0x3f; + if (ratio[i] > 4) + freq_c_pll[i] = sysclk * ratio[i]; + else + freq_c_pll[i] = sys_info->freq_systembus * ratio[i]; + } +#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2 + /* + * As per CHASSIS2 architeture total 12 clusters are posible and + * Each cluster has up to 4 cores, sharing the same PLL selection. + * The cluster clock assignment is SoC defined. + * + * Total 4 clock groups are possible with 3 PLLs each. + * as per array indices, clock group A has 0, 1, 2 numbered PLLs & + * clock group B has 3, 4, 6 and so on. + * + * Clock group A having PLL1, PLL2, PLL3, feeding cores of any cluster + * depends upon the SoC architeture. Same applies to other + * clock groups and clusters. + * + */ + 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]; + cplx_pll += cc_group[cluster] - 1; + sys_info->freq_processor[cpu] = + freq_c_pll[cplx_pll] / core_cplx_pll_div[c_pll_sel]; + } +#if defined(CONFIG_PPC_B4860) || defined(CONFIG_PPC_B4420) || \ + defined(CONFIG_PPC_T2080) || defined(CONFIG_PPC_T2081) +#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 +#if !defined(CONFIG_FM_PLAT_CLK_DIV) || !defined(CONFIG_PME_PLAT_CLK_DIV) + rcw_tmp = in_be32(&gur->rcwsr[7]); +#endif + +#ifdef CONFIG_SYS_DPAA_PME +#ifndef CONFIG_PME_PLAT_CLK_DIV + switch ((rcw_tmp & PME_CLK_SEL) >> PME_CLK_SHIFT) { + case 1: + sys_info->freq_pme = freq_c_pll[CONFIG_SYS_PME_CLK]; + break; + case 2: + sys_info->freq_pme = freq_c_pll[CONFIG_SYS_PME_CLK] / 2; + break; + case 3: + sys_info->freq_pme = freq_c_pll[CONFIG_SYS_PME_CLK] / 3; + break; + case 4: + sys_info->freq_pme = freq_c_pll[CONFIG_SYS_PME_CLK] / 4; + break; + case 6: + sys_info->freq_pme = freq_c_pll[CONFIG_SYS_PME_CLK + 1] / 2; + break; + case 7: + sys_info->freq_pme = freq_c_pll[CONFIG_SYS_PME_CLK + 1] / 3; + break; + default: + printf("Error: Unknown PME clock select!\n"); + case 0: + sys_info->freq_pme = sys_info->freq_systembus / 2; + break; + + } +#else + sys_info->freq_pme = sys_info->freq_systembus / CONFIG_SYS_PME_CLK; + +#endif +#endif + +#ifdef CONFIG_SYS_DPAA_QBMAN + sys_info->freq_qman = sys_info->freq_systembus / 2; +#endif + +#ifdef CONFIG_SYS_DPAA_FMAN +#ifndef CONFIG_FM_PLAT_CLK_DIV + switch ((rcw_tmp & FM1_CLK_SEL) >> FM1_CLK_SHIFT) { + case 1: + sys_info->freq_fman[0] = freq_c_pll[CONFIG_SYS_FM1_CLK]; + break; + case 2: + sys_info->freq_fman[0] = freq_c_pll[CONFIG_SYS_FM1_CLK] / 2; + break; + case 3: + sys_info->freq_fman[0] = freq_c_pll[CONFIG_SYS_FM1_CLK] / 3; + break; + case 4: + sys_info->freq_fman[0] = freq_c_pll[CONFIG_SYS_FM1_CLK] / 4; + break; + case 5: + sys_info->freq_fman[0] = sys_info->freq_systembus; + break; + case 6: + sys_info->freq_fman[0] = freq_c_pll[CONFIG_SYS_FM1_CLK + 1] / 2; + break; + case 7: + sys_info->freq_fman[0] = freq_c_pll[CONFIG_SYS_FM1_CLK + 1] / 3; + break; + default: + printf("Error: Unknown FMan1 clock select!\n"); + case 0: + sys_info->freq_fman[0] = sys_info->freq_systembus / 2; + break; + } +#if (CONFIG_SYS_NUM_FMAN) == 2 +#ifdef CONFIG_SYS_FM2_CLK +#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: + sys_info->freq_fman[1] = freq_c_pll[CONFIG_SYS_FM2_CLK + 1]; + break; + case 2: + sys_info->freq_fman[1] = freq_c_pll[CONFIG_SYS_FM2_CLK + 1] / 2; + break; + case 3: + sys_info->freq_fman[1] = freq_c_pll[CONFIG_SYS_FM2_CLK + 1] / 3; + break; + case 4: + sys_info->freq_fman[1] = freq_c_pll[CONFIG_SYS_FM2_CLK + 1] / 4; + break; + case 5: + sys_info->freq_fman[1] = sys_info->freq_systembus; + break; + case 6: + sys_info->freq_fman[1] = freq_c_pll[CONFIG_SYS_FM2_CLK] / 2; + break; + case 7: + sys_info->freq_fman[1] = freq_c_pll[CONFIG_SYS_FM2_CLK] / 3; + break; + default: + printf("Error: Unknown FMan2 clock select!\n"); + case 0: + sys_info->freq_fman[1] = sys_info->freq_systembus / 2; + break; + } +#endif +#endif /* CONFIG_SYS_NUM_FMAN == 2 */ +#else + sys_info->freq_fman[0] = sys_info->freq_systembus / CONFIG_SYS_FM1_CLK; +#endif +#endif + +#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]; + + sys_info->freq_processor[cpu] = + freq_c_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) + sys_info->freq_pme = freq_c_pll[HWA_CC_PLL] / 4; + else + sys_info->freq_pme = freq_c_pll[HWA_CC_PLL] / 2; + } else { + sys_info->freq_pme = sys_info->freq_systembus / 2; + } +#endif + +#ifdef CONFIG_SYS_DPAA_FMAN + if (rcw_tmp & FM1_CLK_SEL) { + if (rcw_tmp & HWA_ASYNC_DIV) + sys_info->freq_fman[0] = freq_c_pll[HWA_CC_PLL] / 4; + else + sys_info->freq_fman[0] = freq_c_pll[HWA_CC_PLL] / 2; + } else { + sys_info->freq_fman[0] = sys_info->freq_systembus / 2; + } +#if (CONFIG_SYS_NUM_FMAN) == 2 + if (rcw_tmp & FM2_CLK_SEL) { + if (rcw_tmp & HWA_ASYNC_DIV) + sys_info->freq_fman[1] = freq_c_pll[HWA_CC_PLL] / 4; + else + sys_info->freq_fman[1] = freq_c_pll[HWA_CC_PLL] / 2; + } else { + sys_info->freq_fman[1] = sys_info->freq_systembus / 2; + } +#endif +#endif + +#ifdef CONFIG_SYS_DPAA_QBMAN + sys_info->freq_qman = sys_info->freq_systembus / 2; +#endif + +#endif /* CONFIG_SYS_FSL_QORIQ_CHASSIS2 */ + +#ifdef CONFIG_U_QE + sys_info->freq_qe = sys_info->freq_systembus / 2; +#endif + +#else /* CONFIG_FSL_CORENET */ + uint plat_ratio, e500_ratio, half_freq_systembus; + int i; +#ifdef CONFIG_QE + __maybe_unused u32 qe_ratio; +#endif + + plat_ratio = (gur->porpllsr) & 0x0000003e; + plat_ratio >>= 1; + sys_info->freq_systembus = plat_ratio * CONFIG_SYS_CLK_FREQ; + + /* Divide before multiply to avoid integer + * overflow for processor speeds above 2GHz */ + half_freq_systembus = sys_info->freq_systembus/2; + for (i = 0; i < cpu_numcores(); i++) { + e500_ratio = ((gur->porpllsr) >> (i * 8 + 16)) & 0x3f; + sys_info->freq_processor[i] = e500_ratio * half_freq_systembus; + } + + /* Note: freq_ddrbus is the MCLK frequency, not the data rate. */ + sys_info->freq_ddrbus = sys_info->freq_systembus; + +#ifdef CONFIG_DDR_CLK_FREQ + { + u32 ddr_ratio = ((gur->porpllsr) & MPC85xx_PORPLLSR_DDR_RATIO) + >> MPC85xx_PORPLLSR_DDR_RATIO_SHIFT; + if (ddr_ratio != 0x7) + sys_info->freq_ddrbus = ddr_ratio * CONFIG_DDR_CLK_FREQ; + } +#endif + +#ifdef CONFIG_QE +#if defined(CONFIG_P1012) || defined(CONFIG_P1021) || defined(CONFIG_P1025) + sys_info->freq_qe = sys_info->freq_systembus; +#else + qe_ratio = ((gur->porpllsr) & MPC85xx_PORPLLSR_QE_RATIO) + >> MPC85xx_PORPLLSR_QE_RATIO_SHIFT; + sys_info->freq_qe = qe_ratio * CONFIG_SYS_CLK_FREQ; +#endif +#endif + +#ifdef CONFIG_SYS_DPAA_FMAN + sys_info->freq_fman[0] = sys_info->freq_systembus; +#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 + sys_info->freq_localbus = sys_info->freq_systembus / lcrr_div; + } else { + /* In case anyone cares what the unknown value is */ + sys_info->freq_localbus = 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; + + sys_info->freq_localbus = sys_info->freq_systembus / 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.freq_processor[0]; + gd->bus_clk = sys_info.freq_systembus; + gd->mem_clk = sys_info.freq_ddrbus; + gd->arch.lbc_clk = sys_info.freq_localbus; + +#ifdef CONFIG_QE + gd->arch.qe_clk = sys_info.freq_qe; + 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) || \ + defined(CONFIG_P1022) + gd->arch.i2c1_clk = sys_info.freq_systembus; +#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.freq_systembus / 3; + else + gd->arch.i2c1_clk = sys_info.freq_systembus / 2; +#else + /* Most 85xx SOCs use CCB/2, so this is the default behavior. */ + gd->arch.i2c1_clk = sys_info.freq_systembus / 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.freq_systembus; + 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/spl_minimal.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/spl_minimal.c new file mode 100644 index 000000000..cc45f715e --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/spl_minimal.c @@ -0,0 +1,45 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +ulong 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 + + return 0; +} + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/start.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/start.S new file mode 100644 index 000000000..d8c9fb6b2 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/start.S @@ -0,0 +1,1978 @@ +/* + * Copyright 2004, 2007-2012 Freescale Semiconductor, Inc. + * Copyright (C) 2003 Motorola,Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* 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 +#include +#include +#include + +#include +#include + +#include +#include + +#undef MSR_KERNEL +#define MSR_KERNEL ( MSR_ME ) /* Machine Check */ + +#define LAW_EN 0x80000000 + +#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) && !defined(CONFIG_SRIO_PCIE_BOOT_SLAVE) +#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 + + /* + * If we got an ePAPR device tree pointer passed in as r3, we need that + * later in cpu_init_early_f(). Save it to a safe register before we + * clobber it so that we can fetch it from there later. + */ + mr r24, r3 + +#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 +#ifdef CONFIG_SYS_FSL_ERRATUM_A005125 + msync + isync + mfspr r3, SPRN_HDBCR0 + oris r3, r3, 0x0080 + mtspr SPRN_HDBCR0, r3 +#endif + + +#if defined(CONFIG_SECURE_BOOT) && defined(CONFIG_E500MC) && \ + !defined(CONFIG_E6500) + /* 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 + +#if !defined(CONFIG_E500MC) && !defined(CONFIG_QEMU_E500) + 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) && \ + !defined(CONFIG_SECURE_BOOT) +/* + * 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 + +#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_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) */ + +#if defined(CONFIG_SYS_FSL_QORIQ_CHASSIS2) && defined(CONFIG_E6500) +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 +#ifdef CONFIG_RAMBOOT_PBL + erratum_set_ccsr 0x10f00 0x495e5000 +#else + erratum_set_ccsr 0x10f00 0x415e5000 +#endif + 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 + + /* Pass our potential ePAPR device tree pointer to cpu_init_early_f */ + mr r3, r24 + + 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 /* return boot_flag for calling board_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 +#ifndef CONFIG_SPL_SKIP_RELOCATE + 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! */ +#endif + .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 +#endif /* !MINIMAL_SPL */ diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t1040_ids.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t1040_ids.c new file mode 100644 index 000000000..1034cd485 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t1040_ids.c @@ -0,0 +1,84 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#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), +}; +#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_NEXUS_LIODN(557), -- not yet implemented */ + SET_QE_LIODN(559), +}; +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), +}; +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); + +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 +}; diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t1040_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t1040_serdes.c new file mode 100644 index 000000000..d86bb2737 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t1040_serdes.c @@ -0,0 +1,68 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + + +static u8 serdes_cfg_tbl[][SRDS_MAX_LANES] = { + [0x00] = {PCIE1, PCIE1, PCIE1, PCIE1, + PCIE2, PCIE2, PCIE2, PCIE2}, + [0x06] = {PCIE1, PCIE1, PCIE1, PCIE1, + PCIE2, PCIE3, PCIE4, SATA1}, + [0x08] = {PCIE1, PCIE1, PCIE1, PCIE1, + PCIE2, PCIE3, SATA2, SATA1}, + [0x40] = {PCIE1, PCIE1, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + PCIE2, PCIE2, PCIE2, PCIE2}, + [0x60] = {PCIE1, SGMII_FM1_DTSEC3, QSGMII_SW1_A, QSGMII_SW1_B, + PCIE2, PCIE2, PCIE2, PCIE2}, + [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}, + [0x69] = {PCIE1, SGMII_FM1_DTSEC3, QSGMII_SW1_A, QSGMII_SW1_B, + PCIE2, PCIE3, SGMII_FM1_DTSEC4, SATA1}, + [0x86] = {PCIE1, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + PCIE2, PCIE3, PCIE4, SATA1}, + [0x85] = {PCIE1, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + PCIE2, PCIE2, SGMII_FM1_DTSEC4, SGMII_FM1_DTSEC5}, + [0x87] = {PCIE1, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + PCIE2, PCIE3, PCIE4, SGMII_FM1_DTSEC5}, + [0x89] = {PCIE1, QSGMII_SW1_A, QSGMII_SW1_A, QSGMII_SW1_A, + PCIE2, PCIE3, QSGMII_SW1_B, SATA1}, + [0x8D] = {PCIE1, QSGMII_SW1_A, QSGMII_SW1_A, QSGMII_SW1_A, + PCIE2, QSGMII_SW1_B, QSGMII_SW1_B, QSGMII_SW1_B}, + [0x8F] = {PCIE1, SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + AURORA, NONE, 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}, + [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}, +}; + +enum srds_prtcl serdes_get_prtcl(int serdes, int cfg, int lane) +{ + return serdes_cfg_tbl[cfg][lane]; +} + +int is_serdes_prtcl_valid(int serdes, 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t2080_ids.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t2080_ids.c new file mode 100644 index 000000000..0bfd44738 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t2080_ids.c @@ -0,0 +1,144 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#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), +}; +#endif + +#ifdef CONFIG_SYS_SRIO +struct srio_liodn_id_table srio_liodn_tbl[] = { + SET_SRIO_LIODN_BASE(1, 307), + SET_SRIO_LIODN_BASE(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_PME_LIODN(117), + + SET_USB_LIODN(1, "fsl-usb2-mph", 553), + SET_USB_LIODN(2, "fsl-usb2-dr", 554), + +#ifdef CONFIG_FSL_SATA_V2 + SET_SATA_LIODN(1, 555), + SET_SATA_LIODN(2, 556), +#endif + + SET_PCI_LIODN_BASE(CONFIG_SYS_FSL_PCIE_COMPAT, 1, 148), + SET_PCI_LIODN_BASE(CONFIG_SYS_FSL_PCIE_COMPAT, 2, 228), + SET_PCI_LIODN_BASE(CONFIG_SYS_FSL_PCIE_COMPAT, 3, 308), + SET_PCI_LIODN_BASE(CONFIG_SYS_FSL_PCIE_COMPAT, 4, 388), + + SET_DMA_LIODN(1, 147), + SET_DMA_LIODN(2, 227), + SET_DMA_LIODN(3, 226), + + 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); +#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, 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[] = { +#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), +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t2080_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t2080_serdes.c new file mode 100644 index 000000000..07e27deb1 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t2080_serdes.c @@ -0,0 +1,207 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * Shengzhou Liu + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include "fsl_corenet2_serdes.h" + +struct serdes_config { + u32 protocol; + u8 lanes[SRDS_MAX_LANES]; +}; + +static const struct serdes_config serdes1_cfg_tbl[] = { + /* SerDes 1 */ + {0x6E, {XFI_FM1_MAC9, XFI_FM1_MAC10, + SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + PCIE4, PCIE4, SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0xBC, {PCIE3, PCIE3, SGMII_FM1_DTSEC1, + SGMII_FM1_DTSEC2, PCIE4, PCIE4, PCIE4, PCIE4} }, + {0xC8, {PCIE3, SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC1, + SGMII_FM1_DTSEC2, PCIE4, PCIE4, + SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0xD6, {PCIE3, SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC1, + SGMII_FM1_DTSEC2, PCIE4, PCIE4, + SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0xDE, {PCIE3, PCIE3, PCIE3, PCIE3, + PCIE4, PCIE1, PCIE2, SGMII_FM1_DTSEC6} }, + {0xE0, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, + PCIE1, SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0xF2, {PCIE3, SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC1, + SGMII_FM1_DTSEC2, PCIE4, PCIE1, PCIE2, SGMII_FM1_DTSEC6} }, + {0xF8, {PCIE3, SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC1, + SGMII_FM1_DTSEC2, PCIE4, PCIE1, PCIE2, SGMII_FM1_DTSEC6} }, + {0xFA, {PCIE3, SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC1, + SGMII_FM1_DTSEC2, PCIE4, PCIE1, + SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0x6C, {XFI_FM1_MAC9, XFI_FM1_MAC10, + SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + PCIE4, PCIE4, PCIE4, PCIE4} }, + {0x1C, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC10, + SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, + SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0x95, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC10, + SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, + SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0xA2, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC10, + SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, + SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0x94, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC10, + SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + SGMII_FM1_DTSEC3, SGMII_FM1_DTSEC4, + SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0x51, {XAUI_FM1_MAC9, XAUI_FM1_MAC9, + XAUI_FM1_MAC9, XAUI_FM1_MAC9, + PCIE4, SGMII_FM1_DTSEC4, + SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0x5F, {HIGIG_FM1_MAC9, HIGIG_FM1_MAC9, + HIGIG_FM1_MAC9, HIGIG_FM1_MAC9, + PCIE4, SGMII_FM1_DTSEC4, + SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0x65, {HIGIG_FM1_MAC9, HIGIG_FM1_MAC9, + HIGIG_FM1_MAC9, HIGIG_FM1_MAC9, + PCIE4, SGMII_FM1_DTSEC4, + SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0x6B, {XFI_FM1_MAC9, XFI_FM1_MAC10, + XFI_FM1_MAC1, XFI_FM1_MAC2, + PCIE4, SGMII_FM1_DTSEC4, + SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0x6D, {XFI_FM1_MAC9, XFI_FM1_MAC10, + SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + PCIE4, PCIE4, PCIE4, PCIE4} }, + {0x71, {XFI_FM1_MAC9, XFI_FM1_MAC10, + SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, PCIE4, + SGMII_FM1_DTSEC4, SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0xA6, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC10, + SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, PCIE4, + PCIE4, SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0x8E, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC10, + SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, PCIE4, + PCIE4, SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0x8F, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC10, + SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, PCIE4, + PCIE4, SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0x82, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC10, + SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + PCIE4, PCIE4, SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0x83, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC10, + SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + PCIE4, PCIE4, SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0xA4, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC10, + SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + PCIE4, PCIE4, PCIE4, PCIE4} }, + {0x96, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC10, + SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + PCIE4, PCIE4, PCIE4, PCIE4} }, + {0x8A, {SGMII_FM1_DTSEC9, SGMII_FM1_DTSEC10, + SGMII_FM1_DTSEC1, SGMII_FM1_DTSEC2, + PCIE4, PCIE4, PCIE4, PCIE4} }, + {0x67, {XFI_FM1_MAC9, XFI_FM1_MAC10, + XFI_FM1_MAC1, XFI_FM1_MAC2, + PCIE4, PCIE4, PCIE4, PCIE4} }, + {0xAB, {PCIE3, PCIE3, PCIE3, PCIE3, + PCIE4, PCIE4, PCIE4, PCIE4} }, + {0xDA, {PCIE3, PCIE3, PCIE3, PCIE3, + PCIE3, PCIE3, PCIE3, PCIE3} }, + {0xD9, {PCIE3, SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC1, + SGMII_FM1_DTSEC2, PCIE4, SGMII_FM1_DTSEC4, + SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0xD3, {PCIE3, SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC1, + SGMII_FM1_DTSEC2, PCIE4, SGMII_FM1_DTSEC4, + SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0xCB, {PCIE3, SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC1, + SGMII_FM1_DTSEC2, PCIE4, SGMII_FM1_DTSEC4, + SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0xD8, {PCIE3, SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC1, + SGMII_FM1_DTSEC2, PCIE4, SGMII_FM1_DTSEC4, + SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0x66, {XFI_FM1_MAC9, XFI_FM1_MAC10, + XFI_FM1_MAC1, XFI_FM1_MAC2, + PCIE4, PCIE4, PCIE4, PCIE4} }, + +#if defined(CONFIG_PPC_T2081) + {0xAA, {PCIE3, PCIE3, PCIE3, PCIE3, + PCIE4, PCIE4, PCIE4, PCIE4} }, + {0xCA, {PCIE3, SGMII_FM1_DTSEC10, SGMII_FM1_DTSEC1, + SGMII_FM1_DTSEC2, PCIE4, SGMII_FM1_DTSEC4, + SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, + {0x70, {XFI_FM1_MAC9, XFI_FM1_MAC10, SGMII_FM1_DTSEC1, + SGMII_FM1_DTSEC2, PCIE4, SGMII_FM1_DTSEC4, + SGMII_FM1_DTSEC5, SGMII_FM1_DTSEC6} }, +#endif + {} +}; + +#ifndef CONFIG_PPC_T2081 +static const struct serdes_config serdes2_cfg_tbl[] = { + /* SerDes 2 */ + {0x1F, {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2} }, + {0x16, {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, SATA1, SATA2} }, + {0x01, {PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1} }, + {0x29, {SRIO2, SRIO2, SRIO2, SRIO2, SRIO1, SRIO1, SRIO1, SRIO1} }, + {0x2D, {SRIO2, SRIO2, SRIO2, SRIO2, SRIO1, SRIO1, SRIO1, SRIO1} }, + {0x15, {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, SATA1, SATA2} }, + {0x18, {PCIE1, PCIE1, PCIE1, PCIE1, AURORA, AURORA, SATA1, SATA2} }, + {0x02, {PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1, PCIE1} }, + {0x36, {SRIO2, SRIO2, SRIO2, SRIO2, AURORA, AURORA, SATA1, SATA2} }, + {} +}; +#endif + +static const struct serdes_config *serdes_cfg_tbl[] = { + serdes1_cfg_tbl, +#ifndef CONFIG_PPC_T2081 + serdes2_cfg_tbl, +#endif +}; + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t4240_ids.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t4240_ids.c new file mode 100644 index 000000000..1a3cb3398 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t4240_ids.c @@ -0,0 +1,189 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#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 + +#ifdef CONFIG_SYS_SRIO +struct srio_liodn_id_table srio_liodn_tbl[] = { + SET_SRIO_LIODN_BASE(1, 307), + SET_SRIO_LIODN_BASE(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_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_BASE(CONFIG_SYS_FSL_PCIE_COMPAT, 1, 148), + SET_PCI_LIODN_BASE(CONFIG_SYS_FSL_PCIE_COMPAT, 2, 228), + SET_PCI_LIODN_BASE(CONFIG_SYS_FSL_PCIE_COMPAT, 3, 308), + SET_PCI_LIODN_BASE(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, 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[] = { +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t4240_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t4240_serdes.c new file mode 100644 index 000000000..1f99a0a89 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/t4240_serdes.c @@ -0,0 +1,353 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#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_FM2_A, NONE} }, + {40, {SGMII_FM2_DTSEC5, SGMII_FM2_DTSEC6, + SGMII_FM2_DTSEC10, SGMII_FM2_DTSEC9, + NONE, NONE, QSGMII_FM2_A, NONE} }, + {46, {SGMII_FM2_DTSEC5, SGMII_FM2_DTSEC6, + SGMII_FM2_DTSEC10, SGMII_FM2_DTSEC9, + NONE, NONE, QSGMII_FM2_A, NONE} }, + {48, {SGMII_FM2_DTSEC5, SGMII_FM2_DTSEC6, + SGMII_FM2_DTSEC10, SGMII_FM2_DTSEC9, + NONE, NONE, QSGMII_FM2_A, NONE} }, + {50, {XAUI_FM2_MAC9, XAUI_FM2_MAC9, + XAUI_FM2_MAC9, XAUI_FM2_MAC9, + NONE, NONE, QSGMII_FM2_A, NONE} }, + {52, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9, + HIGIG_FM2_MAC9, HIGIG_FM2_MAC9, + NONE, NONE, QSGMII_FM2_A, NONE} }, + {54, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9, + HIGIG_FM2_MAC9, HIGIG_FM2_MAC9, + NONE, NONE, QSGMII_FM2_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) || defined(CONFIG_PPC_T4080) +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/tlb.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/tlb.c new file mode 100644 index 000000000..129ec662f --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/tlb.c @@ -0,0 +1,346 @@ +/* + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#ifdef CONFIG_ADDR_MAP +#include +#endif + +DECLARE_GLOBAL_DATA_PTR; + +void invalidate_tlb(u8 tlb) +{ + if (tlb == 0) + mtspr(MMUCSR0, 0x4); + if (tlb == 1) + mtspr(MMUCSR0, 0x2); +} + +__weak 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) || !defined(CONFIG_SPL_INIT_MINIMAL)) +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 + +uint64_t tlb_map_range(ulong v_addr, phys_addr_t p_addr, uint64_t size, + enum tlb_map_type map_type) +{ + int i; + unsigned int tlb_size; + unsigned int wimge; + unsigned int perm; + unsigned int max_cam, tsize_mask; + + if (map_type == TLB_MAP_RAM) { + perm = MAS3_SX|MAS3_SW|MAS3_SR; + wimge = MAS2_M; +#ifdef CONFIG_SYS_PPC_DDR_WIMGE + wimge = CONFIG_SYS_PPC_DDR_WIMGE; +#endif + } else { + perm = MAS3_SW|MAS3_SR; + wimge = MAS2_I|MAS2_G; + } + + 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 tlb_index = find_free_tlbcam(); + u32 camsize = __ilog2_u64(size) & tsize_mask; + u32 align = __ilog2(v_addr) & tsize_mask; + + if (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, v_addr, p_addr, perm, wimge, + 0, tlb_index, tlb_size, 1); + + size -= 1ULL << camsize; + v_addr += 1UL << camsize; + p_addr += 1UL << camsize; + } + + return size; +} + +unsigned int setup_ddr_tlbs_phys(phys_addr_t p_addr, + unsigned int memsize_in_meg) +{ + unsigned int ram_tlb_address = (unsigned int)CONFIG_SYS_DDR_SDRAM_BASE; + u64 memsize = (u64)memsize_in_meg << 20; + + memsize = min(memsize, CONFIG_MAX_MEM_MAPPED); + memsize = tlb_map_range(ram_tlb_address, p_addr, memsize, TLB_MAP_RAM); + + 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/traps.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/traps.c new file mode 100644 index 000000000..24adbc307 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/traps.c @@ -0,0 +1,296 @@ +/* + * 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. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include +#include +#include +#include + +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. + */ +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/u-boot-nand.lds b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/u-boot-nand.lds new file mode 100644 index 000000000..f933b2194 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/u-boot-nand.lds @@ -0,0 +1,98 @@ +/* + * Copyright 2009-2012 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "config.h" + +#ifndef CONFIG_SYS_MONITOR_LEN +#define CONFIG_SYS_MONITOR_LEN 0x80000 +#endif + +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) + CONFIG_SYS_MONITOR_LEN; + + __bss_start = .; + .bss (NOLOAD) : + { + *(.sbss*) + *(.bss*) + *(COMMON) + } :bss + + . = ALIGN(4); + __bss_end = . ; + PROVIDE (end = .); +} diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/u-boot-nand_spl.lds b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/u-boot-nand_spl.lds new file mode 100644 index 000000000..b83c55388 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/u-boot-nand_spl.lds @@ -0,0 +1,69 @@ +/* + * (C) Copyright 2006 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de + * + * Copyright 2009 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "config.h" + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds new file mode 100644 index 000000000..5ae7b3eed --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds @@ -0,0 +1,115 @@ +/* + * (C) Copyright 2006 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de + * + * Copyright 2009 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "config.h" + +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(4); + .u_boot_list : { + KEEP(*(SORT(.u_boot_list*))); + } + + . = .; + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(8); + __init_begin = .; + __init_end = .; +#ifdef CONFIG_SPL_SKIP_RELOCATE + . = ALIGN(4); + __bss_start = .; + .bss : { + *(.sbss*) + *(.bss*) + } + . = ALIGN(4); + __bss_end = .; +#endif + +/* For ifc, elbc, esdhc, espi, all need the SPL without section .resetvec */ +#ifdef CONFIG_SYS_MPC85XX_NO_RESETVEC + .bootpg ADDR(.text) - 0x1000 : + { + KEEP(*(.bootpg)) + } :text = 0xffff +#else +#if defined(CONFIG_FSL_IFC) /* Restrict bootpg at 4K boundry for IFC */ +#ifndef BOOT_PAGE_OFFSET +#define BOOT_PAGE_OFFSET 0x1000 +#endif + .bootpg ADDR(.text) + BOOT_PAGE_OFFSET : + { + arch/powerpc/cpu/mpc85xx/start.o (.bootpg) + } +#ifndef RESET_VECTOR_OFFSET +#define RESET_VECTOR_OFFSET 0x1ffc /* IFC has 8K sram */ +#endif +#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 +#endif + +#ifndef CONFIG_SPL_SKIP_RELOCATE + /* + * 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 = .; +#endif +} diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/u-boot.lds b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/u-boot.lds new file mode 100644 index 000000000..2cf0b2595 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc85xx/u-boot.lds @@ -0,0 +1,129 @@ +/* + * Copyright 2007-2009, 2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "config.h" + +#ifdef CONFIG_RESET_VECTOR_ADDRESS +#define RESET_VECTOR_ADDRESS CONFIG_RESET_VECTOR_ADDRESS +#else +#define RESET_VECTOR_ADDRESS 0xfffffffc +#endif + +#ifndef CONFIG_SYS_MONITOR_LEN +#define CONFIG_SYS_MONITOR_LEN 0x80000 +#endif + +OUTPUT_ARCH(powerpc) +ENTRY(_start_e500) + +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) + CONFIG_SYS_MONITOR_LEN; +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/Makefile b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/Makefile new file mode 100644 index 000000000..0f790b0ef --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/Makefile @@ -0,0 +1,24 @@ +# +# 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 +# SPDX-License-Identifier: GPL-2.0+ +# + +extra-y = start.o +extra-y += traps.o + +obj-y += cache.o +obj-$(CONFIG_MP) += release.o + +obj-y += cpu.o +obj-y += cpu_init.o +obj-$(CONFIG_OF_LIBFDT) += fdt.o +obj-y += interrupts.o +obj-$(CONFIG_MP) += mp.o +obj-$(CONFIG_MPC8610) += mpc8610_serdes.o +obj-$(CONFIG_MPC8641) += mpc8641_serdes.o +obj-y += speed.o diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/cache.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/cache.S new file mode 100644 index 000000000..0bb058b04 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/cache.S @@ -0,0 +1,378 @@ +#include +#include +#include + +#include +#include + +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/config.mk b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/config.mk new file mode 100644 index 000000000..4c7235fcd --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/config.mk @@ -0,0 +1,8 @@ +# +# (C) Copyright 2004 Freescale Semiconductor. +# Jeff Brown +# +# SPDX-License-Identifier: GPL-2.0+ +# + +PLATFORM_CPPFLAGS += -DCONFIG_MPC86xx -mstring -maltivec -mabi=altivec -msoft-float diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/cpu.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/cpu.c new file mode 100644 index 000000000..30518544d --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/cpu.c @@ -0,0 +1,202 @@ +/* + * Copyright 2006,2009-2010 Freescale Semiconductor, Inc. + * Jeff Brown + * Srikanth Srinivasan (srikanth.srinivasan@freescale.com) + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +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.freq_processor)); + printf("MPX:%-4s MHz\n", strmhz(buf1, sysinfo.freq_systembus)); + printf(" DDR:%-4s MHz (%s MT/s data rate), ", + strmhz(buf1, sysinfo.freq_systembus / 2), + strmhz(buf2, sysinfo.freq_systembus)); + + if (sysinfo.freq_localbus > LCRR_CLKDIV) { + printf("LBC:%-4s MHz\n", strmhz(buf1, sysinfo.freq_localbus)); + } else { + printf("LBC: unknown (LCRR[CLKDIV] = 0x%02lx)\n", + sysinfo.freq_localbus); + } + + puts("L1: D-cache 32 KiB enabled\n"); + puts(" I-cache 32 KiB enabled\n"); + + puts("L2: "); + if (get_l2cr() & 0x80000000) { +#if defined(CONFIG_MPC8610) + puts("256"); +#elif defined(CONFIG_MPC8641) + puts("512"); +#endif + puts(" KiB 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.freq_systembus + 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/cpu_init.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/cpu_init.c new file mode 100644 index 000000000..752751588 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/cpu_init.c @@ -0,0 +1,102 @@ +/* + * Copyright 2004,2009-2011 Freescale Semiconductor, Inc. + * Jeff Brown + * Srikanth Srinivasan (srikanth.srinivasan@freescale.com) + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * cpu_init.c - low level cpu init + */ + +#include +#include +#include +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/fdt.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/fdt.c new file mode 100644 index 000000000..26a65c586 --- /dev/null +++ b/qemu/roms/u-boot/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 +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/interrupts.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/interrupts.c new file mode 100644 index 000000000..765aab5cf --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/interrupts.c @@ -0,0 +1,115 @@ +/* + * (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) + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#ifdef CONFIG_POST +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/mp.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/mp.c new file mode 100644 index 000000000..66c1162f7 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/mp.c @@ -0,0 +1,129 @@ +/* + * Copyright 2008-2010 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c new file mode 100644 index 000000000..2a7e3bff8 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c @@ -0,0 +1,69 @@ +/* + * Copyright 2010 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c new file mode 100644 index 000000000..cc0f8e90c --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c @@ -0,0 +1,78 @@ +/* + * Copyright 2010 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/release.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/release.S new file mode 100644 index 000000000..461f6ec7d --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/release.S @@ -0,0 +1,151 @@ +/* + * Copyright 2004, 2007, 2008 Freescale Semiconductor. + * Srikanth Srinivasan + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include +#include +#include + +#include +#include + +#include +#include + +/* 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/speed.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/speed.c new file mode 100644 index 000000000..5abe6f0bf --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/speed.c @@ -0,0 +1,146 @@ +/* + * Copyright 2004 Freescale Semiconductor. + * Jeff Brown + * Srikanth Srinivasan (srikanth.srinivasan@freescale.com) + * + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +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 *sys_info) +{ + 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: + sys_info->freq_systembus = 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: + sys_info->freq_systembus = plat_ratio * CONFIG_SYS_CLK_FREQ; + break; + default: + sys_info->freq_systembus = 0; + break; + } + + e600_ratio = (gur->porpllsr) & 0x003f0000; + e600_ratio >>= 16; + + switch (e600_ratio) { + case 0x10: + sys_info->freq_processor = 2 * sys_info->freq_systembus; + break; + case 0x19: + sys_info->freq_processor = 5 * sys_info->freq_systembus / 2; + break; + case 0x20: + sys_info->freq_processor = 3 * sys_info->freq_systembus; + break; + case 0x39: + sys_info->freq_processor = 7 * sys_info->freq_systembus / 2; + break; + case 0x28: + sys_info->freq_processor = 4 * sys_info->freq_systembus; + break; + case 0x1d: + sys_info->freq_processor = 9 * sys_info->freq_systembus / 2; + break; + default: + sys_info->freq_processor = e600_ratio + + sys_info->freq_systembus; + 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) { + sys_info->freq_localbus = sys_info->freq_systembus + / (lcrr_div * 2); + } else { + /* In case anyone cares what the unknown value is */ + sys_info->freq_localbus = 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.freq_processor; + gd->bus_clk = sys_info.freq_systembus; + gd->arch.lbc_clk = sys_info.freq_localbus; + + /* + * 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.freq_systembus; +#else + gd->arch.i2c1_clk = sys_info.freq_systembus / 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.freq_systembus; + + return val; +} diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/start.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/start.S new file mode 100644 index 000000000..ec5f4a756 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/start.S @@ -0,0 +1,993 @@ +/* + * Copyright 2004, 2007, 2011 Freescale Semiconductor. + * Srikanth Srinivasan + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* 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 +#include +#include +#include + +#include +#include + +#include +#include +#include + +/* + * 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) */ + li r3, 0 /* clear boot_flag for calling board_init_f */ + 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/traps.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/traps.c new file mode 100644 index 000000000..92fb53745 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/traps.c @@ -0,0 +1,207 @@ +/* + * 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. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include +#include +#include +#include + +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. + */ +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/u-boot.lds b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/u-boot.lds new file mode 100644 index 000000000..58467c2cc --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc86xx/u-boot.lds @@ -0,0 +1,79 @@ +/* + * Copyright 2006, 2007 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/Makefile b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/Makefile new file mode 100644 index 000000000..f83fd5ecf --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/Makefile @@ -0,0 +1,27 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +# ccflags-y += -DET_DEBUG + +extra-y += start.o +extra-y += traps.o +obj-y += bedbug_860.o +obj-y += commproc.o +obj-y += cpu.o +obj-y += cpu_init.o +obj-y += fec.o +obj-$(CONFIG_OF_LIBFDT) += fdt.o +obj-y += i2c.o +obj-y += interrupts.o +obj-y += scc.o +obj-y += serial.o +obj-y += speed.o +obj-y += spi.o +obj-y += upatch.o +obj-y += video.o +obj-y += kgdb.o +obj-y += plprcr_write.o diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/bedbug_860.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/bedbug_860.c new file mode 100644 index 000000000..c0016f72f --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/bedbug_860.c @@ -0,0 +1,314 @@ +/* + * Bedbug Functions specific to the MPC860 chip + */ + +#include +#include +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/commproc.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/commproc.c new file mode 100644 index 000000000..f8581d130 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/commproc.c @@ -0,0 +1,69 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/config.mk b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/config.mk new file mode 100644 index 000000000..ee2c88366 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/config.mk @@ -0,0 +1,8 @@ +# +# (C) Copyright 2000-2010 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +PLATFORM_CPPFLAGS += -DCONFIG_8xx -mstring -mcpu=860 -msoft-float diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu.c new file mode 100644 index 000000000..5c96b5fe1 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu.c @@ -0,0 +1,641 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * m8xx.c + * + * CPU specific code + * + * written or collected and sometimes rewritten by + * Magnus Damm + * + * minor modifications by + * Wolfgang Denk + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_OF_LIBFDT) +#include +#include +#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 + print_size(checkicache(), " I-Cache "); + print_size(checkdcache(), " D-Cache"); + + /* 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)); + + print_size(checkicache(), " I-Cache "); + print_size(checkdcache(), " D-Cache"); + + /* 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)); + + print_size(checkicache(), " I-Cache "); + print_size(checkdcache(), " D-Cache"); + + /* 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)); + + print_size(checkicache(), " I-Cache "); + print_size(checkdcache(), " D-Cache"); + + /* 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<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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu_init.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu_init.c new file mode 100644 index 000000000..9c3102dc6 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/cpu_init.c @@ -0,0 +1,246 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +#include +#include + +#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) +{ + volatile memctl8xx_t *memctl = &immr->im_memctl; +# ifdef CONFIG_SYS_PLPRCR + ulong mfmask; +# 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; + + /* 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_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 + + /* + * 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); + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/fdt.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/fdt.c new file mode 100644 index 000000000..97830e3c8 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/fdt.c @@ -0,0 +1,30 @@ +/* + * Copyright 2008 (C) Bryan O'Donoghue + * + * Code copied & edited from Freescale mpc85xx stuff. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/fec.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/fec.c new file mode 100644 index 000000000..65dfeabba --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/fec.c @@ -0,0 +1,1013 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +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 + +#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 = ðer_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) { + 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) { + 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/fec.h b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/fec.h new file mode 100644 index 000000000..e025c3f46 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/fec.h @@ -0,0 +1,12 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _FEC_H_ +#define _FEC_H_ + + +#endif /* _FEC_H_ */ diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/i2c.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/i2c.c new file mode 100644 index 000000000..2f8b1393f --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/i2c.c @@ -0,0 +1,688 @@ +/* + * (C) Copyright 2000 + * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it + * + * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH + * Marius Groeger + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Back ported to the 8xx platform (from the 8260 platform) by + * Murray.Jensen@cmst.csiro.au, 27-Jan-01. + */ + +#include + +#ifdef CONFIG_HARD_I2C + +#include +#include +#ifdef CONFIG_LWMON +#include +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/interrupts.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/interrupts.c new file mode 100644 index 000000000..482ceecb9 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/interrupts.c @@ -0,0 +1,278 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +/************************************************************************/ + +/* + * 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/kgdb.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/kgdb.S new file mode 100644 index 000000000..e774d1e70 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/kgdb.S @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2000 Murray Jensen + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/plprcr_write.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/plprcr_write.S new file mode 100644 index 000000000..e28292f5e --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/plprcr_write.S @@ -0,0 +1,119 @@ +/* + * (C) Copyright 2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/scc.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/scc.c new file mode 100644 index 000000000..5da697366 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/scc.c @@ -0,0 +1,535 @@ +/* + * File: scc.c + * Description: + * Basic ET HW initialization and packet RX/TX routines + * + * NOTE <<>>: + * 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 +#include +#include +#include +#include + +#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) 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) 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 + +#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 */ + +#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 */ +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/serial.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/serial.c new file mode 100644 index 000000000..932141144 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/serial.c @@ -0,0 +1,746 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +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) + /* 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) + /* 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 + + /* 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/speed.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/speed.c new file mode 100644 index 000000000..42442b8c9 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/speed.c @@ -0,0 +1,400 @@ +/* + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +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<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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/spi.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/spi.c new file mode 100644 index 000000000..c442af979 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/spi.c @@ -0,0 +1,540 @@ +/* + * Copyright (c) 2001 Navin Boppuri / Prashant Patel + * , + * + * Copyright (c) 2001 Gerd Mennchen + * Copyright (c) 2001 Wolfgang Denk, DENX Software Engineering, . + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * 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 +#include +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/start.S b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/start.S new file mode 100644 index 000000000..f8aa93d61 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/start.S @@ -0,0 +1,650 @@ +/* + * Copyright (C) 1998 Dan Malek + * Copyright (C) 1999 Magnus Damm + * Copyright (C) 2000,2001,2002 Wolfgang Denk + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* 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 +#include +#include +#include + +#include +#include + +#include +#include +#include + +/* 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/traps.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/traps.c new file mode 100644 index 000000000..01f24ac1a --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/traps.c @@ -0,0 +1,216 @@ +/* + * 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. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/upatch.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/upatch.c new file mode 100644 index 000000000..a8cb735ab --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/upatch.c @@ -0,0 +1,194 @@ +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/video.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/video.c new file mode 100644 index 000000000..fc351585b --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xx/video.c @@ -0,0 +1,1318 @@ +/* + * (C) Copyright 2000 + * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it + * (C) Copyright 2002 + * Wolfgang Denk, wd@denx.de + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* #define DEBUG */ + +/************************************************************************/ +/* ** HEADER FILES */ +/************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#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 /* 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 /* 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 /* 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 /* Get font data, width and height */ + +#ifdef CONFIG_VIDEO_LOGO +#include /* 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"); +#ifdef CONFIG_SYS_I2C + i2c_init_all(); +#else + i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); +#endif + +#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; iim_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 MiB RAM, %ld MiB 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, "2MiB FLASH - 8MiB DRAM - 4MiB 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/Makefile b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/Makefile new file mode 100644 index 000000000..e95539e0a --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/Makefile @@ -0,0 +1,30 @@ +# +# 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. +# + +MINIMAL= + +ifdef CONFIG_SPL_BUILD +ifdef CONFIG_SPL_INIT_MINIMAL +MINIMAL=y +endif +endif + +ifdef MINIMAL + +obj-$(CONFIG_FSL_LAW) += law.o + +else +obj-$(CONFIG_MPC85xx) += cpu.o +obj-$(CONFIG_MPC86xx) += cpu.o + +obj-$(CONFIG_OF_LIBFDT) += fdt.o +obj-$(CONFIG_FSL_LBC) += fsl_lbc.o +obj-$(CONFIG_SYS_SRIO) += srio.o +obj-$(CONFIG_FSL_LAW) += law.o + +endif diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/cpu.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/cpu.c new file mode 100644 index 000000000..13bd0acdf --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/cpu.c @@ -0,0 +1,271 @@ +/* + * 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. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +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(T4080, T4080, 4), + 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(T2080, T2080, 0), + CPU_TYPE_ENTRY(T2081, T2081, 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), + CPU_TYPE_ENTRY(C291, C291, 1), + CPU_TYPE_ENTRY(C292, C292, 1), + CPU_TYPE_ENTRY(C293, C293, 1), +#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. + */ +__weak 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. + */ +__weak 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/fdt.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/fdt.c new file mode 100644 index 000000000..927374529 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/fdt.c @@ -0,0 +1,428 @@ +/* + * 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. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT +#define CONFIG_USB_MAX_CONTROLLER_COUNT 1 +#endif + +#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 *dr_mode_type = NULL; + const char *dr_phy_type = NULL; + int usb_mode_off = -1; + int usb_phy_off = -1; + char str[5]; + int i, j; + + for (i = 1; i <= CONFIG_USB_MAX_CONTROLLER_COUNT; 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]; + + 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; + } +} +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/fsl_lbc.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/fsl_lbc.c new file mode 100644 index 000000000..c1fe5790a --- /dev/null +++ b/qemu/roms/u-boot/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 +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/law.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/law.c new file mode 100644 index 000000000..33d53a8cf --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/law.c @@ -0,0 +1,354 @@ +/* + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +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) || !defined(CONFIG_SPL_INIT_MINIMAL)) +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) || !defined(CONFIG_SPL_INIT_MINIMAL)) +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 disable_non_ddr_laws(void) +{ + int i; + int id; + for (i = 0; i < FSL_HW_NUM_LAWS; i++) { + u32 lawar = in_be32(LAWAR_ADDR(i)); + + if (lawar & LAW_EN) { + id = (lawar & ~LAW_EN) >> 20; + switch (id) { + case LAW_TRGT_IF_DDR_1: + case LAW_TRGT_IF_DDR_2: + case LAW_TRGT_IF_DDR_3: + case LAW_TRGT_IF_DDR_4: + case LAW_TRGT_IF_DDR_INTRLV: + case LAW_TRGT_IF_DDR_INTLV_34: + case LAW_TRGT_IF_DDR_INTLV_123: + case LAW_TRGT_IF_DDR_INTLV_1234: + continue; + default: + disable_law(i); + } + } + } +} + +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 + +#if defined(CONFIG_SECURE_BOOT) && defined(CONFIG_E500) && \ + !defined(CONFIG_E500MC) + /* ISBC (Boot ROM) creates a LAW 0 entry for non PBL platforms, + * which is not disabled before transferring the control to uboot. + * Disable the LAW 0 entry here. + */ + disable_law(0); +#endif + +#if !defined(CONFIG_SECURE_BOOT) + /* + * if any non DDR LAWs has been created earlier, remove them before + * LAW table is parsed. + */ + disable_non_ddr_laws(); +#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); + } + + 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/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/srio.c b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/srio.c new file mode 100644 index 000000000..0ab9aac4a --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/mpc8xxx/srio.c @@ -0,0 +1,446 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/40x_spd_sdram.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/40x_spd_sdram.c new file mode 100644 index 000000000..717e7badb --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/40x_spd_sdram.c @@ -0,0 +1,444 @@ +/* + * 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. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +#if defined(CONFIG_SPD_EEPROM) && !defined(CONFIG_440) + +/* + * Set default values + */ +#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_set_bus_num(CONFIG_SYS_SPD_BUS_NUM); + } + + /* 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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/44x_spd_ddr.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/44x_spd_ddr.c new file mode 100644 index 000000000..36e7b01e8 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/44x_spd_ddr.c @@ -0,0 +1,1224 @@ +/* + * 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. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* define DEBUG for debugging output (obviously ;-)) */ +#if 0 +#define DEBUG +#endif + +#include +#include +#include +#include +#include + +#include "ecc.h" + +#if defined(CONFIG_SPD_EEPROM) && \ + (defined(CONFIG_440GP) || defined(CONFIG_440GX) || \ + defined(CONFIG_440EP) || defined(CONFIG_440GR)) + +/* + * Set default values + */ +#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_set_bus_num(CONFIG_SYS_SPD_BUS_NUM); + + /* + * 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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/44x_spd_ddr2.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/44x_spd_ddr2.c new file mode 100644 index 000000000..f8d03cba2 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/44x_spd_ddr2.c @@ -0,0 +1,3129 @@ +/* + * 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 + + * (C) Copyright 2007-2009 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * COPYRIGHT AMCC CORPORATION 2004 + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* define DEBUG for debugging output (obviously ;-)) */ +#if 0 +#define DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#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) + +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); + } + } +} + +#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)) + +/*-----------------------------------------------------------------------------+ + * 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); +} + +#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_num(CONFIG_SYS_SPD_BUS_NUM); + + /*------------------------------------------------------------------ + * 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 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) +{ + 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) + /*------------------------------------------------------------------ + | DQS calibration. + +-----------------------------------------------------------------*/ + DQS_autocalibration(); +#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 */ + + return (CONFIG_SYS_MBYTES_SDRAM << 20); +} +#endif /* CONFIG_SPD_EEPROM */ + +#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) */ + +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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c new file mode 100644 index 000000000..67f149dee --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c @@ -0,0 +1,1227 @@ +/* + * 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 + * + * (C) Copyright 2007-2008 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * COPYRIGHT AMCC CORPORATION 2004 + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* define DEBUG for debugging output (obviously ;-)) */ +#undef DEBUG + +#include +#include +#include +#include + +#include "ecc.h" + +#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; lSDRAM_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; +} diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_pci.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_pci.c new file mode 100644 index 000000000..33dc72585 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_pci.c @@ -0,0 +1,864 @@ +/* + * SPDX-License-Identifier: GPL-2.0 IBM-pibs + * + * 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 +#include +#include +#include +#include +#include + +#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, ®); + 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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_pcie.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_pcie.c new file mode 100644 index 000000000..f0f3462ef --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_pcie.c @@ -0,0 +1,1280 @@ +/* + * (C) Copyright 2006 - 2008 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Roland Dreier + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* define DEBUG for debugging output (obviously ;-)) */ +#if 0 +#define DEBUG +#endif + +#include +#include +#include +#include +#include +#include + +#if (defined(CONFIG_440SPE) || defined(CONFIG_405EX) || \ + defined(CONFIG_460EX) || defined(CONFIG_460GT)) && \ + defined(CONFIG_PCI) && !defined(CONFIG_PCI_DISABLE_PCIE) + +#include + +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//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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_uart.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_uart.c new file mode 100644 index 000000000..c02058f79 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/4xx_uart.c @@ -0,0 +1,268 @@ +/* + * (C) Copyright 2000-2006 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2010 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * SPDX-License-Identifier: GPL-2.0 IBM-pibs + */ + +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_405GP) || \ + 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 */ +#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_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 + +#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 */ diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/Makefile b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/Makefile new file mode 100644 index 000000000..4b792ae2d --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/Makefile @@ -0,0 +1,49 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +extra-y := resetvec.o +extra-y += start.o + +obj-y := cache.o +obj-y += dcr.o +obj-y += kgdb.o + +obj-y += 40x_spd_sdram.o + +obj-y += 44x_spd_ddr.o +obj-$(CONFIG_SDRAM_PPC4xx_IBM_DDR2) += 44x_spd_ddr2.o +obj-$(CONFIG_PPC4xx_DDR_AUTOCALIBRATION) += 4xx_ibm_ddr2_autocalib.o +obj-y += 4xx_pci.o +obj-y += 4xx_pcie.o +obj-y += bedbug_405.o +obj-$(CONFIG_CMD_CHIP_CONFIG) += cmd_chip_config.o +obj-y += cpu.o +obj-y += cpu_init.o +obj-y += denali_data_eye.o +obj-y += denali_spd_ddr2.o +obj-y += ecc.o +obj-$(CONFIG_CMD_ECCTEST) += cmd_ecctest.o +obj-y += fdt.o +obj-y += interrupts.o +obj-$(CONFIG_CMD_REGINFO) += reginfo.o +obj-y += sdram.o +obj-y += speed.o +obj-y += tlb.o +obj-y += traps.o +obj-y += usb.o +obj-y += usb_ohci.o +obj-$(CONFIG_XILINX_440) += xilinx_irq.o +ifndef CONFIG_XILINX_440 +obj-y += 4xx_uart.o +obj-y += gpio.o +obj-y += miiphy.o +obj-y += uic.o +endif + +ifdef CONFIG_SPL_BUILD +obj-y += spl_boot.o +endif diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/bedbug_405.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/bedbug_405.c new file mode 100644 index 000000000..e1500cc04 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/bedbug_405.c @@ -0,0 +1,308 @@ +/* + * Bedbug Functions specific to the PPC405 chip + */ + +#include +#include +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cache.S b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cache.S new file mode 100644 index 000000000..2714c2f93 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cache.S @@ -0,0 +1,231 @@ +/* + * 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. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * 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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cmd_chip_config.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cmd_chip_config.c new file mode 100644 index 000000000..4e9a40d58 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cmd_chip_config.c @@ -0,0 +1,131 @@ +/* + * (C) Copyright 2008-2009 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * (C) Copyright 2009 + * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +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_num(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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cmd_ecctest.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cmd_ecctest.c new file mode 100644 index 000000000..958ba6c94 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cmd_ecctest.c @@ -0,0 +1,262 @@ +/* + * (C) Copyright 2010 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/config.mk b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/config.mk new file mode 100644 index 000000000..102f069f9 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/config.mk @@ -0,0 +1,17 @@ +# +# (C) Copyright 2000-2010 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +PLATFORM_CPPFLAGS += -DCONFIG_4xx -mstring -msoft-float + +cfg=$(shell grep configs $(objtree)/include/config.h | sed 's/.*<\(configs.*\)>/\1/') +is440:=$(shell grep CONFIG_440 $(srctree)/include/$(cfg)) + +ifneq (,$(findstring CONFIG_440,$(is440))) +PLATFORM_CPPFLAGS += -Wa,-m440 -mcpu=440 +else +PLATFORM_CPPFLAGS += -Wa,-m405 -mcpu=405 +endif diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cpu.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cpu.c new file mode 100644 index 000000000..d1fc7f3fc --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cpu.c @@ -0,0 +1,719 @@ +/* + * (C) Copyright 2000-2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * CPU specific code + * + * written or collected and sometimes rewritten by + * Magnus Damm + * + * minor modifications by + * Wolfgang Denk + */ + +#include +#include +#include +#include +#include +#include + +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; + + case PVR_405GP_RE: + puts("405GP Rev. E"); + break; + + 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 KiB I-Cache 16 KiB D-Cache"); +#elif defined(CONFIG_440) + printf(" 32 KiB I-Cache 32 KiB D-Cache"); +#else + printf(" 16 KiB I-Cache %d KiB 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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cpu_init.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cpu_init.c new file mode 100644 index 000000000..d465dcda8 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/cpu_init.c @@ -0,0 +1,543 @@ +/* + * (C) Copyright 2000-2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +#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_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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/dcr.S b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/dcr.S new file mode 100644 index 000000000..6b13528c9 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/dcr.S @@ -0,0 +1,180 @@ +/* + * (C) Copyright 2001 + * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include + +#if defined(CONFIG_4xx) && defined(CONFIG_CMD_SETGETDCR) + +#include + +#include +#include + +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/denali_data_eye.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/denali_data_eye.c new file mode 100644 index 000000000..a955a5ba6 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/denali_data_eye.c @@ -0,0 +1,376 @@ +/* + * arch/powerpc/cpu/ppc4xx/denali_data_eye.c + * Extracted from board/amcc/sequoia/sdram.c by Larry Johnson . + * + * (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. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* define DEBUG for debugging output (obviously ;-)) */ +#if 0 +#define DEBUG +#endif + +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/denali_spd_ddr2.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/denali_spd_ddr2.c new file mode 100644 index 000000000..916451a2b --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/denali_spd_ddr2.c @@ -0,0 +1,1231 @@ +/* + * 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 + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* define DEBUG for debugging output (obviously ;-)) */ +#if 0 +#define DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#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_num(CONFIG_SYS_SPD_BUS_NUM); + + /*------------------------------------------------------------------ + * 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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/ecc.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/ecc.c new file mode 100644 index 000000000..88a4605ad --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/ecc.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2008 Nuovation System Designs, LLC + * Grant Erickson + * + * (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 + * + * SPDX-License-Identifier: GPL-2.0+ + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/ecc.h b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/ecc.h new file mode 100644 index 000000000..bc94257fa --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/ecc.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008 Nuovation System Designs, LLC + * Grant Erickson + * + * Copyright (c) 2007-2009 DENX Software Engineering, GmbH + * Stefan Roese + * + * SPDX-License-Identifier: GPL-2.0+ + * + * 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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/fdt.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/fdt.c new file mode 100644 index 000000000..bd905d158 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/fdt.c @@ -0,0 +1,160 @@ +/* + * (C) Copyright 2007-2008 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/gpio.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/gpio.c new file mode 100644 index 000000000..6d480dab8 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/gpio.c @@ -0,0 +1,244 @@ +/* + * (C) Copyright 2007-2008 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +/* 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> (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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/interrupts.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/interrupts.c new file mode 100644 index 000000000..d9b565468 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/interrupts.c @@ -0,0 +1,193 @@ +/* + * (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) + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/kgdb.S b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/kgdb.S new file mode 100644 index 000000000..f274c5d56 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/kgdb.S @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2000 Murray Jensen + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +#define CONFIG_405GP 1 /* needed for Linux kernel header files */ + +#include +#include + +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/miiphy.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/miiphy.c new file mode 100644 index 000000000..10147de08 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/miiphy.c @@ -0,0 +1,346 @@ +/* + * SPDX-License-Identifier: GPL-2.0 IBM-pibs + */ +/*-----------------------------------------------------------------------------+ + | + | 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 +#include +#include +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/reginfo.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/reginfo.c new file mode 100644 index 000000000..339d38aa9 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/reginfo.c @@ -0,0 +1,357 @@ +/* + *(C) Copyright 2005-2009 Netstal Maschinen AG + * Bruno Hars (Bruno.Hars@netstal.com) + * Niklaus Giger (Niklaus.Giger@netstal.com) + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * reginfo.c - register dump of HW-configuratin register for PPC4xx based board + */ + +#include +#include +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/resetvec.S b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/resetvec.S new file mode 100644 index 000000000..b3308bd6a --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/resetvec.S @@ -0,0 +1,12 @@ +/* Copyright MontaVista Software Incorporated, 2000 */ +#include + .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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/sdram.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/sdram.c new file mode 100644 index 000000000..d4ef36d39 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/sdram.c @@ -0,0 +1,452 @@ +/* + * (C) Copyright 2005-2007 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * (C) Copyright 2006 + * DAVE Srl + * + * (C) Copyright 2002-2004 + * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#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 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 all done + */ + return size; + } + } + + return 0; /* nothing found ! */ +} + +#endif /* CONFIG_440 */ + +#endif /* CONFIG_SDRAM_BANK0 */ diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/sdram.h b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/sdram.h new file mode 100644 index 000000000..1e249f40d --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/sdram.h @@ -0,0 +1,60 @@ +/* + * (C) Copyright 2006 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * (C) Copyright 2006 + * DAVE Srl + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _SDRAM_H_ +#define _SDRAM_H_ + +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/speed.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/speed.c new file mode 100644 index 000000000..7e077d5a9 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/speed.c @@ -0,0 +1,1209 @@ +/* + * (C) Copyright 2000-2008 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +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) + +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_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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/spl_boot.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/spl_boot.c new file mode 100644 index 000000000..318f23b64 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/spl_boot.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2013 Stefan Roese + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/start.S b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/start.S new file mode 100644 index 000000000..11b55d5a5 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/start.S @@ -0,0 +1,1954 @@ +/* + * Copyright (C) 1998 Dan Malek + * Copyright (C) 1999 Magnus Damm + * Copyright (C) 2000,2001,2002 Wolfgang Denk + * Copyright (C) 2007 Stefan Roese , DENX Software Engineering + * Copyright (c) 2008 Nuovation System Designs, LLC + * Grant Erickson + * + * SPDX-License-Identifier: GPL-2.0 IBM-pibs + */ + +/* + * 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 +#include +#include +#include + +#include +#include + +#include +#include +#include + +#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 + +/* + * Set up GOT: Global Offset Table + * + * Use r12 to access the GOT + */ +#if !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_SPL_BUILD */ + +#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) + .section .bootpg,"ax" + .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_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) */ + +#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 /* CONFIG_440 */ + +/*****************************************************************************/ +#if defined(CONFIG_405GP) || \ + 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 */ + + 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_405GP || CONFIG_405 || CONFIG_405EP */ + /*----------------------------------------------------------------------- */ + + +#if !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_SPL_BUILD */ + +/*------------------------------------------------------------------------------- */ +/* 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 */ diff --git a/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/tlb.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/tlb.c new file mode 100644 index 000000000..3cb09bda4 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/tlb.c @@ -0,0 +1,336 @@ +/* + * (C) Copyright 2007 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +#if defined(CONFIG_440) + +#include +#include +#include +#include + +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= 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= 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) + 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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/traps.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/traps.c new file mode 100644 index 000000000..df527e4b2 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/traps.c @@ -0,0 +1,392 @@ +/* + * 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. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include +#include +#include +#include + +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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/u-boot-spl.lds b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/u-boot-spl.lds new file mode 100644 index 000000000..b4e49aaef --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/u-boot-spl.lds @@ -0,0 +1,61 @@ +/* + * Copyright 2012-2013 Stefan Roese + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/u-boot.lds b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/u-boot.lds new file mode 100644 index 000000000..87731785e --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/u-boot.lds @@ -0,0 +1,133 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/uic.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/uic.c new file mode 100644 index 000000000..bd955ed83 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/uic.c @@ -0,0 +1,164 @@ +/* + * (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) + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/usb.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/usb.c new file mode 100644 index 000000000..16b44ccea --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/usb.c @@ -0,0 +1,45 @@ +/* + * (C) Copyright 2007 + * Markus Klotzbuecher, DENX Software Engineering + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT) + +#ifdef CONFIG_4xx_DCACHE +#include +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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/usb_ohci.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/usb_ohci.c new file mode 100644 index 000000000..d1e78f6b0 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/usb_ohci.c @@ -0,0 +1,1525 @@ +/* + * URB OHCI HCD (Host Controller Driver) for USB on the PPC440EP. + * + * (C) Copyright 2003-2004 + * Gary Jennejohn, DENX Software Engineering + * + * (C) Copyright 2004 + * Pierre Aubert, Staubli Faverges + * + * Note: Much of this code has been derived from Linux 2.4 + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * + * SPDX-License-Identifier: GPL-2.0+ + */ +/* + * 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 + +#ifdef CONFIG_USB_OHCI + +#include +#include +#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 (®s->revision) & 0xff; + if (temp != 0x10) + dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f)); + + temp = readl (®s->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 (®s->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 (®s->intrstatus)); + ohci_dump_intr_mask ("intrenable", readl (®s->intrenable)); + + maybe_print_eds ("ed_periodcurrent", readl (®s->ed_periodcurrent)); + + maybe_print_eds ("ed_controlhead", readl (®s->ed_controlhead)); + maybe_print_eds ("ed_controlcurrent", readl (®s->ed_controlcurrent)); + + maybe_print_eds ("ed_bulkhead", readl (®s->ed_bulkhead)); + maybe_print_eds ("ed_bulkcurrent", readl (®s->ed_bulkcurrent)); + + maybe_print_eds ("donehead", readl (®s->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 + *-------------------------------------------------------------------------*/ + +#include + +/* 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 (®s->intrstatus)) == ~(u32)0) { + ohci->disabled++; + err ("%s device removed!", ohci->slot_name); + return -1; + + } else if ((ints &= readl (®s->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, ®s->intrdisable); + stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci)); + writel (OHCI_INTR_WDH, ®s->intrenable); + } + + if (ints & OHCI_INTR_SO) { + dbg("USB Schedule overrun\n"); + writel (OHCI_INTR_SO, ®s->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, ®s->intrdisable); + if (ohci->ed_rm_list[frame] != NULL) + writel (OHCI_INTR_SF, ®s->intrenable); + stat = 0xff; + } + + writel (ints, ®s->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, enum usb_init_type init, 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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/usb_ohci.h b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/usb_ohci.h new file mode 100644 index 000000000..2c3dc4f99 --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/usb_ohci.h @@ -0,0 +1,410 @@ +/* + * URB OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2001 David Brownell + * + * 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/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/xilinx_irq.c b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/xilinx_irq.c new file mode 100644 index 000000000..71e1be02a --- /dev/null +++ b/qemu/roms/u-boot/arch/powerpc/cpu/ppc4xx/xilinx_irq.c @@ -0,0 +1,89 @@ +/* + * (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 + * SPDX-License-Identifier: GPL-2.0+ +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} -- cgit 1.2.3-korg