Merge git://git.denx.de/u-boot-dm

- MPC83xx device tree additions (CPU and RAM)
- Fix sandbox build error
- Sync bitrev with Linux
- Various ofnode/DT improvements
diff --git a/Documentation/devicetree/bindings/clk/fsl,mpc83xx-clk.txt b/Documentation/devicetree/bindings/clk/fsl,mpc83xx-clk.txt
new file mode 100644
index 0000000..8313da8
--- /dev/null
+++ b/Documentation/devicetree/bindings/clk/fsl,mpc83xx-clk.txt
@@ -0,0 +1,23 @@
+MPC83xx system clock devices
+
+MPC83xx SoCs supply a variety of clocks to drive various components of a
+system.
+
+Required properties:
+- compatible: must be one of "fsl,mpc8308-clk",
+                             "fsl,mpc8309-clk",
+                             "fsl,mpc8313-clk",
+                             "fsl,mpc8315-clk",
+                             "fsl,mpc832x-clk",
+                             "fsl,mpc8349-clk",
+                             "fsl,mpc8360-clk",
+                             "fsl,mpc8379-clk"
+  depending on which SoC is employed
+- #clock-cells: Must be 1
+
+Example:
+
+socclocks: clocks {
+	compatible = "fsl,mpc832x-clk";
+	#clock-cells = <1>;
+};
diff --git a/Documentation/devicetree/bindings/cpu/fsl,mpc83xx.txt b/Documentation/devicetree/bindings/cpu/fsl,mpc83xx.txt
new file mode 100644
index 0000000..ac563d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpu/fsl,mpc83xx.txt
@@ -0,0 +1,34 @@
+MPC83xx CPU devices
+
+MPC83xx SoCs contain a e300 core as their main processor.
+
+Required properties:
+- compatible: must be one of "fsl,mpc83xx",
+                             "fsl,mpc8308",
+                             "fsl,mpc8309",
+                             "fsl,mpc8313",
+                             "fsl,mpc8315",
+                             "fsl,mpc832x",
+                             "fsl,mpc8349",
+                             "fsl,mpc8360",
+                             "fsl,mpc8379"
+- clocks: has to have two entries, which must be the core clock at index 0 and
+  the CSB (Coherent System Bus) clock at index 1. Both are given by a suitable
+  "fsl,mpc83xx-clk" device
+
+Example:
+
+socclocks: clocks {
+	compatible = "fsl,mpc8315-clk";
+	#clock-cells = <1>;
+};
+
+cpus {
+	compatible = "cpu_bus";
+
+	PowerPC,8315@0 {
+		compatible = "fsl,mpc8315";
+		clocks = <&socclocks MPC83XX_CLK_CORE
+		          &socclocks MPC83XX_CLK_CSB>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/misc/fsl,mpc83xx-serdes.txt b/Documentation/devicetree/bindings/misc/fsl,mpc83xx-serdes.txt
new file mode 100644
index 0000000..64a9b5b
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/fsl,mpc83xx-serdes.txt
@@ -0,0 +1,24 @@
+MPC83xx SerDes controller devices
+
+MPC83xx SoCs contain a built-in SerDes controller that determines which
+protocols (SATA, PCI Express, SGMII, ...) are used on the system's serdes lines
+and how the lines are configured.
+
+Required properties:
+- compatible: must be "fsl,mpc83xx-serdes"
+- reg: must point to the serdes controller's register map
+- proto: selects for which protocol the serdes lines are configured. One of
+  "sata", "pex", "pex-x2", "sgmii"
+- serdes-clk: determines the frequency the serdes lines are configured for. One
+  of 100, 125, 150.
+- vdd: determines whether 1.0V core VDD is used or not
+
+Example:
+
+SERDES: serdes@e3000 {
+	reg = <0xe3000 0x200>;
+	compatible = "fsl,mpc83xx-serdes";
+	proto = "pex";
+	serdes-clk = <100>;
+	vdd;
+};
diff --git a/Documentation/devicetree/bindings/ram/fsl,mpc83xx-mem-controller.txt b/Documentation/devicetree/bindings/ram/fsl,mpc83xx-mem-controller.txt
new file mode 100644
index 0000000..da01fe9
--- /dev/null
+++ b/Documentation/devicetree/bindings/ram/fsl,mpc83xx-mem-controller.txt
@@ -0,0 +1,314 @@
+MPC83xx RAM controller
+
+This driver supplies support for the embedded RAM controller on MCP83xx-series
+SoCs.
+
+For static configuration mode, each controller node should have child nodes
+describing the actual RAM modules installed.
+
+Controller node
+===============
+
+Required properties:
+- compatible:                Must be "fsl,mpc83xx-mem-controller"
+- reg:                       The address of the RAM controller's register space
+- #address-cells:            Must be 2
+- #size-cells:               Must be 1
+- driver_software_override:  DDR driver software override is enabled (1) or
+                             disabled (0)
+- p_impedance_override:      DDR driver software p-impedance override; possible
+                             values:
+                              * DSO_P_IMPEDANCE_HIGHEST_Z
+                              * DSO_P_IMPEDANCE_MUCH_HIGHER_Z
+                              * DSO_P_IMPEDANCE_HIGHER_Z
+                              * DSO_P_IMPEDANCE_NOMINAL
+                              * DSO_P_IMPEDANCE_LOWER_Z
+- n_impedance_override:      DDR driver software n-impedance override; possible
+                             values:
+                              * DSO_N_IMPEDANCE_HIGHEST_Z
+                              * DSO_N_IMPEDANCE_MUCH_HIGHER_Z
+                              * DSO_N_IMPEDANCE_HIGHER_Z
+                              * DSO_N_IMPEDANCE_NOMINAL
+                              * DSO_N_IMPEDANCE_LOWER_Z
+- odt_termination_value:     ODT termination value for I/Os; possible values:
+                              * ODT_TERMINATION_75_OHM
+                              * ODT_TERMINATION_150_OHM
+- ddr_type:                  Selects voltage level for DDR pads; possible
+                             values:
+                              * DDR_TYPE_DDR2_1_8_VOLT
+                              * DDR_TYPE_DDR1_2_5_VOLT
+- mvref_sel:                 Determine where MVREF_SEL signal is generated;
+                             possible values:
+                              * MVREF_SEL_EXTERNAL
+                              * MVREF_SEL_INTERNAL_GVDD
+- m_odr:                     Disable memory transaction reordering; possible
+                             values:
+                              * M_ODR_ENABLE
+                              * M_ODR_DISABLE
+- clock_adjust:              Clock adjust; possible values:
+                              * CLOCK_ADJUST_025
+                              * CLOCK_ADJUST_05
+                              * CLOCK_ADJUST_075
+                              * CLOCK_ADJUST_1
+- ext_refresh_rec:           Extended refresh recovery time; possible values:
+                              0, 16, 32, 48, 64, 80, 96, 112
+- read_to_write:             Read-to-write turnaround; possible values:
+                              0, 1, 2, 3
+- write_to_read:             Write-to-read turnaround; possible values:
+                              0, 1, 2, 3
+- read_to_read:              Read-to-read turnaround; possible values:
+                              0, 1, 2, 3
+- write_to_write:            Write-to-write turnaround; possible values:
+                              0, 1, 2, 3
+- active_powerdown_exit:     Active powerdown exit timing; possible values:
+                              1, 2, 3, 4, 5, 6, 7
+- precharge_powerdown_exit:  Precharge powerdown exit timing; possible values:
+                              1, 2, 3, 4, 5, 6, 7
+- odt_powerdown_exit:        ODT powerdown exit timing; possible values:
+                              0, 1, 2, 3, 4, 5, 6, 7, 8,
+                              9, 10, 11, 12, 13, 14, 15
+- mode_reg_set_cycle:        Mode register set cycle time; possible values:
+                              1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+- precharge_to_activate:     Precharge-to-acitvate interval; possible values:
+                              1, 2, 3, 4, 5, 6, 7
+- activate_to_precharge:     Activate to precharge interval; possible values:
+                              4, 5, 6, 7, 8, 9, 10, 11, 12,
+                              13, 14, 15, 16, 17, 18, 19
+- activate_to_readwrite:     Activate to read/write interval for SDRAM;
+                             possible values:
+                              1, 2, 3, 4, 5, 6, 7
+- mcas_latency:              MCAS latency from READ command; possible values:
+                              * CASLAT_20
+                              * CASLAT_25
+                              * CASLAT_30
+                              * CASLAT_35
+                              * CASLAT_40
+                              * CASLAT_45
+                              * CASLAT_50
+                              * CASLAT_55
+                              * CASLAT_60
+                              * CASLAT_65
+                              * CASLAT_70
+                              * CASLAT_75
+                              * CASLAT_80
+- refresh_recovery:          Refresh recovery time; possible values:
+                              8, 9, 10, 11, 12, 13, 14, 15,
+                              16, 17, 18, 19, 20, 21, 22, 23
+- last_data_to_precharge:    Last data to precharge minimum interval; possible
+                             values:
+                              1, 2, 3, 4, 5, 6, 7
+- activate_to_activate:      Activate-to-activate interval; possible values:
+                              1, 2, 3, 4, 5, 6, 7
+- last_write_data_to_read:   Last write data pair to read command issue
+                             interval; possible values:
+                              1, 2, 3, 4, 5, 6, 7
+- additive_latency:          Additive latency; possible values:
+                              0, 1, 2, 3, 4, 5
+- mcas_to_preamble_override: MCAS-to-preamble-override; possible values:
+                              * READ_LAT
+                              * READ_LAT_PLUS_1_4
+                              * READ_LAT_PLUS_1_2
+                              * READ_LAT_PLUS_3_4
+                              * READ_LAT_PLUS_1
+                              * READ_LAT_PLUS_5_4
+                              * READ_LAT_PLUS_3_2
+                              * READ_LAT_PLUS_7_4
+                              * READ_LAT_PLUS_2
+                              * READ_LAT_PLUS_9_4
+                              * READ_LAT_PLUS_5_2
+                              * READ_LAT_PLUS_11_4
+                              * READ_LAT_PLUS_3
+                              * READ_LAT_PLUS_13_4
+                              * READ_LAT_PLUS_7_2
+                              * READ_LAT_PLUS_15_4
+                              * READ_LAT_PLUS_4
+                              * READ_LAT_PLUS_17_4
+                              * READ_LAT_PLUS_9_2
+                              * READ_LAT_PLUS_19_4
+- write_latency:             Write latency; possible values:
+                              1, 2, 3, 4, 5, 6, 7
+- read_to_precharge:         Read to precharge; possible values:
+                              1, 2, 3, 4
+- write_cmd_to_write_data:   Write command to write data strobe timing
+                             adjustment; possible values:
+                              * CLOCK_DELAY_0
+                              * CLOCK_DELAY_1_4
+                              * CLOCK_DELAY_1_2
+                              * CLOCK_DELAY_3_4
+                              * CLOCK_DELAY_1
+                              * CLOCK_DELAY_5_4
+                              * CLOCK_DELAY_3_2
+- minimum_cke_pulse_width:   Minimum CKE pulse width; possible values:
+                              1, 2, 3, 4
+- four_activates_window:     Window for four activates; possible values:
+                              1, 2, 3, 4 8, 9, 10, 11, 12,
+                              13, 14, 15, 16, 17, 18, 19
+- self_refresh:              Self refresh (during sleep); possible values:
+                              * SREN_DISABLE
+                              * SREN_ENABLE
+- ecc:                       Support for ECC; possible values:
+                              * ECC_DISABLE
+                              * ECC_ENABLE
+- registered_dram:           Support for registered DRAM; possible values:
+                              * RD_DISABLE
+                              * RD_ENABLE
+- sdram_type:                Type of SDRAM device to be used; possible values:
+                              * TYPE_DDR1
+                              * TYPE_DDR2
+- dynamic_power_management:  Dynamic power management mode; possible values:
+                              * DYN_PWR_DISABLE
+                              * DYN_PWR_ENABLE
+- databus_width:             DRAM data bus width; possible values
+                              * DATA_BUS_WIDTH_16
+                              * DATA_BUS_WIDTH_32
+- nc_auto_precharge:         Non-concurrent auto-precharge; possible values:
+                              * NCAP_DISABLE
+                              * NCAP_ENABLE
+- timing_2t:                 2T timing; possible values:
+                              * TIMING_1T
+                              * TIMING_2T
+- bank_interleaving_ctrl:    Bank (chip select) interleaving control; possible
+                             values:
+                              * INTERLEAVE_NONE
+                              * INTERLEAVE_1_AND_2
+- precharge_bit_8:           Precharge bin 8; possible values
+                              * PRECHARGE_MA_10
+                              * PRECHARGE_MA_8
+- half_strength:             Global half-strength override; possible values:
+                              * STRENGTH_FULL
+                              * STRENGTH_HALF
+- bypass_initialization:     Bypass initialization; possible values:
+                              * INITIALIZATION_DONT_BYPASS
+                              * INITIALIZATION_BYPASS
+- force_self_refresh:         Force self refresh; possible values:
+                               * MODE_NORMAL
+                               * MODE_REFRESH
+- dll_reset:                  DLL reset; possible values:
+                               * DLL_RESET_ENABLE
+                               * DLL_RESET_DISABLE
+- dqs_config:                 DQS configuration; possible values:
+                               * DQS_TRUE
+- odt_config:                 ODT configuration; possible values:
+                               * ODT_ASSERT_NEVER
+                               * ODT_ASSERT_WRITES
+                               * ODT_ASSERT_READS
+                               * ODT_ASSERT_ALWAYS
+- posted_refreshes:           Number of posted refreshes
+                               1, 2, 3, 4, 5, 6, 7, 8
+- sdmode:                     Initial value loaded into the DDR SDRAM mode
+                              register
+- esdmode:                    Initial value loaded into the DDR SDRAM extended
+                              mode register
+- esdmode2:                   Initial value loaded into the DDR SDRAM extended
+                              mode 2 register
+- esdmode3:                   Initial value loaded into the DDR SDRAM extended
+                              mode 3 register
+- refresh_interval:           Refresh interval; possible values:
+                               0 - 65535
+- precharge_interval:         Precharge interval; possible values:
+                               0 - 16383
+
+RAM module node:
+================
+
+Required properties:
+- reg:            A triple <cs addr size>, which consists of:
+                   * cs - the chipselect used to drive this RAM module
+                   * addr - the address where this RAM module's memory is map
+                     to in the global memory space
+                   * size - the size of the RAM module's memory in bytes
+- auto_precharge: Chip select auto-precharge; possible values:
+                   * AUTO_PRECHARGE_ENABLE
+                   * AUTO_PRECHARGE_DISABLE
+- odt_rd_cfg:     ODT for reads configuration; possible values:
+                   * ODT_RD_NEVER
+                   * ODT_RD_ONLY_CURRENT
+                   * ODT_RD_ONLY_OTHER_CS
+                   * ODT_RD_ONLY_OTHER_DIMM
+                   * ODT_RD_ALL
+- odt_wr_cfg:     ODT for writes configuration; possible values:
+                   * ODT_WR_NEVER
+                   * ODT_WR_ONLY_CURRENT
+                   * ODT_WR_ONLY_OTHER_CS
+                   * ODT_WR_ONLY_OTHER_DIMM
+                   * ODT_WR_ALL
+- bank_bits:      Number of bank bits for SDRAM on chip select; possible
+                  values:
+                   2, 3
+- row_bits:       Number of row bits for SDRAM on chip select; possible values:
+                   12, 13, 14
+- col_bits:       Number of column bits for SDRAM on chip select; possible
+                  values:
+                   8, 9, 10, 11
+
+Example:
+
+memory@2000 {
+	#address-cells = <2>;
+	#size-cells = <1>;
+	compatible = "fsl,mpc83xx-mem-controller";
+	reg = <0x2000 0x1000>;
+	device_type = "memory";
+	u-boot,dm-pre-reloc;
+
+	driver_software_override = <DSO_ENABLE>;
+	p_impedance_override = <DSO_P_IMPEDANCE_NOMINAL>;
+	n_impedance_override = <DSO_N_IMPEDANCE_NOMINAL>;
+	odt_termination_value = <ODT_TERMINATION_150_OHM>;
+	ddr_type = <DDR_TYPE_DDR2_1_8_VOLT>;
+
+	clock_adjust = <CLOCK_ADJUST_05>;
+
+	read_to_write = <0>;
+	write_to_read = <0>;
+	read_to_read = <0>;
+	write_to_write = <0>;
+	active_powerdown_exit = <2>;
+	precharge_powerdown_exit = <6>;
+	odt_powerdown_exit = <8>;
+	mode_reg_set_cycle = <2>;
+
+	precharge_to_activate = <2>;
+	activate_to_precharge = <6>;
+	activate_to_readwrite = <2>;
+	mcas_latency = <CASLAT_40>;
+	refresh_recovery = <17>;
+	last_data_to_precharge = <2>;
+	activate_to_activate = <2>;
+	last_write_data_to_read = <2>;
+
+	additive_latency = <0>;
+	mcas_to_preamble_override = <READ_LAT_PLUS_1_2>;
+	write_latency = <3>;
+	read_to_precharge = <2>;
+	write_cmd_to_write_data = <CLOCK_DELAY_1_2>;
+	minimum_cke_pulse_width = <3>;
+	four_activates_window = <5>;
+
+	self_refresh = <SREN_ENABLE>;
+	sdram_type = <TYPE_DDR2>;
+	databus_width = <DATA_BUS_WIDTH_32>;
+
+	force_self_refresh = <MODE_NORMAL>;
+	dll_reset = <DLL_RESET_ENABLE>;
+	dqs_config = <DQS_TRUE>;
+	odt_config = <ODT_ASSERT_READS>;
+	posted_refreshes = <1>;
+
+	refresh_interval = <2084>;
+	precharge_interval = <256>;
+
+	sdmode = <0x0242>;
+	esdmode = <0x0440>;
+
+	ram@0 {
+		reg = <0x0 0x0 0x8000000>;
+		compatible = "nanya,nt5tu64m16hg";
+
+		odt_rd_cfg = <ODT_RD_NEVER>;
+		odt_wr_cfg = <ODT_WR_ONLY_CURRENT>;
+		bank_bits = <3>;
+		row_bits = <13>;
+		col_bits = <10>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/timer/fsl,mpc83xx-timer.txt b/Documentation/devicetree/bindings/timer/fsl,mpc83xx-timer.txt
new file mode 100644
index 0000000..608d241
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/fsl,mpc83xx-timer.txt
@@ -0,0 +1,21 @@
+MPC83xx timer devices
+
+MPC83xx SoCs offer a decrementer interrupt that can be used to implement delay
+functionality, and periodically triggered actions.
+
+Required properties:
+- compatible: must be "fsl,mpc83xx-timer"
+- clocks: must be a reference to the system's CSB (coherent system bus) clock,
+  provided by one of the "fsl,mpc83xx-clk" devices
+
+Example:
+
+socclocks: clocks {
+	compatible = "fsl,mpc832x-clk";
+	#clock-cells = <1>;
+};
+
+timer {
+	compatible = "fsl,mpc83xx-timer";
+	clocks = <&socclocks MPC83XX_CLK_CSB>;
+};
diff --git a/MAINTAINERS b/MAINTAINERS
index 39d28e5..237a022 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -519,6 +519,17 @@
 M:	Mario Six <mario.six@gdsys.cc>
 S:	Maintained
 T:	git git://git.denx.de/u-boot-mpc83xx.git
+F:	drivers/ram/mpc83xx_sdram.c
+F:	include/dt-bindings/memory/mpc83xx-sdram.h
+F:	drivers/sysreset/sysreset_mpc83xx.c
+F:	drivers/sysreset/sysreset_mpc83xx.h
+F:	drivers/clk/mpc83xx_clk.c
+F:	drivers/clk/mpc83xx_clk.h
+F:	include/dt-bindings/clk/mpc83xx-clk.h
+F:	drivers/timer/mpc83xx_timer.c
+F:	drivers/cpu/mpc83xx_cpu.c
+F:	drivers/cpu/mpc83xx_cpu.h
+F:	drivers/misc/mpc83xx_serdes.c
 F:	arch/powerpc/cpu/mpc83xx/
 F:	arch/powerpc/include/asm/arch-mpc83xx/
 
diff --git a/arch/Kconfig b/arch/Kconfig
index bf1b4a9..11900b0 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -78,6 +78,7 @@
 	select LZO
 	select SPI
 	select SUPPORT_OF_CONTROL
+	imply BITREVERSE
 	imply CMD_DM
 	imply CMD_GETTIME
 	imply CMD_HASH
diff --git a/arch/powerpc/cpu/mpc83xx/cpu.c b/arch/powerpc/cpu/mpc83xx/cpu.c
index 82370b5..b29f271 100644
--- a/arch/powerpc/cpu/mpc83xx/cpu.c
+++ b/arch/powerpc/cpu/mpc83xx/cpu.c
@@ -25,6 +25,7 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+#ifndef CONFIG_CPU_MPC83XX
 int checkcpu(void)
 {
 	volatile immap_t *immr;
@@ -114,7 +115,9 @@
 
 	return 0;
 }
+#endif
 
+#ifndef CONFIG_SYSRESET
 int
 do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 {
@@ -169,17 +172,17 @@
 
 	return 1;
 }
-
+#endif
 
 /*
  * Get timebase clock frequency (like cpu_clk in Hz)
  */
-
+#ifndef CONFIG_TIMER
 unsigned long get_tbclk(void)
 {
 	return (gd->bus_clk + 3L) / 4L;
 }
-
+#endif
 
 #if defined(CONFIG_WATCHDOG)
 void watchdog_reset (void)
diff --git a/arch/powerpc/cpu/mpc83xx/cpu_init.c b/arch/powerpc/cpu/mpc83xx/cpu_init.c
index fcac9f6..1555205 100644
--- a/arch/powerpc/cpu/mpc83xx/cpu_init.c
+++ b/arch/powerpc/cpu/mpc83xx/cpu_init.c
@@ -464,6 +464,7 @@
 }
 #endif /* CONFIG_DISPLAY_AER_xxxx */
 
+#ifndef CONFIG_CPU_MPC83XX
 /*
  * Figure out the cause of the reset
  */
@@ -505,3 +506,4 @@
 
 	return 0;
 }
+#endif
diff --git a/arch/powerpc/cpu/mpc83xx/serdes.c b/arch/powerpc/cpu/mpc83xx/serdes.c
index 982a447..8242f95 100644
--- a/arch/powerpc/cpu/mpc83xx/serdes.c
+++ b/arch/powerpc/cpu/mpc83xx/serdes.c
@@ -8,6 +8,8 @@
  * Author: Li Yang <leoli@freescale.com>
  */
 
+#ifndef CONFIG_MPC83XX_SERDES
+
 #include <config.h>
 #include <common.h>
 #include <asm/io.h>
@@ -148,3 +150,5 @@
 	tmp |= FSL_SRDSRSTCTL_RST;
 	out_be32(regs + FSL_SRDSRSTCTL_OFFS, tmp);
 }
+
+#endif /* !CONFIG_MPC83XX_SERDES */
diff --git a/arch/powerpc/cpu/mpc83xx/spd_sdram.c b/arch/powerpc/cpu/mpc83xx/spd_sdram.c
index bbc8ef0..328a018 100644
--- a/arch/powerpc/cpu/mpc83xx/spd_sdram.c
+++ b/arch/powerpc/cpu/mpc83xx/spd_sdram.c
@@ -10,6 +10,8 @@
  * Xianghua Xiao (X.Xiao@motorola.com)
  */
 
+#ifndef CONFIG_MPC83XX_SDRAM
+
 #include <common.h>
 #include <asm/processor.h>
 #include <asm/io.h>
@@ -924,3 +926,5 @@
 	__asm__ __volatile__ ("isync");
 }
 #endif	/* CONFIG_DDR_ECC */
+
+#endif /* !CONFIG_MPC83XX_SDRAM */
diff --git a/arch/powerpc/cpu/mpc83xx/speed.c b/arch/powerpc/cpu/mpc83xx/speed.c
index f094528..39bc1c5 100644
--- a/arch/powerpc/cpu/mpc83xx/speed.c
+++ b/arch/powerpc/cpu/mpc83xx/speed.c
@@ -6,6 +6,8 @@
  * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
  */
 
+#ifndef CONFIG_CLK_MPC83XX
+
 #include <common.h>
 #include <mpc83xx.h>
 #include <command.h>
@@ -590,3 +592,5 @@
 	"print clock configuration",
 	"    clocks"
 );
+
+#endif
diff --git a/arch/powerpc/include/asm/arch-mpc83xx/soc.h b/arch/powerpc/include/asm/arch-mpc83xx/soc.h
new file mode 100644
index 0000000..39bf7d5
--- /dev/null
+++ b/arch/powerpc/include/asm/arch-mpc83xx/soc.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+#ifndef _MPC83XX_SOC_H_
+#define _MPC83XX_SOC_H_
+
+enum soc_type {
+	SOC_MPC8308,
+	SOC_MPC8309,
+	SOC_MPC8313,
+	SOC_MPC8315,
+	SOC_MPC832X,
+	SOC_MPC8349,
+	SOC_MPC8360,
+	SOC_MPC8379,
+};
+
+bool mpc83xx_has_sdhc(int type)
+{
+	return (type == SOC_MPC8308) ||
+	       (type == SOC_MPC8309) ||
+	       (type == SOC_MPC8379);
+}
+
+bool mpc83xx_has_tsec(int type)
+{
+	return (type == SOC_MPC8308) ||
+	       (type == SOC_MPC8313) ||
+	       (type == SOC_MPC8315) ||
+	       (type == SOC_MPC8349) ||
+	       (type == SOC_MPC8379);
+}
+
+bool mpc83xx_has_pcie1(int type)
+{
+	return (type == SOC_MPC8308) ||
+	       (type == SOC_MPC8315) ||
+	       (type == SOC_MPC8379);
+}
+
+bool mpc83xx_has_pcie2(int type)
+{
+	return (type == SOC_MPC8315) ||
+	       (type == SOC_MPC8379);
+}
+
+bool mpc83xx_has_sata(int type)
+{
+	return (type == SOC_MPC8315) ||
+	       (type == SOC_MPC8379);
+}
+
+bool mpc83xx_has_pci(int type)
+{
+	return type != SOC_MPC8308;
+}
+
+bool mpc83xx_has_second_i2c(int type)
+{
+	return (type != SOC_MPC8315) &&
+	       (type != SOC_MPC832X);
+}
+
+bool mpc83xx_has_quicc_engine(int type)
+{
+	return (type == SOC_MPC8309) ||
+	       (type == SOC_MPC832X) ||
+	       (type == SOC_MPC8360);
+}
+
+#endif /* _MPC83XX_SOC_H_ */
diff --git a/arch/powerpc/include/asm/config.h b/arch/powerpc/include/asm/config.h
index bf11f40..849a69a 100644
--- a/arch/powerpc/include/asm/config.h
+++ b/arch/powerpc/include/asm/config.h
@@ -75,7 +75,7 @@
 /* All PPC boards must swap IDE bytes */
 #define CONFIG_IDE_SWAP_IO
 
-#if defined(CONFIG_DM_SERIAL)
+#if defined(CONFIG_DM_SERIAL) && !defined(CONFIG_CLK_MPC83XX)
 /*
  * TODO: Convert this to a clock driver exists that can give us the UART
  * clock here.
diff --git a/arch/powerpc/include/asm/fsl_mpc83xx_serdes.h b/arch/powerpc/include/asm/fsl_mpc83xx_serdes.h
index e51d060..a02b599 100644
--- a/arch/powerpc/include/asm/fsl_mpc83xx_serdes.h
+++ b/arch/powerpc/include/asm/fsl_mpc83xx_serdes.h
@@ -6,6 +6,8 @@
 #ifndef __FSL_MPC83XX_SERDES_H
 #define __FSL_MPC83XX_SERDES_H
 
+#ifndef CONFIG_MPC83XX_SERDES
+
 #include <config.h>
 
 #define FSL_SERDES_CLK_100		(0 << 28)
@@ -19,4 +21,6 @@
 
 extern void fsl_setup_serdes(u32 offset, char proto, u32 rfcks, char vdd);
 
+#endif /* !CONFIG_MPC83XX_SERDES */
+
 #endif /* __FSL_MPC83XX_SERDES_H */
diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h
index 07d5bea..d00cee9 100644
--- a/arch/powerpc/include/asm/global_data.h
+++ b/arch/powerpc/include/asm/global_data.h
@@ -30,6 +30,9 @@
 #endif
 	/* TODO: sjg@chromium.org: Should these be unslgned long? */
 #if defined(CONFIG_MPC83xx)
+#ifdef CONFIG_CLK_MPC83XX
+	u32 core_clk;
+#else
 	/* There are other clocks in the MPC83XX */
 	u32 csb_clk;
 # if defined(CONFIG_MPC8308) || defined(CONFIG_MPC831x) || \
@@ -62,6 +65,7 @@
 	u32 mem_sec_clk;
 # endif /* CONFIG_MPC8360 */
 #endif
+#endif
 #if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
 	u32 lbc_clk;
 	void *cpu;
diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h
index 34fbfdf..6d76e3e 100644
--- a/arch/powerpc/include/asm/io.h
+++ b/arch/powerpc/include/asm/io.h
@@ -282,6 +282,24 @@
 #define setbits_8(addr, set) setbits(8, addr, set)
 #define clrsetbits_8(addr, clear, set) clrsetbits(8, addr, clear, set)
 
+#define readb_be(addr)							\
+	__raw_readb((__force unsigned *)(addr))
+#define readw_be(addr)							\
+	be16_to_cpu(__raw_readw((__force unsigned *)(addr)))
+#define readl_be(addr)							\
+	be32_to_cpu(__raw_readl((__force unsigned *)(addr)))
+#define readq_be(addr)							\
+	be64_to_cpu(__raw_readq((__force unsigned *)(addr)))
+
+#define writeb_be(val, addr)						\
+	__raw_writeb((val), (__force unsigned *)(addr))
+#define writew_be(val, addr)						\
+	__raw_writew(cpu_to_be16((val)), (__force unsigned *)(addr))
+#define writel_be(val, addr)						\
+	__raw_writel(cpu_to_be32((val)), (__force unsigned *)(addr))
+#define writeq_be(val, addr)						\
+	__raw_writeq(cpu_to_be64((val)), (__force unsigned *)(addr))
+
 static inline void *phys_to_virt(phys_addr_t paddr)
 {
 #ifdef CONFIG_ADDR_MAP
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 6fbe8c4..f97ce48 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -1325,7 +1325,9 @@
 /* In misc.c */
 void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
 
+#ifndef CONFIG_CPU_MPC83XX
 int prt_83xx_rsr(void);
+#endif
 
 #endif /* ndef ASSEMBLY*/
 
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index c3acefa..8ac49bd 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -17,13 +17,17 @@
 
 ifdef MINIMAL
 obj-y += cache.o time.o
+ifndef CONFIG_TIMER
 obj-y += ticks.o
+endif
 else
 
 obj-y	+= ppcstring.o
 
 obj-y	+= ppccache.o
+ifndef CONFIG_TIMER
 obj-y	+= ticks.o
+endif
 obj-y	+= reloc.o
 
 obj-$(CONFIG_BAT_RW) += bat_rw.o
diff --git a/arch/powerpc/lib/interrupts.c b/arch/powerpc/lib/interrupts.c
index f63e5cf..19682cf 100644
--- a/arch/powerpc/lib/interrupts.c
+++ b/arch/powerpc/lib/interrupts.c
@@ -14,6 +14,7 @@
 #include <status_led.h>
 #endif
 
+#ifndef CONFIG_MPC83XX_TIMER
 #ifdef CONFIG_SHOW_ACTIVITY
 void board_show_activity (ulong) __attribute__((weak, alias("__board_show_activity")));
 
@@ -44,7 +45,7 @@
 	if (val)
 		asm volatile ("mtdec %0"::"r" (val));
 }
-
+#endif /* !CONFIG_MPC83XX_TIMER */
 
 void enable_interrupts (void)
 {
@@ -60,6 +61,7 @@
 	return ((msr & MSR_EE) != 0);
 }
 
+#ifndef CONFIG_MPC83XX_TIMER
 int interrupt_init (void)
 {
 	/* call cpu specific function from $(CPU)/interrupts.c */
@@ -102,3 +104,4 @@
 {
 	return (timestamp - base);
 }
+#endif /* !CONFIG_MPC83XX_TIMER */
diff --git a/arch/sandbox/config.mk b/arch/sandbox/config.mk
index 2babcde..95f9e3f 100644
--- a/arch/sandbox/config.mk
+++ b/arch/sandbox/config.mk
@@ -3,6 +3,7 @@
 
 PLATFORM_CPPFLAGS += -D__SANDBOX__ -U_FORTIFY_SOURCE
 PLATFORM_CPPFLAGS += -DCONFIG_ARCH_MAP_SYSMEM
+PLATFORM_CPPFLAGS += -fPIC
 PLATFORM_LIBS += -lrt
 
 # Define this to avoid linking with SDL, which requires SDL libraries
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 3668263..b8524e3 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -297,6 +297,18 @@
 		mbox-names = "other", "test";
 	};
 
+	cpu-test1 {
+		compatible = "sandbox,cpu_sandbox";
+	};
+
+	cpu-test2 {
+		compatible = "sandbox,cpu_sandbox";
+	};
+
+	cpu-test3 {
+		compatible = "sandbox,cpu_sandbox";
+	};
+
 	misc-test {
 		compatible = "sandbox,misc_sandbox";
 	};
diff --git a/common/board_f.c b/common/board_f.c
index 88d7700..213d044 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -11,8 +11,9 @@
 
 #include <common.h>
 #include <console.h>
-#include <environment.h>
+#include <cpu.h>
 #include <dm.h>
+#include <environment.h>
 #include <fdtdec.h>
 #include <fs.h>
 #include <i2c.h>
@@ -24,6 +25,7 @@
 #include <relocate.h>
 #include <spi.h>
 #include <status_led.h>
+#include <sysreset.h>
 #include <timer.h>
 #include <trace.h>
 #include <video.h>
@@ -140,6 +142,57 @@
 	return 0;
 }
 
+#ifdef CONFIG_SYSRESET
+static int print_resetinfo(void)
+{
+	struct udevice *dev;
+	char status[256];
+	int ret;
+
+	ret = uclass_first_device_err(UCLASS_SYSRESET, &dev);
+	if (ret) {
+		debug("%s: No sysreset device found (error: %d)\n",
+		      __func__, ret);
+		/* Not all boards have sysreset drivers available during early
+		 * boot, so don't fail if one can't be found.
+		 */
+		return 0;
+	}
+
+	if (!sysreset_get_status(dev, status, sizeof(status)))
+		printf("%s", status);
+
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_DISPLAY_CPUINFO) && CONFIG_IS_ENABLED(CPU)
+static int print_cpuinfo(void)
+{
+	struct udevice *dev;
+	char desc[512];
+	int ret;
+
+	ret = uclass_first_device_err(UCLASS_CPU, &dev);
+	if (ret) {
+		debug("%s: Could not get CPU device (err = %d)\n",
+		      __func__, ret);
+		return ret;
+	}
+
+	ret = cpu_get_desc(dev, desc, sizeof(desc));
+	if (ret) {
+		debug("%s: Could not get CPU description (err = %d)\n",
+		      dev->name, ret);
+		return ret;
+	}
+
+	printf("%s", desc);
+
+	return 0;
+}
+#endif
+
 static int announce_dram_init(void)
 {
 	puts("DRAM:  ");
@@ -790,6 +843,9 @@
 #if defined(CONFIG_PPC) || defined(CONFIG_SH) || defined(CONFIG_X86)
 	checkcpu,
 #endif
+#if defined(CONFIG_SYSRESET)
+	print_resetinfo,
+#endif
 #if defined(CONFIG_DISPLAY_CPUINFO)
 	print_cpuinfo,		/* display cpu info (and speed) */
 #endif
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 809eb3d..c996d65 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -107,4 +107,10 @@
 	  Crystal Oscillator). The output frequency can be programmed via an
 	  I2C interface.
 
+config CLK_MPC83XX
+	bool "Enable MPC83xx clock driver"
+	depends on CLK
+	help
+	  Support for the clock driver of the MPC83xx series of SoCs.
+
 endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 82c36b7..11468f2 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -18,6 +18,7 @@
 obj-$(CONFIG_CLK_BOSTON) += clk_boston.o
 obj-$(CONFIG_CLK_EXYNOS) += exynos/
 obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o
+obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o
 obj-$(CONFIG_CLK_OWL) += owl/
 obj-$(CONFIG_CLK_RENESAS) += renesas/
 obj-$(CONFIG_CLK_STM32F) += clk_stm32f.o
diff --git a/drivers/clk/mpc83xx_clk.c b/drivers/clk/mpc83xx_clk.c
new file mode 100644
index 0000000..4890041
--- /dev/null
+++ b/drivers/clk/mpc83xx_clk.c
@@ -0,0 +1,410 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2017
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <dt-bindings/clk/mpc83xx-clk.h>
+#include <asm/arch/soc.h>
+
+#include "mpc83xx_clk.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct mpc83xx_clk_priv - Private data structure for the MPC83xx clock
+ *			     driver
+ * @speed: Array containing the speed values of all system clocks (initialized
+ *	   once, then only read back)
+ */
+struct mpc83xx_clk_priv {
+	u32 speed[MPC83XX_CLK_COUNT];
+};
+
+/**
+ * is_clk_valid() - Check if clock ID is valid for given clock device
+ * @clk: The clock device for which to check a clock ID
+ * @id:  The clock ID to check
+ *
+ * Return: true if clock ID is valid for clock device, false if not
+ */
+static inline bool is_clk_valid(struct udevice *clk, int id)
+{
+	ulong type = dev_get_driver_data(clk);
+
+	switch (id) {
+	case MPC83XX_CLK_MEM:
+		return true;
+	case MPC83XX_CLK_MEM_SEC:
+		return type == SOC_MPC8360;
+	case MPC83XX_CLK_ENC:
+		return (type == SOC_MPC8308) || (type == SOC_MPC8309);
+	case MPC83XX_CLK_I2C1:
+		return true;
+	case MPC83XX_CLK_TDM:
+		return type == SOC_MPC8315;
+	case MPC83XX_CLK_SDHC:
+		return mpc83xx_has_sdhc(type);
+	case MPC83XX_CLK_TSEC1:
+	case MPC83XX_CLK_TSEC2:
+		return mpc83xx_has_tsec(type);
+	case MPC83XX_CLK_USBDR:
+		return type == SOC_MPC8360;
+	case MPC83XX_CLK_USBMPH:
+		return type == SOC_MPC8349;
+	case MPC83XX_CLK_PCIEXP1:
+		return mpc83xx_has_pcie1(type);
+	case MPC83XX_CLK_PCIEXP2:
+		return mpc83xx_has_pcie2(type);
+	case MPC83XX_CLK_SATA:
+		return mpc83xx_has_sata(type);
+	case MPC83XX_CLK_DMAC:
+		return (type == SOC_MPC8308) || (type == SOC_MPC8309);
+	case MPC83XX_CLK_PCI:
+		return mpc83xx_has_pci(type);
+	case MPC83XX_CLK_CSB:
+		return true;
+	case MPC83XX_CLK_I2C2:
+		return mpc83xx_has_second_i2c(type);
+	case MPC83XX_CLK_QE:
+	case MPC83XX_CLK_BRG:
+		return mpc83xx_has_quicc_engine(type) && (type != SOC_MPC8309);
+	case MPC83XX_CLK_LCLK:
+	case MPC83XX_CLK_LBIU:
+	case MPC83XX_CLK_CORE:
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * init_single_clk() - Initialize a clock with a given ID
+ * @dev: The clock device for which to initialize the clock
+ * @clk: The clock ID
+ *
+ * The clock speed is read from the hardware's registers, and stored in the
+ * private data structure of the driver. From there it is only retrieved, and
+ * not set.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+static int init_single_clk(struct udevice *dev, int clk)
+{
+	struct mpc83xx_clk_priv *priv = dev_get_priv(dev);
+	immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	ulong type = dev_get_driver_data(dev);
+	struct clk_mode mode;
+	ulong mask;
+	u32 csb_clk = get_csb_clk(im);
+	int ret;
+
+	ret = retrieve_mode(clk, type, &mode);
+	if (ret) {
+		debug("%s: Could not retrieve mode for clk %d (ret = %d)\n",
+		      dev->name, clk, ret);
+		return ret;
+	}
+
+	if (mode.type == TYPE_INVALID) {
+		debug("%s: clock %d invalid\n", dev->name, clk);
+		return -EINVAL;
+	}
+
+	if (mode.type == TYPE_SCCR_STANDARD) {
+		mask = GENMASK(31 - mode.low, 31 - mode.high);
+
+		switch (sccr_field(im, mask)) {
+		case 0:
+			priv->speed[clk] = 0;
+			break;
+		case 1:
+			priv->speed[clk] = csb_clk;
+			break;
+		case 2:
+			priv->speed[clk] = csb_clk / 2;
+			break;
+		case 3:
+			priv->speed[clk] = csb_clk / 3;
+			break;
+		default:
+			priv->speed[clk] = 0;
+		}
+
+		return 0;
+	}
+
+	if (mode.type == TYPE_SPMR_DIRECT_MULTIPLY) {
+		mask = GENMASK(31 - mode.low, 31 - mode.high);
+
+		priv->speed[clk] = csb_clk * (1 + sccr_field(im, mask));
+		return 0;
+	}
+
+	if (clk == MPC83XX_CLK_CSB || clk == MPC83XX_CLK_I2C2) {
+		priv->speed[clk] = csb_clk; /* i2c-2 clk is equal to csb clk */
+		return 0;
+	}
+
+	if (clk == MPC83XX_CLK_QE || clk == MPC83XX_CLK_BRG) {
+		u32 pci_sync_in = get_pci_sync_in(im);
+		u32 qepmf = spmr_field(im, SPMR_CEPMF);
+		u32 qepdf = spmr_field(im, SPMR_CEPDF);
+		u32 qe_clk = (pci_sync_in * qepmf) / (1 + qepdf);
+
+		if (clk == MPC83XX_CLK_QE)
+			priv->speed[clk] = qe_clk;
+		else
+			priv->speed[clk] = qe_clk / 2;
+
+		return 0;
+	}
+
+	if (clk == MPC83XX_CLK_LCLK || clk == MPC83XX_CLK_LBIU) {
+		u32 lbiu_clk = csb_clk *
+			(1 + spmr_field(im, SPMR_LBIUCM));
+		u32 clkdiv = lcrr_field(im, LCRR_CLKDIV);
+
+		if (clk == MPC83XX_CLK_LBIU)
+			priv->speed[clk] = lbiu_clk;
+
+		switch (clkdiv) {
+		case 2:
+		case 4:
+		case 8:
+			priv->speed[clk] = lbiu_clk / clkdiv;
+			break;
+		default:
+			/* unknown lcrr */
+			priv->speed[clk] = 0;
+		}
+
+		return 0;
+	}
+
+	if (clk == MPC83XX_CLK_CORE) {
+		u8 corepll = spmr_field(im, SPMR_COREPLL);
+		u32 corecnf_tab_index = ((corepll & 0x1F) << 2) |
+					((corepll & 0x60) >> 5);
+
+		if (corecnf_tab_index > (ARRAY_SIZE(corecnf_tab))) {
+			debug("%s: Core configuration index %02x too high; possible wrong value",
+			      dev->name, corecnf_tab_index);
+			return -EINVAL;
+		}
+
+		switch (corecnf_tab[corecnf_tab_index].core_csb_ratio) {
+		case RAT_BYP:
+		case RAT_1_TO_1:
+			priv->speed[clk] = csb_clk;
+			break;
+		case RAT_1_5_TO_1:
+			priv->speed[clk] = (3 * csb_clk) / 2;
+			break;
+		case RAT_2_TO_1:
+			priv->speed[clk] = 2 * csb_clk;
+			break;
+		case RAT_2_5_TO_1:
+			priv->speed[clk] = (5 * csb_clk) / 2;
+			break;
+		case RAT_3_TO_1:
+			priv->speed[clk] = 3 * csb_clk;
+			break;
+		default:
+			/* unknown core to csb ratio */
+			priv->speed[clk] = 0;
+		}
+
+		return 0;
+	}
+
+	/* Unknown clk value -> error */
+	debug("%s: clock %d invalid\n", dev->name, clk);
+	return -EINVAL;
+}
+
+/**
+ * init_all_clks() - Initialize all clocks of a clock device
+ * @dev: The clock device whose clocks should be initialized
+ *
+ * Return: 0 if OK, -ve on error
+ */
+static inline int init_all_clks(struct udevice *dev)
+{
+	int i;
+
+	for (i = 0; i < MPC83XX_CLK_COUNT; i++) {
+		int ret;
+
+		if (!is_clk_valid(dev, i))
+			continue;
+
+		ret = init_single_clk(dev, i);
+		if (ret) {
+			debug("%s: Failed to initialize %s clock\n",
+			      dev->name, names[i]);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int mpc83xx_clk_request(struct clk *clock)
+{
+	/* Reject requests of clocks that are not available */
+	if (is_clk_valid(clock->dev, clock->id))
+		return 0;
+	else
+		return -ENODEV;
+}
+
+static ulong mpc83xx_clk_get_rate(struct clk *clk)
+{
+	struct mpc83xx_clk_priv *priv = dev_get_priv(clk->dev);
+
+	if (clk->id >= MPC83XX_CLK_COUNT) {
+		debug("%s: clock index %lu invalid\n", __func__, clk->id);
+		return 0;
+	}
+
+	return priv->speed[clk->id];
+}
+
+int get_clocks(void)
+{
+	/* Empty implementation to keep the prototype in common.h happy */
+	return 0;
+}
+
+int get_serial_clock(void)
+{
+	struct mpc83xx_clk_priv *priv;
+	struct udevice *clk;
+	int ret;
+
+	ret = uclass_first_device_err(UCLASS_CLK, &clk);
+	if (ret) {
+		debug("%s: Could not get clock device\n", __func__);
+		return ret;
+	}
+
+	priv = dev_get_priv(clk);
+
+	return priv->speed[MPC83XX_CLK_CSB];
+}
+
+const struct clk_ops mpc83xx_clk_ops = {
+	.request = mpc83xx_clk_request,
+	.get_rate = mpc83xx_clk_get_rate,
+};
+
+static const struct udevice_id mpc83xx_clk_match[] = {
+	{ .compatible = "fsl,mpc8308-clk", .data = SOC_MPC8308 },
+	{ .compatible = "fsl,mpc8309-clk", .data = SOC_MPC8309 },
+	{ .compatible = "fsl,mpc8313-clk", .data = SOC_MPC8313 },
+	{ .compatible = "fsl,mpc8315-clk", .data = SOC_MPC8315 },
+	{ .compatible = "fsl,mpc832x-clk", .data = SOC_MPC832X },
+	{ .compatible = "fsl,mpc8349-clk", .data = SOC_MPC8349 },
+	{ .compatible = "fsl,mpc8360-clk", .data = SOC_MPC8360 },
+	{ .compatible = "fsl,mpc8379-clk", .data = SOC_MPC8379 },
+	{ /* sentinel */ }
+};
+
+static int mpc83xx_clk_probe(struct udevice *dev)
+{
+	struct mpc83xx_clk_priv *priv = dev_get_priv(dev);
+	ulong type;
+	int ret;
+
+	ret = init_all_clks(dev);
+	if (ret) {
+		debug("%s: Could not initialize all clocks (ret = %d)\n",
+		      dev->name, ret);
+		return ret;
+	}
+
+	type = dev_get_driver_data(dev);
+
+	if (mpc83xx_has_sdhc(type))
+		gd->arch.sdhc_clk = priv->speed[MPC83XX_CLK_SDHC];
+
+	gd->arch.core_clk = priv->speed[MPC83XX_CLK_CORE];
+	gd->arch.i2c1_clk = priv->speed[MPC83XX_CLK_I2C1];
+	if (mpc83xx_has_second_i2c(type))
+		gd->arch.i2c2_clk = priv->speed[MPC83XX_CLK_I2C2];
+
+	gd->mem_clk = priv->speed[MPC83XX_CLK_MEM];
+
+	if (mpc83xx_has_pci(type))
+		gd->pci_clk = priv->speed[MPC83XX_CLK_PCI];
+
+	gd->cpu_clk = priv->speed[MPC83XX_CLK_CORE];
+	gd->bus_clk = priv->speed[MPC83XX_CLK_CSB];
+
+	return 0;
+}
+
+static int mpc83xx_clk_bind(struct udevice *dev)
+{
+	int ret;
+	struct udevice *sys_child;
+
+	/*
+	 * Since there is no corresponding device tree entry, and since the
+	 * clock driver has to be present in either case, bind the sysreset
+	 * driver here.
+	 */
+	ret = device_bind_driver(dev, "mpc83xx_sysreset", "sysreset",
+				 &sys_child);
+	if (ret)
+		debug("%s: No sysreset driver: ret=%d\n",
+		      dev->name, ret);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(mpc83xx_clk) = {
+	.name = "mpc83xx_clk",
+	.id = UCLASS_CLK,
+	.of_match = mpc83xx_clk_match,
+	.ops = &mpc83xx_clk_ops,
+	.probe = mpc83xx_clk_probe,
+	.priv_auto_alloc_size	= sizeof(struct mpc83xx_clk_priv),
+	.bind = mpc83xx_clk_bind,
+};
+
+static int do_clocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	int i;
+	char buf[32];
+	struct udevice *clk;
+	int ret;
+	struct mpc83xx_clk_priv *priv;
+
+	ret = uclass_first_device_err(UCLASS_CLK, &clk);
+	if (ret) {
+		debug("%s: Could not get clock device\n", __func__);
+		return ret;
+	}
+
+	for (i = 0; i < MPC83XX_CLK_COUNT; i++) {
+		if (!is_clk_valid(clk, i))
+			continue;
+
+		priv = dev_get_priv(clk);
+
+		printf("%s = %s MHz\n", names[i], strmhz(buf, priv->speed[i]));
+	}
+
+	return 0;
+}
+
+U_BOOT_CMD(clocks,	1,	1,	do_clocks,
+	   "display values of SoC's clocks",
+	   ""
+);
diff --git a/drivers/clk/mpc83xx_clk.h b/drivers/clk/mpc83xx_clk.h
new file mode 100644
index 0000000..7fb8802
--- /dev/null
+++ b/drivers/clk/mpc83xx_clk.h
@@ -0,0 +1,379 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+/**
+ * enum ratio - Description of a core clock ratio
+ * @RAT_UNK:      Unknown ratio
+ * @RAT_BYP:      Bypass
+ * @RAT_1_TO_8:   Ratio 1:8
+ * @RAT_1_TO_4:   Ratio 1:4
+ * @RAT_1_TO_2:   Ratio 1:2
+ * @RAT_1_TO_1:   Ratio 1:1
+ * @RAT_1_5_TO_1: Ratio 1.5:1
+ * @RAT_2_TO_1:   Ratio 2:1
+ * @RAT_2_5_TO_1: Ratio 2.5:1
+ * @RAT_3_TO_1:   Ratio 3:1
+ */
+enum ratio {
+	RAT_UNK,
+	RAT_BYP,
+	RAT_1_TO_8,
+	RAT_1_TO_4,
+	RAT_1_TO_2,
+	RAT_1_TO_1,
+	RAT_1_5_TO_1,
+	RAT_2_TO_1,
+	RAT_2_5_TO_1,
+	RAT_3_TO_1
+};
+
+/**
+ * struct corecnf - Description for a core clock configuration
+ * @core_csb_ratio: Core clock frequency to CSB clock frequency ratio
+ * @vco_divider: VCO divider (Core VCO frequency = Core frequency * VCO divider)
+ */
+struct corecnf {
+	int core_csb_ratio;
+	int vco_divider;
+};
+
+/*
+ * Table with all valid Core CSB frequency ratio / VCO divider combinations as
+ * indexed by the COREPLL field of the SPMR
+ */
+static const struct corecnf corecnf_tab[] = {
+	{RAT_BYP, RAT_BYP},			/* 0x00 */
+	{RAT_BYP, RAT_BYP},			/* 0x01 */
+	{RAT_BYP, RAT_BYP},			/* 0x02 */
+	{RAT_BYP, RAT_BYP},			/* 0x03 */
+	{RAT_BYP, RAT_BYP},			/* 0x04 */
+	{RAT_BYP, RAT_BYP},			/* 0x05 */
+	{RAT_BYP, RAT_BYP},			/* 0x06 */
+	{RAT_BYP, RAT_BYP},			/* 0x07 */
+	{RAT_1_TO_1, RAT_1_TO_2},		/* 0x08 */
+	{RAT_1_TO_1, RAT_1_TO_4},		/* 0x09 */
+	{RAT_1_TO_1, RAT_1_TO_8},		/* 0x0A */
+	{RAT_1_TO_1, RAT_1_TO_8},		/* 0x0B */
+	{RAT_1_5_TO_1, RAT_1_TO_2},		/* 0x0C */
+	{RAT_1_5_TO_1, RAT_1_TO_4},		/* 0x0D */
+	{RAT_1_5_TO_1, RAT_1_TO_8},		/* 0x0E */
+	{RAT_1_5_TO_1, RAT_1_TO_8},		/* 0x0F */
+	{RAT_2_TO_1, RAT_1_TO_2},		/* 0x10 */
+	{RAT_2_TO_1, RAT_1_TO_4},		/* 0x11 */
+	{RAT_2_TO_1, RAT_1_TO_8},		/* 0x12 */
+	{RAT_2_TO_1, RAT_1_TO_8},		/* 0x13 */
+	{RAT_2_5_TO_1, RAT_1_TO_2},		/* 0x14 */
+	{RAT_2_5_TO_1, RAT_1_TO_4},		/* 0x15 */
+	{RAT_2_5_TO_1, RAT_1_TO_8},		/* 0x16 */
+	{RAT_2_5_TO_1, RAT_1_TO_8},		/* 0x17 */
+	{RAT_3_TO_1, RAT_1_TO_2},		/* 0x18 */
+	{RAT_3_TO_1, RAT_1_TO_4},		/* 0x19 */
+	{RAT_3_TO_1, RAT_1_TO_8},		/* 0x1A */
+	{RAT_3_TO_1, RAT_1_TO_8},		/* 0x1B */
+};
+
+/**
+ * enum reg_type - Register to read a field from
+ * @REG_SCCR: Use the SCCR register
+ * @REG_SPMR: Use the SPMR register
+ */
+enum reg_type {
+	REG_SCCR,
+	REG_SPMR,
+};
+
+/**
+ * enum mode_type - Description of how to read a specific frequency value
+ * @TYPE_INVALID: Unknown type, will provoke error
+ * @TYPE_SCCR_STANDARD:        Read a field from the SCCR register, and use it
+ *			       as a divider for the CSB clock to compute the
+ *			       frequency
+ * @TYPE_SCCR_ONOFF:           The field describes a bit flag that can turn the
+ *			       clock on or off
+ * @TYPE_SPMR_DIRECT_MULTIPLY: Read a field from the SPMR register, and use it
+ *			       as a multiplier for the CSB clock to compute the
+ *			       frequency
+ * @TYPE_SPECIAL:              The frequency is calculated in a non-standard way
+ */
+enum mode_type {
+	TYPE_INVALID = 0,
+	TYPE_SCCR_STANDARD,
+	TYPE_SCCR_ONOFF,
+	TYPE_SPMR_DIRECT_MULTIPLY,
+	TYPE_SPECIAL,
+};
+
+/* Map of each clock index to its human-readable name */
+static const char * const names[] = {
+	[MPC83XX_CLK_CORE] = "Core",
+	[MPC83XX_CLK_CSB] = "Coherent System Bus",
+	[MPC83XX_CLK_QE] = "QE",
+	[MPC83XX_CLK_BRG] = "BRG",
+	[MPC83XX_CLK_LBIU] = "Local Bus Controller",
+	[MPC83XX_CLK_LCLK] = "Local Bus",
+	[MPC83XX_CLK_MEM] = "DDR",
+	[MPC83XX_CLK_MEM_SEC] = "DDR Secondary",
+	[MPC83XX_CLK_ENC] = "SEC",
+	[MPC83XX_CLK_I2C1] = "I2C1",
+	[MPC83XX_CLK_I2C2] = "I2C2",
+	[MPC83XX_CLK_TDM] = "TDM",
+	[MPC83XX_CLK_SDHC] = "SDHC",
+	[MPC83XX_CLK_TSEC1] = "TSEC1",
+	[MPC83XX_CLK_TSEC2] = "TSEC2",
+	[MPC83XX_CLK_USBDR] = "USB DR",
+	[MPC83XX_CLK_USBMPH] = "USB MPH",
+	[MPC83XX_CLK_PCIEXP1] = "PCIEXP1",
+	[MPC83XX_CLK_PCIEXP2] = "PCIEXP2",
+	[MPC83XX_CLK_SATA] = "SATA",
+	[MPC83XX_CLK_DMAC] = "DMAC",
+	[MPC83XX_CLK_PCI] = "PCI",
+};
+
+/**
+ * struct clk_mode - Structure for clock mode descriiptions
+ * @low:  The low bit of the data field to read for this mode (may not apply to
+ *	  some modes)
+ * @high: The high bit of the data field to read for this mode (may not apply to
+ *	  some modes)
+ * @type: The type of the mode description (one of enum mode_type)
+ */
+struct clk_mode {
+	u8 low;
+	u8 high;
+	int type;
+};
+
+/**
+ * set_mode() - Build a clock mode description from data
+ * @mode: The clock mode description to be filled out
+ * @low:  The low bit of the data field to read for this mode (may not apply to
+ *	  some modes)
+ * @high: The high bit of the data field to read for this mode (may not apply to
+ *	  some modes)
+ * @type: The type of the mode description (one of enum mode_type)
+ *
+ * Clock mode descriptions are a succinct description of how to read a specific
+ * clock's rate from the hardware; usually by reading a specific field of a
+ * register, such a s the SCCR register, but some types use different methods
+ * for obtaining the clock rate.
+ */
+static void set_mode(struct clk_mode *mode, u8 low, u8 high, int type)
+{
+	mode->low = low;
+	mode->high = high;
+	mode->type = type;
+}
+
+/**
+ * retrieve_mode() - Get the clock mode description for a specific clock
+ * @clk:      The identifier of the clock for which the clock description should
+ *	      be retrieved
+ * @soc_type: The type of MPC83xx SoC for which the clock description should be
+ *	      retrieved
+ * @mode:     Pointer to a clk_mode structure to be filled with data for the
+ *	      clock
+ *
+ * Since some clock rate are stored in different places on different MPC83xx
+ * SoCs, the SoC type has to be supplied along with the clock's identifier.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+static int retrieve_mode(int clk, int soc_type, struct clk_mode *mode)
+{
+	switch (clk) {
+	case MPC83XX_CLK_CORE:
+	case MPC83XX_CLK_CSB:
+	case MPC83XX_CLK_QE:
+	case MPC83XX_CLK_BRG:
+	case MPC83XX_CLK_LCLK:
+	case MPC83XX_CLK_I2C2:
+		set_mode(mode, 0, 0, TYPE_SPECIAL);
+		break;
+	case MPC83XX_CLK_MEM:
+		set_mode(mode, 1, 1, TYPE_SPMR_DIRECT_MULTIPLY);
+		break;
+	case MPC83XX_CLK_LBIU:
+	case MPC83XX_CLK_MEM_SEC:
+		set_mode(mode, 0, 0, TYPE_SPMR_DIRECT_MULTIPLY);
+		break;
+	case MPC83XX_CLK_TSEC1:
+		set_mode(mode, 0, 1, TYPE_SCCR_STANDARD);
+		break;
+	case MPC83XX_CLK_TSEC2:
+		if (soc_type == SOC_MPC8313) /* I2C and TSEC2 are the same register */
+			set_mode(mode, 2, 3, TYPE_SCCR_STANDARD);
+		else /* FIXME(mario.six@gdsys.cc): This has separate enable/disable bit! */
+			set_mode(mode, 0, 1, TYPE_SCCR_STANDARD);
+		break;
+	case MPC83XX_CLK_SDHC:
+		set_mode(mode, 4, 5, TYPE_SCCR_STANDARD);
+		break;
+	case MPC83XX_CLK_ENC:
+		set_mode(mode, 6, 7, TYPE_SCCR_STANDARD);
+		break;
+	case MPC83XX_CLK_I2C1:
+		if (soc_type == SOC_MPC8349)
+			set_mode(mode, 2, 3, TYPE_SCCR_STANDARD);
+		else /* I2C and ENC are the same register */
+			set_mode(mode, 6, 7, TYPE_SCCR_STANDARD);
+		break;
+	case MPC83XX_CLK_PCIEXP1:
+		set_mode(mode, 10, 11, TYPE_SCCR_STANDARD);
+		break;
+	case MPC83XX_CLK_PCIEXP2:
+		set_mode(mode, 12, 13, TYPE_SCCR_STANDARD);
+		break;
+	case MPC83XX_CLK_USBDR:
+		if (soc_type == SOC_MPC8313 || soc_type == SOC_MPC8349)
+			set_mode(mode, 10, 11, TYPE_SCCR_STANDARD);
+		else
+			set_mode(mode, 8, 9, TYPE_SCCR_STANDARD);
+		break;
+	case MPC83XX_CLK_USBMPH:
+		set_mode(mode, 8, 9, TYPE_SCCR_STANDARD);
+		break;
+	case MPC83XX_CLK_PCI:
+		set_mode(mode, 15, 15, TYPE_SCCR_ONOFF);
+		break;
+	case MPC83XX_CLK_DMAC:
+		set_mode(mode, 26, 27, TYPE_SCCR_STANDARD);
+		break;
+	case MPC83XX_CLK_SATA:
+		/* FIXME(mario.six@gdsys.cc): All SATA controllers must have the same clock ratio */
+		if (soc_type == SOC_MPC8379) {
+			set_mode(mode, 24, 25, TYPE_SCCR_STANDARD);
+			set_mode(mode, 26, 27, TYPE_SCCR_STANDARD);
+			set_mode(mode, 28, 29, TYPE_SCCR_STANDARD);
+			set_mode(mode, 30, 31, TYPE_SCCR_STANDARD);
+		} else {
+			set_mode(mode, 18, 19, TYPE_SCCR_STANDARD);
+			set_mode(mode, 20, 21, TYPE_SCCR_STANDARD);
+		}
+		break;
+	case MPC83XX_CLK_TDM:
+		set_mode(mode, 26, 27, TYPE_SCCR_STANDARD);
+		break;
+	default:
+		debug("%s: Unknown clock type %d on soc type %d\n",
+		      __func__, clk, soc_type);
+		set_mode(mode, 0, 0, TYPE_INVALID);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * get_spmr() - Read the SPMR (System PLL Mode Register)
+ * @im: Pointer to the MPC83xx main register map in question
+ *
+ * Return: The SPMR value as a 32-bit number.
+ */
+static inline u32 get_spmr(immap_t *im)
+{
+	u32 res = in_be32(&im->clk.spmr);
+
+	return res;
+}
+
+/**
+ * get_sccr() - Read the SCCR (System Clock Control Register)
+ * @im: Pointer to the MPC83xx main register map in question
+ *
+ * Return: The SCCR value as a 32-bit number.
+ */
+static inline u32 get_sccr(immap_t *im)
+{
+	u32 res = in_be32(&im->clk.sccr);
+
+	return res;
+}
+
+/**
+ * get_lcrr() - Read the LCRR (Clock Ratio Register)
+ * @im: Pointer to the MPC83xx main register map in question
+ *
+ * Return: The LCRR value as a 32-bit number.
+ */
+static inline u32 get_lcrr(immap_t *im)
+{
+	u32 res = in_be32(&im->im_lbc.lcrr);
+
+	return res;
+}
+
+/**
+ * get_pci_sync_in() - Read the PCI synchronization clock speed
+ * @im: Pointer to the MPC83xx main register map in question
+ *
+ * Return: The PCI synchronization clock speed value as a 32-bit number.
+ */
+static inline u32 get_pci_sync_in(immap_t *im)
+{
+	u8 clkin_div;
+
+	clkin_div = (get_spmr(im) & SPMR_CKID) >> SPMR_CKID_SHIFT;
+	return CONFIG_SYS_CLK_FREQ / (1 + clkin_div);
+}
+
+/**
+ * get_csb_clk() - Read the CSB (Coheren System Bus) clock speed
+ * @im: Pointer to the MPC83xx main register map in question
+ *
+ * Return: The CSB clock speed value as a 32-bit number.
+ */
+static inline u32 get_csb_clk(immap_t *im)
+{
+	u8 spmf;
+
+	spmf = (get_spmr(im) & SPMR_SPMF) >> SPMR_SPMF_SHIFT;
+	return CONFIG_SYS_CLK_FREQ * spmf;
+}
+
+/**
+ * spmr_field() - Read a specific SPMR field
+ * @im:   Pointer to the MPC83xx main register map in question
+ * @mask: A bitmask that describes the bitfield to be read
+ *
+ * Return: The value of the bit field as a 32-bit number.
+ */
+static inline uint spmr_field(immap_t *im, u32 mask)
+{
+	/* Extract shift from bitmask */
+	uint shift = mask ? ffs(mask) - 1 : 0;
+
+	return (get_spmr(im) & mask) >> shift;
+}
+
+/**
+ * sccr_field() - Read a specific SCCR field
+ * @im:   Pointer to the MPC83xx main register map in question
+ * @mask: A bitmask that describes the bitfield to be read
+ *
+ * Return: The value of the bit field as a 32-bit number.
+ */
+static inline uint sccr_field(immap_t *im, u32 mask)
+{
+	/* Extract shift from bitmask */
+	uint shift = mask ? ffs(mask) - 1 : 0;
+
+	return (get_sccr(im) & mask) >> shift;
+}
+
+/**
+ * lcrr_field() - Read a specific LCRR field
+ * @im:   Pointer to the MPC83xx main register map in question
+ * @mask: A bitmask that describes the bitfield to be read
+ *
+ * Return: The value of the bit field as a 32-bit number.
+ */
+static inline uint lcrr_field(immap_t *im, u32 mask)
+{
+	/* Extract shift from bitmask */
+	uint shift = mask ? ffs(mask) - 1 : 0;
+
+	return (get_lcrr(im) & mask) >> shift;
+}
diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c
index f8cdbd6..bfd9580 100644
--- a/drivers/core/fdtaddr.c
+++ b/drivers/core/fdtaddr.c
@@ -138,7 +138,7 @@
 
 void *devfdt_remap_addr_index(struct udevice *dev, int index)
 {
-	fdt_addr_t addr = devfdt_get_addr(dev);
+	fdt_addr_t addr = devfdt_get_addr_index(dev, index);
 
 	if (addr == FDT_ADDR_T_NONE)
 		return NULL;
diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c
index 0729dfc..14c020a 100644
--- a/drivers/core/of_access.c
+++ b/drivers/core/of_access.c
@@ -376,6 +376,33 @@
 	return np;
 }
 
+static int of_device_has_prop_value(const struct device_node *device,
+				    const char *propname, const void *propval,
+				    int proplen)
+{
+	struct property *prop = of_find_property(device, propname, NULL);
+
+	if (!prop || !prop->value || prop->length != proplen)
+		return 0;
+	return !memcmp(prop->value, propval, proplen);
+}
+
+struct device_node *of_find_node_by_prop_value(struct device_node *from,
+					       const char *propname,
+					       const void *propval, int proplen)
+{
+	struct device_node *np;
+
+	for_each_of_allnodes_from(from, np) {
+		if (of_device_has_prop_value(np, propname, propval, proplen) &&
+		    of_node_get(np))
+			break;
+	}
+	of_node_put(from);
+
+	return np;
+}
+
 struct device_node *of_find_node_by_phandle(phandle handle)
 {
 	struct device_node *np;
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 0cfb0fb..a7e1927 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -777,3 +777,17 @@
 				gd->fdt_blob, ofnode_to_offset(from), compat));
 	}
 }
+
+ofnode ofnode_by_prop_value(ofnode from, const char *propname,
+			    const void *propval, int proplen)
+{
+	if (of_live_active()) {
+		return np_to_ofnode(of_find_node_by_prop_value(
+			(struct device_node *)ofnode_to_np(from), propname,
+			propval, proplen));
+	} else {
+		return offset_to_ofnode(fdt_node_offset_by_prop_value(
+				gd->fdt_blob, ofnode_to_offset(from),
+				propname, propval, proplen));
+	}
+}
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 72bcc7d..47d10b8 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -330,10 +330,25 @@
 }
 #endif
 
+static int dm_scan_fdt_ofnode_path(const char *path, bool pre_reloc_only)
+{
+	ofnode node;
+
+	node = ofnode_path(path);
+	if (!ofnode_valid(node))
+		return 0;
+
+#if CONFIG_IS_ENABLED(OF_LIVE)
+	if (of_live_active())
+		return dm_scan_fdt_live(gd->dm_root, node.np, pre_reloc_only);
+#endif
+	return dm_scan_fdt_node(gd->dm_root, gd->fdt_blob, node.of_offset,
+				pre_reloc_only);
+}
+
 int dm_extended_scan_fdt(const void *blob, bool pre_reloc_only)
 {
 	int ret;
-	ofnode node;
 
 	ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
 	if (ret) {
@@ -341,21 +356,15 @@
 		return ret;
 	}
 
-	/* bind fixed-clock */
-	node = ofnode_path("/clocks");
-	/* if no DT "clocks" node, no need to go further */
-	if (!ofnode_valid(node))
+	ret = dm_scan_fdt_ofnode_path("/clocks", pre_reloc_only);
+	if (ret) {
+		debug("scan for /clocks failed: %d\n", ret);
 		return ret;
+	}
 
-#if CONFIG_IS_ENABLED(OF_LIVE)
-	if (of_live_active())
-		ret = dm_scan_fdt_live(gd->dm_root, node.np, pre_reloc_only);
-	else
-#endif
-		ret = dm_scan_fdt_node(gd->dm_root, gd->fdt_blob, node.of_offset,
-				       pre_reloc_only);
+	ret = dm_scan_fdt_ofnode_path("/firmware", pre_reloc_only);
 	if (ret)
-		debug("dm_scan_fdt_node() failed: %d\n", ret);
+		debug("scan for /firmware failed: %d\n", ret);
 
 	return ret;
 }
diff --git a/drivers/cpu/Kconfig b/drivers/cpu/Kconfig
index 0d1424d..d405200 100644
--- a/drivers/cpu/Kconfig
+++ b/drivers/cpu/Kconfig
@@ -6,3 +6,10 @@
 	  multiple CPUs, then normally have to be set up in U-Boot so that
 	  they can work correctly in the OS. This provides a framework for
 	  finding out information about available CPUs and making changes.
+
+config CPU_MPC83XX
+	bool "Enable MPC83xx CPU driver"
+	depends on CPU
+	select CLK_MPC83XX
+	help
+	  Support CPU cores for SoCs of the MPC83xx series.
diff --git a/drivers/cpu/Makefile b/drivers/cpu/Makefile
index db515f6..f452ee4 100644
--- a/drivers/cpu/Makefile
+++ b/drivers/cpu/Makefile
@@ -7,3 +7,5 @@
 obj-$(CONFIG_CPU) += cpu-uclass.o
 
 obj-$(CONFIG_ARCH_BMIPS) += bmips_cpu.o
+obj-$(CONFIG_CPU_MPC83XX) += mpc83xx_cpu.o
+obj-$(CONFIG_SANDBOX) += cpu_sandbox.o
diff --git a/drivers/cpu/cpu-uclass.c b/drivers/cpu/cpu-uclass.c
index f362eb1..457f77b 100644
--- a/drivers/cpu/cpu-uclass.c
+++ b/drivers/cpu/cpu-uclass.c
@@ -11,6 +11,29 @@
 #include <dm/lists.h>
 #include <dm/root.h>
 
+int cpu_probe_all(void)
+{
+	struct udevice *cpu;
+	int ret;
+
+	ret = uclass_first_device(UCLASS_CPU, &cpu);
+	if (ret) {
+		debug("%s: No CPU found (err = %d)\n", __func__, ret);
+		return ret;
+	}
+
+	while (cpu) {
+		ret = uclass_next_device(&cpu);
+		if (ret) {
+			debug("%s: Error while probing CPU (err = %d)\n",
+			      __func__, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
 int cpu_get_desc(struct udevice *dev, char *buf, int size)
 {
 	struct cpu_ops *ops = cpu_get_ops(dev);
diff --git a/drivers/cpu/cpu_sandbox.c b/drivers/cpu/cpu_sandbox.c
new file mode 100644
index 0000000..ff87e8a
--- /dev/null
+++ b/drivers/cpu/cpu_sandbox.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <cpu.h>
+
+int cpu_sandbox_get_desc(struct udevice *dev, char *buf, int size)
+{
+	snprintf(buf, size, "LEG Inc. SuperMegaUltraTurbo CPU No. 1");
+
+	return 0;
+}
+
+int cpu_sandbox_get_info(struct udevice *dev, struct cpu_info *info)
+{
+	info->cpu_freq = 42 * 42 * 42 * 42 * 42;
+	info->features = 0x42424242;
+
+	return 0;
+}
+
+int cpu_sandbox_get_count(struct udevice *dev)
+{
+	return 42;
+}
+
+int cpu_sandbox_get_vendor(struct udevice *dev, char *buf, int size)
+{
+	snprintf(buf, size, "Languid Example Garbage Inc.");
+
+	return 0;
+}
+
+static const struct cpu_ops cpu_sandbox_ops = {
+	.get_desc = cpu_sandbox_get_desc,
+	.get_info = cpu_sandbox_get_info,
+	.get_count = cpu_sandbox_get_count,
+	.get_vendor = cpu_sandbox_get_vendor,
+};
+
+int cpu_sandbox_probe(struct udevice *dev)
+{
+	return 0;
+}
+
+static const struct udevice_id cpu_sandbox_ids[] = {
+	{ .compatible = "sandbox,cpu_sandbox" },
+	{ }
+};
+
+U_BOOT_DRIVER(cpu_sandbox) = {
+	.name           = "cpu_sandbox",
+	.id             = UCLASS_CPU,
+	.ops		= &cpu_sandbox_ops,
+	.of_match       = cpu_sandbox_ids,
+	.probe          = cpu_sandbox_probe,
+};
diff --git a/drivers/cpu/mpc83xx_cpu.c b/drivers/cpu/mpc83xx_cpu.c
new file mode 100644
index 0000000..31717af
--- /dev/null
+++ b/drivers/cpu/mpc83xx_cpu.c
@@ -0,0 +1,349 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+#include <common.h>
+#include <bitfield.h>
+#include <clk.h>
+#include <cpu.h>
+#include <dm.h>
+
+#include "mpc83xx_cpu.h"
+
+/**
+ * struct mpc83xx_cpu_priv - Private data for MPC83xx CPUs
+ * @e300_type:      The e300 core type of the MPC83xx CPU
+ * @family:         The MPC83xx family the CPU belongs to
+ * @type:           The MPC83xx type of the CPU
+ * @is_e_processor: Flag indicating whether the CPU is a E processor or not
+ * @is_a_variant:   Flag indicating whtther the CPU is a A variant or not
+ * @revid:          The revision ID of the CPU
+ * @revid.major:    The major part of the CPU's revision ID
+ * @revid.minor:    The minor part of the CPU's revision ID
+ */
+struct mpc83xx_cpu_priv {
+	enum e300_type e300_type;
+	enum mpc83xx_cpu_family family;
+	enum mpc83xx_cpu_type type;
+	bool is_e_processor;
+	bool is_a_variant;
+	struct {
+		uint major;
+		uint minor;
+	} revid;
+};
+
+int checkcpu(void)
+{
+	/* Activate all CPUs  from board_f.c */
+	return cpu_probe_all();
+}
+
+/**
+ * get_spridr() - Read SPRIDR (System Part and Revision ID Register) of CPU
+ *
+ * Return: The SPRIDR value
+ */
+static inline u32 get_spridr(void)
+{
+	immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+
+	return in_be32(&immr->sysconf.spridr);
+}
+
+/**
+ * determine_type() - Determine CPU family of MPC83xx device
+ * @dev: CPU device from which to read CPU family from
+ */
+static inline void determine_family(struct udevice *dev)
+{
+	struct mpc83xx_cpu_priv *priv = dev_get_priv(dev);
+	/* Upper 12 bits of PARTID field (bits 0-23 in SPRIDR) */
+	const u32 PARTID_FAMILY_MASK = 0xFFF00000;
+
+	switch (bitfield_extract_by_mask(get_spridr(), PARTID_FAMILY_MASK)) {
+	case 0x810:
+	case 0x811:
+		priv->family = FAMILY_830X;
+		break;
+	case 0x80B:
+		priv->family = FAMILY_831X;
+		break;
+	case 0x806:
+		priv->family = FAMILY_832X;
+		break;
+	case 0x803:
+		priv->family = FAMILY_834X;
+		break;
+	case 0x804:
+		priv->family = FAMILY_836X;
+		break;
+	case 0x80C:
+		priv->family = FAMILY_837X;
+		break;
+	default:
+		priv->family = FAMILY_UNKNOWN;
+	}
+}
+
+/**
+ * determine_type() - Determine CPU type of MPC83xx device
+ * @dev: CPU device from which to read CPU type from
+ */
+static inline void determine_type(struct udevice *dev)
+{
+	struct mpc83xx_cpu_priv *priv = dev_get_priv(dev);
+	/* Upper 16 bits of PVR (Processor Version Register) */
+	const u32 PCR_UPPER_MASK = 0xFFFF0000;
+	u32 val;
+
+	val = bitfield_extract_by_mask(get_spridr(), PCR_UPPER_MASK);
+
+	/* Mask out E-variant bit */
+	switch (val & 0xFFFE) {
+	case 0x8100:
+		priv->type = TYPE_8308;
+		break;
+	case 0x8110:
+		priv->type = TYPE_8309;
+		break;
+	case 0x80B2:
+		priv->type = TYPE_8311;
+		break;
+	case 0x80B0:
+		priv->type = TYPE_8313;
+		break;
+	case 0x80B6:
+		priv->type = TYPE_8314;
+		break;
+	case 0x80B4:
+		priv->type = TYPE_8315;
+		break;
+	case 0x8066:
+		priv->type = TYPE_8321;
+		break;
+	case 0x8062:
+		priv->type = TYPE_8323;
+		break;
+	case 0x8036:
+		priv->type = TYPE_8343;
+		break;
+	case 0x8032:
+		priv->type = TYPE_8347_TBGA;
+		break;
+	case 0x8034:
+		priv->type = TYPE_8347_PBGA;
+		break;
+	case 0x8030:
+		priv->type = TYPE_8349;
+		break;
+	case 0x804A:
+		priv->type = TYPE_8358_TBGA;
+		break;
+	case 0x804E:
+		priv->type = TYPE_8358_PBGA;
+		break;
+	case 0x8048:
+		priv->type = TYPE_8360;
+		break;
+	case 0x80C6:
+		priv->type = TYPE_8377;
+		break;
+	case 0x80C4:
+		priv->type = TYPE_8378;
+		break;
+	case 0x80C2:
+		priv->type = TYPE_8379;
+		break;
+	default:
+		priv->type = TYPE_UNKNOWN;
+	}
+}
+
+/**
+ * determine_e300_type() - Determine e300 core type of MPC83xx device
+ * @dev: CPU device from which to read e300 core type from
+ */
+static inline void determine_e300_type(struct udevice *dev)
+{
+	struct mpc83xx_cpu_priv *priv = dev_get_priv(dev);
+	/* Upper 16 bits of PVR (Processor Version Register) */
+	const u32 PCR_UPPER_MASK = 0xFFFF0000;
+	u32 pvr = get_pvr();
+
+	switch ((pvr & PCR_UPPER_MASK) >> 16) {
+	case 0x8083:
+		priv->e300_type = E300C1;
+		break;
+	case 0x8084:
+		priv->e300_type = E300C2;
+		break;
+	case 0x8085:
+		priv->e300_type = E300C3;
+		break;
+	case 0x8086:
+		priv->e300_type = E300C4;
+		break;
+	default:
+		priv->e300_type = E300_UNKNOWN;
+	}
+}
+
+/**
+ * determine_revid() - Determine revision ID of CPU device
+ * @dev: CPU device from which to read revision ID
+ */
+static inline void determine_revid(struct udevice *dev)
+{
+	struct mpc83xx_cpu_priv *priv = dev_get_priv(dev);
+	u32 REVID_MAJOR_MASK;
+	u32 REVID_MINOR_MASK;
+	u32 spridr = get_spridr();
+
+	if (priv->family == FAMILY_834X) {
+		REVID_MAJOR_MASK = 0x0000FF00;
+		REVID_MINOR_MASK = 0x000000FF;
+	} else {
+		REVID_MAJOR_MASK = 0x000000F0;
+		REVID_MINOR_MASK = 0x0000000F;
+	}
+
+	priv->revid.major = bitfield_extract_by_mask(spridr, REVID_MAJOR_MASK);
+	priv->revid.minor = bitfield_extract_by_mask(spridr, REVID_MINOR_MASK);
+}
+
+/**
+ * determine_cpu_data() - Determine CPU information from hardware
+ * @dev: CPU device from which to read information
+ */
+static void determine_cpu_data(struct udevice *dev)
+{
+	struct mpc83xx_cpu_priv *priv = dev_get_priv(dev);
+	const u32 E_FLAG_MASK = 0x00010000;
+	u32 spridr = get_spridr();
+
+	determine_family(dev);
+	determine_type(dev);
+	determine_e300_type(dev);
+	determine_revid(dev);
+
+	if ((priv->family == FAMILY_834X ||
+	     priv->family == FAMILY_836X) && priv->revid.major >= 2)
+		priv->is_a_variant = true;
+
+	priv->is_e_processor = !bitfield_extract_by_mask(spridr, E_FLAG_MASK);
+}
+
+static int mpc83xx_cpu_get_desc(struct udevice *dev, char *buf, int size)
+{
+	struct mpc83xx_cpu_priv *priv = dev_get_priv(dev);
+	struct clk core_clk;
+	struct clk csb_clk;
+	char core_freq[32];
+	char csb_freq[32];
+	int ret;
+
+	ret = clk_get_by_index(dev, 0, &core_clk);
+	if (ret) {
+		debug("%s: Failed to get core clock (err = %d)\n",
+		      dev->name, ret);
+		return ret;
+	}
+
+	ret = clk_get_by_index(dev, 1, &csb_clk);
+	if (ret) {
+		debug("%s: Failed to get CSB clock (err = %d)\n",
+		      dev->name, ret);
+		return ret;
+	}
+
+	determine_cpu_data(dev);
+
+	snprintf(buf, size,
+		 "CPU:   %s, MPC%s%s%s, Rev: %d.%d at %s MHz, CSB: %s MHz\n",
+		 e300_names[priv->e300_type],
+		 cpu_type_names[priv->type],
+		 priv->is_e_processor ? "E" : "",
+		 priv->is_a_variant ? "A" : "",
+		 priv->revid.major,
+		 priv->revid.minor,
+		 strmhz(core_freq, clk_get_rate(&core_clk)),
+		 strmhz(csb_freq, clk_get_rate(&csb_clk)));
+
+	return 0;
+}
+
+static int mpc83xx_cpu_get_info(struct udevice *dev, struct cpu_info *info)
+{
+	struct clk clock;
+	int ret;
+	ulong freq;
+
+	ret = clk_get_by_index(dev, 0, &clock);
+	if (ret) {
+		debug("%s: Failed to get core clock (err = %d)\n",
+		      dev->name, ret);
+		return ret;
+	}
+
+	freq = clk_get_rate(&clock);
+	if (!freq) {
+		debug("%s: Core clock speed is zero\n", dev->name);
+		return -EINVAL;
+	}
+
+	info->cpu_freq = freq;
+	info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU);
+
+	return 0;
+}
+
+static int mpc83xx_cpu_get_count(struct udevice *dev)
+{
+	/* We have one e300cX core */
+	return 1;
+}
+
+static int mpc83xx_cpu_get_vendor(struct udevice *dev, char *buf, int size)
+{
+	snprintf(buf, size, "NXP");
+
+	return 0;
+}
+
+static const struct cpu_ops mpc83xx_cpu_ops = {
+	.get_desc = mpc83xx_cpu_get_desc,
+	.get_info = mpc83xx_cpu_get_info,
+	.get_count = mpc83xx_cpu_get_count,
+	.get_vendor = mpc83xx_cpu_get_vendor,
+};
+
+static int mpc83xx_cpu_probe(struct udevice *dev)
+{
+	return 0;
+}
+
+static const struct udevice_id mpc83xx_cpu_ids[] = {
+	{ .compatible = "fsl,mpc83xx", },
+	{ .compatible = "fsl,mpc8308", },
+	{ .compatible = "fsl,mpc8309", },
+	{ .compatible = "fsl,mpc8313", },
+	{ .compatible = "fsl,mpc8315", },
+	{ .compatible = "fsl,mpc832x", },
+	{ .compatible = "fsl,mpc8349", },
+	{ .compatible = "fsl,mpc8360", },
+	{ .compatible = "fsl,mpc8379", },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(mpc83xx_cpu) = {
+	.name = "mpc83xx_cpu",
+	.id = UCLASS_CPU,
+	.of_match = mpc83xx_cpu_ids,
+	.probe = mpc83xx_cpu_probe,
+	.priv_auto_alloc_size = sizeof(struct mpc83xx_cpu_priv),
+	.ops = &mpc83xx_cpu_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/cpu/mpc83xx_cpu.h b/drivers/cpu/mpc83xx_cpu.h
new file mode 100644
index 0000000..2aaa4e1
--- /dev/null
+++ b/drivers/cpu/mpc83xx_cpu.h
@@ -0,0 +1,126 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+#ifndef _MPC83XX_CPU_H_
+#define _MPC83XX_CPU_H_
+
+/**
+ * enum e300_type - Identifiers for e300 cores
+ * @E300C1:       Identifier for e300c1 cores
+ * @E300C2:       Identifier for e300c2 cores
+ * @E300C3:       Identifier for e300c3 cores
+ * @E300C4:       Identifier for e300c4 cores
+ * @E300_UNKNOWN: Identifier for unknown e300 cores
+ */
+enum e300_type {
+	E300C1,
+	E300C2,
+	E300C3,
+	E300C4,
+	E300_UNKNOWN,
+};
+
+/* Array mapping the e300 core types to their human-readable names */
+static const char * const e300_names[] = {
+	[E300C1] = "e300c1",
+	[E300C2] = "e300c2",
+	[E300C3] = "e300c3",
+	[E300C4] = "e300c4",
+	[E300_UNKNOWN] = "Unknown e300",
+};
+
+/**
+ * enum mpc83xx_cpu_family - Identifiers for MPC83xx CPU families
+ * @FAMILY_830X:    Identifier for the MPC830x CPU family
+ * @FAMILY_831X:    Identifier for the MPC831x CPU family
+ * @FAMILY_832X:    Identifier for the MPC832x CPU family
+ * @FAMILY_834X:    Identifier for the MPC834x CPU family
+ * @FAMILY_836X:    Identifier for the MPC836x CPU family
+ * @FAMILY_837X:    Identifier for the MPC837x CPU family
+ * @FAMILY_UNKNOWN: Identifier for an unknown MPC83xx CPU family
+ */
+enum mpc83xx_cpu_family {
+	FAMILY_830X,
+	FAMILY_831X,
+	FAMILY_832X,
+	FAMILY_834X,
+	FAMILY_836X,
+	FAMILY_837X,
+	FAMILY_UNKNOWN,
+};
+
+/**
+ * enum mpc83xx_cpu_type - Identifiers for MPC83xx CPU types
+ * @TYPE_8308:      Identifier for the MPC8308 CPU type
+ * @TYPE_8309:      Identifier for the MPC8309 CPU type
+ * @TYPE_8311:      Identifier for the MPC8311 CPU type
+ * @TYPE_8313:      Identifier for the MPC8313 CPU type
+ * @TYPE_8314:      Identifier for the MPC8314 CPU type
+ * @TYPE_8315:      Identifier for the MPC8315 CPU type
+ * @TYPE_8321:      Identifier for the MPC8321 CPU type
+ * @TYPE_8323:      Identifier for the MPC8323 CPU type
+ * @TYPE_8343:      Identifier for the MPC8343 CPU type
+ * @TYPE_8347_TBGA: Identifier for the MPC8347 CPU type (Tape Ball Grid Array
+ *		    version)
+ * @TYPE_8347_PBGA: Identifier for the MPC8347 CPU type (Plastic Ball Grid Array
+ *		    version)
+ * @TYPE_8349:      Identifier for the MPC8349 CPU type
+ * @TYPE_8358_TBGA: Identifier for the MPC8358 CPU type (Tape Ball Grid Array
+ *		    version)
+ * @TYPE_8358_PBGA: Identifier for the MPC8358 CPU type (Plastic Ball Grid Array
+ *		    version)
+ * @TYPE_8360:      Identifier for the MPC8360 CPU type
+ * @TYPE_8377:      Identifier for the MPC8377 CPU type
+ * @TYPE_8378:      Identifier for the MPC8378 CPU type
+ * @TYPE_8379:      Identifier for the MPC8379 CPU type
+ * @TYPE_UNKNOWN:   Identifier for an unknown MPC83xx CPU type
+ */
+enum mpc83xx_cpu_type {
+	TYPE_8308,
+	TYPE_8309,
+	TYPE_8311,
+	TYPE_8313,
+	TYPE_8314,
+	TYPE_8315,
+	TYPE_8321,
+	TYPE_8323,
+	TYPE_8343,
+	TYPE_8347_TBGA,
+	TYPE_8347_PBGA,
+	TYPE_8349,
+	TYPE_8358_TBGA,
+	TYPE_8358_PBGA,
+	TYPE_8360,
+	TYPE_8377,
+	TYPE_8378,
+	TYPE_8379,
+	TYPE_UNKNOWN,
+};
+
+/* Array mapping the MCP83xx CPUs to their human-readable names */
+static const char * const cpu_type_names[] = {
+	[TYPE_8308] = "8308",
+	[TYPE_8309] = "8309",
+	[TYPE_8311] = "8311",
+	[TYPE_8313] = "8313",
+	[TYPE_8314] = "8314",
+	[TYPE_8315] = "8315",
+	[TYPE_8321] = "8321",
+	[TYPE_8323] = "8323",
+	[TYPE_8343] = "8343",
+	[TYPE_8347_TBGA] = "8347_TBGA",
+	[TYPE_8347_PBGA] = "8347_PBGA",
+	[TYPE_8349] = "8349",
+	[TYPE_8358_TBGA] = "8358_TBGA",
+	[TYPE_8358_PBGA] = "8358_PBGA",
+	[TYPE_8360] = "8360",
+	[TYPE_8377] = "8377",
+	[TYPE_8378] = "8378",
+	[TYPE_8379] = "8379",
+	[TYPE_UNKNOWN] = "Unknown CPU",
+};
+
+#endif /* !_MPC83XX_CPU_H_ */
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index c2b7cc1..bfa5c91 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -288,4 +288,11 @@
 	depends on MISC
 	help
 	  Support gdsys FPGA's IO endpoint driver.
+
+config MPC83XX_SERDES
+	bool "Enable MPC83xx serdes driver"
+	depends on MISC
+	help
+	  Support for serdes found on MPC83xx SoCs.
+
 endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 32ef4a5..da4666f 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -55,3 +55,4 @@
 obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o
 obj-$(CONFIG_GDSYS_IOEP) += gdsys_ioep.o
 obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o
+obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o
diff --git a/drivers/misc/mpc83xx_serdes.c b/drivers/misc/mpc83xx_serdes.c
new file mode 100644
index 0000000..d572dda
--- /dev/null
+++ b/drivers/misc/mpc83xx_serdes.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ *
+ * base on the MPC83xx serdes initialization, which is
+ *
+ * Copyright 2007,2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008 MontaVista Software, Inc.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <misc.h>
+
+#include "mpc83xx_serdes.h"
+
+/**
+ * struct mpc83xx_serdes_priv - Private structure for MPC83xx serdes
+ * @regs:  The device's register map
+ * @rfcks: Variable to keep the serdes reference clock selection set during
+ *	   initialization in (is or'd to every value written to SRDSCR4)
+ */
+struct mpc83xx_serdes_priv {
+	struct mpc83xx_serdes_regs *regs;
+	u32 rfcks;
+};
+
+/**
+ * setup_sata() - Configure the SerDes device to SATA mode
+ * @dev: The device to configure
+ */
+static void setup_sata(struct udevice *dev)
+{
+	struct mpc83xx_serdes_priv *priv = dev_get_priv(dev);
+
+	/* Set and clear reset bits */
+	setbits_be32(&priv->regs->srdsrstctl, SRDSRSTCTL_SATA_RESET);
+	udelay(1000);
+	clrbits_be32(&priv->regs->srdsrstctl, SRDSRSTCTL_SATA_RESET);
+
+	/* Configure SRDSCR0 */
+	clrsetbits_be32(&priv->regs->srdscr0,
+			SRDSCR0_TXEQA_MASK | SRDSCR0_TXEQE_MASK,
+			SRDSCR0_TXEQA_SATA | SRDSCR0_TXEQE_SATA);
+
+	/* Configure SRDSCR1 */
+	clrbits_be32(&priv->regs->srdscr1, SRDSCR1_PLLBW);
+
+	/* Configure SRDSCR2 */
+	clrsetbits_be32(&priv->regs->srdscr2,
+			SRDSCR2_SEIC_MASK,
+			SRDSCR2_SEIC_SATA);
+
+	/* Configure SRDSCR3 */
+	out_be32(&priv->regs->srdscr3,
+		 SRDSCR3_KFR_SATA | SRDSCR3_KPH_SATA |
+		 SRDSCR3_SDFM_SATA_PEX | SRDSCR3_SDTXL_SATA);
+
+	/* Configure SRDSCR4 */
+	out_be32(&priv->regs->srdscr4, priv->rfcks | SRDSCR4_PROT_SATA);
+}
+
+/**
+ * setup_pex() - Configure the SerDes device to PCI Express mode
+ * @dev:  The device to configure
+ * @type: The PCI Express type to configure for (x1 or x2)
+ */
+static void setup_pex(struct udevice *dev, enum pex_type type)
+{
+	struct mpc83xx_serdes_priv *priv = dev_get_priv(dev);
+
+	/* Configure SRDSCR1 */
+	setbits_be32(&priv->regs->srdscr1, SRDSCR1_PLLBW);
+
+	/* Configure SRDSCR2 */
+	clrsetbits_be32(&priv->regs->srdscr2,
+			SRDSCR2_SEIC_MASK,
+			SRDSCR2_SEIC_PEX);
+
+	/* Configure SRDSCR3 */
+	out_be32(&priv->regs->srdscr3, SRDSCR3_SDFM_SATA_PEX);
+
+	/* Configure SRDSCR4 */
+	if (type == PEX_X2)
+		out_be32(&priv->regs->srdscr4,
+			 priv->rfcks | SRDSCR4_PROT_PEX | SRDSCR4_PLANE_X2);
+	else
+		out_be32(&priv->regs->srdscr4,
+			 priv->rfcks | SRDSCR4_PROT_PEX);
+}
+
+/**
+ * setup_sgmii() - Configure the SerDes device to SGMII mode
+ * @dev: The device to configure
+ */
+static void setup_sgmii(struct udevice *dev)
+{
+	struct mpc83xx_serdes_priv *priv = dev_get_priv(dev);
+
+	/* Configure SRDSCR1 */
+	clrbits_be32(&priv->regs->srdscr1, SRDSCR1_PLLBW);
+
+	/* Configure SRDSCR2 */
+	clrsetbits_be32(&priv->regs->srdscr2,
+			SRDSCR2_SEIC_MASK,
+			SRDSCR2_SEIC_SGMII);
+
+	/* Configure SRDSCR3 */
+	out_be32(&priv->regs->srdscr3, 0);
+
+	/* Configure SRDSCR4 */
+	out_be32(&priv->regs->srdscr4, priv->rfcks | SRDSCR4_PROT_SGMII);
+}
+
+static int mpc83xx_serdes_probe(struct udevice *dev)
+{
+	struct mpc83xx_serdes_priv *priv = dev_get_priv(dev);
+	bool vdd;
+	const char *proto;
+
+	priv->regs = map_sysmem(dev_read_addr(dev),
+				sizeof(struct mpc83xx_serdes_regs));
+
+	switch (dev_read_u32_default(dev, "serdes-clk", -1)) {
+	case 100:
+		priv->rfcks = SRDSCR4_RFCKS_100;
+		break;
+	case 125:
+		priv->rfcks = SRDSCR4_RFCKS_125;
+		break;
+	case 150:
+		priv->rfcks = SRDSCR4_RFCKS_150;
+		break;
+	default:
+		debug("%s: Could not read serdes clock value\n", dev->name);
+		return -EINVAL;
+	}
+
+	vdd = dev_read_bool(dev, "vdd");
+
+	/* 1.0V corevdd */
+	if (vdd) {
+		/* DPPE/DPPA = 0 */
+		clrbits_be32(&priv->regs->srdscr0, SRDSCR0_DPP_1V2);
+
+		/* VDD = 0 */
+		clrbits_be32(&priv->regs->srdscr0, SRDSCR2_VDD_1V2);
+	}
+
+	proto = dev_read_string(dev, "proto");
+
+	/* protocol specific configuration */
+	if (!strcmp(proto, "sata")) {
+		setup_sata(dev);
+	} else if (!strcmp(proto, "pex")) {
+		setup_pex(dev, PEX_X1);
+	} else if (!strcmp(proto, "pex-x2")) {
+		setup_pex(dev, PEX_X2);
+	} else if (!strcmp(proto, "sgmii")) {
+		setup_sgmii(dev);
+	} else {
+		debug("%s: Invalid protocol value %s\n", dev->name, proto);
+		return -EINVAL;
+	}
+
+	/* Do a software reset */
+	setbits_be32(&priv->regs->srdsrstctl, SRDSRSTCTL_RST);
+
+	return 0;
+}
+
+static const struct udevice_id mpc83xx_serdes_ids[] = {
+	{ .compatible = "fsl,mpc83xx-serdes" },
+	{ }
+};
+
+U_BOOT_DRIVER(mpc83xx_serdes) = {
+	.name           = "mpc83xx_serdes",
+	.id             = UCLASS_MISC,
+	.of_match       = mpc83xx_serdes_ids,
+	.probe          = mpc83xx_serdes_probe,
+	.priv_auto_alloc_size = sizeof(struct mpc83xx_serdes_priv),
+};
diff --git a/drivers/misc/mpc83xx_serdes.h b/drivers/misc/mpc83xx_serdes.h
new file mode 100644
index 0000000..89ea1db
--- /dev/null
+++ b/drivers/misc/mpc83xx_serdes.h
@@ -0,0 +1,232 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+/**
+ * enum srdscr0_mask - Bit masks for SRDSCR0 (SerDes Control Register 0)
+ * @SRDSCR0_DPPA:       Bitmask for the DPPA (diff pk-pk swing for lane A)
+ *			field of the SRCSCR0
+ * @SRDSCR0_DPPE:       Bitmask for the DPPE (diff pk-pk swing for lane E)
+ *			field of the SRCSCR0
+ * @SRDSCR0_DPP_1V2:    Combined bitmask to set diff pk-pk swing for both lanes
+ * @SRDSCR0_TXEQA_MASK: Bitmask for the TXEQA (transmit equalization for
+ *			lane A) field of the SRCSCR0
+ * @SRDSCR0_TXEQA_SATA: Bitmask to set the TXEQA to the value used for SATA
+ * @SRDSCR0_TXEQE_MASK: Bitmask for the TXEQE (transmit equalization for
+ *			lane E) field of the SRCSCR0
+ * @SRDSCR0_TXEQE_SATA: Bitmask to set the TXEQE to the value used for SATA
+ */
+enum srdscr0_mask {
+	SRDSCR0_DPPA        = BIT(31 - 16),
+	SRDSCR0_DPPE        = BIT(31 - 20),
+	SRDSCR0_DPP_1V2    = SRDSCR0_DPPE | SRDSCR0_DPPA,
+
+	SRDSCR0_TXEQA_MASK = 0x00007000,
+	SRDSCR0_TXEQA_SATA = 0x00001000,
+	SRDSCR0_TXEQE_MASK = 0x00000700,
+	SRDSCR0_TXEQE_SATA = 0x00000100,
+};
+
+/**
+ * enum srdscr1_mask - Bit masks for SRDSCR1 (SerDes Control Register 1)
+ * @SRDSCR1_PLLBW: Bitmask for the PLLBW (PLL bandwidth) field of SRDSCR1
+ */
+enum srdscr1_mask {
+	SRDSCR1_PLLBW = BIT(31 - 25),
+};
+
+/**
+ * enum srdscr2_mask - Bit masks for SRDSCR2 (SerDes Control Register 2)
+ * @SRDSCR2_VDD_1V2:     Bit mask to to set the VDD field of the SCRSCR2
+ * @SRDSCR2_SEICA_MASK:  Bitmask for the SEICA (Receiver electrical idle
+ *			 detection control for lane A) field of the SRCSCR2
+ * @SRDSCR2_SEICE_MASK:  Bitmask for the SEICE (Receiver electrical idle
+ *			 detection control for lane E) field of the SRCSCR2
+ * @SRDSCR2_SEIC_MASK:   Combined bitmask to set the receiver electrical idle
+ *			 detection control for both lanes
+ * @SRDSCR2_SEICA_SATA:  Bitmask to set the SEICA field to the value used for
+ *			 SATA
+ * @SRDSCR2_SEICE_SATA:  Bitmask to set the SEICE field to the value used for
+ *			 SATA
+ * @SRDSCR2_SEIC_SATA:   Combined bitmask to set the value of both SEIC fields
+ *			 to the value used for SATA
+ * @SRDSCR2_SEICA_PEX:   Bitmask to set the SEICA field to the value used for
+ *			 PCI Express
+ * @SRDSCR2_SEICE_PEX:   Bitmask to set the SEICE field to the value used for
+ *			 PCI Express
+ * @SRDSCR2_SEIC_PEX:    Combined bitmask to set the value of both SEIC fields
+ *			 to the value used for PCI Express
+ * @SRDSCR2_SEICA_SGMII: Bitmask to set the SEICA field to the value used for
+ *			 SGMII
+ * @SRDSCR2_SEICE_SGMII: Bitmask to set the SEICE field to the value used for
+ *			 SGMII
+ * @SRDSCR2_SEIC_SGMII:  Combined bitmask to set the value of both SEIC fields
+ *			 to the value used for SGMII
+ */
+enum srdscr2_mask {
+	SRDSCR2_VDD_1V2     = 0x00800000,
+
+	SRDSCR2_SEICA_MASK  = 0x00001c00,
+	SRDSCR2_SEICE_MASK  = 0x0000001c,
+	SRDSCR2_SEIC_MASK   = SRDSCR2_SEICA_MASK | SRDSCR2_SEICE_MASK,
+
+	SRDSCR2_SEICA_SATA  = 0x00001400,
+	SRDSCR2_SEICE_SATA  = 0x00000014,
+	SRDSCR2_SEIC_SATA   = SRDSCR2_SEICA_SATA | SRDSCR2_SEICE_SATA,
+
+	SRDSCR2_SEICA_PEX   = 0x00001000,
+	SRDSCR2_SEICE_PEX   = 0x00000010,
+	SRDSCR2_SEIC_PEX    = SRDSCR2_SEICA_PEX | SRDSCR2_SEICE_PEX,
+
+	SRDSCR2_SEICA_SGMII = 0x00000100,
+	SRDSCR2_SEICE_SGMII = 0x00000001,
+	SRDSCR2_SEIC_SGMII  = SRDSCR2_SEICA_SGMII | SRDSCR2_SEICE_SGMII,
+};
+
+/**
+ * enum srdscr3_mask - Bit masks for SRDSCR3 (SerDes Control Register 3)
+ * @SRDSCR3_KFRA_SATA:      Bitmask to set the KFRA field of SRDSCR3 to the
+ *			    value used by SATA
+ * @SRDSCR3_KFRE_SATA:      Bitmask to set the KFRE field of SRDSCR3 to the
+ *			    value used by SATA
+ * @SRDSCR3_KFR_SATA:       Combined bitmask to set both KFR fields to the
+ *			    value used by SATA
+ * @SRDSCR3_KPHA_SATA:      Bitmask to set the KPHA field of SRDSCR3 to the
+ *			    value used by SATA
+ * @SRDSCR3_KPHE_SATA:      Bitmask to set the KPHE field of SRDSCR3 to the
+ *			    value used by SATA
+ * @SRDSCR3_KPH_SATA:       Combined bitmask to set both KPH fields to the
+ *			    value used by SATA
+ * @SRDSCR3_SDFMA_SATA_PEX: Bitmask to set the SDFMA field of SRDSCR3 to the
+ *			    value used by SATA and PCI Express
+ * @SRDSCR3_SDFME_SATA_PEX: Bitmask to set the SDFME field of SRDSCR3 to the
+ *			    value used by SATA and PCI Express
+ * @SRDSCR3_SDFM_SATA_PEX:  Combined bitmask to set both SDFM fields to the
+ *			    value used by SATA and PCI Express
+ * @SRDSCR3_SDTXLA_SATA:    Bitmask to set the SDTXLA field of SRDSCR3 to the
+ *			    value used by SATA
+ * @SRDSCR3_SDTXLE_SATA:    Bitmask to set the SDTXLE field of SRDSCR3 to the
+ *			    value used by SATA
+ * @SRDSCR3_SDTXL_SATA:     Combined bitmask to set both SDTXL fields to the
+ *			    value used by SATA
+ *
+ * KFRA = 'Kfr' gain selection in the CDR for lane A
+ * KFRE = 'Kfr' gain selection in the CDR for lane E
+ * SDFMA = Bandwidth of digital filter for lane A
+ * SDFME = Bandwidth of digital filter for lane E
+ * SDTXLA = Lane A transmitter amplitude levels
+ * SDTXLE = Lane E transmitter amplitude levels
+ */
+enum srdscr3_mask {
+	SRDSCR3_KFRA_SATA      = 0x10000000,
+	SRDSCR3_KFRE_SATA      = 0x00100000,
+	SRDSCR3_KFR_SATA       = SRDSCR3_KFRA_SATA | SRDSCR3_KFRE_SATA,
+
+	SRDSCR3_KPHA_SATA      = 0x04000000,
+	SRDSCR3_KPHE_SATA      = 0x00040000,
+	SRDSCR3_KPH_SATA       = SRDSCR3_KPHA_SATA | SRDSCR3_KPHE_SATA,
+
+	SRDSCR3_SDFMA_SATA_PEX = 0x01000000,
+	SRDSCR3_SDFME_SATA_PEX = 0x00010000,
+	SRDSCR3_SDFM_SATA_PEX  = SRDSCR3_SDFMA_SATA_PEX | SRDSCR3_SDFME_SATA_PEX,
+
+	SRDSCR3_SDTXLA_SATA    = 0x00000500,
+	SRDSCR3_SDTXLE_SATA    = 0x00000005,
+	SRDSCR3_SDTXL_SATA     = SRDSCR3_SDTXLA_SATA | SRDSCR3_SDTXLE_SATA,
+};
+
+/**
+ * enum srdscr4_mask - Bit masks for SRDSCR4 (SerDes Control Register 4)
+ * @SRDSCR4_PROTA_SATA:  Bitmask to set the PROTA field of SRDSCR4 to the
+ *			 value used by SATA
+ * @SRDSCR4_PROTE_SATA:  Bitmask to set the PROTE field of SRDSCR4 to the
+ *			 value used by SATA
+ * @SRDSCR4_PROT_SATA:   Combined bitmask to set both PROT fields to the
+ *			 value used by SATA
+ * @SRDSCR4_PROTA_PEX:   Bitmask to set the PROTA field of SRDSCR4 to the
+ *			 value used by PCI Express
+ * @SRDSCR4_PROTE_PEX:   Bitmask to set the PROTE field of SRDSCR4 to the
+ *			 value used by PCI Express
+ * @SRDSCR4_PROT_PEX:    Combined bitmask to set both PROT fields to the
+ *			 value used by PCI Express
+ * @SRDSCR4_PROTA_SGMII: Bitmask to set the PROTA field of SRDSCR4 to the
+ *			 value used by SGMII
+ * @SRDSCR4_PROTE_SGMII: Bitmask to set the PROTE field of SRDSCR4 to the
+ *			 value used by SGMII
+ * @SRDSCR4_PROT_SGMII:  Combined bitmask to set both PROT fields to the
+ *			 value used by SGMII
+ * @SRDSCR4_PLANE_X2:    Bitmask to set the PLANE field of SRDSCR4
+ * @SRDSCR4_RFCKS_100:   Bitmask to set the RFCKS field of SRDSCR4 to the
+ *			 value 100Mhz
+ * @SRDSCR4_RFCKS_125:   Bitmask to set the RFCKS field of SRDSCR4 to the
+ *			 value 125Mhz
+ * @SRDSCR4_RFCKS_150:   Bitmask to set the RFCKS field of SRDSCR4 to the
+ *			 value 150Mhz
+ *
+ * PROTA = Lane A protocol select
+ * PROTE = Lane E protocol select
+ * PLAME = Number of PCI Express lanes
+ */
+enum srdscr4_mask {
+	SRDSCR4_PROTA_SATA  = 0x00000800,
+	SRDSCR4_PROTE_SATA  = 0x00000008,
+	SRDSCR4_PROT_SATA   = SRDSCR4_PROTA_SATA | SRDSCR4_PROTE_SATA,
+
+	SRDSCR4_PROTA_PEX   = 0x00000100,
+	SRDSCR4_PROTE_PEX   = 0x00000001,
+	SRDSCR4_PROT_PEX    = SRDSCR4_PROTA_PEX | SRDSCR4_PROTE_PEX,
+
+	SRDSCR4_PROTA_SGMII = 0x00000500,
+	SRDSCR4_PROTE_SGMII = 0x00000005,
+	SRDSCR4_PROT_SGMII  = SRDSCR4_PROTA_SGMII | SRDSCR4_PROTE_SGMII,
+
+	SRDSCR4_PLANE_X2    = 0x01000000,
+
+	SRDSCR4_RFCKS_100 = (0 << 28),
+	SRDSCR4_RFCKS_125 = (1 << 28),
+	SRDSCR4_RFCKS_150 = (3 << 28),
+};
+
+/**
+ * enum srdsrstctl_mask - Bit masks for SRDSRSTCTL (SerDes Reset Control Register)
+ * @SRDSRSTCTL_RST:        Bitmask for the RST (Software reset) field of the
+ *			   SRDSRSTCTL
+ * @SRDSRSTCTL_SATA_RESET: Bitmask for the SATA_RESET (SATA reset) field of the
+ *			   SRDSRSTCTL
+ */
+enum srdsrstctl_mask {
+	SRDSRSTCTL_RST        = 0x80000000,
+	SRDSRSTCTL_SATA_RESET = 0xf,
+};
+
+/**
+ * struct mpc83xx_serdes_regs - Register map of the SerDes controller
+ * @srdscr0:    SerDes Control Register 0
+ * @srdscr1:    SerDes Control Register 1
+ * @srdscr2:    SerDes Control Register 2
+ * @srdscr3:    SerDes Control Register 3
+ * @srdscr4:    SerDes Control Register 4
+ * @fill0:      Reserved space in the register map
+ * @srdsrstctl: SerDes Reset Control Register
+ */
+struct mpc83xx_serdes_regs {
+	u32 srdscr0;
+	u32 srdscr1;
+	u32 srdscr2;
+	u32 srdscr3;
+	u32 srdscr4;
+	u8 fill0[12];
+	u32 srdsrstctl;
+};
+
+/**
+ * enum pex_type - Types of PCI Express
+ * @PEX_X1: PCI Express in x1 mode
+ * @PEX_X2: PCI Express in x2 mode
+ */
+enum pex_type {
+	PEX_X1,
+	PEX_X2,
+};
diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig
index 496e2b7..54bb4b4 100644
--- a/drivers/ram/Kconfig
+++ b/drivers/ram/Kconfig
@@ -34,4 +34,13 @@
 	  support external memories like sdram, psram & nand.
 	  This driver is for the sdram memory interface with the FMC.
 
+config MPC83XX_SDRAM
+	bool "Enable MPC83XX SDRAM support"
+	depends on RAM
+	help
+	  Enable support for the internal DDR Memory Controller of the MPC83xx
+	  family of SoCs. Both static configurations, as well as configuring
+	  the RAM through the use of SPD (Serial Presence Detect) is supported
+	  via device tree settings.
+
 source "drivers/ram/stm32mp1/Kconfig"
diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile
index 3820d03..4ad3604 100644
--- a/drivers/ram/Makefile
+++ b/drivers/ram/Makefile
@@ -5,6 +5,7 @@
 # SPDX-License-Identifier:      GPL-2.0+
 #
 obj-$(CONFIG_RAM) += ram-uclass.o
+obj-$(CONFIG_MPC83XX_SDRAM) += mpc83xx_sdram.o
 obj-$(CONFIG_SANDBOX) += sandbox_ram.o
 obj-$(CONFIG_STM32MP1_DDR) += stm32mp1/
 obj-$(CONFIG_STM32_SDRAM) += stm32_sdram.o
diff --git a/drivers/ram/mpc83xx_sdram.c b/drivers/ram/mpc83xx_sdram.c
new file mode 100644
index 0000000..441baeb
--- /dev/null
+++ b/drivers/ram/mpc83xx_sdram.c
@@ -0,0 +1,1096 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <ram.h>
+#include <dt-bindings/memory/mpc83xx-sdram.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Masks for the CS config register */
+static const u32 CSCONFIG_ENABLE = 0x80000000;
+
+static const u32 BANK_BITS_2;
+static const u32 BANK_BITS_3 = 0x00004000;
+
+static const u32 ROW_BITS_12;
+static const u32 ROW_BITS_13 = 0x00000100;
+static const u32 ROW_BITS_14 = 0x00000200;
+
+static const u32 COL_BITS_8;
+static const u32 COL_BITS_9  = 0x00000001;
+static const u32 COL_BITS_10 = 0x00000002;
+static const u32 COL_BITS_11 = 0x00000003;
+
+/* Shifts for the DDR SDRAM Timing Configuration 3 register */
+static const uint TIMING_CFG3_EXT_REFREC_SHIFT = (31 - 15);
+
+/* Shifts for the DDR SDRAM Timing Configuration 0 register */
+static const uint TIMING_CFG0_RWT_SHIFT         = (31 - 1);
+static const uint TIMING_CFG0_WRT_SHIFT         = (31 - 3);
+static const uint TIMING_CFG0_RRT_SHIFT         = (31 - 5);
+static const uint TIMING_CFG0_WWT_SHIFT         = (31 - 7);
+static const uint TIMING_CFG0_ACT_PD_EXIT_SHIFT = (31 - 11);
+static const uint TIMING_CFG0_PRE_PD_EXIT_SHIFT = (31 - 15);
+static const uint TIMING_CFG0_ODT_PD_EXIT_SHIFT = (31 - 23);
+static const uint TIMING_CFG0_MRS_CYC_SHIFT     = (31 - 31);
+
+/* Shifts for the DDR SDRAM Timing Configuration 1 register */
+static const uint TIMING_CFG1_PRETOACT_SHIFT = (31 - 3);
+static const uint TIMING_CFG1_ACTTOPRE_SHIFT = (31 - 7);
+static const uint TIMING_CFG1_ACTTORW_SHIFT  = (31 - 11);
+static const uint TIMING_CFG1_CASLAT_SHIFT   = (31 - 15);
+static const uint TIMING_CFG1_REFREC_SHIFT   = (31 - 19);
+static const uint TIMING_CFG1_WRREC_SHIFT    = (31 - 23);
+static const uint TIMING_CFG1_ACTTOACT_SHIFT = (31 - 27);
+static const uint TIMING_CFG1_WRTORD_SHIFT   = (31 - 31);
+
+/* Shifts for the DDR SDRAM Timing Configuration 2 register */
+static const uint TIMING_CFG2_CPO_SHIFT	          = (31 - 8);
+static const uint TIMING_CFG2_WR_DATA_DELAY_SHIFT = (31 - 21);
+static const uint TIMING_CFG2_ADD_LAT_SHIFT       = (31 - 3);
+static const uint TIMING_CFG2_WR_LAT_DELAY_SHIFT  = (31 - 12);
+static const uint TIMING_CFG2_RD_TO_PRE_SHIFT     = (31 - 18);
+static const uint TIMING_CFG2_CKE_PLS_SHIFT       = (31 - 25);
+static const uint TIMING_CFG2_FOUR_ACT_SHIFT;
+
+/* Shifts for the DDR SDRAM Control Configuration register */
+static const uint SDRAM_CFG_SREN_SHIFT         = (31 - 1);
+static const uint SDRAM_CFG_ECC_EN_SHIFT       = (31 - 2);
+static const uint SDRAM_CFG_RD_EN_SHIFT        = (31 - 3);
+static const uint SDRAM_CFG_SDRAM_TYPE_SHIFT   = (31 - 7);
+static const uint SDRAM_CFG_DYN_PWR_SHIFT      = (31 - 10);
+static const uint SDRAM_CFG_DBW_SHIFT          = (31 - 12);
+static const uint SDRAM_CFG_NCAP_SHIFT         = (31 - 14);
+static const uint SDRAM_CFG_2T_EN_SHIFT        = (31 - 16);
+static const uint SDRAM_CFG_BA_INTLV_CTL_SHIFT = (31 - 23);
+static const uint SDRAM_CFG_PCHB8_SHIFT        = (31 - 27);
+static const uint SDRAM_CFG_HSE_SHIFT          = (31 - 28);
+static const uint SDRAM_CFG_BI_SHIFT           = (31 - 31);
+
+/* Shifts for the DDR SDRAM Control Configuration 2 register */
+static const uint SDRAM_CFG2_FRC_SR_SHIFT = (31 - 0);
+static const uint SDRAM_CFG2_DLL_RST_DIS  = (31 - 2);
+static const uint SDRAM_CFG2_DQS_CFG      = (31 - 5);
+static const uint SDRAM_CFG2_ODT_CFG      = (31 - 10);
+static const uint SDRAM_CFG2_NUM_PR       = (31 - 19);
+
+/* Shifts for the DDR SDRAM Mode register */
+static const uint SDRAM_MODE_ESD_SHIFT = (31 - 15);
+static const uint SDRAM_MODE_SD_SHIFT  = (31 - 31);
+
+/* Shifts for the DDR SDRAM Mode 2 register */
+static const uint SDRAM_MODE2_ESD2_SHIFT = (31 - 15);
+static const uint SDRAM_MODE2_ESD3_SHIFT = (31 - 31);
+
+/* Shifts for the DDR SDRAM Interval Configuration register */
+static const uint SDRAM_INTERVAL_REFINT_SHIFT  = (31 - 15);
+static const uint SDRAM_INTERVAL_BSTOPRE_SHIFT = (31 - 31);
+
+/* Mask for the DDR SDRAM Mode Control register */
+static const u32 SDRAM_CFG_MEM_EN = 0x80000000;
+
+int dram_init(void)
+{
+	struct udevice *ram_ctrl;
+	int ret;
+
+	/* Current assumption: There is only one RAM controller */
+	ret = uclass_first_device_err(UCLASS_RAM, &ram_ctrl);
+	if (ret) {
+		debug("%s: uclass_first_device_err failed: %d\n",
+		      __func__, ret);
+		return ret;
+	}
+
+	/* FIXME(mario.six@gdsys.cc): Set gd->ram_size? */
+
+	return 0;
+}
+
+phys_size_t get_effective_memsize(void)
+{
+	if (!IS_ENABLED(CONFIG_VERY_BIG_RAM))
+		return gd->ram_size;
+
+	/* Limit stack to what we can reasonable map */
+	return ((gd->ram_size > CONFIG_MAX_MEM_MAPPED) ?
+		CONFIG_MAX_MEM_MAPPED : gd->ram_size);
+}
+
+/**
+ * struct mpc83xx_sdram_priv - Private data for MPC83xx RAM controllers
+ * @total_size: The total size of all RAM modules associated with this RAM
+ *		controller in bytes
+ */
+struct mpc83xx_sdram_priv {
+	ulong total_size;
+};
+
+/**
+ * mpc83xx_sdram_static_init() - Statically initialize a RAM module.
+ * @node:    Device tree node associated with ths module in question
+ * @cs:      The chip select to use for this RAM module
+ * @mapaddr: The address where the RAM module should be mapped
+ * @size:    The size of the RAM module to be mapped in bytes
+ *
+ * Return: 0 if OK, -ve on error
+ */
+static int mpc83xx_sdram_static_init(ofnode node, u32 cs, u32 mapaddr, u32 size)
+{
+	immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	u32 msize = size;
+	u32 msize_log2 = __ilog2(msize);
+	u32 auto_precharge, odt_rd_cfg, odt_wr_cfg, bank_bits, row_bits,
+	    col_bits;
+	u32 bank_bits_mask, row_bits_mask, col_bits_mask;
+
+	/* Configure the DDR local access window */
+	out_be32(&im->sysconf.ddrlaw[cs].bar, mapaddr & 0xfffff000);
+	out_be32(&im->sysconf.ddrlaw[cs].ar, LBLAWAR_EN | (msize_log2 - 1));
+
+	out_be32(&im->ddr.csbnds[cs].csbnds, (msize - 1) >> 24);
+
+	auto_precharge = ofnode_read_u32_default(node, "auto_precharge", 0);
+	switch (auto_precharge) {
+	case AUTO_PRECHARGE_ENABLE:
+	case AUTO_PRECHARGE_DISABLE:
+		break;
+	default:
+		debug("%s: auto_precharge value %d invalid.\n",
+		      ofnode_get_name(node), auto_precharge);
+		return -EINVAL;
+	}
+
+	odt_rd_cfg = ofnode_read_u32_default(node, "odt_rd_cfg", 0);
+	switch (odt_rd_cfg) {
+	case ODT_RD_ONLY_OTHER_DIMM:
+		if (!IS_ENABLED(CONFIG_MPC8360) &&
+		    !IS_ENABLED(CONFIG_MPC837x)) {
+			debug("%s: odt_rd_cfg value %d invalid.\n",
+			      ofnode_get_name(node), odt_rd_cfg);
+			return -EINVAL;
+		}
+		/* fall through */
+	case ODT_RD_NEVER:
+	case ODT_RD_ONLY_CURRENT:
+	case ODT_RD_ONLY_OTHER_CS:
+		if (!IS_ENABLED(CONFIG_MPC830x) &&
+		    !IS_ENABLED(CONFIG_MPC831x) &&
+		    !IS_ENABLED(CONFIG_MPC8360) &&
+		    !IS_ENABLED(CONFIG_MPC837x)) {
+			debug("%s: odt_rd_cfg value %d invalid.\n",
+			      ofnode_get_name(node), odt_rd_cfg);
+			return -EINVAL;
+		}
+		/* fall through */
+	/* Only MPC832x knows this value */
+	case ODT_RD_ALL:
+		break;
+	default:
+		debug("%s: odt_rd_cfg value %d invalid.\n",
+		      ofnode_get_name(node), odt_rd_cfg);
+		return -EINVAL;
+	}
+
+	odt_wr_cfg = ofnode_read_u32_default(node, "odt_wr_cfg", 0);
+	switch (odt_wr_cfg) {
+	case ODT_WR_ONLY_OTHER_DIMM:
+		if (!IS_ENABLED(CONFIG_MPC8360) &&
+		    !IS_ENABLED(CONFIG_MPC837x)) {
+			debug("%s: odt_wr_cfg value %d invalid.\n",
+			      ofnode_get_name(node), odt_wr_cfg);
+			return -EINVAL;
+		}
+		/* fall through */
+	case ODT_WR_NEVER:
+	case ODT_WR_ONLY_CURRENT:
+	case ODT_WR_ONLY_OTHER_CS:
+		if (!IS_ENABLED(CONFIG_MPC830x) &&
+		    !IS_ENABLED(CONFIG_MPC831x) &&
+		    !IS_ENABLED(CONFIG_MPC8360) &&
+		    !IS_ENABLED(CONFIG_MPC837x)) {
+			debug("%s: odt_wr_cfg value %d invalid.\n",
+			      ofnode_get_name(node), odt_wr_cfg);
+			return -EINVAL;
+		}
+		/* fall through */
+	/* MPC832x only knows this value */
+	case ODT_WR_ALL:
+		break;
+	default:
+		debug("%s: odt_wr_cfg value %d invalid.\n",
+		      ofnode_get_name(node), odt_wr_cfg);
+		return -EINVAL;
+	}
+
+	bank_bits = ofnode_read_u32_default(node, "bank_bits", 0);
+	switch (bank_bits) {
+	case 2:
+		bank_bits_mask = BANK_BITS_2;
+		break;
+	case 3:
+		bank_bits_mask = BANK_BITS_3;
+		break;
+	default:
+		debug("%s: bank_bits value %d invalid.\n",
+		      ofnode_get_name(node), bank_bits);
+		return -EINVAL;
+	}
+
+	row_bits = ofnode_read_u32_default(node, "row_bits", 0);
+	switch (row_bits) {
+	case 12:
+		row_bits_mask = ROW_BITS_12;
+		break;
+	case 13:
+		row_bits_mask = ROW_BITS_13;
+		break;
+	case 14:
+		row_bits_mask = ROW_BITS_14;
+		break;
+	default:
+		debug("%s: row_bits value %d invalid.\n",
+		      ofnode_get_name(node), row_bits);
+		return -EINVAL;
+	}
+
+	col_bits = ofnode_read_u32_default(node, "col_bits", 0);
+	switch (col_bits) {
+	case 8:
+		col_bits_mask = COL_BITS_8;
+		break;
+	case 9:
+		col_bits_mask = COL_BITS_9;
+		break;
+	case 10:
+		col_bits_mask = COL_BITS_10;
+		break;
+	case 11:
+		col_bits_mask = COL_BITS_11;
+		break;
+	default:
+		debug("%s: col_bits value %d invalid.\n",
+		      ofnode_get_name(node), col_bits);
+		return -EINVAL;
+	}
+
+	/* Write CS config value */
+	out_be32(&im->ddr.cs_config[cs], CSCONFIG_ENABLE | auto_precharge |
+					 odt_rd_cfg | odt_wr_cfg |
+					 bank_bits_mask | row_bits_mask |
+					 col_bits_mask);
+	return 0;
+}
+
+/**
+ * mpc83xx_sdram_spd_init() - Initialize a RAM module using a SPD flash.
+ * @node:    Device tree node associated with ths module in question
+ * @cs:      The chip select to use for this RAM module
+ * @mapaddr: The address where the RAM module should be mapped
+ * @size:    The size of the RAM module to be mapped in bytes
+ *
+ * Return: 0 if OK, -ve on error
+ */
+static int mpc83xx_sdram_spd_init(ofnode node, u32 cs, u32 mapaddr, u32 size)
+{
+	/* TODO(mario.six@gdsys.cc): Implement */
+	return 0;
+}
+
+static int mpc83xx_sdram_ofdata_to_platdata(struct udevice *dev)
+{
+	return 0;
+}
+
+static int mpc83xx_sdram_probe(struct udevice *dev)
+{
+	struct mpc83xx_sdram_priv *priv = dev_get_priv(dev);
+	immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	int ret = 0;
+	ofnode subnode;
+	/* DDR control driver register values */
+	u32 dso, pz_override, nz_override, odt_term, ddr_type, mvref_sel, m_odr;
+	u32 ddrcdr;
+	/* DDR SDRAM Clock Control register values */
+	u32 clock_adjust;
+	/* DDR SDRAM Timing Configuration 3 register values */
+	u32 ext_refresh_rec, ext_refresh_rec_mask;
+	/* DDR SDRAM Timing Configuration 0 register values */
+	u32 read_to_write, write_to_read, read_to_read, write_to_write,
+	    active_powerdown_exit, precharge_powerdown_exit,
+	    odt_powerdown_exit, mode_reg_set_cycle;
+	u32 timing_cfg_0;
+	/* DDR SDRAM Timing Configuration 1 register values */
+	u32 precharge_to_activate, activate_to_precharge,
+	    activate_to_readwrite, mcas_latency, refresh_recovery,
+	    last_data_to_precharge, activate_to_activate,
+	    last_write_data_to_read;
+	u32 timing_cfg_1;
+	/* DDR SDRAM Timing Configuration 2 register values */
+	u32 additive_latency, mcas_to_preamble_override, write_latency,
+	    read_to_precharge, write_cmd_to_write_data,
+	    minimum_cke_pulse_width, four_activates_window;
+	u32 timing_cfg_2;
+	/* DDR SDRAM Control Configuration register values */
+	u32 self_refresh, ecc, registered_dram, sdram_type,
+	    dynamic_power_management, databus_width, nc_auto_precharge,
+	    timing_2t, bank_interleaving_ctrl, precharge_bit_8, half_strength,
+	    bypass_initialization;
+	u32 sdram_cfg;
+	/* DDR SDRAM Control Configuration 2 register values */
+	u32 force_self_refresh, dll_reset, dqs_config, odt_config,
+	    posted_refreshes;
+	u32 sdram_cfg2;
+	/* DDR SDRAM Mode Configuration register values */
+	u32 sdmode, esdmode;
+	u32 sdram_mode;
+	/* DDR SDRAM Mode Configuration 2 register values */
+	u32 esdmode2, esdmode3;
+	u32 sdram_mode2;
+	/* DDR SDRAM Interval Configuration register values */
+	u32 refresh_interval, precharge_interval;
+	u32 sdram_interval;
+
+	priv->total_size = 0;
+
+	/* Disable both banks initially (might be re-enabled in loop below) */
+	out_be32(&im->ddr.cs_config[0], 0);
+	out_be32(&im->ddr.cs_config[1], 0);
+
+	dso = dev_read_u32_default(dev, "driver_software_override", 0);
+	if (dso > 1) {
+		debug("%s: driver_software_override value %d invalid.\n",
+		      dev->name, dso);
+		return -EINVAL;
+	}
+
+	pz_override = dev_read_u32_default(dev, "p_impedance_override", 0);
+
+	switch (pz_override) {
+	case DSO_P_IMPEDANCE_HIGHEST_Z:
+	case DSO_P_IMPEDANCE_MUCH_HIGHER_Z:
+	case DSO_P_IMPEDANCE_HIGHER_Z:
+	case DSO_P_IMPEDANCE_NOMINAL:
+	case DSO_P_IMPEDANCE_LOWER_Z:
+		break;
+	default:
+		debug("%s: p_impedance_override value %d invalid.\n",
+		      dev->name, pz_override);
+		return -EINVAL;
+	}
+
+	nz_override = dev_read_u32_default(dev, "n_impedance_override", 0);
+
+	switch (nz_override) {
+	case DSO_N_IMPEDANCE_HIGHEST_Z:
+	case DSO_N_IMPEDANCE_MUCH_HIGHER_Z:
+	case DSO_N_IMPEDANCE_HIGHER_Z:
+	case DSO_N_IMPEDANCE_NOMINAL:
+	case DSO_N_IMPEDANCE_LOWER_Z:
+		break;
+	default:
+		debug("%s: n_impedance_override value %d invalid.\n",
+		      dev->name, nz_override);
+		return -EINVAL;
+	}
+
+	odt_term = dev_read_u32_default(dev, "odt_termination_value", 0);
+	if (odt_term > 1) {
+		debug("%s: odt_termination_value value %d invalid.\n",
+		      dev->name, odt_term);
+		return -EINVAL;
+	}
+
+	ddr_type = dev_read_u32_default(dev, "ddr_type", 0);
+	if (ddr_type > 1) {
+		debug("%s: ddr_type value %d invalid.\n",
+		      dev->name, ddr_type);
+		return -EINVAL;
+	}
+
+	mvref_sel = dev_read_u32_default(dev, "mvref_sel", 0);
+	if (mvref_sel > 1) {
+		debug("%s: mvref_sel value %d invalid.\n",
+		      dev->name, mvref_sel);
+		return -EINVAL;
+	}
+
+	m_odr = dev_read_u32_default(dev, "m_odr", 0);
+	if (mvref_sel > 1) {
+		debug("%s: m_odr value %d invalid.\n",
+		      dev->name, m_odr);
+		return -EINVAL;
+	}
+
+	ddrcdr = dso << (31 - 1) |
+		 pz_override << (31 - 5) |
+		 nz_override << (31 - 9) |
+		 odt_term << (31 - 12) |
+		 ddr_type << (31 - 13) |
+		 mvref_sel << (31 - 29) |
+		 m_odr << (31 - 30) | 1;
+
+	/* Configure the DDR control driver register */
+	out_be32(&im->sysconf.ddrcdr, ddrcdr);
+
+	dev_for_each_subnode(subnode, dev) {
+		u32 val[3];
+		u32 cs, addr, size;
+
+		/* CS, map address, size -> three values */
+		ofnode_read_u32_array(subnode, "reg", val, 3);
+
+		cs = val[0];
+		addr = val[1];
+		size = val[2];
+
+		if (cs > 1) {
+			debug("%s: chip select value %d invalid.\n",
+			      dev->name, cs);
+			return -EINVAL;
+		}
+
+		/* TODO(mario.six@gdsys.cc): Sanity check for size. */
+
+		if (ofnode_read_bool(subnode, "read-spd"))
+			ret = mpc83xx_sdram_spd_init(subnode, cs, addr, size);
+		else
+			ret = mpc83xx_sdram_static_init(subnode, cs, addr,
+							size);
+		if (ret) {
+			debug("%s: RAM init failed.\n", dev->name);
+			return ret;
+		}
+	};
+
+	/*
+	 * TODO(mario.six@gdsys.cc): This should only occur for static
+	 *			     configuration
+	 */
+
+	clock_adjust = dev_read_u32_default(dev, "clock_adjust", 0);
+	switch (clock_adjust) {
+	case CLOCK_ADJUST_025:
+	case CLOCK_ADJUST_05:
+	case CLOCK_ADJUST_075:
+	case CLOCK_ADJUST_1:
+		break;
+	default:
+		debug("%s: clock_adjust value %d invalid.\n",
+		      dev->name, clock_adjust);
+		return -EINVAL;
+	}
+
+	/* Configure the DDR SDRAM Clock Control register */
+	out_be32(&im->ddr.sdram_clk_cntl, clock_adjust);
+
+	ext_refresh_rec = dev_read_u32_default(dev, "ext_refresh_rec", 0);
+	switch (ext_refresh_rec) {
+	case 0:
+		ext_refresh_rec_mask = 0 << TIMING_CFG3_EXT_REFREC_SHIFT;
+		break;
+	case 16:
+		ext_refresh_rec_mask = 1 << TIMING_CFG3_EXT_REFREC_SHIFT;
+		break;
+	case 32:
+		ext_refresh_rec_mask = 2 << TIMING_CFG3_EXT_REFREC_SHIFT;
+		break;
+	case 48:
+		ext_refresh_rec_mask = 3 << TIMING_CFG3_EXT_REFREC_SHIFT;
+		break;
+	case 64:
+		ext_refresh_rec_mask = 4 << TIMING_CFG3_EXT_REFREC_SHIFT;
+		break;
+	case 80:
+		ext_refresh_rec_mask = 5 << TIMING_CFG3_EXT_REFREC_SHIFT;
+		break;
+	case 96:
+		ext_refresh_rec_mask = 6 << TIMING_CFG3_EXT_REFREC_SHIFT;
+		break;
+	case 112:
+		ext_refresh_rec_mask = 7 << TIMING_CFG3_EXT_REFREC_SHIFT;
+		break;
+	default:
+		debug("%s: ext_refresh_rec value %d invalid.\n",
+		      dev->name, ext_refresh_rec);
+		return -EINVAL;
+	}
+
+	/* Configure the DDR SDRAM Timing Configuration 3 register */
+	out_be32(&im->ddr.timing_cfg_3, ext_refresh_rec_mask);
+
+	read_to_write = dev_read_u32_default(dev, "read_to_write", 0);
+	if (read_to_write > 3) {
+		debug("%s: read_to_write value %d invalid.\n",
+		      dev->name, read_to_write);
+		return -EINVAL;
+	}
+
+	write_to_read = dev_read_u32_default(dev, "write_to_read", 0);
+	if (write_to_read > 3) {
+		debug("%s: write_to_read value %d invalid.\n",
+		      dev->name, write_to_read);
+		return -EINVAL;
+	}
+
+	read_to_read = dev_read_u32_default(dev, "read_to_read", 0);
+	if (read_to_read > 3) {
+		debug("%s: read_to_read value %d invalid.\n",
+		      dev->name, read_to_read);
+		return -EINVAL;
+	}
+
+	write_to_write = dev_read_u32_default(dev, "write_to_write", 0);
+	if (write_to_write > 3) {
+		debug("%s: write_to_write value %d invalid.\n",
+		      dev->name, write_to_write);
+		return -EINVAL;
+	}
+
+	active_powerdown_exit =
+		dev_read_u32_default(dev, "active_powerdown_exit", 0);
+	if (active_powerdown_exit > 7) {
+		debug("%s: active_powerdown_exit value %d invalid.\n",
+		      dev->name, active_powerdown_exit);
+		return -EINVAL;
+	}
+
+	precharge_powerdown_exit =
+		dev_read_u32_default(dev, "precharge_powerdown_exit", 0);
+	if (precharge_powerdown_exit > 7) {
+		debug("%s: precharge_powerdown_exit value %d invalid.\n",
+		      dev->name, precharge_powerdown_exit);
+		return -EINVAL;
+	}
+
+	odt_powerdown_exit = dev_read_u32_default(dev, "odt_powerdown_exit", 0);
+	if (odt_powerdown_exit > 15) {
+		debug("%s: odt_powerdown_exit value %d invalid.\n",
+		      dev->name, odt_powerdown_exit);
+		return -EINVAL;
+	}
+
+	mode_reg_set_cycle = dev_read_u32_default(dev, "mode_reg_set_cycle", 0);
+	if (mode_reg_set_cycle > 15) {
+		debug("%s: mode_reg_set_cycle value %d invalid.\n",
+		      dev->name, mode_reg_set_cycle);
+		return -EINVAL;
+	}
+
+	timing_cfg_0 = read_to_write << TIMING_CFG0_RWT_SHIFT |
+		       write_to_read << TIMING_CFG0_WRT_SHIFT |
+		       read_to_read << TIMING_CFG0_RRT_SHIFT |
+		       write_to_write << TIMING_CFG0_WWT_SHIFT |
+		       active_powerdown_exit << TIMING_CFG0_ACT_PD_EXIT_SHIFT |
+		       precharge_powerdown_exit << TIMING_CFG0_PRE_PD_EXIT_SHIFT |
+		       odt_powerdown_exit << TIMING_CFG0_ODT_PD_EXIT_SHIFT |
+		       mode_reg_set_cycle << TIMING_CFG0_MRS_CYC_SHIFT;
+
+	out_be32(&im->ddr.timing_cfg_0, timing_cfg_0);
+
+	precharge_to_activate =
+		dev_read_u32_default(dev, "precharge_to_activate", 0);
+	if (precharge_to_activate > 7 || precharge_to_activate == 0) {
+		debug("%s: precharge_to_activate value %d invalid.\n",
+		      dev->name, precharge_to_activate);
+		return -EINVAL;
+	}
+
+	activate_to_precharge =
+		dev_read_u32_default(dev, "activate_to_precharge", 0);
+	if (activate_to_precharge > 19) {
+		debug("%s: activate_to_precharge value %d invalid.\n",
+		      dev->name, activate_to_precharge);
+		return -EINVAL;
+	}
+
+	activate_to_readwrite =
+		dev_read_u32_default(dev, "activate_to_readwrite", 0);
+	if (activate_to_readwrite > 7 || activate_to_readwrite == 0) {
+		debug("%s: activate_to_readwrite value %d invalid.\n",
+		      dev->name, activate_to_readwrite);
+		return -EINVAL;
+	}
+
+	mcas_latency = dev_read_u32_default(dev, "mcas_latency", 0);
+	switch (mcas_latency) {
+	case CASLAT_20:
+	case CASLAT_25:
+		if (!IS_ENABLED(CONFIG_ARCH_MPC8308)) {
+			debug("%s: MCAS latency < 3.0 unsupported on MPC8308\n",
+			      dev->name);
+			return -EINVAL;
+		}
+		/* fall through */
+	case CASLAT_30:
+	case CASLAT_35:
+	case CASLAT_40:
+	case CASLAT_45:
+	case CASLAT_50:
+	case CASLAT_55:
+	case CASLAT_60:
+	case CASLAT_65:
+	case CASLAT_70:
+	case CASLAT_75:
+	case CASLAT_80:
+		break;
+	default:
+		debug("%s: mcas_latency value %d invalid.\n",
+		      dev->name, mcas_latency);
+		return -EINVAL;
+	}
+
+	refresh_recovery = dev_read_u32_default(dev, "refresh_recovery", 0);
+	if (refresh_recovery > 23 || refresh_recovery < 8) {
+		debug("%s: refresh_recovery value %d invalid.\n",
+		      dev->name, refresh_recovery);
+		return -EINVAL;
+	}
+
+	last_data_to_precharge =
+		dev_read_u32_default(dev, "last_data_to_precharge", 0);
+	if (last_data_to_precharge > 7 || last_data_to_precharge == 0) {
+		debug("%s: last_data_to_precharge value %d invalid.\n",
+		      dev->name, last_data_to_precharge);
+		return -EINVAL;
+	}
+
+	activate_to_activate =
+		dev_read_u32_default(dev, "activate_to_activate", 0);
+	if (activate_to_activate > 7 || activate_to_activate == 0) {
+		debug("%s: activate_to_activate value %d invalid.\n",
+		      dev->name, activate_to_activate);
+		return -EINVAL;
+	}
+
+	last_write_data_to_read =
+		dev_read_u32_default(dev, "last_write_data_to_read", 0);
+	if (last_write_data_to_read > 7 || last_write_data_to_read == 0) {
+		debug("%s: last_write_data_to_read value %d invalid.\n",
+		      dev->name, last_write_data_to_read);
+		return -EINVAL;
+	}
+
+	timing_cfg_1 = precharge_to_activate << TIMING_CFG1_PRETOACT_SHIFT |
+		       (activate_to_precharge > 15 ?
+			activate_to_precharge - 16 :
+			activate_to_precharge) << TIMING_CFG1_ACTTOPRE_SHIFT |
+		       activate_to_readwrite << TIMING_CFG1_ACTTORW_SHIFT |
+		       mcas_latency << TIMING_CFG1_CASLAT_SHIFT |
+		       (refresh_recovery - 8) << TIMING_CFG1_REFREC_SHIFT |
+		       last_data_to_precharge << TIMING_CFG1_WRREC_SHIFT |
+		       activate_to_activate << TIMING_CFG1_ACTTOACT_SHIFT |
+		       last_write_data_to_read << TIMING_CFG1_WRTORD_SHIFT;
+
+	/* Configure the DDR SDRAM Timing Configuration 1 register */
+	out_be32(&im->ddr.timing_cfg_1, timing_cfg_1);
+
+	additive_latency = dev_read_u32_default(dev, "additive_latency", 0);
+	if (additive_latency > 5) {
+		debug("%s: additive_latency value %d invalid.\n",
+		      dev->name, additive_latency);
+		return -EINVAL;
+	}
+
+	mcas_to_preamble_override =
+		dev_read_u32_default(dev, "mcas_to_preamble_override", 0);
+	switch (mcas_to_preamble_override) {
+	case READ_LAT_PLUS_1:
+	case READ_LAT:
+	case READ_LAT_PLUS_1_4:
+	case READ_LAT_PLUS_1_2:
+	case READ_LAT_PLUS_3_4:
+	case READ_LAT_PLUS_5_4:
+	case READ_LAT_PLUS_3_2:
+	case READ_LAT_PLUS_7_4:
+	case READ_LAT_PLUS_2:
+	case READ_LAT_PLUS_9_4:
+	case READ_LAT_PLUS_5_2:
+	case READ_LAT_PLUS_11_4:
+	case READ_LAT_PLUS_3:
+	case READ_LAT_PLUS_13_4:
+	case READ_LAT_PLUS_7_2:
+	case READ_LAT_PLUS_15_4:
+	case READ_LAT_PLUS_4:
+	case READ_LAT_PLUS_17_4:
+	case READ_LAT_PLUS_9_2:
+	case READ_LAT_PLUS_19_4:
+		break;
+	default:
+		debug("%s: mcas_to_preamble_override value %d invalid.\n",
+		      dev->name, mcas_to_preamble_override);
+		return -EINVAL;
+	}
+
+	write_latency = dev_read_u32_default(dev, "write_latency", 0);
+	if (write_latency > 7 || write_latency == 0) {
+		debug("%s: write_latency value %d invalid.\n",
+		      dev->name, write_latency);
+		return -EINVAL;
+	}
+
+	read_to_precharge = dev_read_u32_default(dev, "read_to_precharge", 0);
+	if (read_to_precharge > 4 || read_to_precharge == 0) {
+		debug("%s: read_to_precharge value %d invalid.\n",
+		      dev->name, read_to_precharge);
+		return -EINVAL;
+	}
+
+	write_cmd_to_write_data =
+		dev_read_u32_default(dev, "write_cmd_to_write_data", 0);
+	switch (write_cmd_to_write_data) {
+	case CLOCK_DELAY_0:
+	case CLOCK_DELAY_1_4:
+	case CLOCK_DELAY_1_2:
+	case CLOCK_DELAY_3_4:
+	case CLOCK_DELAY_1:
+	case CLOCK_DELAY_5_4:
+	case CLOCK_DELAY_3_2:
+		break;
+	default:
+		debug("%s: write_cmd_to_write_data value %d invalid.\n",
+		      dev->name, write_cmd_to_write_data);
+		return -EINVAL;
+	}
+
+	minimum_cke_pulse_width =
+		dev_read_u32_default(dev, "minimum_cke_pulse_width", 0);
+	if (minimum_cke_pulse_width > 4 || minimum_cke_pulse_width == 0) {
+		debug("%s: minimum_cke_pulse_width value %d invalid.\n",
+		      dev->name, minimum_cke_pulse_width);
+		return -EINVAL;
+	}
+
+	four_activates_window =
+		dev_read_u32_default(dev, "four_activates_window", 0);
+	if (four_activates_window > 20 || four_activates_window == 0) {
+		debug("%s: four_activates_window value %d invalid.\n",
+		      dev->name, four_activates_window);
+		return -EINVAL;
+	}
+
+	timing_cfg_2 = additive_latency << TIMING_CFG2_ADD_LAT_SHIFT |
+		       mcas_to_preamble_override << TIMING_CFG2_CPO_SHIFT |
+		       write_latency << TIMING_CFG2_WR_LAT_DELAY_SHIFT |
+		       read_to_precharge << TIMING_CFG2_RD_TO_PRE_SHIFT |
+		       write_cmd_to_write_data << TIMING_CFG2_WR_DATA_DELAY_SHIFT |
+		       minimum_cke_pulse_width << TIMING_CFG2_CKE_PLS_SHIFT |
+		       four_activates_window << TIMING_CFG2_FOUR_ACT_SHIFT;
+
+	out_be32(&im->ddr.timing_cfg_2, timing_cfg_2);
+
+	self_refresh = dev_read_u32_default(dev, "self_refresh", 0);
+	switch (self_refresh) {
+	case SREN_DISABLE:
+	case SREN_ENABLE:
+		break;
+	default:
+		debug("%s: self_refresh value %d invalid.\n",
+		      dev->name, self_refresh);
+		return -EINVAL;
+	}
+
+	ecc = dev_read_u32_default(dev, "ecc", 0);
+	switch (ecc) {
+	case ECC_DISABLE:
+	case ECC_ENABLE:
+		break;
+	default:
+		debug("%s: ecc value %d invalid.\n", dev->name, ecc);
+		return -EINVAL;
+	}
+
+	registered_dram = dev_read_u32_default(dev, "registered_dram", 0);
+	switch (registered_dram) {
+	case RD_DISABLE:
+	case RD_ENABLE:
+		break;
+	default:
+		debug("%s: registered_dram value %d invalid.\n",
+		      dev->name, registered_dram);
+		return -EINVAL;
+	}
+
+	sdram_type = dev_read_u32_default(dev, "sdram_type", 0);
+	switch (sdram_type) {
+	case TYPE_DDR1:
+	case TYPE_DDR2:
+		break;
+	default:
+		debug("%s: sdram_type value %d invalid.\n",
+		      dev->name, sdram_type);
+		return -EINVAL;
+	}
+
+	dynamic_power_management =
+		dev_read_u32_default(dev, "dynamic_power_management", 0);
+	switch (dynamic_power_management) {
+	case DYN_PWR_DISABLE:
+	case DYN_PWR_ENABLE:
+		break;
+	default:
+		debug("%s: dynamic_power_management value %d invalid.\n",
+		      dev->name, dynamic_power_management);
+		return -EINVAL;
+	}
+
+	databus_width = dev_read_u32_default(dev, "databus_width", 0);
+	switch (databus_width) {
+	case DATA_BUS_WIDTH_16:
+	case DATA_BUS_WIDTH_32:
+		break;
+	default:
+		debug("%s: databus_width value %d invalid.\n",
+		      dev->name, databus_width);
+		return -EINVAL;
+	}
+
+	nc_auto_precharge = dev_read_u32_default(dev, "nc_auto_precharge", 0);
+	switch (nc_auto_precharge) {
+	case NCAP_DISABLE:
+	case NCAP_ENABLE:
+		break;
+	default:
+		debug("%s: nc_auto_precharge value %d invalid.\n",
+		      dev->name, nc_auto_precharge);
+		return -EINVAL;
+	}
+
+	timing_2t = dev_read_u32_default(dev, "timing_2t", 0);
+	switch (timing_2t) {
+	case TIMING_1T:
+	case TIMING_2T:
+		break;
+	default:
+		debug("%s: timing_2t value %d invalid.\n",
+		      dev->name, timing_2t);
+		return -EINVAL;
+	}
+
+	bank_interleaving_ctrl =
+		dev_read_u32_default(dev, "bank_interleaving_ctrl", 0);
+	switch (bank_interleaving_ctrl) {
+	case INTERLEAVE_NONE:
+	case INTERLEAVE_1_AND_2:
+		break;
+	default:
+		debug("%s: bank_interleaving_ctrl value %d invalid.\n",
+		      dev->name, bank_interleaving_ctrl);
+		return -EINVAL;
+	}
+
+	precharge_bit_8 = dev_read_u32_default(dev, "precharge_bit_8", 0);
+	switch (precharge_bit_8) {
+	case PRECHARGE_MA_10:
+	case PRECHARGE_MA_8:
+		break;
+	default:
+		debug("%s: precharge_bit_8 value %d invalid.\n",
+		      dev->name, precharge_bit_8);
+		return -EINVAL;
+	}
+
+	half_strength = dev_read_u32_default(dev, "half_strength", 0);
+	switch (half_strength) {
+	case STRENGTH_FULL:
+	case STRENGTH_HALF:
+		break;
+	default:
+		debug("%s: half_strength value %d invalid.\n",
+		      dev->name, half_strength);
+		return -EINVAL;
+	}
+
+	bypass_initialization =
+		dev_read_u32_default(dev, "bypass_initialization", 0);
+	switch (bypass_initialization) {
+	case INITIALIZATION_DONT_BYPASS:
+	case INITIALIZATION_BYPASS:
+		break;
+	default:
+		debug("%s: bypass_initialization value %d invalid.\n",
+		      dev->name, bypass_initialization);
+		return -EINVAL;
+	}
+
+	sdram_cfg = self_refresh << SDRAM_CFG_SREN_SHIFT |
+		    ecc << SDRAM_CFG_ECC_EN_SHIFT |
+		    registered_dram << SDRAM_CFG_RD_EN_SHIFT |
+		    sdram_type << SDRAM_CFG_SDRAM_TYPE_SHIFT |
+		    dynamic_power_management << SDRAM_CFG_DYN_PWR_SHIFT |
+		    databus_width << SDRAM_CFG_DBW_SHIFT |
+		    nc_auto_precharge << SDRAM_CFG_NCAP_SHIFT |
+		    timing_2t << SDRAM_CFG_2T_EN_SHIFT |
+		    bank_interleaving_ctrl << SDRAM_CFG_BA_INTLV_CTL_SHIFT |
+		    precharge_bit_8 << SDRAM_CFG_PCHB8_SHIFT |
+		    half_strength << SDRAM_CFG_HSE_SHIFT |
+		    bypass_initialization << SDRAM_CFG_BI_SHIFT;
+
+	out_be32(&im->ddr.sdram_cfg, sdram_cfg);
+
+	force_self_refresh = dev_read_u32_default(dev, "force_self_refresh", 0);
+	switch (force_self_refresh) {
+	case MODE_NORMAL:
+	case MODE_REFRESH:
+		break;
+	default:
+		debug("%s: force_self_refresh value %d invalid.\n",
+		      dev->name, force_self_refresh);
+		return -EINVAL;
+	}
+
+	dll_reset = dev_read_u32_default(dev, "dll_reset", 0);
+	switch (dll_reset) {
+	case DLL_RESET_ENABLE:
+	case DLL_RESET_DISABLE:
+		break;
+	default:
+		debug("%s: dll_reset value %d invalid.\n",
+		      dev->name, dll_reset);
+		return -EINVAL;
+	}
+
+	dqs_config = dev_read_u32_default(dev, "dqs_config", 0);
+	switch (dqs_config) {
+	case DQS_TRUE:
+		break;
+	default:
+		debug("%s: dqs_config value %d invalid.\n",
+		      dev->name, dqs_config);
+		return -EINVAL;
+	}
+
+	odt_config = dev_read_u32_default(dev, "odt_config", 0);
+	switch (odt_config) {
+	case ODT_ASSERT_NEVER:
+	case ODT_ASSERT_WRITES:
+	case ODT_ASSERT_READS:
+	case ODT_ASSERT_ALWAYS:
+		break;
+	default:
+		debug("%s: odt_config value %d invalid.\n",
+		      dev->name, odt_config);
+		return -EINVAL;
+	}
+
+	posted_refreshes = dev_read_u32_default(dev, "posted_refreshes", 0);
+	if (posted_refreshes > 8 || posted_refreshes == 0) {
+		debug("%s: posted_refreshes value %d invalid.\n",
+		      dev->name, posted_refreshes);
+		return -EINVAL;
+	}
+
+	sdram_cfg2 = force_self_refresh << SDRAM_CFG2_FRC_SR_SHIFT |
+		     dll_reset << SDRAM_CFG2_DLL_RST_DIS |
+		     dqs_config << SDRAM_CFG2_DQS_CFG |
+		     odt_config << SDRAM_CFG2_ODT_CFG |
+		     posted_refreshes << SDRAM_CFG2_NUM_PR;
+
+	out_be32(&im->ddr.sdram_cfg2, sdram_cfg2);
+
+	sdmode = dev_read_u32_default(dev, "sdmode", 0);
+	if (sdmode > 0xFFFF) {
+		debug("%s: sdmode value %d invalid.\n",
+		      dev->name, sdmode);
+		return -EINVAL;
+	}
+
+	esdmode = dev_read_u32_default(dev, "esdmode", 0);
+	if (esdmode > 0xFFFF) {
+		debug("%s: esdmode value %d invalid.\n", dev->name, esdmode);
+		return -EINVAL;
+	}
+
+	sdram_mode = sdmode << SDRAM_MODE_SD_SHIFT |
+		     esdmode << SDRAM_MODE_ESD_SHIFT;
+
+	out_be32(&im->ddr.sdram_mode, sdram_mode);
+
+	esdmode2 = dev_read_u32_default(dev, "esdmode2", 0);
+	if (esdmode2 > 0xFFFF) {
+		debug("%s: esdmode2 value %d invalid.\n", dev->name, esdmode2);
+		return -EINVAL;
+	}
+
+	esdmode3 = dev_read_u32_default(dev, "esdmode3", 0);
+	if (esdmode3 > 0xFFFF) {
+		debug("%s: esdmode3 value %d invalid.\n", dev->name, esdmode3);
+		return -EINVAL;
+	}
+
+	sdram_mode2 = esdmode2 << SDRAM_MODE2_ESD2_SHIFT |
+		      esdmode3 << SDRAM_MODE2_ESD3_SHIFT;
+
+	out_be32(&im->ddr.sdram_mode2, sdram_mode2);
+
+	refresh_interval = dev_read_u32_default(dev, "refresh_interval", 0);
+	if (refresh_interval > 0xFFFF) {
+		debug("%s: refresh_interval value %d invalid.\n",
+		      dev->name, refresh_interval);
+		return -EINVAL;
+	}
+
+	precharge_interval = dev_read_u32_default(dev, "precharge_interval", 0);
+	if (precharge_interval > 0x3FFF) {
+		debug("%s: precharge_interval value %d invalid.\n",
+		      dev->name, precharge_interval);
+		return -EINVAL;
+	}
+
+	sdram_interval = refresh_interval << SDRAM_INTERVAL_REFINT_SHIFT |
+			 precharge_interval << SDRAM_INTERVAL_BSTOPRE_SHIFT;
+
+	out_be32(&im->ddr.sdram_interval, sdram_interval);
+	sync();
+
+	/* Enable DDR controller */
+	setbits_be32(&im->ddr.sdram_cfg, SDRAM_CFG_MEM_EN);
+	sync();
+
+	dev_for_each_subnode(subnode, dev) {
+		u32 val[3];
+		u32 addr, size;
+
+		/* CS, map address, size -> three values */
+		ofnode_read_u32_array(subnode, "reg", val, 3);
+
+		addr = val[1];
+		size = val[2];
+
+		priv->total_size += get_ram_size((long int *)addr, size);
+	};
+
+	gd->ram_size = priv->total_size;
+
+	return 0;
+}
+
+static int mpc83xx_sdram_get_info(struct udevice *dev, struct ram_info *info)
+{
+	/* TODO(mario.six@gdsys.cc): Implement */
+	return 0;
+}
+
+static struct ram_ops mpc83xx_sdram_ops = {
+	.get_info = mpc83xx_sdram_get_info,
+};
+
+static const struct udevice_id mpc83xx_sdram_ids[] = {
+	{ .compatible = "fsl,mpc83xx-mem-controller" },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(mpc83xx_sdram) = {
+	.name = "mpc83xx_sdram",
+	.id = UCLASS_RAM,
+	.of_match = mpc83xx_sdram_ids,
+	.ops = &mpc83xx_sdram_ops,
+	.ofdata_to_platdata = mpc83xx_sdram_ofdata_to_platdata,
+	.probe = mpc83xx_sdram_probe,
+	.priv_auto_alloc_size = sizeof(struct mpc83xx_sdram_priv),
+};
diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig
index ed1d437..8ce3e2e 100644
--- a/drivers/sysreset/Kconfig
+++ b/drivers/sysreset/Kconfig
@@ -64,4 +64,9 @@
 	help
 	  Reboot support for generic x86 processor reset.
 
+config SYSRESET_MCP83XX
+	bool "Enable support MPC83xx SoC family reboot driver"
+	help
+	  Reboot support for NXP MPC83xx SoCs.
+
 endmenu
diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
index 02ee1df..b3728ac 100644
--- a/drivers/sysreset/Makefile
+++ b/drivers/sysreset/Makefile
@@ -3,15 +3,16 @@
 # (C) Copyright 2016 Cadence Design Systems Inc.
 
 obj-$(CONFIG_SYSRESET) += sysreset-uclass.o
+obj-$(CONFIG_ARCH_ASPEED) += sysreset_ast.o
+obj-$(CONFIG_ARCH_ROCKCHIP) += sysreset_rockchip.o
+obj-$(CONFIG_ARCH_STI) += sysreset_sti.o
+obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o
 obj-$(CONFIG_SYSRESET_GPIO) += sysreset_gpio.o
+obj-$(CONFIG_SYSRESET_MCP83XX) += sysreset_mpc83xx.o
 obj-$(CONFIG_SYSRESET_MICROBLAZE) += sysreset_microblaze.o
 obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o
 obj-$(CONFIG_SYSRESET_TI_SCI) += sysreset-ti-sci.o
 obj-$(CONFIG_SYSRESET_SYSCON) += sysreset_syscon.o
 obj-$(CONFIG_SYSRESET_WATCHDOG) += sysreset_watchdog.o
 obj-$(CONFIG_SYSRESET_X86) += sysreset_x86.o
-obj-$(CONFIG_ARCH_ROCKCHIP) += sysreset_rockchip.o
-obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o
-obj-$(CONFIG_ARCH_STI) += sysreset_sti.o
 obj-$(CONFIG_TARGET_XTFPGA) += sysreset_xtfpga.o
-obj-$(CONFIG_ARCH_ASPEED) += sysreset_ast.o
diff --git a/drivers/sysreset/sysreset-uclass.c b/drivers/sysreset/sysreset-uclass.c
index b918365..06ef0ed 100644
--- a/drivers/sysreset/sysreset-uclass.c
+++ b/drivers/sysreset/sysreset-uclass.c
@@ -24,6 +24,16 @@
 	return ops->request(dev, type);
 }
 
+int sysreset_get_status(struct udevice *dev, char *buf, int size)
+{
+	struct sysreset_ops *ops = sysreset_get_ops(dev);
+
+	if (!ops->get_status)
+		return -ENOSYS;
+
+	return ops->get_status(dev, buf, size);
+}
+
 int sysreset_walk(enum sysreset_t type)
 {
 	struct udevice *dev;
diff --git a/drivers/sysreset/sysreset_mpc83xx.c b/drivers/sysreset/sysreset_mpc83xx.c
new file mode 100644
index 0000000..9092764
--- /dev/null
+++ b/drivers/sysreset/sysreset_mpc83xx.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <sysreset.h>
+#include <wait_bit.h>
+
+#include "sysreset_mpc83xx.h"
+
+/* Magic 4-byte word to enable reset ('RSTE' in ASCII) */
+static const u32 RPR_MAGIC = 0x52535445;
+/* Wait at most 2000ms for reset control enable bit */
+static const uint RESET_WAIT_TIMEOUT = 2000;
+
+/**
+ * __do_reset() - Execute the system reset
+ *
+ * Return: The functions resets the system, and never returns.
+ */
+static int __do_reset(void)
+{
+	ulong msr;
+	int res;
+
+	immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
+
+	puts("Resetting the board.\n");
+
+	/* Interrupts and MMU off */
+	msr = mfmsr();
+	msr &= ~(MSR_EE | MSR_IR | MSR_DR);
+	mtmsr(msr);
+
+	/* Enable Reset Control Reg */
+	out_be32(&immap->reset.rpr, RPR_MAGIC);
+	sync();
+	isync();
+
+	/* Confirm Reset Control Reg is enabled */
+	res = wait_for_bit_be32(&immap->reset.rcer, RCER_CRE, true,
+				RESET_WAIT_TIMEOUT, false);
+	if (res) {
+		debug("%s: Timed out waiting for reset control to be set\n",
+		      __func__);
+		return res;
+	}
+
+	udelay(200);
+
+	/* Perform reset, only one bit */
+	out_be32(&immap->reset.rcr, RCR_SWHR);
+
+	/* Never executes */
+	return 0;
+}
+
+static int mpc83xx_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+	switch (type) {
+	case SYSRESET_WARM:
+	case SYSRESET_COLD:
+		return __do_reset();
+	default:
+		return -EPROTONOSUPPORT;
+	}
+
+	return -EINPROGRESS;
+}
+
+/**
+ * print_83xx_arb_event() - Print arbiter events to buffer
+ * @force: Print arbiter events, even if none are indicated by the system
+ * @buf:   The buffer to receive the printed arbiter event information
+ * @size:  The size of the buffer to receive the printed arbiter event
+ *	   information in bytes
+ *
+ * Return: Number of bytes printed to buffer, -ve on error
+ */
+static int print_83xx_arb_event(bool force, char *buf, int size)
+{
+	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;
+	int tsize_val = (tbst << 3) | tsize;
+	int tsize_bytes = tbst ? (tsize ? tsize : 8) : 16 + 8 * tsize;
+	int res = 0;
+
+	/*
+	 * If we don't force output, and there is no event (event address ==
+	 * 0), then don't print anything
+	 */
+	if (!force && !gd->arch.arbiter_event_address)
+		return 0;
+
+	if (CONFIG_IS_ENABLED(CONFIG_DISPLAY_AER_FULL)) {
+		res = snprintf(buf, size,
+			       "Arbiter Event Status:\n"
+			       "    %s: 0x%08lX\n"
+			       "    %s:    0x%1x  = %s\n"
+			       "    %s:     0x%02x = %s\n"
+			       "    %s: 0x%1x  = %d bytes\n"
+			       "    %s: 0x%02x = %s\n",
+			       "Event Address", gd->arch.arbiter_event_address,
+			       "Event Type", etype, event[etype],
+			       "Master ID", mstr_id, master[mstr_id],
+			       "Transfer Size", tsize_val, tsize_bytes,
+			       "Transfer Type", ttype, transfer[ttype]);
+	} else if (CONFIG_IS_ENABLED(CONFIG_DISPLAY_AER_BRIEF)) {
+		res = snprintf(buf, size,
+			       "Arbiter Event Status: AEATR=0x%08lX, AEADR=0x%08lX\n",
+			       gd->arch.arbiter_event_attributes,
+			       gd->arch.arbiter_event_address);
+	}
+
+	return res;
+}
+
+static int mpc83xx_sysreset_get_status(struct udevice *dev, char *buf, int size)
+{
+	/* Ad-hoc data structure to map RSR bit values to their descriptions */
+	static const struct {
+		/* Bit mask for the bit in question */
+		ulong mask;
+		/* Description of the bitmask in question */
+		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"}
+	};
+	int res;
+	ulong rsr = gd->arch.reset_status;
+	int i;
+	char *sep;
+
+	res = snprintf(buf, size, "Reset Status:");
+	if (res < 0) {
+		debug("%s: Could not write reset status message (err = %d)\n",
+		      dev->name, res);
+		return -EIO;
+	}
+
+	buf += res;
+	size -= res;
+
+	sep = " ";
+	for (i = 0; i < ARRAY_SIZE(bits); i++)
+		/* Print description of set bits */
+		if (rsr & bits[i].mask) {
+			res = snprintf(buf, size, "%s%s%s", sep, bits[i].desc,
+				       (i == ARRAY_SIZE(bits) - 1) ? "\n" : "");
+			if (res < 0) {
+				debug("%s: Could not write reset status message (err = %d)\n",
+				      dev->name, res);
+				return -EIO;
+			}
+			buf += res;
+			size -= res;
+			sep = ", ";
+		}
+
+	/*
+	 * TODO(mario.six@gdsys.cc): Move this into a dedicated
+	 *			     arbiter driver
+	 */
+	if (CONFIG_IS_ENABLED(CONFIG_DISPLAY_AER_FULL) ||
+	    CONFIG_IS_ENABLED(CONFIG_DISPLAY_AER_BRIEF)) {
+		/*
+		 * If there was a bus monitor reset event, we force the arbiter
+		 * event to be printed
+		 */
+		res = print_83xx_arb_event(rsr & RSR_BMRS, buf, size);
+		if (res < 0) {
+			debug("%s: Could not write arbiter event message (err = %d)\n",
+			      dev->name, res);
+			return -EIO;
+		}
+		buf += res;
+		size -= res;
+	}
+	snprintf(buf, size, "\n");
+
+	return 0;
+}
+
+static struct sysreset_ops mpc83xx_sysreset = {
+	.request	= mpc83xx_sysreset_request,
+	.get_status	= mpc83xx_sysreset_get_status,
+};
+
+U_BOOT_DRIVER(sysreset_mpc83xx) = {
+	.name	= "mpc83xx_sysreset",
+	.id	= UCLASS_SYSRESET,
+	.ops	= &mpc83xx_sysreset,
+};
diff --git a/drivers/sysreset/sysreset_mpc83xx.h b/drivers/sysreset/sysreset_mpc83xx.h
new file mode 100644
index 0000000..dc3c059
--- /dev/null
+++ b/drivers/sysreset/sysreset_mpc83xx.h
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+#ifndef _SYSRESET_MPC83XX_H_
+#define _SYSRESET_MPC83XX_H_
+
+/*
+ * String array for all possible event types; indexed by the EVENT field of the
+ * AEATR register.
+ */
+static const char * const event[] = {
+	"Address Time Out",
+	"Data Time Out",
+	"Address Only Transfer Type",
+	"External Control Word Transfer Type",
+	"Reserved Transfer Type",
+	"Transfer Error",
+	"reserved",
+	"reserved"
+};
+
+/*
+ * String array for all possible master IDs, which reflects the source of the
+ * transaction that caused the error; indexed by the MSTR_ID field of the AEATR
+ * register.
+ */
+static const char * const 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"
+};
+
+/*
+ * String array for all possible transfer types; indexed by the TTYPE field of
+ * the AEATR register.
+ */
+static const char * const 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"
+};
+#endif /* _SYSRESET_MPC83XX_H_ */
diff --git a/drivers/sysreset/sysreset_sandbox.c b/drivers/sysreset/sysreset_sandbox.c
index f12c4e8..75004d9 100644
--- a/drivers/sysreset/sysreset_sandbox.c
+++ b/drivers/sysreset/sysreset_sandbox.c
@@ -29,6 +29,13 @@
 	return -EINPROGRESS;
 }
 
+int sandbox_warm_sysreset_get_status(struct udevice *dev, char *buf, int size)
+{
+	strlcpy(buf, "Reset Status: WARM", size);
+
+	return 0;
+}
+
 static int sandbox_sysreset_request(struct udevice *dev, enum sysreset_t type)
 {
 	struct sandbox_state *state = state_get_current();
@@ -60,8 +67,16 @@
 	return -EINPROGRESS;
 }
 
+int sandbox_sysreset_get_status(struct udevice *dev, char *buf, int size)
+{
+	strlcpy(buf, "Reset Status: COLD", size);
+
+	return 0;
+}
+
 static struct sysreset_ops sandbox_sysreset_ops = {
 	.request	= sandbox_sysreset_request,
+	.get_status	= sandbox_sysreset_get_status,
 };
 
 static const struct udevice_id sandbox_sysreset_ids[] = {
@@ -78,6 +93,7 @@
 
 static struct sysreset_ops sandbox_warm_sysreset_ops = {
 	.request	= sandbox_warm_sysreset_request,
+	.get_status	= sandbox_warm_sysreset_get_status,
 };
 
 static const struct udevice_id sandbox_warm_sysreset_ids[] = {
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index 5ab6749..a7d600b 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -140,4 +140,11 @@
 	  Select this to enable support for the timer found on
 	  STM32 devices.
 
+config MPC83XX_TIMER
+        bool "MPC83xx timer support"
+	depends on TIMER
+	help
+	  Select this to enable support for the timer found on
+	  devices based on the MPC83xx family of SoCs.
+
 endmenu
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index 0c8a627..7f19c49 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -3,17 +3,18 @@
 # Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
 
 obj-y += timer-uclass.o
+obj-$(CONFIG_AG101P_TIMER) += ag101p_timer.o
 obj-$(CONFIG_ALTERA_TIMER)	+= altera_timer.o
+obj-$(CONFIG_ARC_TIMER)	+= arc_timer.o
+obj-$(CONFIG_AST_TIMER)	+= ast_timer.o
+obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o
+obj-$(CONFIG_ATMEL_PIT_TIMER) += atmel_pit_timer.o
 obj-$(CONFIG_CADENCE_TTC_TIMER)	+= cadence-ttc.o
 obj-$(CONFIG_DESIGNWARE_APB_TIMER)	+= dw-apb-timer.o
-obj-$(CONFIG_SANDBOX_TIMER)	+= sandbox_timer.o
-obj-$(CONFIG_X86_TSC_TIMER)	+= tsc_timer.o
+obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o
 obj-$(CONFIG_OMAP_TIMER)	+= omap-timer.o
-obj-$(CONFIG_AST_TIMER)	+= ast_timer.o
-obj-$(CONFIG_STI_TIMER)		+= sti-timer.o
-obj-$(CONFIG_ARC_TIMER)	+= arc_timer.o
-obj-$(CONFIG_AG101P_TIMER) += ag101p_timer.o
-obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o
 obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o
-obj-$(CONFIG_ATMEL_PIT_TIMER) += atmel_pit_timer.o
+obj-$(CONFIG_SANDBOX_TIMER)	+= sandbox_timer.o
+obj-$(CONFIG_STI_TIMER)		+= sti-timer.o
 obj-$(CONFIG_STM32_TIMER)	+= stm32_timer.o
+obj-$(CONFIG_X86_TSC_TIMER)	+= tsc_timer.o
diff --git a/drivers/timer/mpc83xx_timer.c b/drivers/timer/mpc83xx_timer.c
new file mode 100644
index 0000000..84a9ab0
--- /dev/null
+++ b/drivers/timer/mpc83xx_timer.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+#include <common.h>
+#include <board.h>
+#include <clk.h>
+#include <dm.h>
+#include <timer.h>
+#include <watchdog.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct mpc83xx_timer_priv - Private data structure for MPC83xx timer driver
+ * @decrementer_count: Value to which the decrementer register should be re-set
+ *		       to when a timer interrupt occurs, thus determines the
+ *		       interrupt frequency (value for 1e6/HZ microseconds)
+ * @timestamp:         Counter for the number of timer interrupts that have
+ *		       occurred (i.e. can be used to trigger events
+ *		       periodically in the timer interrupt)
+ */
+struct mpc83xx_timer_priv {
+	uint decrementer_count;
+	ulong timestamp;
+};
+
+/*
+ * Bitmask for enabling the time base in the SPCR (System Priority
+ * Configuration Register)
+ */
+static const u32 SPCR_TBEN_MASK = BIT(31 - 9);
+
+/**
+ * get_dec() - Get the value of the decrementer register
+ *
+ * Return: The value of the decrementer register
+ */
+static inline unsigned long get_dec(void)
+{
+	unsigned long val;
+
+	asm volatile ("mfdec %0" : "=r" (val) : );
+
+	return val;
+}
+
+/**
+ * set_dec() - Set the value of the decrementer register
+ * @val: The value of the decrementer register to be set
+ */
+static inline void set_dec(unsigned long val)
+{
+	if (val)
+		asm volatile ("mtdec %0"::"r" (val));
+}
+
+/**
+ * mftbu() - Get value of TBU (upper time base) register
+ *
+ * Return: Value of the TBU register
+ */
+static inline u32 mftbu(void)
+{
+	u32 rval;
+
+	asm volatile("mftbu %0" : "=r" (rval));
+	return rval;
+}
+
+/**
+ * mftb() - Get value of TBL (lower time base) register
+ *
+ * Return: Value of the TBL register
+ */
+static inline u32 mftb(void)
+{
+	u32 rval;
+
+	asm volatile("mftb %0" : "=r" (rval));
+	return rval;
+}
+
+/*
+ * TODO(mario.six@gdsys.cc): This should really be done by timer_init, and the
+ * interrupt init should go into a interrupt driver.
+ */
+int interrupt_init(void)
+{
+	immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+	struct udevice *csb;
+	struct udevice *board;
+	struct udevice *timer;
+	struct mpc83xx_timer_priv *timer_priv;
+	struct clk clock;
+	int ret;
+
+	ret = uclass_first_device_err(UCLASS_TIMER, &timer);
+	if (ret) {
+		debug("%s: Could not find timer device (error: %d)",
+		      __func__, ret);
+		return ret;
+	}
+
+	timer_priv = dev_get_priv(timer);
+
+	if (board_get(&board)) {
+		debug("%s: board device could not be fetched.\n", __func__);
+		return -ENOENT;
+	}
+
+	ret = uclass_get_device_by_phandle(UCLASS_SIMPLE_BUS, board,
+					   "csb", &csb);
+	if (ret) {
+		debug("%s: Could not retrieve CSB device (error: %d)",
+		      __func__, ret);
+		return ret;
+	}
+
+	ret = clk_get_by_index(csb, 0, &clock);
+	if (ret) {
+		debug("%s: Could not retrieve clock (error: %d)",
+		      __func__, ret);
+		return ret;
+	}
+
+	timer_priv->decrementer_count = (clk_get_rate(&clock) / 4)
+					/ CONFIG_SYS_HZ;
+	/* Enable e300 time base */
+	setbits_be32(&immr->sysconf.spcr, SPCR_TBEN_MASK);
+
+	set_dec(timer_priv->decrementer_count);
+
+	/* Switch on interrupts */
+	set_msr(get_msr() | MSR_EE);
+
+	return 0;
+}
+
+/**
+ * timer_interrupt() - Handler for the timer interrupt
+ * @regs: Array of register values
+ */
+void timer_interrupt(struct pt_regs *regs)
+{
+	struct udevice *timer = gd->timer;
+	struct mpc83xx_timer_priv *priv;
+
+	/*
+	 * During initialization, gd->timer might not be set yet, but the timer
+	 * interrupt may already be enabled. In this case, wait for the
+	 * initialization to complete
+	 */
+	if (!timer)
+		return;
+
+	priv = dev_get_priv(timer);
+
+	/* Restore Decrementer Count */
+	set_dec(priv->decrementer_count);
+
+	priv->timestamp++;
+
+#if defined(CONFIG_WATCHDOG) || defined(CONFIG_HW_WATCHDOG)
+	if ((timestamp % (CONFIG_SYS_WATCHDOG_FREQ)) == 0)
+		WATCHDOG_RESET();
+#endif    /* CONFIG_WATCHDOG || CONFIG_HW_WATCHDOG */
+
+#ifdef CONFIG_LED_STATUS
+	status_led_tick(priv->timestamp);
+#endif /* CONFIG_LED_STATUS */
+
+#ifdef CONFIG_SHOW_ACTIVITY
+	board_show_activity(priv->timestamp);
+#endif /* CONFIG_SHOW_ACTIVITY */
+}
+
+void wait_ticks(ulong ticks)
+{
+	ulong end = get_ticks() + ticks;
+
+	while (end > get_ticks())
+		WATCHDOG_RESET();
+}
+
+static int mpc83xx_timer_get_count(struct udevice *dev, u64 *count)
+{
+	u32 tbu, tbl;
+
+	/*
+	 * To make sure that no tbl overflow occurred between reading tbl and
+	 * tbu, read tbu again, and compare it with the previously read tbu
+	 * value: If they're different, a tbl overflow has occurred.
+	 */
+	do {
+		tbu = mftbu();
+		tbl = mftb();
+	} while (tbu != mftbu());
+
+	*count = (tbu * 0x10000ULL) + tbl;
+
+	return 0;
+}
+
+static int mpc83xx_timer_probe(struct udevice *dev)
+{
+	struct timer_dev_priv *uc_priv = dev->uclass_priv;
+	struct clk clock;
+	int ret;
+
+	ret = interrupt_init();
+	if (ret) {
+		debug("%s: interrupt_init failed (err = %d)\n",
+		      dev->name, ret);
+		return ret;
+	}
+
+	ret = clk_get_by_index(dev, 0, &clock);
+	if (ret) {
+		debug("%s: Could not retrieve clock (err = %d)\n",
+		      dev->name, ret);
+		return ret;
+	}
+
+	uc_priv->clock_rate = (clk_get_rate(&clock) + 3L) / 4L;
+
+	return 0;
+}
+
+static const struct timer_ops mpc83xx_timer_ops = {
+	.get_count = mpc83xx_timer_get_count,
+};
+
+static const struct udevice_id mpc83xx_timer_ids[] = {
+	{ .compatible = "fsl,mpc83xx-timer" },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(mpc83xx_timer) = {
+	.name	= "mpc83xx_timer",
+	.id	= UCLASS_TIMER,
+	.of_match = mpc83xx_timer_ids,
+	.probe = mpc83xx_timer_probe,
+	.ops	= &mpc83xx_timer_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+	.priv_auto_alloc_size = sizeof(struct mpc83xx_timer_priv),
+};
diff --git a/include/cpu.h b/include/cpu.h
index 5cc7c5a..367c5f4 100644
--- a/include/cpu.h
+++ b/include/cpu.h
@@ -9,19 +9,21 @@
 
 /**
  * struct cpu_platdata - platform data for a CPU
+ * @cpu_id:	   Platform-specific way of identifying the CPU.
+ * @ucode_version: Microcode version, if CPU_FEAT_UCODE is set
+ * @device_id:     Driver-defined device identifier
+ * @family:        DMTF CPU Family identifier
+ * @id:            DMTF CPU Processor identifier
  *
  * This can be accessed with dev_get_parent_platdata() for any UCLASS_CPU
  * device.
- *
- * @cpu_id:	Platform-specific way of identifying the CPU.
- * @ucode_version: Microcode version, if CPU_FEAT_UCODE is set
  */
 struct cpu_platdata {
 	int cpu_id;
 	int ucode_version;
 	ulong device_id;
-	u16 family;		/* DMTF CPU Family */
-	u32 id[2];		/* DMTF CPU Processor IDs */
+	u16 family;
+	u32 id[2];
 };
 
 /* CPU features - mostly just a placeholder for now */
@@ -88,39 +90,46 @@
 
 /**
  * cpu_get_desc() - Get a description string for a CPU
- *
  * @dev:	Device to check (UCLASS_CPU)
  * @buf:	Buffer to place string
  * @size:	Size of string space
- * @return 0 if OK, -ENOSPC if buffer is too small, other -ve on error
+ *
+ * Return: 0 if OK, -ENOSPC if buffer is too small, other -ve on error
  */
 int cpu_get_desc(struct udevice *dev, char *buf, int size);
 
 /**
  * cpu_get_info() - Get information about a CPU
- *
  * @dev:	Device to check (UCLASS_CPU)
  * @info:	Returns CPU info
- * @return 0 if OK, -ve on error
+ *
+ * Return: 0 if OK, -ve on error
  */
 int cpu_get_info(struct udevice *dev, struct cpu_info *info);
 
 /**
  * cpu_get_count() - Get number of CPUs
- *
  * @dev:	Device to check (UCLASS_CPU)
- * @return CPU count if OK, -ve on error
+ *
+ * Return: CPU count if OK, -ve on error
  */
 int cpu_get_count(struct udevice *dev);
 
 /**
  * cpu_get_vendor() - Get vendor name of a CPU
- *
  * @dev:	Device to check (UCLASS_CPU)
  * @buf:	Buffer to place string
  * @size:	Size of string space
- * @return 0 if OK, -ENOSPC if buffer is too small, other -ve on error
+ *
+ * Return: 0 if OK, -ENOSPC if buffer is too small, other -ve on error
  */
 int cpu_get_vendor(struct udevice *dev, char *buf, int size);
 
+/**
+ * cpu_probe_all() - Probe all available CPUs
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int cpu_probe_all(void);
+
 #endif
diff --git a/include/dm/of_access.h b/include/dm/of_access.h
index dd1abb8..5ed1a0c 100644
--- a/include/dm/of_access.h
+++ b/include/dm/of_access.h
@@ -194,6 +194,22 @@
 				const char *type, const char *compatible);
 
 /**
+ * of_find_node_by_prop_value() - find a node with a given property value
+ *
+ * Find a node based on a property value.
+ * @from: Node to start searching from or NULL. the node you pass will not be
+ *	searched, only the next one will; typically, you pass what the previous
+ *	call returned.
+ * @propname: property name to check
+ * @propval: property value to search for
+ * @proplen: length of the value in propval
+ * @return node pointer or NULL if not found
+ */
+struct device_node *of_find_node_by_prop_value(struct device_node *from,
+					       const char *propname,
+					       const void *propval,
+					       int proplen);
+/**
  * of_find_node_by_phandle() - Find a node given a phandle
  *
  * @handle:	phandle of the node to find
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index ab36b74..c06d778 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -703,6 +703,20 @@
 ofnode ofnode_by_compatible(ofnode from, const char *compat);
 
 /**
+ * ofnode_by_prop_value() - Find the next node with given property value
+ *
+ * Find the next node after @from that has a @propname with a value
+ * @propval and a length @proplen.
+ *
+ * @from: ofnode to start from (use ofnode_null() to start at the
+ * beginning) @propname: property name to check @propval: property value to
+ * search for @proplen: length of the value in propval @return ofnode
+ * found, or ofnode_null() if none
+ */
+ofnode ofnode_by_prop_value(ofnode from, const char *propname,
+			    const void *propval, int proplen);
+
+/**
  * ofnode_for_each_subnode() - iterate over all subnodes of a parent
  *
  * @node:       child node (ofnode, lvalue)
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index 0e882ce..6e7c1cd 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -58,6 +58,7 @@
  * @post_probe: Called after a new device is probed
  * @pre_remove: Called before a device is removed
  * @child_post_bind: Called after a child is bound to a device in this uclass
+ * @child_pre_probe: Called before a child is probed in this uclass
  * @init: Called to set up the uclass
  * @destroy: Called to destroy the uclass
  * @priv_auto_alloc_size: If non-zero this is the size of the private data
diff --git a/include/dt-bindings/clk/mpc83xx-clk.h b/include/dt-bindings/clk/mpc83xx-clk.h
new file mode 100644
index 0000000..db4ea15
--- /dev/null
+++ b/include/dt-bindings/clk/mpc83xx-clk.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+#ifndef DT_BINDINGS_MPC83XX_CLK_H
+#define DT_BINDINGS_MPC83XX_CLK_H
+#define MPC83XX_CLK_CORE	0
+#define MPC83XX_CLK_CSB		1
+#define MPC83XX_CLK_QE		2
+#define MPC83XX_CLK_BRG		3
+#define MPC83XX_CLK_LBIU	4
+#define MPC83XX_CLK_LCLK	5
+#define MPC83XX_CLK_MEM		6
+#define MPC83XX_CLK_MEM_SEC	7
+#define MPC83XX_CLK_ENC		8
+#define MPC83XX_CLK_I2C1	9
+#define MPC83XX_CLK_I2C2	10
+#define MPC83XX_CLK_TDM		11
+#define MPC83XX_CLK_SDHC	12
+#define MPC83XX_CLK_TSEC1	13
+#define MPC83XX_CLK_TSEC2	14
+#define MPC83XX_CLK_USBDR	15
+#define MPC83XX_CLK_USBMPH	16
+#define MPC83XX_CLK_PCIEXP1	17
+#define MPC83XX_CLK_PCIEXP2	18
+#define MPC83XX_CLK_SATA	19
+#define MPC83XX_CLK_DMAC	20
+#define MPC83XX_CLK_PCI		21
+/* Count */
+#define MPC83XX_CLK_COUNT	22
+#endif /* DT_BINDINGS_MPC83XX_CLK_H */
diff --git a/include/dt-bindings/memory/mpc83xx-sdram.h b/include/dt-bindings/memory/mpc83xx-sdram.h
new file mode 100644
index 0000000..7d4ce01
--- /dev/null
+++ b/include/dt-bindings/memory/mpc83xx-sdram.h
@@ -0,0 +1,161 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+#ifndef DT_BINDINGS_MPC83XX_SDRAM_H
+#define DT_BINDINGS_MPC83XX_SDRAM_H
+
+/* DDR Control Driver register */
+
+#define DSO_DISABLE	0
+#define DSO_ENABLE	1
+
+#define DSO_P_IMPEDANCE_HIGHEST_Z	0x0
+#define DSO_P_IMPEDANCE_MUCH_HIGHER_Z	0x8
+#define DSO_P_IMPEDANCE_HIGHER_Z	0xC
+#define DSO_P_IMPEDANCE_NOMINAL		0xE
+#define DSO_P_IMPEDANCE_LOWER_Z		0xF
+
+#define DSO_N_IMPEDANCE_HIGHEST_Z	0x0
+#define DSO_N_IMPEDANCE_MUCH_HIGHER_Z	0x8
+#define DSO_N_IMPEDANCE_HIGHER_Z	0xC
+#define DSO_N_IMPEDANCE_NOMINAL		0xE
+#define DSO_N_IMPEDANCE_LOWER_Z		0xF
+
+#define ODT_TERMINATION_75_OHM		0
+#define ODT_TERMINATION_150_OHM		1
+
+#define DDR_TYPE_DDR2_1_8_VOLT		0
+#define DDR_TYPE_DDR1_2_5_VOLT		1
+
+#define MVREF_SEL_EXTERNAL		0
+#define MVREF_SEL_INTERNAL_GVDD		1
+
+#define M_ODR_ENABLE			0
+#define M_ODR_DISABLE			1
+
+/* CS config register */
+
+#define AUTO_PRECHARGE_ENABLE	0x00800000
+#define AUTO_PRECHARGE_DISABLE	0x00000000
+
+#define ODT_RD_NEVER		0x00000000
+#define ODT_RD_ONLY_CURRENT	0x00100000
+#define ODT_RD_ONLY_OTHER_CS	0x00200000
+#define ODT_RD_ONLY_OTHER_DIMM	0x00300000
+#define ODT_RD_ALL		0x00400000
+
+#define ODT_WR_NEVER		0x00000000
+#define ODT_WR_ONLY_CURRENT	0x00010000
+#define ODT_WR_ONLY_OTHER_CS	0x00020000
+#define ODT_WR_ONLY_OTHER_DIMM	0x00030000
+#define ODT_WR_ALL		0x00040000
+
+/* DDR SDRAM Clock Control register */
+
+#define CLOCK_ADJUST_025	0x01000000
+#define CLOCK_ADJUST_05		0x02000000
+#define CLOCK_ADJUST_075	0x03000000
+#define CLOCK_ADJUST_1		0x04000000
+
+#define CASLAT_20		0x3	/* CAS latency = 2.0 */
+#define CASLAT_25		0x4	/* CAS latency = 2.5 */
+#define CASLAT_30		0x5	/* CAS latency = 3.0 */
+#define CASLAT_35		0x6	/* CAS latency = 3.5 */
+#define CASLAT_40		0x7	/* CAS latency = 4.0 */
+#define CASLAT_45		0x8	/* CAS latency = 4.5 */
+#define CASLAT_50		0x9	/* CAS latency = 5.0 */
+#define CASLAT_55		0xa	/* CAS latency = 5.5 */
+#define CASLAT_60		0xb	/* CAS latency = 6.0 */
+#define CASLAT_65		0xc	/* CAS latency = 6.5 */
+#define CASLAT_70		0xd	/* CAS latency = 7.0 */
+#define CASLAT_75		0xe	/* CAS latency = 7.5 */
+#define CASLAT_80		0xf	/* CAS latency = 8.0 */
+
+/* DDR SDRAM Timing Configuration 2 register */
+
+#define READ_LAT_PLUS_1		0x0
+#define READ_LAT		0x2
+#define READ_LAT_PLUS_1_4	0x3
+#define READ_LAT_PLUS_1_2	0x4
+#define READ_LAT_PLUS_3_4	0x5
+#define READ_LAT_PLUS_5_4	0x7
+#define READ_LAT_PLUS_3_2	0x8
+#define READ_LAT_PLUS_7_4	0x9
+#define READ_LAT_PLUS_2		0xA
+#define READ_LAT_PLUS_9_4	0xB
+#define READ_LAT_PLUS_5_2	0xC
+#define READ_LAT_PLUS_11_4	0xD
+#define READ_LAT_PLUS_3		0xE
+#define READ_LAT_PLUS_13_4	0xF
+#define READ_LAT_PLUS_7_2	0x10
+#define READ_LAT_PLUS_15_4	0x11
+#define READ_LAT_PLUS_4		0x12
+#define READ_LAT_PLUS_17_4	0x13
+#define READ_LAT_PLUS_9_2	0x14
+#define READ_LAT_PLUS_19_4	0x15
+
+#define CLOCK_DELAY_0		0x0
+#define CLOCK_DELAY_1_4		0x1
+#define CLOCK_DELAY_1_2		0x2
+#define CLOCK_DELAY_3_4		0x3
+#define CLOCK_DELAY_1		0x4
+#define CLOCK_DELAY_5_4		0x5
+#define CLOCK_DELAY_3_2		0x6
+
+/* DDR SDRAM Control Configuration */
+
+#define SREN_DISABLE	0x0
+#define SREN_ENABLE	0x1
+
+#define ECC_DISABLE	0x0
+#define ECC_ENABLE	0x1
+
+#define RD_DISABLE	0x0
+#define RD_ENABLE	0x1
+
+#define TYPE_DDR1	0x2
+#define TYPE_DDR2	0x3
+
+#define DYN_PWR_DISABLE		0x0
+#define DYN_PWR_ENABLE		0x1
+
+#define DATA_BUS_WIDTH_16	0x1
+#define DATA_BUS_WIDTH_32	0x2
+
+#define NCAP_DISABLE	0x0
+#define NCAP_ENABLE	0x1
+
+#define TIMING_1T	0x0
+#define TIMING_2T	0x1
+
+#define INTERLEAVE_NONE		0x0
+#define INTERLEAVE_1_AND_2	0x1
+
+#define PRECHARGE_MA_10		0x0
+#define PRECHARGE_MA_8		0x1
+
+#define STRENGTH_FULL		0x0
+#define STRENGTH_HALF		0x1
+
+#define INITIALIZATION_DONT_BYPASS	0x0
+#define INITIALIZATION_BYPASS		0x1
+
+/* DDR SDRAM Control Configuration 2 register */
+
+#define MODE_NORMAL	0x0
+#define MODE_REFRESH	0x1
+
+#define DLL_RESET_ENABLE	0x0
+#define DLL_RESET_DISABLE	0x1
+
+#define DQS_TRUE	0x0
+
+#define ODT_ASSERT_NEVER	0x0
+#define ODT_ASSERT_WRITES	0x1
+#define ODT_ASSERT_READS	0x2
+#define ODT_ASSERT_ALWAYS	0x3
+
+#endif
diff --git a/include/init.h b/include/init.h
index f114a88..afc953d 100644
--- a/include/init.h
+++ b/include/init.h
@@ -27,7 +27,7 @@
  * board_f.c for where it is called. If this is not provided, a default
  * version (which does nothing) will be used.
  *
- * @return: 0 on success, otherwise error
+ * Return: 0 on success, otherwise error
  */
 int arch_cpu_init(void);
 
@@ -38,7 +38,7 @@
  * relocation. This is similar to arch_cpu_init() but is able to reference
  * devices
  *
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int arch_cpu_init_dm(void);
 
@@ -50,7 +50,7 @@
  * board_f.c for where it is called. If this is not provided, a default
  * version (which does nothing) will be used.
  *
- * @return: 0 on success, otherwise error
+ * Return: 0 on success, otherwise error
  */
 int mach_cpu_init(void);
 
@@ -60,6 +60,8 @@
  * Where U-Boot relies on binary blobs to handle part of the system init, this
  * function can be used to set up the blobs. This is used on some Intel
  * platforms.
+ *
+ * Return: 0
  */
 int arch_fsp_init(void);
 
@@ -78,12 +80,12 @@
  * CONFIG_SYS_SDRAM_BASE and the size will be determined by a call to
  * get_effective_memsize().
  *
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int dram_init_banksize(void);
 
 /**
- * Reserve all necessary stacks
+ * arch_reserve_stacks() - Reserve all necessary stacks
  *
  * This is used in generic board init sequence in common/board_f.c. Each
  * architecture could provide this function to tailor the required stacks.
@@ -96,21 +98,29 @@
  * positions of the stack. The stack pointer(s) will be set to this later.
  * gd->irq_sp is only required, if the architecture needs it.
  *
- * @return 0 if no error
+ * Return: 0 if no error
  */
 int arch_reserve_stacks(void);
 
 /**
  * init_cache_f_r() - Turn on the cache in preparation for relocation
  *
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int init_cache_f_r(void);
 
+#if !CONFIG_IS_ENABLED(CPU)
+/**
+ * print_cpuinfo() - Display information about the CPU
+ *
+ * Return: 0 if OK, -ve on error
+ */
 int print_cpuinfo(void);
+#endif
 int timer_init(void);
 int reserve_mmu(void);
 int misc_init_f(void);
+
 #if defined(CONFIG_DTB_RESELECT)
 int embedded_dtb_select(void);
 #endif
@@ -120,28 +130,28 @@
 
 /**
  * ulong board_init_f_alloc_reserve - allocate reserved area
+ * @top: top of the reserve area, growing down.
  *
  * This function is called by each architecture very early in the start-up
  * code to allow the C runtime to reserve space on the stack for writable
  * 'globals' such as GD and the malloc arena.
  *
- * @top:	top of the reserve area, growing down.
- * @return:	bottom of reserved area
+ * Return: bottom of reserved area
  */
 ulong board_init_f_alloc_reserve(ulong top);
 
 /**
  * board_init_f_init_reserve - initialize the reserved area(s)
+ * @base:	top from which reservation was done
  *
  * This function is called once the C runtime has allocated the reserved
  * area on the stack. It must initialize the GD at the base of that area.
- *
- * @base:	top from which reservation was done
  */
 void board_init_f_init_reserve(ulong base);
 
 /**
  * arch_setup_gd() - Set up the global_data pointer
+ * @gd_ptr: Pointer to global data
  *
  * This pointer is special in some architectures and cannot easily be assigned
  * to. For example on x86 it is implemented by adding a specific record to its
@@ -149,8 +159,6 @@
  * For most architectures this can simply be:
  *
  *    gd = gd_ptr;
- *
- * @gd_ptr:	Pointer to global data
  */
 void arch_setup_gd(gd_t *gd_ptr);
 
diff --git a/include/linux/bitrev.h b/include/linux/bitrev.h
index cc5abd7..8ec9411 100644
--- a/include/linux/bitrev.h
+++ b/include/linux/bitrev.h
@@ -1,21 +1,105 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Based on bitrev from the Linux kernel, by Akinobu Mita
- */
-
+/* SPDX-License-Identifier: GPL-2.0 */
 #ifndef _LINUX_BITREV_H
 #define _LINUX_BITREV_H
 
 #include <linux/types.h>
 
-extern u8 const byte_rev_table[256];
+#ifdef CONFIG_HAVE_ARCH_BITREVERSE
+#include <asm/bitrev.h>
 
-static inline u8 bitrev8(u8 byte)
+#define __bitrev32 __arch_bitrev32
+#define __bitrev16 __arch_bitrev16
+#define __bitrev8 __arch_bitrev8
+
+#else
+extern u8 const byte_rev_table[256];
+static inline u8 __bitrev8(u8 byte)
 {
 	return byte_rev_table[byte];
 }
 
+static inline u16 __bitrev16(u16 x)
+{
+	return (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8);
+}
+
+static inline u32 __bitrev32(u32 x)
+{
+	return (__bitrev16(x & 0xffff) << 16) | __bitrev16(x >> 16);
+}
+
+#endif /* CONFIG_HAVE_ARCH_BITREVERSE */
+
+#define __bitrev8x4(x)	(__bitrev32(swab32(x)))
+
+#define __constant_bitrev32(x)		\
+({					\
+	u32 __x = x;			\
+	__x = (__x >> 16) | (__x << 16);\
+	__x = ((__x & (u32)0xFF00FF00UL) >> 8) | ((__x & (u32)0x00FF00FFUL) << 8);	\
+	__x = ((__x & (u32)0xF0F0F0F0UL) >> 4) | ((__x & (u32)0x0F0F0F0FUL) << 4);	\
+	__x = ((__x & (u32)0xCCCCCCCCUL) >> 2) | ((__x & (u32)0x33333333UL) << 2);	\
+	__x = ((__x & (u32)0xAAAAAAAAUL) >> 1) | ((__x & (u32)0x55555555UL) << 1);	\
+	__x;				\
+})
+
+#define __constant_bitrev16(x)		\
+({					\
+	u16 __x = x;			\
+	__x = (__x >> 8) | (__x << 8);	\
+	__x = ((__x & (u16)0xF0F0U) >> 4) | ((__x & (u16)0x0F0FU) << 4); \
+	__x = ((__x & (u16)0xCCCCU) >> 2) | ((__x & (u16)0x3333U) << 2); \
+	__x = ((__x & (u16)0xAAAAU) >> 1) | ((__x & (u16)0x5555U) << 1); \
+	__x;				\
+})
+
-u16 bitrev16(u16 in);
-u32 bitrev32(u32 in);
+#define __constant_bitrev8x4(x)		\
+({					\
+	u32 __x = x;			\
+	__x = ((__x & (u32)0xF0F0F0F0UL) >> 4) | ((__x & (u32)0x0F0F0F0FUL) << 4);	\
+	__x = ((__x & (u32)0xCCCCCCCCUL) >> 2) | ((__x & (u32)0x33333333UL) << 2);	\
+	__x = ((__x & (u32)0xAAAAAAAAUL) >> 1) | ((__x & (u32)0x55555555UL) << 1);	\
+	__x;				\
+})
+
+#define __constant_bitrev8(x)		\
+({					\
+	u8 __x = x;			\
+	__x = (__x >> 4) | (__x << 4);	\
+	__x = ((__x & (u8)0xCCU) >> 2) | ((__x & (u8)0x33U) << 2);	\
+	__x = ((__x & (u8)0xAAU) >> 1) | ((__x & (u8)0x55U) << 1);	\
+	__x;				\
+})
+
+#define bitrev32(x)			\
+({					\
+	u32 __x = x;			\
+	__builtin_constant_p(__x) ?	\
+	__constant_bitrev32(__x) :	\
+	__bitrev32(__x);		\
+})
+
+#define bitrev16(x)			\
+({					\
+	u16 __x = x;			\
+	__builtin_constant_p(__x) ?	\
+	__constant_bitrev16(__x) :	\
+	__bitrev16(__x);		\
+})
+
+#define bitrev8x4(x)			\
+({					\
+	u32 __x = x;			\
+	__builtin_constant_p(__x) ?	\
+	__constant_bitrev8x4(__x) :	\
+	__bitrev8x4(__x);		\
+})
 
+#define bitrev8(x)			\
+({					\
+	u8 __x = x;			\
+	__builtin_constant_p(__x) ?	\
+	__constant_bitrev8(__x) :	\
+	__bitrev8(__x)	;		\
+})
 #endif /* _LINUX_BITREV_H */
diff --git a/include/mpc83xx.h b/include/mpc83xx.h
index e1e50ab..a4c5bd3 100644
--- a/include/mpc83xx.h
+++ b/include/mpc83xx.h
@@ -1110,6 +1110,8 @@
 #define CSBNDS_EA			0x000000FF
 #define CSBNDS_EA_SHIFT			24
 
+#ifndef CONFIG_MPC83XX_SDRAM
+
 /*
  * CSn_CONFIG - Chip Select Configuration Register
  */
@@ -1407,6 +1409,8 @@
 #define ECC_ERROR_MAN_SBEC		(0xff000000 >> 24)
 #define ECC_ERROR_MAN_SBEC_SHIFT	0
 
+#endif /* !CONFIG_MPC83XX_SDRAM */
+
 /*
  * CONFIG_ADDRESS - PCI Config Address Register
  */
@@ -1510,6 +1514,7 @@
  */
 #define PMCCR1_POWER_OFF		0x00000020
 
+#ifndef CONFIG_RAM
 /*
  * DDRCDR - DDR Control Driver Register
  */
@@ -1531,6 +1536,7 @@
 #define DDRCDR_DDR_CFG		0x00040000
 #define DDRCDR_M_ODR		0x00000002
 #define DDRCDR_Q_DRN		0x00000001
+#endif /* !CONFIG_RAM */
 
 /*
  * PCIE Bridge Register
diff --git a/include/sysreset.h b/include/sysreset.h
index 81318bd..a5c0b74 100644
--- a/include/sysreset.h
+++ b/include/sysreset.h
@@ -28,6 +28,14 @@
 	 *		(in which case this method will not actually return)
 	 */
 	int (*request)(struct udevice *dev, enum sysreset_t type);
+	/**
+	 * get_status() - get printable reset status information
+	 *
+	 * @buf:	Buffer to receive the textual reset information
+	 * @size:	Size of the passed buffer
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*get_status)(struct udevice *dev, char *buf, int size);
 };
 
 #define sysreset_get_ops(dev)        ((struct sysreset_ops *)(dev)->driver->ops)
@@ -41,6 +49,15 @@
 int sysreset_request(struct udevice *dev, enum sysreset_t type);
 
 /**
+ * get_status() - get printable reset status information
+ *
+ * @buf:	Buffer to receive the textual reset information
+ * @size:	Size of the passed buffer
+ * @return 0 if OK, -ve on error
+ */
+int sysreset_get_status(struct udevice *dev, char *buf, int size);
+
+/**
  * sysreset_walk() - cause a system reset
  *
  * This works through the available sysreset devices until it finds one that can
diff --git a/lib/bitrev.c b/lib/bitrev.c
index 4d494e1..08231c0 100644
--- a/lib/bitrev.c
+++ b/lib/bitrev.c
@@ -1,13 +1,14 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- *
- * Based on bitrev from the Linux kernel, by Akinobu Mita
- */
+// SPDX-License-Identifier: GPL-2.0
 
-
+#ifndef CONFIG_HAVE_ARCH_BITREVERSE
 #include <linux/types.h>
+#include <linux/compat.h>
 #include <linux/bitrev.h>
 
+MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
+MODULE_DESCRIPTION("Bit ordering reversal functions");
+MODULE_LICENSE("GPL");
+
 const u8 byte_rev_table[256] = {
 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
@@ -42,17 +43,6 @@
 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
 };
-
-u16 bitrev16(u16 x)
-{
-	return (bitrev8(x & 0xff) << 8) | bitrev8(x >> 8);
-}
+EXPORT_SYMBOL_GPL(byte_rev_table);
 
-/**
- * bitrev32 - reverse the order of bits in a u32 value
- * @x: value to be bit-reversed
- */
-u32 bitrev32(u32 x)
-{
-	return (bitrev16(x & 0xffff) << 16) | bitrev16(x >> 16);
-}
+#endif /* CONFIG_HAVE_ARCH_BITREVERSE */
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 3f5a634..8b1ba91 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -47,4 +47,5 @@
 obj-$(CONFIG_AXI) += axi.o
 obj-$(CONFIG_MISC) += misc.o
 obj-$(CONFIG_DM_SERIAL) += serial.o
+obj-$(CONFIG_CPU) += cpu.o
 endif
diff --git a/test/dm/cmd_dm.c b/test/dm/cmd_dm.c
index 624fc82..7b271db 100644
--- a/test/dm/cmd_dm.c
+++ b/test/dm/cmd_dm.c
@@ -82,7 +82,7 @@
 U_BOOT_CMD(
 	dm,	3,	1,	do_dm,
 	"Driver model low level access",
-	"tree         Dump driver model tree ('*' = activated)\n"
+	"tree          Dump driver model tree ('*' = activated)\n"
 	"dm uclass        Dump list of instances for each uclass\n"
 	"dm devres        Dump list of device resources for each device"
 );
diff --git a/test/dm/cpu.c b/test/dm/cpu.c
new file mode 100644
index 0000000..f5f1cae
--- /dev/null
+++ b/test/dm/cpu.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/test.h>
+#include <dm/uclass-internal.h>
+#include <cpu.h>
+#include <test/ut.h>
+
+static int dm_test_cpu(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	char text[128];
+	struct cpu_info info;
+
+	ut_assertok(cpu_probe_all());
+
+	/* Check that cpu_probe_all really activated all CPUs */
+	for (uclass_find_first_device(UCLASS_CPU, &dev);
+	     dev;
+	     uclass_find_next_device(&dev))
+		ut_assert(dev->flags & DM_FLAG_ACTIVATED);
+
+	ut_assertok(uclass_get_device_by_name(UCLASS_CPU, "cpu-test1", &dev));
+
+	ut_assertok(cpu_get_desc(dev, text, sizeof(text)));
+	ut_assertok(strcmp(text, "LEG Inc. SuperMegaUltraTurbo CPU No. 1"));
+
+	ut_assertok(cpu_get_info(dev, &info));
+	ut_asserteq(info.cpu_freq, 42 * 42 * 42 * 42 * 42);
+	ut_asserteq(info.features, 0x42424242);
+
+	ut_asserteq(cpu_get_count(dev), 42);
+
+	ut_assertok(cpu_get_vendor(dev, text, sizeof(text)));
+	ut_assertok(strcmp(text, "Languid Example Garbage Inc."));
+
+	return 0;
+}
+
+DM_TEST(dm_test_cpu, DM_TESTF_SCAN_FDT);
diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c
index 8db1f98..907d1dd 100644
--- a/test/dm/ofnode.c
+++ b/test/dm/ofnode.c
@@ -15,3 +15,30 @@
 	return 0;
 }
 DM_TEST(dm_test_ofnode_compatible, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+static int dm_test_ofnode_by_prop_value(struct unit_test_state *uts)
+{
+	const char propname[] = "compatible";
+	const char propval[] = "denx,u-boot-fdt-test";
+	const char *str;
+	ofnode node = ofnode_null();
+
+	/* Find first matching node, there should be at least one */
+	node = ofnode_by_prop_value(node, propname, propval, sizeof(propval));
+	ut_assert(ofnode_valid(node));
+	str = ofnode_read_string(node, propname);
+	ut_assert(str && !strcmp(str, propval));
+
+	/* Find the rest of the matching nodes */
+	while (true) {
+		node = ofnode_by_prop_value(node, propname, propval,
+					    sizeof(propval));
+		if (!ofnode_valid(node))
+			break;
+		str = ofnode_read_string(node, propname);
+		ut_assert(str && !strcmp(str, propval));
+	}
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_by_prop_value, DM_TESTF_SCAN_FDT);
diff --git a/test/dm/sysreset.c b/test/dm/sysreset.c
index 33a8bfb..04d4621 100644
--- a/test/dm/sysreset.c
+++ b/test/dm/sysreset.c
@@ -45,6 +45,26 @@
 }
 DM_TEST(dm_test_sysreset_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 
+static int dm_test_sysreset_get_status(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	char msg[64];
+
+	/* Device 1 is the warm sysreset device */
+	ut_assertok(uclass_get_device(UCLASS_SYSRESET, 1, &dev));
+	ut_assertok(sysreset_get_status(dev, msg, sizeof(msg)));
+	ut_asserteq_str("Reset Status: WARM", msg);
+
+	/* Device 2 is the cold sysreset device */
+	ut_assertok(uclass_get_device(UCLASS_SYSRESET, 2, &dev));
+	ut_assertok(sysreset_get_status(dev, msg, sizeof(msg)));
+	ut_asserteq_str("Reset Status: COLD", msg);
+
+	return 0;
+}
+
+DM_TEST(dm_test_sysreset_get_status, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
 /* Test that we can walk through the sysreset devices */
 static int dm_test_sysreset_walk(struct unit_test_state *uts)
 {
diff --git a/tools/binman/README b/tools/binman/README
index cb34171..9d9d183 100644
--- a/tools/binman/README
+++ b/tools/binman/README
@@ -130,9 +130,9 @@
 
 Binman considers the output files created by mkimage to be binary blobs
 which it can place in an image. Binman does not replace the mkimage tool or
-this purpose. It would be possible in some situtions to create a new entry
+this purpose. It would be possible in some situations to create a new entry
 type for the images in mkimage, but this would not add functionality. It
-seems better to use the mkiamge tool to generate binaries and avoid blurring
+seems better to use the mkimage tool to generate binaries and avoid blurring
 the boundaries between building input files (mkimage) and packaging then
 into a final image (binman).
 
@@ -169,7 +169,7 @@
 In most cases x86 images have a lot of binary blobs, 'black-box' code
 provided by Intel which must be run for the platform to work. Typically
 these blobs are not relocatable and must be placed at fixed areas in the
-firmare image.
+firmware image.
 
 Currently this is handled by ifdtool, which places microcode, FSP, MRC, VGA
 BIOS, reference code and Intel ME binaries into a u-boot.rom file.
@@ -406,7 +406,7 @@
 different name for each and specifying the type with the 'type' attribute.
 
 
-Sections and hiearchical images
+Sections and hierachical images
 -------------------------------
 
 Sometimes it is convenient to split an image into several pieces, each of which