All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 1/8] core: Add uclass_{first,next}_device_compat
@ 2018-03-28 12:38 Mario Six
  2018-03-28 12:38 ` [U-Boot] [PATCH 2/8] test: Add tests for uclass_{first, next}_device_compat Mario Six
                   ` (7 more replies)
  0 siblings, 8 replies; 22+ messages in thread
From: Mario Six @ 2018-03-28 12:38 UTC (permalink / raw)
  To: u-boot

A lot of times one wants to cycle through the devices in a uclass, but
only certain ones, especially ones identified by their compatibility
string, and ignore all others (in the best case this procedure should
not even activate the devices one is not interested in).

Hence, we add a pair of functions similar to uclass_{first,next}_device,
but taking a compatibility string as an additional argument, which cycle
through the devices of a uclass that conform to this compatibility
string.

Signed-off-by: Mario Six <mario.six@gdsys.cc>
---
 drivers/core/uclass.c | 33 +++++++++++++++++++++++++++++++++
 include/dm/uclass.h   | 37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+)

diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 1aedaa08f0..19cec1e929 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -469,6 +469,23 @@ int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
 }
 #endif
 
+int uclass_first_device_compat(enum uclass_id id, struct udevice **devp,
+			       const char *compat)
+{
+	struct udevice *dev;
+	int ret;
+
+	*devp = NULL;
+	ret = uclass_find_first_device(id, &dev);
+	if (!dev)
+		return 0;
+	if (!device_is_compatible(dev, compat)) {
+		*devp = dev;
+		return uclass_next_device_compat(devp, compat);
+	}
+	return uclass_get_device_tail(dev, ret, devp);
+}
+
 int uclass_first_device(enum uclass_id id, struct udevice **devp)
 {
 	struct udevice *dev;
@@ -494,6 +511,22 @@ int uclass_first_device_err(enum uclass_id id, struct udevice **devp)
 	return 0;
 }
 
+int uclass_next_device_compat(struct udevice **devp, const char *compat)
+{
+	struct udevice *dev = *devp;
+	int ret;
+
+	*devp = NULL;
+	ret = uclass_find_next_device(&dev);
+	if (!dev)
+		return 0;
+	if (!device_is_compatible(dev, compat)) {
+		*devp = dev;
+		return uclass_next_device_compat(devp, compat);
+	}
+	return uclass_get_device_tail(dev, ret, devp);
+}
+
 int uclass_next_device(struct udevice **devp)
 {
 	struct udevice *dev = *devp;
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index 3a01abc239..0320f1fbee 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -260,6 +260,25 @@ int uclass_get_device_by_driver(enum uclass_id id, const struct driver *drv,
  */
 int uclass_first_device(enum uclass_id id, struct udevice **devp);
 
+/**
+ * uclass_first_device_compat() - Get the first device in a uclass compatible
+ *				  to a given compat string
+ *
+ * The device returned is probed if necessary, and ready for use.
+ *
+ * This function is useful to start iterating through a list of devices which
+ * are functioning correctly, can be probed, and are compatible with a certain
+ * compat string.
+ *
+ * @id: Uclass ID to look up
+ * @devp: Returns pointer to the first device in that uclass if no error
+ * occurred, or NULL if there is no first device, or an error occurred with
+ * that device.
+ * @compat: The compatible string the device has to adhere to
+ * @return 0 if OK (found or not found), other -ve on error
+ */
+int uclass_first_device_compat(enum uclass_id id, struct udevice **devp, const char *compat);
+
 /**
  * uclass_first_device_err() - Get the first device in a uclass
  *
@@ -286,6 +305,24 @@ int uclass_first_device_err(enum uclass_id id, struct udevice **devp);
  */
 int uclass_next_device(struct udevice **devp);
 
+/**
+ * uclass_next_device_compat() - Get the next device in a uclass compatible to
+ *				 a given compat string
+ *
+ * The device returned is probed if necessary, and ready for use
+ *
+ * This function is useful to start iterating through a list of devices which
+ * are functioning correctly, can be probed, and are compatible with a certain
+ * compat string.
+ *
+ * @devp: On entry, pointer to device to lookup. On exit, returns pointer
+ * to the next device in the uclass if no error occurred, or NULL if there is
+ * no next device, or an error occurred with that next device.
+ * @compat: The compatible string the device has to adhere to
+ * @return 0 if OK (found or not found), other -ve on error
+ */
+int uclass_next_device_compat(struct udevice **devp, const char *compat);
+
 /**
  * uclass_first_device() - Get the first device in a uclass
  *
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 2/8] test: Add tests for uclass_{first, next}_device_compat
  2018-03-28 12:38 [U-Boot] [PATCH 1/8] core: Add uclass_{first,next}_device_compat Mario Six
@ 2018-03-28 12:38 ` Mario Six
  2018-03-28 12:38 ` [U-Boot] [PATCH 3/8] ram: Add driver for MPC83xx Mario Six
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 22+ messages in thread
From: Mario Six @ 2018-03-28 12:38 UTC (permalink / raw)
  To: u-boot

Add tests for the uclass_{first,next}_device_compat functions.

Signed-off-by: Mario Six <mario.six@gdsys.cc>
---
 test/dm/core.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/test/dm/core.c b/test/dm/core.c
index 052bf8fffb..7df197eb40 100644
--- a/test/dm/core.c
+++ b/test/dm/core.c
@@ -852,6 +852,35 @@ static int dm_test_uclass_devices_get_by_name(struct unit_test_state *uts)
 }
 DM_TEST(dm_test_uclass_devices_get_by_name, DM_TESTF_SCAN_FDT);

+static int dm_test_uclass_devices_get_by_compat(struct unit_test_state *uts)
+{
+	struct udevice *testdev;
+	int ret;
+
+	for (ret = uclass_first_device_compat(UCLASS_TEST_FDT, &testdev, "denx,u-boot-fdt-test");
+	     testdev;
+	     ret = uclass_next_device_compat(&testdev, "denx,u-boot-fdt-test")) {
+		ut_assertok(ret);
+		ut_assert(testdev);
+		ut_assert(device_active(testdev));
+		ut_asserteq(device_is_compatible(testdev, "denx,u-boot-fdt-test"), true);
+		ut_asserteq(device_is_compatible(testdev, "google,another-fdt-test"), false);
+	}
+
+	for (ret = uclass_first_device_compat(UCLASS_TEST_FDT, &testdev, "google,another-fdt-test");
+	     testdev;
+	     ret = uclass_next_device_compat(&testdev, "google,another-fdt-test")) {
+		ut_assertok(ret);
+		ut_assert(testdev);
+		ut_assert(device_active(testdev));
+		ut_asserteq(device_is_compatible(testdev, "denx,u-boot-fdt-test"), false);
+		ut_asserteq(device_is_compatible(testdev, "google,another-fdt-test"), true);
+	}
+
+	return 0;
+}
+DM_TEST(dm_test_uclass_devices_get_by_compat, DM_TESTF_SCAN_FDT);
+
 static int dm_test_device_get_uclass_id(struct unit_test_state *uts)
 {
 	struct udevice *dev;
--
2.16.1

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 3/8] ram: Add driver for MPC83xx
  2018-03-28 12:38 [U-Boot] [PATCH 1/8] core: Add uclass_{first,next}_device_compat Mario Six
  2018-03-28 12:38 ` [U-Boot] [PATCH 2/8] test: Add tests for uclass_{first, next}_device_compat Mario Six
@ 2018-03-28 12:38 ` Mario Six
  2018-03-28 12:38 ` [U-Boot] [PATCH 4/8] clk: Add MPC83xx clock driver Mario Six
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 22+ messages in thread
From: Mario Six @ 2018-03-28 12:38 UTC (permalink / raw)
  To: u-boot

Add a RAM driver for the MPC83xx architecture.

Signed-off-by: Mario Six <mario.six@gdsys.cc>
---
 arch/powerpc/cpu/mpc83xx/spd_sdram.c       |   4 +
 drivers/ram/Kconfig                        |   8 +
 drivers/ram/Makefile                       |   1 +
 drivers/ram/mpc83xx_sdram.c                | 948 +++++++++++++++++++++++++++++
 include/dt-bindings/memory/mpc83xx-sdram.h | 143 +++++
 include/mpc83xx.h                          |   6 +
 6 files changed, 1110 insertions(+)
 create mode 100644 drivers/ram/mpc83xx_sdram.c
 create mode 100644 include/dt-bindings/memory/mpc83xx-sdram.h

diff --git a/arch/powerpc/cpu/mpc83xx/spd_sdram.c b/arch/powerpc/cpu/mpc83xx/spd_sdram.c
index 21ab0153fc..f1e2dbf7c4 100644
--- a/arch/powerpc/cpu/mpc83xx/spd_sdram.c
+++ b/arch/powerpc/cpu/mpc83xx/spd_sdram.c
@@ -11,6 +11,8 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
+#ifndef CONFIG_MPC83XX_SDRAM
+
 #include <common.h>
 #include <asm/processor.h>
 #include <asm/io.h>
@@ -925,3 +927,5 @@ void ddr_enable_ecc(unsigned int dram_size)
 	__asm__ __volatile__ ("isync");
 }
 #endif	/* CONFIG_DDR_ECC */
+
+#endif /* !CONFIG_MPC83XX_SDRAM */
diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig
index 496e2b793b..18532e71be 100644
--- a/drivers/ram/Kconfig
+++ b/drivers/ram/Kconfig
@@ -34,4 +34,12 @@ config STM32_SDRAM
 	  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 is supported via device tree settings.
+
 source "drivers/ram/stm32mp1/Kconfig"
diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile
index 3820d03aa4..4ad3604d16 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 0000000000..1a73f7b3da
--- /dev/null
+++ b/drivers/ram/mpc83xx_sdram.c
@@ -0,0 +1,948 @@
+#define DEBUG
+
+#include <common.h>
+#include <dm.h>
+#include <ram.h>
+#include <asm/io.h>
+#include <dt-bindings/memory/mpc83xx-sdram.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define CSCONFIG_ENABLE			0x80000000
+
+#define BANK_BITS_2		0x00000000
+#define BANK_BITS_3		0x00004000
+
+#define ROW_BITS_12		0x00000000
+#define ROW_BITS_13		0x00000100
+#define ROW_BITS_14		0x00000200
+
+#define COL_BITS_8		0x00000000
+#define COL_BITS_9		0x00000001
+#define COL_BITS_10		0x00000002
+#define COL_BITS_11		0x00000003
+
+#define TIMING_CFG3_EXT_REFREC_SHIFT	16
+
+#define TIMING_CFG0_RWT_SHIFT		30
+#define TIMING_CFG0_WRT_SHIFT		28
+#define TIMING_CFG0_RRT_SHIFT		26
+#define TIMING_CFG0_WWT_SHIFT		24
+#define TIMING_CFG0_ACT_PD_EXIT_SHIFT	20
+#define TIMING_CFG0_PRE_PD_EXIT_SHIFT	16
+#define TIMING_CFG0_ODT_PD_EXIT_SHIFT	8
+#define TIMING_CFG0_MRS_CYC_SHIFT	0
+
+#define TIMING_CFG1_PRETOACT_SHIFT	28
+#define TIMING_CFG1_ACTTOPRE_SHIFT	24
+#define TIMING_CFG1_ACTTORW_SHIFT	20
+#define TIMING_CFG1_CASLAT_SHIFT	16
+#define TIMING_CFG1_REFREC_SHIFT	12
+#define TIMING_CFG1_WRREC_SHIFT		8
+#define TIMING_CFG1_ACTTOACT_SHIFT	4
+#define TIMING_CFG1_WRTORD_SHIFT	0
+
+#define TIMING_CFG2_CPO_SHIFT		23
+#define TIMING_CFG2_WR_DATA_DELAY_SHIFT	10
+#define TIMING_CFG2_ADD_LAT_SHIFT	28
+#define TIMING_CFG2_WR_LAT_DELAY_SHIFT	19
+#define TIMING_CFG2_RD_TO_PRE_SHIFT	13
+#define TIMING_CFG2_CKE_PLS_SHIFT	6
+#define TIMING_CFG2_FOUR_ACT_SHIFT	0
+
+#define SDRAM_CFG_SREN_SHIFT		(31 - 1)
+#define SDRAM_CFG_ECC_EN_SHIFT		(31 - 2)
+#define SDRAM_CFG_RD_EN_SHIFT		(31 - 3)
+#define SDRAM_CFG_SDRAM_TYPE_SHIFT	(31 - 7)
+#define SDRAM_CFG_DYN_PWR_SHIFT		(31 - 10)
+#define SDRAM_CFG_DBW_SHIFT		(31 - 12)
+#define SDRAM_CFG_NCAP_SHIFT		(31 - 14)
+#define SDRAM_CFG_2T_EN_SHIFT		(31 - 16)
+#define SDRAM_CFG_BA_INTLV_CTL_SHIFT	(31 - 23)
+#define SDRAM_CFG_PCHB8_SHIFT		(31 - 27)
+#define SDRAM_CFG_HSE_SHIFT		(31 - 28)
+#define SDRAM_CFG_BI_SHIFT		(31 - 31)
+
+#define SDRAM_CFG2_FRC_SR_SHIFT	(31 - 0)
+#define SDRAM_CFG2_DLL_RST_DIS	(31 - 2)
+#define SDRAM_CFG2_DQS_CFG	(31 - 5)
+#define SDRAM_CFG2_ODT_CFG	(31 - 10)
+#define SDRAM_CFG2_NUM_PR	(31 - 19)
+
+#define SDRAM_MODE_ESD_SHIFT		16
+#define SDRAM_MODE_SD_SHIFT		0
+
+#define SDRAM_MODE2_ESD2_SHIFT		(31 - 15)
+#define SDRAM_MODE2_ESD3_SHIFT		(31 - 31)
+
+#define SDRAM_INTERVAL_REFINT_SHIFT	16
+#define SDRAM_INTERVAL_BSTOPRE_SHIFT	0
+
+#define 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("uclass_first_device_err failed: %d\n", ret);
+		return ret;
+	}
+
+	/* Set gd->ram_size? */
+
+	return 0;
+}
+
+phys_size_t get_effective_memsize(void)
+{
+#ifndef CONFIG_VERY_BIG_RAM
+	return gd->ram_size;
+#else
+	/* limit stack to what we can reasonable map */
+	return ((gd->ram_size > CONFIG_MAX_MEM_MAPPED) ?
+		CONFIG_MAX_MEM_MAPPED : gd->ram_size);
+#endif
+}
+
+struct mpc83xx_sdram_priv {
+	ulong total_size;
+};
+
+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("auto_precharge value invalid.\n");
+		return -EINVAL;
+	}
+
+	odt_rd_cfg = ofnode_read_u32_default(node, "odt_rd_cfg", 0);
+	switch (odt_rd_cfg) {
+#if defined(CONFIG_MPC830x) || defined(CONFIG_MPC831x) || \
+	defined(CONFIG_MPC8360) || defined(CONFIG_MPC837x)
+	case ODT_RD_NEVER:
+	case ODT_RD_ONLY_CURRENT:
+	case ODT_RD_ONLY_OTHER_CS:
+#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC837x)
+	case ODT_RD_ONLY_OTHER_DIMM:
+#endif
+#endif
+	/* MPC832x only knows this value */
+	case ODT_RD_ALL:
+		break;
+	default:
+		debug("odt_rd_cfg value invalid.\n");
+		return -EINVAL;
+	}
+
+	odt_wr_cfg = ofnode_read_u32_default(node, "odt_wr_cfg", 0);
+	switch (odt_wr_cfg) {
+#if defined(CONFIG_MPC830x) || defined(CONFIG_MPC831x) || \
+	defined(CONFIG_MPC8360) || defined(CONFIG_MPC837x)
+	case ODT_WR_NEVER:
+	case ODT_WR_ONLY_CURRENT:
+	case ODT_WR_ONLY_OTHER_CS:
+#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC837x)
+	case ODT_WR_ONLY_OTHER_DIMM:
+#endif
+#endif
+	/* MPC832x only knows this value */
+	case ODT_WR_ALL:
+		break;
+	default:
+		debug("odt_wr_cfg value invalid.\n");
+		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("bank_bits value invalid.\n");
+		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("row_bits value invalid.\n");
+		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("col_bits value invalid.\n");
+		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;
+}
+
+int mpc83xx_sdram_spd_init(ofnode node, u32 cs, u32 mapaddr, u32 size)
+{
+	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 res = 0;
+	ofnode subnode;
+	u32 dso, pz_override, nz_override, odt_term, ddr_type, mvref_sel, m_odr;
+	u32 ddrcdr;
+	u32 clock_adjust;
+	u32 ext_refresh_rec, ext_refresh_rec_mask;
+	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;
+	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;
+	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;
+	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;
+	u32 force_self_refresh, dll_reset, dqs_config, odt_config,
+	    posted_refreshes;
+	u32 sdram_cfg2;
+	u32 refresh_interval, precharge_interval, sdmode, esdmode, esdmode2,
+	    esdmode3;
+	u32 sdram_interval;
+	u32 sdram_mode;
+	u32 sdram_mode2;
+
+	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("driver_software_override value invalid.\n");
+		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("p_impedance_override value invalid.\n");
+		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("n_impedance_override value invalid.\n");
+		return -EINVAL;
+	}
+
+	odt_term = dev_read_u32_default(dev, "odt_termination_value", 0);
+	if (odt_term > 1) {
+		debug("odt_termination_value value invalid.\n");
+		return -EINVAL;
+	}
+
+	ddr_type = dev_read_u32_default(dev, "ddr_type", 0);
+	if (ddr_type > 1) {
+		debug("ddr_type value invalid.\n");
+		return -EINVAL;
+	}
+
+	mvref_sel = dev_read_u32_default(dev, "mvref_sel", 0);
+	if (mvref_sel > 1) {
+		debug("mvref_sel value invalid.\n");
+		return -EINVAL;
+	}
+
+	m_odr = dev_read_u32_default(dev, "m_odr", 0);
+	if (mvref_sel > 1) {
+		debug("m_odr value invalid.\n");
+		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("chip select value invalid.\n");
+			return -EINVAL;
+		}
+
+		/* TODO: Sanity check for size. */
+
+		if (ofnode_read_bool(subnode, "read-spd"))
+			res = mpc83xx_sdram_spd_init(subnode, cs, addr, size);
+		else
+			res = mpc83xx_sdram_static_init(subnode, cs, addr,
+							size);
+		if (res)
+			return res;
+	};
+
+	/* TODO: 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("clock_adjust value invalid.\n");
+		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("ext_refresh_rec value invalid.\n");
+		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("read_to_write value invalid.\n");
+		return -EINVAL;
+	}
+
+	write_to_read = dev_read_u32_default(dev, "write_to_read", 0);
+	if (write_to_read > 3) {
+		debug("write_to_read value invalid.\n");
+		return -EINVAL;
+	}
+
+	read_to_read = dev_read_u32_default(dev, "read_to_read", 0);
+	if (read_to_read > 3) {
+		debug("read_to_read value invalid.\n");
+		return -EINVAL;
+	}
+
+	write_to_write = dev_read_u32_default(dev, "write_to_write", 0);
+	if (write_to_write > 3) {
+		debug("write_to_write value invalid.\n");
+		return -EINVAL;
+	}
+
+	active_powerdown_exit =
+		dev_read_u32_default(dev, "active_powerdown_exit", 0);
+	if (active_powerdown_exit > 7) {
+		debug("active_powerdown_exit value invalid.\n");
+		return -EINVAL;
+	}
+
+	precharge_powerdown_exit =
+		dev_read_u32_default(dev, "precharge_powerdown_exit", 0);
+	if (precharge_powerdown_exit > 7) {
+		debug("precharge_powerdown_exit value invalid.\n");
+		return -EINVAL;
+	}
+
+	odt_powerdown_exit = dev_read_u32_default(dev, "odt_powerdown_exit", 0);
+	if (odt_powerdown_exit > 15) {
+		debug("odt_powerdown_exit value invalid.\n");
+		return -EINVAL;
+	}
+
+	mode_reg_set_cycle = dev_read_u32_default(dev, "mode_reg_set_cycle", 0);
+	if (mode_reg_set_cycle > 15) {
+		debug("mode_reg_set_cycle value invalid.\n");
+		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("precharge_to_activate value invalid.\n");
+		return -EINVAL;
+	}
+
+	activate_to_precharge =
+		dev_read_u32_default(dev, "activate_to_precharge", 0);
+	if (activate_to_precharge > 15 || activate_to_precharge == 0) {
+		debug("activate_to_precharge value invalid.\n");
+		return -EINVAL;
+	}
+
+	activate_to_readwrite =
+		dev_read_u32_default(dev, "activate_to_readwrite", 0);
+	if (activate_to_readwrite > 7 || activate_to_readwrite == 0) {
+		debug("activate_to_readwrite value invalid.\n");
+		return -EINVAL;
+	}
+
+	/* TODO: MPC8308 only supports caslat >= 3 clocks */
+	mcas_latency = dev_read_u32_default(dev, "mcas_latency", 0);
+	switch (mcas_latency) {
+	case CASLAT_20:
+	case CASLAT_25:
+	case CASLAT_30:
+	case CASLAT_35:
+	case CASLAT_40:
+	case CASLAT_45:
+	case CASLAT_50:
+		break;
+	default:
+		debug("ext_refresh_rec value invalid.\n");
+		return -EINVAL;
+	}
+
+	refresh_recovery = dev_read_u32_default(dev, "refresh_recovery", 0);
+	if (refresh_recovery > 23 || refresh_recovery < 8) {
+		debug("refresh_recovery value invalid.\n");
+		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("last_data_to_precharge value invalid.\n");
+		return -EINVAL;
+	}
+
+	activate_to_activate =
+		dev_read_u32_default(dev, "activate_to_activate", 0);
+	if (activate_to_activate > 7 || activate_to_activate == 0) {
+		debug("activate_to_activate value invalid.\n");
+		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("last_write_data_to_read value invalid.\n");
+		return -EINVAL;
+	}
+
+	timing_cfg_1 = precharge_to_activate << TIMING_CFG1_PRETOACT_SHIFT |
+		       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("additive_latency value invalid.\n");
+		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("mcas_to_preamble_override value invalid.\n");
+		return -EINVAL;
+	}
+
+	write_latency = dev_read_u32_default(dev, "write_latency", 0);
+	if (write_latency > 7 || write_latency == 0) {
+		debug("write_latency value invalid.\n");
+		return -EINVAL;
+	}
+
+	read_to_precharge = dev_read_u32_default(dev, "read_to_precharge", 0);
+	if (read_to_precharge > 4 || read_to_precharge == 0) {
+		debug("read_to_precharge value invalid.\n");
+		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("write_cmd_to_write_data value invalid.\n");
+		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("minimum_cke_pulse_width value invalid.\n");
+		return -EINVAL;
+	}
+
+	four_activates_window =
+		dev_read_u32_default(dev, "four_activates_window", 0);
+	if (four_activates_window > 20 || four_activates_window == 0) {
+		debug("four_activates_window value invalid.\n");
+		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("self_refresh value invalid.\n");
+		return -EINVAL;
+	}
+
+	ecc = dev_read_u32_default(dev, "ecc", 0);
+	switch (ecc) {
+	case ECC_DISABLE:
+	case ECC_ENABLE:
+		break;
+	default:
+		debug("ecc value invalid.\n");
+		return -EINVAL;
+	}
+
+	registered_dram = dev_read_u32_default(dev, "registered_dram", 0);
+	switch (registered_dram) {
+	case RD_DISABLE:
+	case RD_ENABLE:
+		break;
+	default:
+		debug("registered_dram value invalid.\n");
+		return -EINVAL;
+	}
+
+	sdram_type = dev_read_u32_default(dev, "sdram_type", 0);
+	switch (sdram_type) {
+	case TYPE_DDR1:
+	case TYPE_DDR2:
+		break;
+	default:
+		debug("sdram_type value invalid.\n");
+		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("dynamic_power_management value invalid.\n");
+		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("databus_width value invalid.\n");
+		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("nc_auto_precharge value invalid.\n");
+		return -EINVAL;
+	}
+
+	timing_2t = dev_read_u32_default(dev, "timing_2t", 0);
+	switch (timing_2t) {
+	case TIMING_1T:
+	case TIMING_2T:
+		break;
+	default:
+		debug("timing_2t value invalid.\n");
+		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("bank_interleaving_ctrl value invalid.\n");
+		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("precharge_bit_8 value invalid.\n");
+		return -EINVAL;
+	}
+
+	half_strength = dev_read_u32_default(dev, "half_strength", 0);
+	switch (half_strength) {
+	case STRENGTH_FULL:
+	case STRENGTH_HALF:
+		break;
+	default:
+		debug("half_strength value invalid.\n");
+		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("bypass_initialization value invalid.\n");
+		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("force_self_refresh value invalid.\n");
+		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("dll_reset value invalid.\n");
+		return -EINVAL;
+	}
+
+	dqs_config = dev_read_u32_default(dev, "dqs_config", 0);
+	switch (dqs_config) {
+	case DQS_TRUE:
+		break;
+	default:
+		debug("dqs_config value invalid.\n");
+		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("odt_config value invalid.\n");
+		return -EINVAL;
+	}
+
+	posted_refreshes = dev_read_u32_default(dev, "posted_refreshes", 0);
+	if (posted_refreshes > 8 || posted_refreshes == 0) {
+		debug("posted_refreshes value invalid.\n");
+		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("sdmode value invalid.\n");
+		return -EINVAL;
+	}
+
+	esdmode = dev_read_u32_default(dev, "esdmode", 0);
+	if (esdmode > 0xFFFF) {
+		debug("esdmode value invalid.\n");
+		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("esdmode2 value invalid.\n");
+		return -EINVAL;
+	}
+
+	esdmode3 = dev_read_u32_default(dev, "esdmode3", 0);
+	if (esdmode3 > 0xFFFF) {
+		debug("esdmode3 value invalid.\n");
+		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("refresh_interval value invalid.\n");
+		return -EINVAL;
+	}
+
+	precharge_interval = dev_read_u32_default(dev, "precharge_interval", 0);
+	if (precharge_interval > 0x3FFF) {
+		debug("precharge_interval value invalid.\n");
+		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)
+{
+	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/include/dt-bindings/memory/mpc83xx-sdram.h b/include/dt-bindings/memory/mpc83xx-sdram.h
new file mode 100644
index 0000000000..0f970008b6
--- /dev/null
+++ b/include/dt-bindings/memory/mpc83xx-sdram.h
@@ -0,0 +1,143 @@
+#ifndef DT_BINDINGS_MPC83XX_SDRAM_H
+#define DT_BINDINGS_MPC83XX_SDRAM_H
+
+#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_ALL		0x00400000
+#define ODT_WR_NEVER		0x00000000
+#define ODT_WR_ONLY_CURRENT	0x00010000
+#define ODT_WR_ONLY_OTHER_CS	0x00020000
+#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 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_1		0x6 */
+#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 */
+
+#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/mpc83xx.h b/include/mpc83xx.h
index b5a0bbf847..26258126d6 100644
--- a/include/mpc83xx.h
+++ b/include/mpc83xx.h
@@ -1111,6 +1111,8 @@
 #define CSBNDS_EA			0x000000FF
 #define CSBNDS_EA_SHIFT			24
 
+#ifndef CONFIG_MPC83XX_SDRAM
+
 /*
  * CSn_CONFIG - Chip Select Configuration Register
  */
@@ -1408,6 +1410,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
  */
@@ -1511,6 +1515,7 @@
  */
 #define PMCCR1_POWER_OFF		0x00000020
 
+#ifndef CONFIG_RAM
 /*
  * DDRCDR - DDR Control Driver Register
  */
@@ -1532,6 +1537,7 @@
 #define DDRCDR_DDR_CFG		0x00040000
 #define DDRCDR_M_ODR		0x00000002
 #define DDRCDR_Q_DRN		0x00000001
+#endif /* !CONFIG_RAM */
 
 /*
  * PCIE Bridge Register
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 4/8] clk: Add MPC83xx clock driver
  2018-03-28 12:38 [U-Boot] [PATCH 1/8] core: Add uclass_{first,next}_device_compat Mario Six
  2018-03-28 12:38 ` [U-Boot] [PATCH 2/8] test: Add tests for uclass_{first, next}_device_compat Mario Six
  2018-03-28 12:38 ` [U-Boot] [PATCH 3/8] ram: Add driver for MPC83xx Mario Six
@ 2018-03-28 12:38 ` Mario Six
  2018-03-28 12:38 ` [U-Boot] [PATCH 5/8] timer: Add MPC83xx timer driver Mario Six
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 22+ messages in thread
From: Mario Six @ 2018-03-28 12:38 UTC (permalink / raw)
  To: u-boot

Add a clock driver for the MPC83xx architecture.

Signed-off-by: Mario Six <mario.six@gdsys.cc>
---
 arch/powerpc/cpu/mpc83xx/speed.c      |   4 +
 arch/powerpc/include/asm/config.h     |   2 +-
 drivers/clk/Kconfig                   |   6 +
 drivers/clk/Makefile                  |   1 +
 drivers/clk/mpc83xx_clk.c             | 415 ++++++++++++++++++++++++++++++++++
 drivers/clk/mpc83xx_clk.h             | 115 ++++++++++
 include/dt-bindings/clk/mpc83xx-clk.h |  27 +++
 7 files changed, 569 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/mpc83xx_clk.c
 create mode 100644 drivers/clk/mpc83xx_clk.h
 create mode 100644 include/dt-bindings/clk/mpc83xx-clk.h

diff --git a/arch/powerpc/cpu/mpc83xx/speed.c b/arch/powerpc/cpu/mpc83xx/speed.c
index 5498c19e25..c9bdec0bc0 100644
--- a/arch/powerpc/cpu/mpc83xx/speed.c
+++ b/arch/powerpc/cpu/mpc83xx/speed.c
@@ -7,6 +7,8 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
+#ifndef CONFIG_CLK_MPC83XX
+
 #include <common.h>
 #include <mpc83xx.h>
 #include <command.h>
@@ -591,3 +593,5 @@ U_BOOT_CMD(clocks, 1, 0, do_clocks,
 	"print clock configuration",
 	"    clocks"
 );
+
+#endif
diff --git a/arch/powerpc/include/asm/config.h b/arch/powerpc/include/asm/config.h
index 39eeb39901..d9dfb670af 100644
--- a/arch/powerpc/include/asm/config.h
+++ b/arch/powerpc/include/asm/config.h
@@ -79,7 +79,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/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c382e8865f..acac9413e1 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -83,6 +83,12 @@ config CLK_STM32MP1
 	  Enable the STM32 clock (RCC) driver. Enable support for
 	  manipulating STM32MP1's on-SoC clocks.
 
+config CLK_MPC83XX
+	bool "Enable MPC83xx clock driver"
+	depends on CLK
+	help
+	  Support for the clock driver of the MPC83xx series of SoCs.
+
 source "drivers/clk/tegra/Kconfig"
 source "drivers/clk/uniphier/Kconfig"
 source "drivers/clk/exynos/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index e05c607223..67da125669 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_CLK_BCM6345) += clk_bcm6345.o
 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_RENESAS) += renesas/
 obj-$(CONFIG_CLK_STM32F) += clk_stm32f.o
 obj-$(CONFIG_CLK_STM32MP1) += clk_stm32mp1.o
diff --git a/drivers/clk/mpc83xx_clk.c b/drivers/clk/mpc83xx_clk.c
new file mode 100644
index 0000000000..9560ae56a9
--- /dev/null
+++ b/drivers/clk/mpc83xx_clk.c
@@ -0,0 +1,415 @@
+/*
+ * (C) Copyright 2017
+ * Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <dt-bindings/clk/mpc83xx-clk.h>
+
+#include "mpc83xx_clk.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static u32 *speed;
+
+struct mpc83xx_clk_priv {
+	u32 *speed;
+};
+
+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 {
+	u8 low;
+	u8 high;
+	int type;
+};
+
+const struct clk_mode modes[] = {
+
+	[MPC83XX_CLK_CORE] = {0, 0, TYPE_SPECIAL},
+	[MPC83XX_CLK_CSB] = {0, 0, TYPE_SPECIAL},
+	[MPC83XX_CLK_QE] = {0, 0, TYPE_SPECIAL},
+	[MPC83XX_CLK_BRG] = {0, 0, TYPE_SPECIAL},
+	[MPC83XX_CLK_MEM] = {1, 1, TYPE_SPMR_DIRECT_MULTIPLY },
+	[MPC83XX_CLK_LBIU] = {0, 0, TYPE_SPMR_DIRECT_MULTIPLY },
+	[MPC83XX_CLK_LCLK] = {0, 0, TYPE_SPECIAL},
+	[MPC83XX_CLK_MEM_SEC] = {0, 0, TYPE_SPMR_DIRECT_MULTIPLY }, /* The same as LBIU */
+#ifndef CONFIG_MPC8313
+	[MPC83XX_CLK_TSEC1] = {0, 1, TYPE_SCCR_STANDARD },
+	[MPC83XX_CLK_TSEC2] = {2, 3, TYPE_SCCR_STANDARD },
+#else
+	[MPC83XX_CLK_TSEC1] = {0, 1, TYPE_SCCR_STANDARD }, /* FIXME: This has separate enable/disable bit! */
+	[MPC83XX_CLK_TSEC2] = {0, 1, TYPE_SCCR_STANDARD }, /* FIXME: This has separate enable/disable bit! */
+#endif
+	[MPC83XX_CLK_SDHC] = {4, 5, TYPE_SCCR_STANDARD },
+#ifdef CONFIG_MPC834x
+	[MPC83XX_CLK_ENC] = {6, 7, TYPE_SCCR_STANDARD },
+	[MPC83XX_CLK_I2C1] = {2, 3, TYPE_SCCR_STANDARD }, /* I2C and TSEC2 are the same register */
+#else
+	[MPC83XX_CLK_ENC] = {6, 7, TYPE_SCCR_STANDARD },
+	[MPC83XX_CLK_I2C1] = {6, 7, TYPE_SCCR_STANDARD }, /* I2C and ENC are the same register */
+#endif
+	[MPC83XX_CLK_I2C2] = {0, 0, TYPE_SPECIAL },
+	[MPC83XX_CLK_PCIEXP1] = {10, 11, TYPE_SCCR_STANDARD },
+	[MPC83XX_CLK_PCIEXP2] = {12, 13, TYPE_SCCR_STANDARD },
+#if defined(CONFIG_MPC8313) || defined(CONFIG_MPC834x)
+	[MPC83XX_CLK_USBDR] = {10, 11, TYPE_SCCR_STANDARD },
+#else
+	[MPC83XX_CLK_USBDR] = {8, 9, TYPE_SCCR_STANDARD },
+#endif
+	[MPC83XX_CLK_USBMPH] = {8, 9, TYPE_SCCR_STANDARD },
+	[MPC83XX_CLK_PCI] = {15, 15, TYPE_SCCR_ONOFF },
+#if defined(CONFIG_MPC8308) || defined(CONFIG_MPC8309)
+	[MPC83XX_CLK_DMAC] = {26, 27, TYPE_SCCR_STANDARD },
+#endif
+#if 0
+/* FIXME: All SATA controllers must have the same clock ratio */
+#ifdef CONFIG_MPC83XX_SATA_SUPPORT
+#ifdef CONFIG_MPC8379
+	[MPC83XX_CLK_SATA] = {24, 25, TYPE_SCCR_STANDARD },
+	[MPC83XX_CLK_SATA] = {26, 27, TYPE_SCCR_STANDARD },
+	[MPC83XX_CLK_SATA] = {28, 29, TYPE_SCCR_STANDARD },
+	[MPC83XX_CLK_SATA] = {30, 31, TYPE_SCCR_STANDARD },
+#else
+	[MPC83XX_CLK_SATA] = {18, 19, TYPE_SCCR_STANDARD },
+	[MPC83XX_CLK_SATA] = {20, 21, TYPE_SCCR_STANDARD },
+#endif
+#endif
+#endif
+	[MPC83XX_CLK_TDM] = {26, 27, TYPE_SCCR_STANDARD },
+};
+
+int get_clocks(void)
+{
+	return 0;
+}
+
+inline bool is_clk_valid(int id)
+{
+	switch (id) {
+	case MPC83XX_CLK_MEM:
+#if defined(CONFIG_MPC8360)
+	case MPC83XX_CLK_MEM_SEC:
+#endif
+#ifndef CONFIG_MPC830x
+	case MPC83XX_CLK_ENC:
+#endif
+	case MPC83XX_CLK_I2C1:
+#ifdef CONFIG_MPC8315
+	case MPC83XX_CLK_TDM:
+#endif
+#ifdef CONFIG_MPC83XX_SDHC_SUPPORT
+	case MPC83XX_CLK_SDHC:
+#endif
+#ifdef CONFIG_MPC83XX_TSEC1_SUPPORT
+	case MPC83XX_CLK_TSEC1:
+#endif
+#ifdef CONFIG_MPC83XX_TSEC2_SUPPORT
+	case MPC83XX_CLK_TSEC2:
+#endif
+#if !defined(CONFIG_MPC8360)
+	case MPC83XX_CLK_USBDR:
+#endif
+#ifdef CONFIG_MPC834x
+	case MPC83XX_CLK_USBMPH:
+#endif
+#ifdef CONFIG_MPC83XX_PCIE1_SUPPORT
+	case MPC83XX_CLK_PCIEXP1:
+#endif
+#ifdef CONFIG_MPC83XX_PCIE2_SUPPORT
+	case MPC83XX_CLK_PCIEXP2:
+#endif
+#ifdef CONFIG_MPC83XX_SATA_SUPPORT
+	case MPC83XX_CLK_SATA:
+#endif
+#ifdef CONFIG_MPC830x
+	case MPC83XX_CLK_DMAC:
+#endif
+#ifdef CONFIG_MPC83XX_PCI_SUPPORT
+	case MPC83XX_CLK_PCI:
+#endif
+	case MPC83XX_CLK_CSB:
+#ifdef CONFIG_MPC83XX_SECOND_I2C_SUPPORT
+	case MPC83XX_CLK_I2C2:
+#endif
+#if defined(CONFIG_MPC83XX_QUICC_ENGINE) && !defined(CONFIG_MPC8309)
+	case MPC83XX_CLK_QE:
+	case MPC83XX_CLK_BRG:
+#endif
+	case MPC83XX_CLK_LCLK:
+	case MPC83XX_CLK_LBIU:
+	case MPC83XX_CLK_CORE:
+		return true;
+	}
+
+	return false;
+}
+
+static int mpc83xx_clk_request(struct clk *clock)
+{
+	/* Reject requests of clocks that are not available */
+	if (is_clk_valid(clock->id))
+		return 0;
+	else
+		return -ENODEV;
+}
+
+static inline void init_clks(u32 *speed)
+{
+	int i;
+	immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+	u32 csb_clk = get_csb_clk(im);
+
+	for (i = 0; i < MPC83XX_CLK_COUNT; i++) {
+		struct clk_mode mode = modes[i];
+		ulong mask;
+
+		if (mode.type == TYPE_INVALID)
+			continue;
+
+		if (mode.type == TYPE_SCCR_STANDARD) {
+			mask = GENMASK(31 - mode.low, 31 - mode.high);
+
+			switch (sccr_field(im, mask, 31 - mode.high)) {
+			case 0:
+				speed[i] = 0;
+				break;
+			case 1:
+				speed[i] = csb_clk;
+				break;
+			case 2:
+				speed[i] = csb_clk / 2;
+				break;
+			case 3:
+				speed[i] = csb_clk / 3;
+				break;
+			default:
+				speed[i] = 0;
+			}
+
+			continue;
+		}
+
+		if (mode.type == TYPE_SPMR_DIRECT_MULTIPLY) {
+			mask = GENMASK(31 - mode.low, 31 - mode.high);
+
+			speed[i] = csb_clk * (1 + sccr_field(im, mask, 31 - mode.high));
+			continue;
+		}
+
+		if (i == MPC83XX_CLK_CSB || i == MPC83XX_CLK_I2C2) {
+			speed[i] = csb_clk; /* i2c-2 clk is equal to csb clk */
+			continue;
+		}
+
+		if (i == MPC83XX_CLK_QE || i == MPC83XX_CLK_BRG) {
+			u32 pci_sync_in = get_pci_sync_in(im);
+			u32 qepmf = spmr_field(im, SPMR_CEPMF, SPMR_CEPMF_SHIFT);
+			u32 qepdf = spmr_field(im, SPMR_CEPDF, SPMR_CEPDF_SHIFT);
+			u32 qe_clk = (pci_sync_in * qepmf) / (1 + qepdf);
+
+			if (i == MPC83XX_CLK_QE)
+				speed[i] = qe_clk;
+			else
+				speed[i] = qe_clk / 2;
+
+			continue;
+		}
+
+		if (i == MPC83XX_CLK_LCLK || i == MPC83XX_CLK_LBIU) {
+			u32 lbiu_clk = csb_clk *
+				(1 + spmr_field(im, SPMR_LBIUCM, SPMR_LBIUCM_SHIFT));
+			u32 clkdiv = lcrr_field(im, LCRR_CLKDIV, LCRR_CLKDIV_SHIFT);
+
+			if (i == MPC83XX_CLK_LBIU)
+				speed[i] = lbiu_clk;
+
+			switch (clkdiv) {
+			case 2:
+			case 4:
+			case 8:
+				speed[i] = lbiu_clk / clkdiv;
+				break;
+			default:
+				/* unknown lcrr */
+				speed[i] = 0;
+			}
+
+			continue;
+		}
+
+		if (i == MPC83XX_CLK_CORE) {
+			u8 corepll = spmr_field(im, SPMR_COREPLL, SPMR_COREPLL_SHIFT);
+			u32 corecnf_tab_index = ((corepll & 0x1F) << 2) |
+						((corepll & 0x60) >> 5);
+
+			if (corecnf_tab_index > (ARRAY_SIZE(corecnf_tab))) {
+				/* corecnf_tab_index is too high, possibly wrong value */
+				speed[i] = 0;
+			}
+
+			switch (corecnf_tab[corecnf_tab_index].core_csb_ratio) {
+			case _byp:
+			case _x1:
+			case _1x:
+				speed[i] = csb_clk;
+				break;
+			case _1_5x:
+				speed[i] = (3 * csb_clk) / 2;
+				break;
+			case _2x:
+				speed[i] = 2 * csb_clk;
+				break;
+			case _2_5x:
+				speed[i] = (5 * csb_clk) / 2;
+				break;
+			case _3x:
+				speed[i] = 3 * csb_clk;
+				break;
+			default:
+				/* unknown core to csb ratio */
+				speed[i] = 0;
+			}
+
+			continue;
+		}
+	}
+}
+
+static ulong mpc83xx_clk_get_rate(struct clk *clk)
+{
+	struct mpc83xx_clk_priv *priv = dev_get_priv(clk->dev);
+
+	return priv->speed[clk->id];
+}
+
+int get_serial_clock(void)
+{
+	return 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,mpc83xx-clk", },
+	{ /* sentinel */ }
+};
+
+static int mpc83xx_clk_probe(struct udevice *dev)
+{
+	struct mpc83xx_clk_priv *priv = dev_get_priv(dev);
+
+	speed = malloc((MPC83XX_CLK_COUNT + 1) * sizeof(u32));
+	priv->speed = speed;
+	init_clks(priv->speed);
+
+	gd->arch.csb_clk = speed[MPC83XX_CLK_CSB];
+#if defined(CONFIG_MPC8308) || defined(CONFIG_MPC831x) || \
+	defined(CONFIG_MPC834x) || defined(CONFIG_MPC837x)
+	gd->arch.tsec1_clk = speed[MPC83XX_CLK_TSEC1];
+	gd->arch.tsec2_clk = speed[MPC83XX_CLK_TSEC2];
+	gd->arch.usbdr_clk = speed[MPC83XX_CLK_USBDR];
+#elif defined(CONFIG_MPC8309)
+	gd->arch.usbdr_clk = speed[MPC83XX_CLK_USBDR];
+#endif
+#if defined(CONFIG_MPC834x)
+	gd->arch.usbmph_clk = speed[MPC83XX_CLK_USBMPH];
+#endif
+#if defined(CONFIG_MPC8315)
+	gd->arch.tdm_clk = speed[MPC83XX_CLK_TDM];
+#endif
+#if defined(CONFIG_FSL_ESDHC)
+	gd->arch.sdhc_clk = speed[MPC83XX_CLK_SDHC];
+#endif
+	gd->arch.core_clk = speed[MPC83XX_CLK_CORE];
+	gd->arch.i2c1_clk = speed[MPC83XX_CLK_I2C1];
+#if !defined(CONFIG_MPC832x)
+	gd->arch.i2c2_clk = speed[MPC83XX_CLK_I2C2];
+#endif
+#if !defined(CONFIG_MPC8309)
+	gd->arch.enc_clk = speed[MPC83XX_CLK_ENC];
+#endif
+	gd->arch.lbiu_clk = speed[MPC83XX_CLK_LBIU];
+	gd->arch.lclk_clk = speed[MPC83XX_CLK_LCLK];
+	gd->mem_clk = speed[MPC83XX_CLK_MEM];
+#if defined(CONFIG_MPC8360)
+	gd->arch.mem_sec_clk = speed[MPC83XX_CLK_MEM_SEC];
+#endif
+#if defined(CONFIG_QE)
+	gd->arch.qe_clk = speed[MPC83XX_CLK_QE];
+	gd->arch.brg_clk = speed[MPC83XX_CLK_BRG];
+#endif
+#if defined(CONFIG_MPC8308) || defined(CONFIG_MPC831x) || \
+	defined(CONFIG_MPC837x)
+	gd->arch.pciexp1_clk = speed[MPC83XX_CLK_PCIEXP1];
+	gd->arch.pciexp2_clk = speed[MPC83XX_CLK_PCIEXP2];
+#endif
+#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC8315)
+	gd->arch.sata_clk = speed[MPC83XX_CLK_SATA];
+#endif
+	gd->pci_clk = speed[MPC83XX_CLK_PCI];
+	gd->cpu_clk = speed[MPC83XX_CLK_CORE];
+	gd->bus_clk = speed[MPC83XX_CLK_CSB];
+
+	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),
+};
+
+static int do_clocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	int i;
+	char buf[32];
+
+	for (i = 0; i < MPC83XX_CLK_COUNT; i++) {
+		if (!is_clk_valid(i))
+			continue;
+
+		printf("%s = %s MHz\n", names[i], strmhz(buf, 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 0000000000..75db2f3699
--- /dev/null
+++ b/drivers/clk/mpc83xx_clk.h
@@ -0,0 +1,115 @@
+enum {
+	_unk,
+	_off,
+	_byp,
+	_x8,
+	_x4,
+	_x2,
+	_x1,
+	_1x,
+	_1_5x,
+	_2x,
+	_2_5x,
+	_3x
+};
+
+struct corecnf {
+	int core_csb_ratio;
+	int vco_divider;
+};
+
+static struct corecnf corecnf_tab[] = {
+	{_byp, _byp},		/* 0x00 */
+	{_byp, _byp},		/* 0x01 */
+	{_byp, _byp},		/* 0x02 */
+	{_byp, _byp},		/* 0x03 */
+	{_byp, _byp},		/* 0x04 */
+	{_byp, _byp},		/* 0x05 */
+	{_byp, _byp},		/* 0x06 */
+	{_byp, _byp},		/* 0x07 */
+	{_1x, _x2},		/* 0x08 */
+	{_1x, _x4},		/* 0x09 */
+	{_1x, _x8},		/* 0x0A */
+	{_1x, _x8},		/* 0x0B */
+	{_1_5x, _x2},		/* 0x0C */
+	{_1_5x, _x4},		/* 0x0D */
+	{_1_5x, _x8},		/* 0x0E */
+	{_1_5x, _x8},		/* 0x0F */
+	{_2x, _x2},		/* 0x10 */
+	{_2x, _x4},		/* 0x11 */
+	{_2x, _x8},		/* 0x12 */
+	{_2x, _x8},		/* 0x13 */
+	{_2_5x, _x2},		/* 0x14 */
+	{_2_5x, _x4},		/* 0x15 */
+	{_2_5x, _x8},		/* 0x16 */
+	{_2_5x, _x8},		/* 0x17 */
+	{_3x, _x2},		/* 0x18 */
+	{_3x, _x4},		/* 0x19 */
+	{_3x, _x8},		/* 0x1A */
+	{_3x, _x8},		/* 0x1B */
+};
+
+enum reg_type {
+	REG_SCCR,
+	REG_SPMR,
+};
+
+enum mode_type {
+	TYPE_INVALID = 0,
+	TYPE_SCCR_STANDARD,
+	TYPE_SCCR_ONOFF,
+	TYPE_SPMR_DIRECT_MULTIPLY,
+	TYPE_SPECIAL,
+};
+
+static inline u32 get_spmr(immap_t *im)
+{
+	u32 res = in_be32(&im->clk.spmr);
+
+	return res;
+}
+
+static inline u32 get_sccr(immap_t *im)
+{
+	u32 res = in_be32(&im->clk.sccr);
+
+	return res;
+}
+
+static inline u32 get_lcrr(immap_t *im)
+{
+	u32 res = in_be32(&im->im_lbc.lcrr);
+
+	return res;
+}
+
+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);
+}
+
+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;
+}
+
+static inline uint spmr_field(immap_t *im, u32 mask, uint shift)
+{
+	return (get_spmr(im) & mask) >> shift;
+}
+
+static inline uint sccr_field(immap_t *im, u32 mask, uint shift)
+{
+	return (get_sccr(im) & mask) >> shift;
+}
+
+static inline uint lcrr_field(immap_t *im, u32 mask, uint shift)
+{
+	return (get_lcrr(im) & mask) >> shift;
+}
diff --git a/include/dt-bindings/clk/mpc83xx-clk.h b/include/dt-bindings/clk/mpc83xx-clk.h
new file mode 100644
index 0000000000..3e5b2858c0
--- /dev/null
+++ b/include/dt-bindings/clk/mpc83xx-clk.h
@@ -0,0 +1,27 @@
+#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 */
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 5/8] timer: Add MPC83xx timer driver
  2018-03-28 12:38 [U-Boot] [PATCH 1/8] core: Add uclass_{first,next}_device_compat Mario Six
                   ` (2 preceding siblings ...)
  2018-03-28 12:38 ` [U-Boot] [PATCH 4/8] clk: Add MPC83xx clock driver Mario Six
@ 2018-03-28 12:38 ` Mario Six
  2018-03-28 12:38 ` [U-Boot] [PATCH 6/8] cpu: Add cpu_print_info function Mario Six
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 22+ messages in thread
From: Mario Six @ 2018-03-28 12:38 UTC (permalink / raw)
  To: u-boot

Add a timer driver for the MPC83xx architecture.

Signed-off-by: Mario Six <mario.six@gdsys.cc>
---
 arch/powerpc/cpu/mpc83xx/cpu.c |   4 +-
 arch/powerpc/lib/Makefile      |   4 ++
 arch/powerpc/lib/interrupts.c  |   5 +-
 drivers/timer/Kconfig          |   7 ++
 drivers/timer/Makefile         |   1 +
 drivers/timer/mpc83xx_timer.c  | 158 +++++++++++++++++++++++++++++++++++++++++
 6 files changed, 176 insertions(+), 3 deletions(-)
 create mode 100644 drivers/timer/mpc83xx_timer.c

diff --git a/arch/powerpc/cpu/mpc83xx/cpu.c b/arch/powerpc/cpu/mpc83xx/cpu.c
index 3bdebd845c..d25a935297 100644
--- a/arch/powerpc/cpu/mpc83xx/cpu.c
+++ b/arch/powerpc/cpu/mpc83xx/cpu.c
@@ -175,12 +175,12 @@ do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 /*
  * 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/lib/Makefile b/arch/powerpc/lib/Makefile
index 9a3043abf8..537693e3bc 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -19,13 +19,17 @@ endif
 
 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 e8784aa16e..56a697d28c 100644
--- a/arch/powerpc/lib/interrupts.c
+++ b/arch/powerpc/lib/interrupts.c
@@ -15,6 +15,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")));
 
@@ -45,7 +46,7 @@ static __inline__ void set_dec (unsigned long val)
 	if (val)
 		asm volatile ("mtdec %0"::"r" (val));
 }
-
+#endif /* !CONFIG_MPC83XX_TIMER */
 
 void enable_interrupts (void)
 {
@@ -61,6 +62,7 @@ int disable_interrupts (void)
 	return ((msr & MSR_EE) != 0);
 }
 
+#ifndef CONFIG_MPC83XX_TIMER
 int interrupt_init (void)
 {
 	/* call cpu specific function from $(CPU)/interrupts.c */
@@ -103,3 +105,4 @@ ulong get_timer (ulong base)
 {
 	return (timestamp - base);
 }
+#endif /* !CONFIG_MPC83XX_TIMER */
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index 2c96896726..1b78ce784a 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -126,4 +126,11 @@ config STM32_TIMER
 	  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 a6e7832154..d35d235195 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -17,3 +17,4 @@ 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_STM32_TIMER)	+= stm32_timer.o
+obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o
diff --git a/drivers/timer/mpc83xx_timer.c b/drivers/timer/mpc83xx_timer.c
new file mode 100644
index 0000000000..f17898cc47
--- /dev/null
+++ b/drivers/timer/mpc83xx_timer.c
@@ -0,0 +1,158 @@
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <clk.h>
+#include <timer.h>
+#include <watchdog.h>
+
+struct mpc83xx_timer_priv {
+};
+
+static uint decrementer_count; /* count value for 1e6/HZ microseconds */
+
+static inline unsigned long get_dec(void)
+{
+	unsigned long val;
+
+	asm volatile ("mfdec %0":"=r" (val):);
+
+	return val;
+}
+
+static inline void set_dec(unsigned long val)
+{
+	if (val)
+		asm volatile ("mtdec %0"::"r" (val));
+}
+
+/* TODO(mario.six at gdsys.cc): This should really be done by timer_init, and the
+ * interrupt init should go into a interrupt driver.
+ */
+int interrupt_init(void)
+{
+	//volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
+	immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+	struct udevice *csb;
+	struct clk clock;
+
+	uclass_first_device_compat(UCLASS_SIMPLE_BUS, &csb, "fsl,mpc8308-immr");
+	clk_get_by_index(csb, 0, &clock);
+
+	decrementer_count = (clk_get_rate(&clock) / 4) / CONFIG_SYS_HZ;
+
+	/* Enable e300 time base */
+
+	//immr->sysconf.spcr |= 0x00400000;
+	setbits_be32(&immr->sysconf.spcr, 0x00400000);
+
+	set_dec(decrementer_count);
+
+	set_msr(get_msr() | MSR_EE);
+
+	return 0;
+}
+
+static volatile ulong timestamp = 0;
+
+void timer_interrupt(struct pt_regs *regs)
+{
+	/* Restore Decrementer Count */
+	set_dec(decrementer_count);
+
+	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(timestamp);
+#endif /* CONFIG_LED_STATUS */
+
+#ifdef CONFIG_SHOW_ACTIVITY
+	board_show_activity(timestamp);
+#endif /* CONFIG_SHOW_ACTIVITY */
+}
+
+ulong get_timer(ulong base)
+{
+	return (timestamp - base);
+}
+
+static inline u32 mftbu(void)
+{
+	u32 rval;
+
+	asm volatile("mftbu %0" : "=r" (rval));
+	return rval;
+}
+
+static inline u32 mftb(void)
+{
+	u32 rval;
+
+	asm volatile("mftb %0" : "=r" (rval));
+	return rval;
+}
+
+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;
+
+	do {
+		tbu = mftbu();
+		tbl = mftb();
+	} while (tbu != mftbu());
+
+	*count = (tbu * 0x10000ULL) + tbl;
+
+	return 0;
+}
+
+static int mpc83xx_timer_probe(struct udevice *dev)
+{
+	//struct mpc83xx_timer_priv *priv = dev_get_priv(dev);
+	struct timer_dev_priv *uc_priv = dev->uclass_priv;
+	struct clk clock;
+
+	interrupt_init();
+
+	clk_get_by_index(dev, 0, &clock);
+
+	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,
+};
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 6/8] cpu: Add cpu_print_info function
  2018-03-28 12:38 [U-Boot] [PATCH 1/8] core: Add uclass_{first,next}_device_compat Mario Six
                   ` (3 preceding siblings ...)
  2018-03-28 12:38 ` [U-Boot] [PATCH 5/8] timer: Add MPC83xx timer driver Mario Six
@ 2018-03-28 12:38 ` Mario Six
  2018-03-30  8:41   ` Simon Glass
  2018-03-28 12:38 ` [U-Boot] [PATCH 7/8] cpu: Add MPC83xx CPU driver Mario Six
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 22+ messages in thread
From: Mario Six @ 2018-03-28 12:38 UTC (permalink / raw)
  To: u-boot

Add a cpu_print_info function to the CPU uclass to emulate the behavior
of some current non-DM drivers (e.g. MPC83xx) to print CPU information
during startup.

Signed-off-by: Mario Six <mario.six@gdsys.cc>
---
 drivers/cpu/cpu-uclass.c | 10 ++++++++++
 include/cpu.h            | 15 +++++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/drivers/cpu/cpu-uclass.c b/drivers/cpu/cpu-uclass.c
index 73e4853939..854cedd1b0 100644
--- a/drivers/cpu/cpu-uclass.c
+++ b/drivers/cpu/cpu-uclass.c
@@ -54,6 +54,16 @@ int cpu_get_vendor(struct udevice *dev, char *buf, int size)
 	return ops->get_vendor(dev, buf, size);
 }
 
+int cpu_print_info(struct udevice *dev)
+{
+	struct cpu_ops *ops = cpu_get_ops(dev);
+
+	if (!ops->get_vendor)
+		return -ENOSYS;
+
+	return ops->print_info(dev);
+}
+
 U_BOOT_DRIVER(cpu_bus) = {
 	.name	= "cpu_bus",
 	.id	= UCLASS_SIMPLE_BUS,
diff --git a/include/cpu.h b/include/cpu.h
index 954257715a..37ff000bf9 100644
--- a/include/cpu.h
+++ b/include/cpu.h
@@ -83,6 +83,14 @@ struct cpu_ops {
 	 * @return 0 if OK, -ENOSPC if buffer is too small, other -ve on error
 	 */
 	int (*get_vendor)(struct udevice *dev, char *buf, int size);
+
+	/**
+	 * print_info() - Print information about a CPU
+	 *
+	 * @dev:	Device to check (UCLASS_CPU)
+	 * @return 0 if OK, -ENOSPC if buffer is too small, other -ve on error
+	 */
+	int (*print_info)(struct udevice *dev);
 };
 
 #define cpu_get_ops(dev)        ((struct cpu_ops *)(dev)->driver->ops)
@@ -124,4 +132,11 @@ int cpu_get_count(struct udevice *dev);
  */
 int cpu_get_vendor(struct udevice *dev, char *buf, int size);
 
+/**
+ * cpu_print_info() - Print information about a CPU
+ *
+ * @dev:	Device to check (UCLASS_CPU)
+ * @return 0 if OK, -ENOSPC if buffer is too small, other -ve on error
+ */
+int cpu_print_info(struct udevice *dev);
 #endif
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 7/8] cpu: Add MPC83xx CPU driver
  2018-03-28 12:38 [U-Boot] [PATCH 1/8] core: Add uclass_{first,next}_device_compat Mario Six
                   ` (4 preceding siblings ...)
  2018-03-28 12:38 ` [U-Boot] [PATCH 6/8] cpu: Add cpu_print_info function Mario Six
@ 2018-03-28 12:38 ` Mario Six
  2018-03-28 12:38 ` [U-Boot] [PATCH 8/8] misc: Add MPC83xx serdes driver Mario Six
  2018-03-30  8:41 ` [U-Boot] [PATCH 1/8] core: Add uclass_{first, next}_device_compat Simon Glass
  7 siblings, 0 replies; 22+ messages in thread
From: Mario Six @ 2018-03-28 12:38 UTC (permalink / raw)
  To: u-boot

Add a CPU driver for the MPC83xx architecture.

Signed-off-by: Mario Six <mario.six@gdsys.cc>
---
 arch/powerpc/cpu/mpc83xx/cpu.c       |   2 +
 arch/powerpc/cpu/mpc83xx/cpu_init.c  |   2 +
 arch/powerpc/include/asm/processor.h |   2 +
 drivers/cpu/Kconfig                  |   7 +
 drivers/cpu/Makefile                 |   1 +
 drivers/cpu/mpc83xx_cpu.c            | 358 +++++++++++++++++++++++++++++++++++
 drivers/cpu/mpc83xx_cpu.h            | 173 +++++++++++++++++
 include/cpu.h                        |   1 +
 8 files changed, 546 insertions(+)
 create mode 100644 drivers/cpu/mpc83xx_cpu.c
 create mode 100644 drivers/cpu/mpc83xx_cpu.h

diff --git a/arch/powerpc/cpu/mpc83xx/cpu.c b/arch/powerpc/cpu/mpc83xx/cpu.c
index d25a935297..f8da3f3d49 100644
--- a/arch/powerpc/cpu/mpc83xx/cpu.c
+++ b/arch/powerpc/cpu/mpc83xx/cpu.c
@@ -26,6 +26,7 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+#ifndef CONFIG_CPU_MPC83XX
 int checkcpu(void)
 {
 	volatile immap_t *immr;
@@ -115,6 +116,7 @@ int checkcpu(void)
 
 	return 0;
 }
+#endif
 
 int
 do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
diff --git a/arch/powerpc/cpu/mpc83xx/cpu_init.c b/arch/powerpc/cpu/mpc83xx/cpu_init.c
index 2a9db0c51b..afbfa9e9b0 100644
--- a/arch/powerpc/cpu/mpc83xx/cpu_init.c
+++ b/arch/powerpc/cpu/mpc83xx/cpu_init.c
@@ -465,6 +465,7 @@ static int print_83xx_arb_event(int force)
 }
 #endif /* CONFIG_DISPLAY_AER_xxxx */
 
+#ifndef CONFIG_CPU_MPC83XX
 /*
  * Figure out the cause of the reset
  */
@@ -506,3 +507,4 @@ int prt_83xx_rsr(void)
 
 	return 0;
 }
+#endif
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 57b11b8365..1c9386e503 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -1327,7 +1327,9 @@ void ll_puts(const char *);
 /* 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/drivers/cpu/Kconfig b/drivers/cpu/Kconfig
index 0d1424d38e..d4052005e2 100644
--- a/drivers/cpu/Kconfig
+++ b/drivers/cpu/Kconfig
@@ -6,3 +6,10 @@ config CPU
 	  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 db515f6f17..29d7da42fa 100644
--- a/drivers/cpu/Makefile
+++ b/drivers/cpu/Makefile
@@ -7,3 +7,4 @@
 obj-$(CONFIG_CPU) += cpu-uclass.o
 
 obj-$(CONFIG_ARCH_BMIPS) += bmips_cpu.o
+obj-$(CONFIG_CPU_MPC83XX) += mpc83xx_cpu.o
diff --git a/drivers/cpu/mpc83xx_cpu.c b/drivers/cpu/mpc83xx_cpu.c
new file mode 100644
index 0000000000..2a7de10e53
--- /dev/null
+++ b/drivers/cpu/mpc83xx_cpu.c
@@ -0,0 +1,358 @@
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <cpu.h>
+#include <clk.h>
+#include <asm/immap_83xx.h>
+
+#include "mpc83xx_cpu.h"
+
+struct mpc83xx_cpu_priv {
+	struct mpc83xx_cpu_info info;
+};
+
+int checkcpu(void)
+{
+	struct udevice *cpu;
+
+	for (uclass_first_device_compat(UCLASS_CPU, &cpu, "fsl,mpc8308");
+	     cpu;
+	     uclass_next_device_compat(&cpu, "fsl,mpc8308")) {
+	}
+
+	return 0;
+}
+
+#if defined(CONFIG_DISPLAY_AER_FULL)
+static int print_83xx_arb_event(int force)
+{
+	int etype = (gd->arch.arbiter_event_attributes & AEATR_EVENT)
+		    >> AEATR_EVENT_SHIFT;
+	int mstr_id = (gd->arch.arbiter_event_attributes & AEATR_MSTR_ID)
+		      >> AEATR_MSTR_ID_SHIFT;
+	int tbst = (gd->arch.arbiter_event_attributes & AEATR_TBST)
+		   >> AEATR_TBST_SHIFT;
+	int tsize = (gd->arch.arbiter_event_attributes & AEATR_TSIZE)
+		    >> AEATR_TSIZE_SHIFT;
+	int ttype = (gd->arch.arbiter_event_attributes & AEATR_TTYPE)
+		    >> AEATR_TTYPE_SHIFT;
+
+	if (!force && !gd->arch.arbiter_event_address)
+		return 0;
+
+	puts("Arbiter Event Status:\n");
+	printf("       Event Address: 0x%08lX\n",
+	       gd->arch.arbiter_event_address);
+	printf("       Event Type:    0x%1x  = %s\n", etype, event[etype]);
+	printf("       Master ID:     0x%02x = %s\n", mstr_id, master[mstr_id]);
+	printf("       Transfer Size: 0x%1x  = %d bytes\n", (tbst << 3) | tsize,
+	       tbst ? (tsize ? tsize : 8) : 16 + 8 * tsize);
+	printf("       Transfer Type: 0x%02x = %s\n", ttype, transfer[ttype]);
+
+	return gd->arch.arbiter_event_address;
+}
+
+#elif defined(CONFIG_DISPLAY_AER_BRIEF)
+
+static int print_83xx_arb_event(int force)
+{
+	if (!force && !gd->arch.arbiter_event_address)
+		return 0;
+
+	printf("Arbiter Event Status: AEATR=0x%08lX, AEADR=0x%08lX\n",
+	       gd->arch.arbiter_event_attributes,
+	       gd->arch.arbiter_event_address);
+
+	return gd->arch.arbiter_event_address;
+}
+#endif /* CONFIG_DISPLAY_AER_xxxx */
+
+void prt_83xx_rsr(void)
+{
+	static const struct {
+		ulong mask;
+		char *desc;
+	} bits[] = {
+		{
+		RSR_SWSR, "Software Soft"}, {
+		RSR_SWHR, "Software Hard"}, {
+		RSR_JSRS, "JTAG Soft"}, {
+		RSR_CSHR, "Check Stop"}, {
+		RSR_SWRS, "Software Watchdog"}, {
+		RSR_BMRS, "Bus Monitor"}, {
+		RSR_SRS,  "External/Internal Soft"}, {
+		RSR_HRS,  "External/Internal Hard"}
+	};
+	static int n = ARRAY_SIZE(bits);
+	ulong rsr = gd->arch.reset_status;
+	int i;
+	char *sep;
+
+	printf("Reset Status:");
+
+	puts("");
+
+	sep = " ";
+	for (i = 0; i < n; i++)
+		if (rsr & bits[i].mask) {
+			printf("%s%s%s", sep, bits[i].desc, (i == n - 1) ? "\n" : "");
+			sep = ", ";
+		}
+#if defined(CONFIG_DISPLAY_AER_FULL) || defined(CONFIG_DISPLAY_AER_BRIEF)
+	print_83xx_arb_event(rsr & RSR_BMRS);
+#endif
+	printf("\n");
+}
+
+static inline u32 get_spridr(void)
+{
+	immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
+
+	return in_be32(&immr->sysconf.spridr);
+}
+
+static inline void determine_family(struct udevice *dev)
+{
+	struct mpc83xx_cpu_priv *priv = dev_get_priv(dev);
+
+	switch ((get_spridr() & 0xFFFE0000) >> 16) {
+	case 0x80B:
+		priv->info.family = FAMILY_831X;
+		break;
+	case 0x806:
+		priv->info.family = FAMILY_832X;
+		break;
+	case 0x803:
+		priv->info.family = FAMILY_834X;
+		break;
+	case 0x804:
+		priv->info.family = FAMILY_836X;
+		break;
+	case 0x80C:
+		priv->info.family = FAMILY_837X;
+		break;
+	default:
+		priv->info.family = FAMILY_UNKNOWN;
+	}
+}
+
+static inline void determine_type(struct udevice *dev)
+{
+	struct mpc83xx_cpu_priv *priv = dev_get_priv(dev);
+
+	switch ((get_spridr() & 0xFFFE0000) >> 16) {
+	case 0x8100:
+		priv->info.type = TYPE_8308;
+		break;
+	case 0x8110:
+		priv->info.type = TYPE_8309;
+		break;
+	case 0x80B2:
+		priv->info.type = TYPE_8311;
+		break;
+	case 0x80B0:
+		priv->info.type = TYPE_8313;
+		break;
+	case 0x80B6:
+		priv->info.type = TYPE_8314;
+		break;
+	case 0x80B4:
+		priv->info.type = TYPE_8315;
+		break;
+	case 0x8066:
+		priv->info.type = TYPE_8321;
+		break;
+	case 0x8062:
+		priv->info.type = TYPE_8323;
+		break;
+	case 0x8036:
+		priv->info.type = TYPE_8343;
+		break;
+	case 0x8032:
+		priv->info.type = TYPE_8347_TBGA;
+		break;
+	case 0x8034:
+		priv->info.type = TYPE_8347_PBGA;
+		break;
+	case 0x8030:
+		priv->info.type = TYPE_8349;
+		break;
+	case 0x804A:
+		priv->info.type = TYPE_8358_TBGA;
+		break;
+	case 0x804E:
+		priv->info.type = TYPE_8358_PBGA;
+		break;
+	case 0x8048:
+		priv->info.type = TYPE_8360;
+		break;
+	case 0x80C6:
+		priv->info.type = TYPE_8377;
+		break;
+	case 0x80C4:
+		priv->info.type = TYPE_8378;
+		break;
+	case 0x80C2:
+		priv->info.type = TYPE_8379;
+		break;
+	default:
+		priv->info.type = TYPE_UNKNOWN;
+	}
+}
+
+static inline void determine_e300_type(struct udevice *dev)
+{
+	struct mpc83xx_cpu_priv *priv = dev_get_priv(dev);
+	u32 pvr = get_pvr();
+
+	switch (pvr & 0xffff0000) {
+	case 0x80830000:
+		priv->info.e300_type = E300C1;
+		break;
+	case 0x80840000:
+		priv->info.e300_type = E300C2;
+		break;
+	case 0x80850000:
+		priv->info.e300_type = E300C3;
+		break;
+	case 0x80860000:
+		priv->info.e300_type = E300C4;
+		break;
+	default:
+		priv->info.e300_type = E300_UNKNOWN;
+	}
+}
+
+static inline void determine_revid_other(struct udevice *dev)
+{
+	struct mpc83xx_cpu_priv *priv = dev_get_priv(dev);
+	u32 spridr = get_spridr();
+
+	priv->info.revid.major = (spridr & 0x000000F0) >> 4;
+	priv->info.revid.minor = spridr & 0x0000000F;
+}
+
+static inline void determine_revid_mpc834x(struct udevice *dev)
+{
+	struct mpc83xx_cpu_priv *priv = dev_get_priv(dev);
+	u32 spridr = get_spridr();
+
+	priv->info.revid.major = (spridr & 0x0000FF00) >> 8;
+	priv->info.revid.minor = spridr & 0x000000FF;
+}
+
+static void determine_cpu_data(struct udevice *dev)
+{
+	struct mpc83xx_cpu_priv *priv = dev_get_priv(dev);
+	u32 spridr = get_spridr();
+
+	determine_family(dev);
+	determine_type(dev);
+	determine_e300_type(dev);
+
+	if (priv->info.family == FAMILY_834X)
+		determine_revid_mpc834x(dev);
+	else
+		determine_revid_other(dev);
+
+	if ((priv->info.family == FAMILY_834X ||
+	     priv->info.family == FAMILY_836X) && priv->info.revid.major >= 2)
+		priv->info.is_a_variant = true;
+
+	priv->info.is_e_processor = !(spridr & 0x00010000);
+}
+
+static int mpc83xx_cpu_get_desc(struct udevice *dev, char *buf, int size)
+{
+	return 0;
+}
+
+static int mpc83xx_cpu_get_info(struct udevice *dev, struct cpu_info *info)
+{
+	struct clk clock;
+
+	clk_get_by_index(dev, 0, &clock);
+
+	info->cpu_freq = clk_get_rate(&clock);
+	info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU);
+
+	return 0;
+}
+
+static int mpc83xx_cpu_get_count(struct udevice *dev)
+{
+	/* TODO: Fix */
+	return 42;
+}
+
+static int mpc83xx_cpu_get_vendor(struct udevice *dev, char *buf, int size)
+{
+	snprintf(buf, size, "NXP");
+
+	return 0;
+}
+
+static int mpc83xx_cpu_print_info(struct udevice *dev)
+{
+	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];
+
+	clk_get_by_index(dev, 0, &core_clk);
+	clk_get_by_index(dev, 1, &csb_clk);
+
+	determine_cpu_data(dev);
+
+	prt_83xx_rsr();
+
+	printf("CPU:   %s, MPC%s%s%s, Rev: %d.%d at %s MHz, CSB: %s MHz",
+	       e300_names[priv->info.e300_type],
+	       cpu_type_names[priv->info.type],
+	       priv->info.is_e_processor ? "E" : "",
+	       priv->info.is_a_variant ? "A" : "",
+	       priv->info.revid.major,
+	       priv->info.revid.minor,
+	       strmhz(core_freq, clk_get_rate(&core_clk)),
+	       strmhz(csb_freq, clk_get_rate(&csb_clk)));
+
+	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,
+	.print_info = mpc83xx_cpu_print_info,
+};
+
+int mpc83xx_cpu_probe(struct udevice *dev)
+{
+	cpu_print_info(dev);
+	printf("\n");
+
+	return 0;
+}
+
+static const struct udevice_id mpc83xx_cpu_ids[] = {
+	{ .compatible = "fsl,mpc8308", },
+	{ /* 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 0000000000..f4a256eaf6
--- /dev/null
+++ b/drivers/cpu/mpc83xx_cpu.h
@@ -0,0 +1,173 @@
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _MPC83XX_CPU_H_
+#define _MPC83XX_CPU_H_
+
+enum e300_type {
+	E300C1,
+	E300C2,
+	E300C3,
+	E300C4,
+	E300_UNKNOWN,
+};
+
+static const char * const e300_names[] = {
+	[E300C1] = "e300c1",
+	[E300C2] = "e300c2",
+	[E300C3] = "e300c3",
+	[E300C4] = "e300c4",
+	[E300_UNKNOWN] = "Unknown e300",
+};
+
+enum mpc83xx_cpu_family {
+	FAMILY_831X,
+	FAMILY_832X,
+	FAMILY_834X,
+	FAMILY_836X,
+	FAMILY_837X,
+	FAMILY_UNKNOWN,
+};
+
+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,
+};
+
+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",
+};
+
+struct mpc83xx_cpu_info {
+	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;
+};
+
+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"
+};
+
+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"
+};
+
+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 /* !_MPC83XX_CPU_H_ */
diff --git a/include/cpu.h b/include/cpu.h
index 37ff000bf9..eb521e4e66 100644
--- a/include/cpu.h
+++ b/include/cpu.h
@@ -44,6 +44,7 @@ enum {
 struct cpu_info {
 	ulong cpu_freq;
 	ulong features;
+	void *specific_info;
 };
 
 struct cpu_ops {
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 8/8] misc: Add MPC83xx serdes driver
  2018-03-28 12:38 [U-Boot] [PATCH 1/8] core: Add uclass_{first,next}_device_compat Mario Six
                   ` (5 preceding siblings ...)
  2018-03-28 12:38 ` [U-Boot] [PATCH 7/8] cpu: Add MPC83xx CPU driver Mario Six
@ 2018-03-28 12:38 ` Mario Six
  2018-03-30  8:41 ` [U-Boot] [PATCH 1/8] core: Add uclass_{first, next}_device_compat Simon Glass
  7 siblings, 0 replies; 22+ messages in thread
From: Mario Six @ 2018-03-28 12:38 UTC (permalink / raw)
  To: u-boot

Add a driver to configure the SerDes (Serializer/Deserializer) lanes on
the MPC83xx architecture.

Signed-off-by: Mario Six <mario.six@gdsys.cc>
---
 arch/powerpc/cpu/mpc83xx/serdes.c             |   4 +
 arch/powerpc/include/asm/fsl_mpc83xx_serdes.h |   4 +
 drivers/misc/Kconfig                          |   5 +
 drivers/misc/Makefile                         |   1 +
 drivers/misc/mpc83xx_serdes.c                 | 229 ++++++++++++++++++++++++++
 5 files changed, 243 insertions(+)
 create mode 100644 drivers/misc/mpc83xx_serdes.c

diff --git a/arch/powerpc/cpu/mpc83xx/serdes.c b/arch/powerpc/cpu/mpc83xx/serdes.c
index a0bc477dc3..67b9f152d1 100644
--- a/arch/powerpc/cpu/mpc83xx/serdes.c
+++ b/arch/powerpc/cpu/mpc83xx/serdes.c
@@ -9,6 +9,8 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
+#ifndef CONFIG_MPC83XX_SERDES
+
 #include <config.h>
 #include <common.h>
 #include <asm/io.h>
@@ -149,3 +151,5 @@ void fsl_setup_serdes(u32 offset, char proto, u32 rfcks, char vdd)
 	tmp |= FSL_SRDSRSTCTL_RST;
 	out_be32(regs + FSL_SRDSRSTCTL_OFFS, tmp);
 }
+
+#endif /* !CONFIG_MPC83XX_SERDES */
diff --git a/arch/powerpc/include/asm/fsl_mpc83xx_serdes.h b/arch/powerpc/include/asm/fsl_mpc83xx_serdes.h
index 5a06a09567..a66c878c1f 100644
--- a/arch/powerpc/include/asm/fsl_mpc83xx_serdes.h
+++ b/arch/powerpc/include/asm/fsl_mpc83xx_serdes.h
@@ -7,6 +7,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)
@@ -20,4 +22,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/drivers/misc/Kconfig b/drivers/misc/Kconfig
index d774569cbc..1afb003444 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -263,5 +263,10 @@ config SYS_I2C_EEPROM_ADDR_OVERFLOW
 
 endif
 
+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 e8d598cd47..30bc30b9eb 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -54,3 +54,4 @@ obj-$(CONFIG_QFW) += qfw.o
 obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o
 obj-$(CONFIG_STM32_RCC) += stm32_rcc.o
 obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.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 0000000000..ea538dfd11
--- /dev/null
+++ b/drivers/misc/mpc83xx_serdes.c
@@ -0,0 +1,229 @@
+/*
+ * (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.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <misc.h>
+#include <mapmem.h>
+
+enum {
+	SRDSCR0_DPP_1V2    = 0x00008800,
+
+	SRDSCR0_TXEQA_MASK = 0x00007000,
+	SRDSCR0_TXEQA_SATA = 0x00001000,
+	SRDSCR0_TXEQE_MASK = 0x00000700,
+	SRDSCR0_TXEQE_SATA = 0x00000100,
+};
+
+enum {
+	SRDSCR1_PLLBW = 0x00000040
+};
+
+enum {
+	SRDSCR2_VDD_1V2    = 0x00800000,
+
+	SRDSCR2_SEIC_MASK  = 0x00001c1c,
+	SRDSCR2_SEIC_SATA  = 0x00001414,
+	SRDSCR2_SEIC_PEX   = 0x00001010,
+	SRDSCR2_SEIC_SGMII = 0x00000101,
+};
+
+enum {
+	SRDSCR3_KFR_SATA      = 0x10100000,
+	SRDSCR3_KPH_SATA      = 0x04040000,
+	SRDSCR3_SDFM_SATA_PEX = 0x01010000,
+	SRDSCR3_SDTXL_SATA    = 0x00000505,
+};
+
+enum {
+	SRDSCR4_PROT_SATA  = 0x00000808,
+	SRDSCR4_PROT_PEX   = 0x00000101,
+	SRDSCR4_PROT_SGMII = 0x00000505,
+
+	SRDSCR4_PLANE_X2   = 0x01000000,
+};
+
+enum {
+	SRDSRSTCTL_RST        = 0x80000000,
+	SRDSRSTCTL_SATA_RESET = 0xf,
+};
+
+enum {
+	SERDES_CLK_100 = (0 << 28),
+	SERDES_CLK_125 = (1 << 28),
+	SERDES_CLK_150 = (3 << 28),
+};
+
+struct mpc83xx_serdes_regs {
+	u32 srdscr0;
+	u32 srdscr1;
+	u32 srdscr2;
+	u32 srdscr3;
+	u32 srdscr4;
+	u8 fill0[12];
+	u32 srdsrstctl;
+};
+
+enum pex_type {
+	PEX_X1,
+	PEX_X2,
+};
+
+struct mpc83xx_serdes_priv {
+	struct mpc83xx_serdes_regs *regs;
+	u32 rfcks;
+};
+
+static const struct misc_ops mpc83xx_serdes_ops = {
+};
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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));
+
+	vdd = dev_read_bool(dev, "vdd");
+
+	switch (dev_read_u32_default(dev, "serdes-clk", -1)) {
+	case 100:
+		priv->rfcks = SERDES_CLK_100;
+		break;
+	case 125:
+		priv->rfcks = SERDES_CLK_125;
+		break;
+	case 150:
+		priv->rfcks = SERDES_CLK_150;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* 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
+		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,
+	.ops		= &mpc83xx_serdes_ops,
+	.of_match       = mpc83xx_serdes_ids,
+	.probe          = mpc83xx_serdes_probe,
+	.priv_auto_alloc_size = sizeof(struct mpc83xx_serdes_priv),
+};
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 1/8] core: Add uclass_{first, next}_device_compat
  2018-03-28 12:38 [U-Boot] [PATCH 1/8] core: Add uclass_{first,next}_device_compat Mario Six
                   ` (6 preceding siblings ...)
  2018-03-28 12:38 ` [U-Boot] [PATCH 8/8] misc: Add MPC83xx serdes driver Mario Six
@ 2018-03-30  8:41 ` Simon Glass
  2018-04-11  7:15   ` Mario Six
  7 siblings, 1 reply; 22+ messages in thread
From: Simon Glass @ 2018-03-30  8:41 UTC (permalink / raw)
  To: u-boot

Hi Mario,

On 28 March 2018 at 20:38, Mario Six <mario.six@gdsys.cc> wrote:
> A lot of times one wants to cycle through the devices in a uclass, but
> only certain ones, especially ones identified by their compatibility
> string, and ignore all others (in the best case this procedure should
> not even activate the devices one is not interested in).
>
> Hence, we add a pair of functions similar to uclass_{first,next}_device,
> but taking a compatibility string as an additional argument, which cycle
> through the devices of a uclass that conform to this compatibility
> string.

Can we not use a phandle to find the device? Using raw compatible
strings feel bad (and slow to me).

If not, a please add a sandbox test.

>
> Signed-off-by: Mario Six <mario.six@gdsys.cc>
> ---
>  drivers/core/uclass.c | 33 +++++++++++++++++++++++++++++++++
>  include/dm/uclass.h   | 37 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 70 insertions(+)

Regards,
Simon

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 6/8] cpu: Add cpu_print_info function
  2018-03-28 12:38 ` [U-Boot] [PATCH 6/8] cpu: Add cpu_print_info function Mario Six
@ 2018-03-30  8:41   ` Simon Glass
  2018-04-11  6:39     ` Mario Six
  0 siblings, 1 reply; 22+ messages in thread
From: Simon Glass @ 2018-03-30  8:41 UTC (permalink / raw)
  To: u-boot

Hi,

On 28 March 2018 at 20:38, Mario Six <mario.six@gdsys.cc> wrote:
> Add a cpu_print_info function to the CPU uclass to emulate the behavior
> of some current non-DM drivers (e.g. MPC83xx) to print CPU information
> during startup.
>
> Signed-off-by: Mario Six <mario.six@gdsys.cc>
> ---
>  drivers/cpu/cpu-uclass.c | 10 ++++++++++
>  include/cpu.h            | 15 +++++++++++++++
>  2 files changed, 25 insertions(+)
>

I really don't want drivers printing stuff. Can you use the existing
get_info() method?

Regards,
Simon

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 6/8] cpu: Add cpu_print_info function
  2018-03-30  8:41   ` Simon Glass
@ 2018-04-11  6:39     ` Mario Six
  2018-04-12 16:37       ` Simon Glass
  0 siblings, 1 reply; 22+ messages in thread
From: Mario Six @ 2018-04-11  6:39 UTC (permalink / raw)
  To: u-boot

Hi Simon,

On Fri, Mar 30, 2018 at 10:41 AM, Simon Glass <sjg@chromium.org> wrote:
> Hi,
>
> On 28 March 2018 at 20:38, Mario Six <mario.six@gdsys.cc> wrote:
>> Add a cpu_print_info function to the CPU uclass to emulate the behavior
>> of some current non-DM drivers (e.g. MPC83xx) to print CPU information
>> during startup.
>>
>> Signed-off-by: Mario Six <mario.six@gdsys.cc>
>> ---
>>  drivers/cpu/cpu-uclass.c | 10 ++++++++++
>>  include/cpu.h            | 15 +++++++++++++++
>>  2 files changed, 25 insertions(+)
>>
>
> I really don't want drivers printing stuff. Can you use the existing
> get_info() method?
>

I could, but I'm just emulating the behavior of the legacy code here, which
prints some information when the CPU is initialized. I think that's pretty
useful, and I can do that in our board file, but that would mean implementing
the same routine in every MPC83xx board to get the legacy behavior back.

> Regards,
> Simon
>

Best regards,

Mario

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 1/8] core: Add uclass_{first, next}_device_compat
  2018-03-30  8:41 ` [U-Boot] [PATCH 1/8] core: Add uclass_{first, next}_device_compat Simon Glass
@ 2018-04-11  7:15   ` Mario Six
  2018-04-12 16:31     ` Simon Glass
  0 siblings, 1 reply; 22+ messages in thread
From: Mario Six @ 2018-04-11  7:15 UTC (permalink / raw)
  To: u-boot

Hi Simon,

On Fri, Mar 30, 2018 at 10:41 AM, Simon Glass <sjg@chromium.org> wrote:
> Hi Mario,
>
> On 28 March 2018 at 20:38, Mario Six <mario.six@gdsys.cc> wrote:
>> A lot of times one wants to cycle through the devices in a uclass, but
>> only certain ones, especially ones identified by their compatibility
>> string, and ignore all others (in the best case this procedure should
>> not even activate the devices one is not interested in).
>>
>> Hence, we add a pair of functions similar to uclass_{first,next}_device,
>> but taking a compatibility string as an additional argument, which cycle
>> through the devices of a uclass that conform to this compatibility
>> string.
>
> Can we not use a phandle to find the device? Using raw compatible
> strings feel bad (and slow to me).
>
> If not, a please add a sandbox test.
>

A phandle would indeed be the cleaner solution, but it won't work if you have
to get device handles in board files, since there is no device for a board you
could query for a phandle. And the MPC83xx board this series leads up to needs
to gather numerous device handles for configuration and querying purposes.

If there was a underlying device for the board functions there would be no
issue with using a phandle, but as it is, it sadly won't work.

>>
>> Signed-off-by: Mario Six <mario.six@gdsys.cc>
>> ---
>>  drivers/core/uclass.c | 33 +++++++++++++++++++++++++++++++++
>>  include/dm/uclass.h   | 37 +++++++++++++++++++++++++++++++++++++
>>  2 files changed, 70 insertions(+)
>
> Regards,
> Simon
>

Best regards,

Mario

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 1/8] core: Add uclass_{first, next}_device_compat
  2018-04-11  7:15   ` Mario Six
@ 2018-04-12 16:31     ` Simon Glass
  2018-04-18  9:02       ` Mario Six
  0 siblings, 1 reply; 22+ messages in thread
From: Simon Glass @ 2018-04-12 16:31 UTC (permalink / raw)
  To: u-boot

Hi Mario,

On 11 April 2018 at 01:15, Mario Six <mario.six@gdsys.cc> wrote:
> Hi Simon,
>
> On Fri, Mar 30, 2018 at 10:41 AM, Simon Glass <sjg@chromium.org> wrote:
>> Hi Mario,
>>
>> On 28 March 2018 at 20:38, Mario Six <mario.six@gdsys.cc> wrote:
>>> A lot of times one wants to cycle through the devices in a uclass, but
>>> only certain ones, especially ones identified by their compatibility
>>> string, and ignore all others (in the best case this procedure should
>>> not even activate the devices one is not interested in).
>>>
>>> Hence, we add a pair of functions similar to uclass_{first,next}_device,
>>> but taking a compatibility string as an additional argument, which cycle
>>> through the devices of a uclass that conform to this compatibility
>>> string.
>>
>> Can we not use a phandle to find the device? Using raw compatible
>> strings feel bad (and slow to me).
>>
>> If not, a please add a sandbox test.
>>
>
> A phandle would indeed be the cleaner solution, but it won't work if you have
> to get device handles in board files, since there is no device for a board you
> could query for a phandle. And the MPC83xx board this series leads up to needs
> to gather numerous device handles for configuration and querying purposes.
>
> If there was a underlying device for the board functions there would be no
> issue with using a phandle, but as it is, it sadly won't work.

Yes, actually this comes up a lot. Perhaps we should support a 'board'
device which can have phandles pointing to things? It would be easy to
implement. I'm not sure how Linux handles this stuff?

Regards,
Simon

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 6/8] cpu: Add cpu_print_info function
  2018-04-11  6:39     ` Mario Six
@ 2018-04-12 16:37       ` Simon Glass
  2018-04-18  8:35         ` Mario Six
  0 siblings, 1 reply; 22+ messages in thread
From: Simon Glass @ 2018-04-12 16:37 UTC (permalink / raw)
  To: u-boot

Hi Mario,

On 11 April 2018 at 00:39, Mario Six <mario.six@gdsys.cc> wrote:
> Hi Simon,
>
> On Fri, Mar 30, 2018 at 10:41 AM, Simon Glass <sjg@chromium.org> wrote:
>> Hi,
>>
>> On 28 March 2018 at 20:38, Mario Six <mario.six@gdsys.cc> wrote:
>>> Add a cpu_print_info function to the CPU uclass to emulate the behavior
>>> of some current non-DM drivers (e.g. MPC83xx) to print CPU information
>>> during startup.
>>>
>>> Signed-off-by: Mario Six <mario.six@gdsys.cc>
>>> ---
>>>  drivers/cpu/cpu-uclass.c | 10 ++++++++++
>>>  include/cpu.h            | 15 +++++++++++++++
>>>  2 files changed, 25 insertions(+)
>>>
>>
>> I really don't want drivers printing stuff. Can you use the existing
>> get_info() method?
>>
>
> I could, but I'm just emulating the behavior of the legacy code here, which
> prints some information when the CPU is initialized. I think that's pretty
> useful, and I can do that in our board file, but that would mean implementing
> the same routine in every MPC83xx board to get the legacy behavior back.

Yes, but I don't want the legacy code creeping into the eclass. Can
you convert the board to use the CPU eclass instead?

Regards,
Simon

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 6/8] cpu: Add cpu_print_info function
  2018-04-12 16:37       ` Simon Glass
@ 2018-04-18  8:35         ` Mario Six
  2018-04-18 15:45           ` Simon Glass
  0 siblings, 1 reply; 22+ messages in thread
From: Mario Six @ 2018-04-18  8:35 UTC (permalink / raw)
  To: u-boot

Hi Simon,

On Thu, Apr 12, 2018 at 6:37 PM, Simon Glass <sjg@chromium.org> wrote:
> Hi Mario,
>
> On 11 April 2018 at 00:39, Mario Six <mario.six@gdsys.cc> wrote:
>> Hi Simon,
>>
>> On Fri, Mar 30, 2018 at 10:41 AM, Simon Glass <sjg@chromium.org> wrote:
>>> Hi,
>>>
>>> On 28 March 2018 at 20:38, Mario Six <mario.six@gdsys.cc> wrote:
>>>> Add a cpu_print_info function to the CPU uclass to emulate the behavior
>>>> of some current non-DM drivers (e.g. MPC83xx) to print CPU information
>>>> during startup.
>>>>
>>>> Signed-off-by: Mario Six <mario.six@gdsys.cc>
>>>> ---
>>>>  drivers/cpu/cpu-uclass.c | 10 ++++++++++
>>>>  include/cpu.h            | 15 +++++++++++++++
>>>>  2 files changed, 25 insertions(+)
>>>>
>>>
>>> I really don't want drivers printing stuff. Can you use the existing
>>> get_info() method?
>>>
>>
>> I could, but I'm just emulating the behavior of the legacy code here, which
>> prints some information when the CPU is initialized. I think that's pretty
>> useful, and I can do that in our board file, but that would mean implementing
>> the same routine in every MPC83xx board to get the legacy behavior back.
>
> Yes, but I don't want the legacy code creeping into the eclass. Can
> you convert the board to use the CPU eclass instead?
>

That's what I did, and I just discovered DISPLAY_CPUINFO, which does exactly
what is needed. I'll implement the print_cpuinfo function in the CPU driver, so
I can get rid of the print function in the uclass (and still retain the
information printing at bootup).

> Regards,
> Simon
>

Best regards,
Mario

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 1/8] core: Add uclass_{first, next}_device_compat
  2018-04-12 16:31     ` Simon Glass
@ 2018-04-18  9:02       ` Mario Six
  0 siblings, 0 replies; 22+ messages in thread
From: Mario Six @ 2018-04-18  9:02 UTC (permalink / raw)
  To: u-boot

Hi Simon,

On Thu, Apr 12, 2018 at 6:31 PM, Simon Glass <sjg@chromium.org> wrote:
> Hi Mario,
>
> On 11 April 2018 at 01:15, Mario Six <mario.six@gdsys.cc> wrote:
>> Hi Simon,
>>
>> On Fri, Mar 30, 2018 at 10:41 AM, Simon Glass <sjg@chromium.org> wrote:
>>> Hi Mario,
>>>
>>> On 28 March 2018 at 20:38, Mario Six <mario.six@gdsys.cc> wrote:
>>>> A lot of times one wants to cycle through the devices in a uclass, but
>>>> only certain ones, especially ones identified by their compatibility
>>>> string, and ignore all others (in the best case this procedure should
>>>> not even activate the devices one is not interested in).
>>>>
>>>> Hence, we add a pair of functions similar to uclass_{first,next}_device,
>>>> but taking a compatibility string as an additional argument, which cycle
>>>> through the devices of a uclass that conform to this compatibility
>>>> string.
>>>
>>> Can we not use a phandle to find the device? Using raw compatible
>>> strings feel bad (and slow to me).
>>>
>>> If not, a please add a sandbox test.
>>>
>>
>> A phandle would indeed be the cleaner solution, but it won't work if you have
>> to get device handles in board files, since there is no device for a board you
>> could query for a phandle. And the MPC83xx board this series leads up to needs
>> to gather numerous device handles for configuration and querying purposes.
>>
>> If there was a underlying device for the board functions there would be no
>> issue with using a phandle, but as it is, it sadly won't work.
>
> Yes, actually this comes up a lot. Perhaps we should support a 'board'
> device which can have phandles pointing to things? It would be easy to
> implement. I'm not sure how Linux handles this stuff?
>

I'll see what I can do. And, well, the whole concept of a "board" doesn't
really exist in Linux the way it does in U-Boot, but from what I can tell, the
drivers in drivers/platfrom seem to be kind of similar to that.

> Regards,
> Simon
>

Best regards,
Mario

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 6/8] cpu: Add cpu_print_info function
  2018-04-18  8:35         ` Mario Six
@ 2018-04-18 15:45           ` Simon Glass
  2018-04-19  7:50             ` Mario Six
  0 siblings, 1 reply; 22+ messages in thread
From: Simon Glass @ 2018-04-18 15:45 UTC (permalink / raw)
  To: u-boot

Hi Mario,

On 18 April 2018 at 02:35, Mario Six <mario.six@gdsys.cc> wrote:
> Hi Simon,
>
> On Thu, Apr 12, 2018 at 6:37 PM, Simon Glass <sjg@chromium.org> wrote:
>> Hi Mario,
>>
>> On 11 April 2018 at 00:39, Mario Six <mario.six@gdsys.cc> wrote:
>>> Hi Simon,
>>>
>>> On Fri, Mar 30, 2018 at 10:41 AM, Simon Glass <sjg@chromium.org> wrote:
>>>> Hi,
>>>>
>>>> On 28 March 2018 at 20:38, Mario Six <mario.six@gdsys.cc> wrote:
>>>>> Add a cpu_print_info function to the CPU uclass to emulate the behavior
>>>>> of some current non-DM drivers (e.g. MPC83xx) to print CPU information
>>>>> during startup.
>>>>>
>>>>> Signed-off-by: Mario Six <mario.six@gdsys.cc>
>>>>> ---
>>>>>  drivers/cpu/cpu-uclass.c | 10 ++++++++++
>>>>>  include/cpu.h            | 15 +++++++++++++++
>>>>>  2 files changed, 25 insertions(+)
>>>>>
>>>>
>>>> I really don't want drivers printing stuff. Can you use the existing
>>>> get_info() method?
>>>>
>>>
>>> I could, but I'm just emulating the behavior of the legacy code here, which
>>> prints some information when the CPU is initialized. I think that's pretty
>>> useful, and I can do that in our board file, but that would mean implementing
>>> the same routine in every MPC83xx board to get the legacy behavior back.
>>
>> Yes, but I don't want the legacy code creeping into the eclass. Can
>> you convert the board to use the CPU eclass instead?
>>
>
> That's what I did, and I just discovered DISPLAY_CPUINFO, which does exactly
> what is needed. I'll implement the print_cpuinfo function in the CPU driver, so
> I can get rid of the print function in the uclass (and still retain the
> information printing at bootup).

OK I see. Ideally we would have a function (perhaps in board_f) which
prints out the CPU info after obtaining it from the uclass. So could
you move your print_cpuinfo() function into board_f? Would it be
possible to use that if CONFIG_CPU is defined?

At some point print_cpuinfo() could be removed from various board files.

Regards,
Simon

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 6/8] cpu: Add cpu_print_info function
  2018-04-18 15:45           ` Simon Glass
@ 2018-04-19  7:50             ` Mario Six
  2018-04-24 21:53               ` Simon Glass
  0 siblings, 1 reply; 22+ messages in thread
From: Mario Six @ 2018-04-19  7:50 UTC (permalink / raw)
  To: u-boot

Hi Simon,

On Wed, Apr 18, 2018 at 5:45 PM, Simon Glass <sjg@chromium.org> wrote:
> Hi Mario,
>
> On 18 April 2018 at 02:35, Mario Six <mario.six@gdsys.cc> wrote:
>> Hi Simon,
>>
>> On Thu, Apr 12, 2018 at 6:37 PM, Simon Glass <sjg@chromium.org> wrote:
>>> Hi Mario,
>>>
>>> On 11 April 2018 at 00:39, Mario Six <mario.six@gdsys.cc> wrote:
>>>> Hi Simon,
>>>>
>>>> On Fri, Mar 30, 2018 at 10:41 AM, Simon Glass <sjg@chromium.org> wrote:
>>>>> Hi,
>>>>>
>>>>> On 28 March 2018 at 20:38, Mario Six <mario.six@gdsys.cc> wrote:
>>>>>> Add a cpu_print_info function to the CPU uclass to emulate the behavior
>>>>>> of some current non-DM drivers (e.g. MPC83xx) to print CPU information
>>>>>> during startup.
>>>>>>
>>>>>> Signed-off-by: Mario Six <mario.six@gdsys.cc>
>>>>>> ---
>>>>>>  drivers/cpu/cpu-uclass.c | 10 ++++++++++
>>>>>>  include/cpu.h            | 15 +++++++++++++++
>>>>>>  2 files changed, 25 insertions(+)
>>>>>>
>>>>>
>>>>> I really don't want drivers printing stuff. Can you use the existing
>>>>> get_info() method?
>>>>>
>>>>
>>>> I could, but I'm just emulating the behavior of the legacy code here, which
>>>> prints some information when the CPU is initialized. I think that's pretty
>>>> useful, and I can do that in our board file, but that would mean implementing
>>>> the same routine in every MPC83xx board to get the legacy behavior back.
>>>
>>> Yes, but I don't want the legacy code creeping into the eclass. Can
>>> you convert the board to use the CPU eclass instead?
>>>
>>
>> That's what I did, and I just discovered DISPLAY_CPUINFO, which does exactly
>> what is needed. I'll implement the print_cpuinfo function in the CPU driver, so
>> I can get rid of the print function in the uclass (and still retain the
>> information printing at bootup).
>
> OK I see. Ideally we would have a function (perhaps in board_f) which
> prints out the CPU info after obtaining it from the uclass. So could
> you move your print_cpuinfo() function into board_f? Would it be
> possible to use that if CONFIG_CPU is defined?
>
> At some point print_cpuinfo() could be removed from various board files.
>

The function prints the following (example for our device):

--- >8 ---

Reset Status: External/Internal Soft, External/Internal Hard

CPU:   e300c3, MPC8308, Rev: 1.1 at 400 MHz, CSB: 133.333 MHz

--- >8 ---

So there are some values that are very specific to the platform, such as the
CSB (Coherent System Bus) frequency, or the reset status. While it's probably
possible to put some of that into a generic info printing routine, lots of it
is so MPC83xx-specific that it doesn't make much sense for other CPUs.

Any idea how to tackle this? I don't really want to get rid of the Reset Status
printing especially, since it's pretty useful information for debugging devices
in the field.

> Regards,
> Simon
>

Best regards,
Mario

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 6/8] cpu: Add cpu_print_info function
  2018-04-19  7:50             ` Mario Six
@ 2018-04-24 21:53               ` Simon Glass
  2018-04-26  6:07                 ` Mario Six
  0 siblings, 1 reply; 22+ messages in thread
From: Simon Glass @ 2018-04-24 21:53 UTC (permalink / raw)
  To: u-boot

Hi Mario,

On 19 April 2018 at 01:50, Mario Six <mario.six@gdsys.cc> wrote:
>
> Hi Simon,
>
> On Wed, Apr 18, 2018 at 5:45 PM, Simon Glass <sjg@chromium.org> wrote:
> > Hi Mario,
> >
> > On 18 April 2018 at 02:35, Mario Six <mario.six@gdsys.cc> wrote:
> >> Hi Simon,
> >>
> >> On Thu, Apr 12, 2018 at 6:37 PM, Simon Glass <sjg@chromium.org> wrote:
> >>> Hi Mario,
> >>>
> >>> On 11 April 2018 at 00:39, Mario Six <mario.six@gdsys.cc> wrote:
> >>>> Hi Simon,
> >>>>
> >>>> On Fri, Mar 30, 2018 at 10:41 AM, Simon Glass <sjg@chromium.org> wrote:
> >>>>> Hi,
> >>>>>
> >>>>> On 28 March 2018 at 20:38, Mario Six <mario.six@gdsys.cc> wrote:
> >>>>>> Add a cpu_print_info function to the CPU uclass to emulate the behavior
> >>>>>> of some current non-DM drivers (e.g. MPC83xx) to print CPU information
> >>>>>> during startup.
> >>>>>>
> >>>>>> Signed-off-by: Mario Six <mario.six@gdsys.cc>
> >>>>>> ---
> >>>>>>  drivers/cpu/cpu-uclass.c | 10 ++++++++++
> >>>>>>  include/cpu.h            | 15 +++++++++++++++
> >>>>>>  2 files changed, 25 insertions(+)
> >>>>>>
> >>>>>
> >>>>> I really don't want drivers printing stuff. Can you use the existing
> >>>>> get_info() method?
> >>>>>
> >>>>
> >>>> I could, but I'm just emulating the behavior of the legacy code here, which
> >>>> prints some information when the CPU is initialized. I think that's pretty
> >>>> useful, and I can do that in our board file, but that would mean implementing
> >>>> the same routine in every MPC83xx board to get the legacy behavior back.
> >>>
> >>> Yes, but I don't want the legacy code creeping into the eclass. Can
> >>> you convert the board to use the CPU eclass instead?
> >>>
> >>
> >> That's what I did, and I just discovered DISPLAY_CPUINFO, which does exactly
> >> what is needed. I'll implement the print_cpuinfo function in the CPU driver, so
> >> I can get rid of the print function in the uclass (and still retain the
> >> information printing at bootup).
> >
> > OK I see. Ideally we would have a function (perhaps in board_f) which
> > prints out the CPU info after obtaining it from the uclass. So could
> > you move your print_cpuinfo() function into board_f? Would it be
> > possible to use that if CONFIG_CPU is defined?
> >
> > At some point print_cpuinfo() could be removed from various board files.
> >
>
> The function prints the following (example for our device):
>
> --- >8 ---
>
> Reset Status: External/Internal Soft, External/Internal Hard
>
> CPU:   e300c3, MPC8308, Rev: 1.1 at 400 MHz, CSB: 133.333 MHz
>
> --- >8 ---
>
> So there are some values that are very specific to the platform, such as the
> CSB (Coherent System Bus) frequency, or the reset status. While it's probably
> possible to put some of that into a generic info printing routine, lots of it
> is so MPC83xx-specific that it doesn't make much sense for other CPUs.

Well you get to provide a string from get_desc() so you can add
whatever you like!

>
> Any idea how to tackle this? I don't really want to get rid of the Reset Status
> printing especially, since it's pretty useful information for debugging devices
> in the field.

Re the reset status, shouldn't that come from the sysreset driver? I
wonder if we should add an API call for that? Or is it something
printed by the board?

Regards,
Simon

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 6/8] cpu: Add cpu_print_info function
  2018-04-24 21:53               ` Simon Glass
@ 2018-04-26  6:07                 ` Mario Six
  2018-04-26 14:40                   ` Simon Glass
  0 siblings, 1 reply; 22+ messages in thread
From: Mario Six @ 2018-04-26  6:07 UTC (permalink / raw)
  To: u-boot

Hi Simon,

On Tue, Apr 24, 2018 at 11:53 PM, Simon Glass <sjg@chromium.org> wrote:
> Hi Mario,
>
> On 19 April 2018 at 01:50, Mario Six <mario.six@gdsys.cc> wrote:
>>
>> Hi Simon,
>>
>> On Wed, Apr 18, 2018 at 5:45 PM, Simon Glass <sjg@chromium.org> wrote:
>> > Hi Mario,
>> >
>> > On 18 April 2018 at 02:35, Mario Six <mario.six@gdsys.cc> wrote:
>> >> Hi Simon,
>> >>
>> >> On Thu, Apr 12, 2018 at 6:37 PM, Simon Glass <sjg@chromium.org> wrote:
>> >>> Hi Mario,
>> >>>
>> >>> On 11 April 2018 at 00:39, Mario Six <mario.six@gdsys.cc> wrote:
>> >>>> Hi Simon,
>> >>>>
>> >>>> On Fri, Mar 30, 2018 at 10:41 AM, Simon Glass <sjg@chromium.org> wrote:
>> >>>>> Hi,
>> >>>>>
>> >>>>> On 28 March 2018 at 20:38, Mario Six <mario.six@gdsys.cc> wrote:
>> >>>>>> Add a cpu_print_info function to the CPU uclass to emulate the behavior
>> >>>>>> of some current non-DM drivers (e.g. MPC83xx) to print CPU information
>> >>>>>> during startup.
>> >>>>>>
>> >>>>>> Signed-off-by: Mario Six <mario.six@gdsys.cc>
>> >>>>>> ---
>> >>>>>>  drivers/cpu/cpu-uclass.c | 10 ++++++++++
>> >>>>>>  include/cpu.h            | 15 +++++++++++++++
>> >>>>>>  2 files changed, 25 insertions(+)
>> >>>>>>
>> >>>>>
>> >>>>> I really don't want drivers printing stuff. Can you use the existing
>> >>>>> get_info() method?
>> >>>>>
>> >>>>
>> >>>> I could, but I'm just emulating the behavior of the legacy code here, which
>> >>>> prints some information when the CPU is initialized. I think that's pretty
>> >>>> useful, and I can do that in our board file, but that would mean implementing
>> >>>> the same routine in every MPC83xx board to get the legacy behavior back.
>> >>>
>> >>> Yes, but I don't want the legacy code creeping into the eclass. Can
>> >>> you convert the board to use the CPU eclass instead?
>> >>>
>> >>
>> >> That's what I did, and I just discovered DISPLAY_CPUINFO, which does exactly
>> >> what is needed. I'll implement the print_cpuinfo function in the CPU driver, so
>> >> I can get rid of the print function in the uclass (and still retain the
>> >> information printing at bootup).
>> >
>> > OK I see. Ideally we would have a function (perhaps in board_f) which
>> > prints out the CPU info after obtaining it from the uclass. So could
>> > you move your print_cpuinfo() function into board_f? Would it be
>> > possible to use that if CONFIG_CPU is defined?
>> >
>> > At some point print_cpuinfo() could be removed from various board files.
>> >
>>
>> The function prints the following (example for our device):
>>
>> --- >8 ---
>>
>> Reset Status: External/Internal Soft, External/Internal Hard
>>
>> CPU:   e300c3, MPC8308, Rev: 1.1 at 400 MHz, CSB: 133.333 MHz
>>
>> --- >8 ---
>>
>> So there are some values that are very specific to the platform, such as the
>> CSB (Coherent System Bus) frequency, or the reset status. While it's probably
>> possible to put some of that into a generic info printing routine, lots of it
>> is so MPC83xx-specific that it doesn't make much sense for other CPUs.
>
> Well you get to provide a string from get_desc() so you can add
> whatever you like!
>

OK, I thought I was supposed to decode the cpu_info and print that in the
function. If i can use get_desc(), then it's fine. :-)

>>
>> Any idea how to tackle this? I don't really want to get rid of the Reset Status
>> printing especially, since it's pretty useful information for debugging devices
>> in the field.
>
> Re the reset status, shouldn't that come from the sysreset driver? I
> wonder if we should add an API call for that? Or is it something
> printed by the board?
>

No, that's indeed printed on every MPC83xx board (see prt_83xx_rsr in
arch/powerpc/cpu/mpc83xx/cpu_init.c). A sysreset driver would probably be a
good canonical candidate for printing such a message, true. But since there is
no real system reset on MPC83xx to speak of, that would (for now at least) be
the only thing a MPC83xx sysreset driver did. Also, we'd need another function
in board_f.c, and I don't really know if reset cause printing is very
wide-spread on other platforms to justify that.

> Regards,
> Simon
>

Best regards,
Mario

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 6/8] cpu: Add cpu_print_info function
  2018-04-26  6:07                 ` Mario Six
@ 2018-04-26 14:40                   ` Simon Glass
  2018-04-27 12:16                     ` Mario Six
  0 siblings, 1 reply; 22+ messages in thread
From: Simon Glass @ 2018-04-26 14:40 UTC (permalink / raw)
  To: u-boot

Hi Mario,

On 26 April 2018 at 00:07, Mario Six <mario.six@gdsys.cc> wrote:
> Hi Simon,
>
> On Tue, Apr 24, 2018 at 11:53 PM, Simon Glass <sjg@chromium.org> wrote:
>> Hi Mario,
>>
>> On 19 April 2018 at 01:50, Mario Six <mario.six@gdsys.cc> wrote:
>>>
>>> Hi Simon,
>>>
>>> On Wed, Apr 18, 2018 at 5:45 PM, Simon Glass <sjg@chromium.org> wrote:
>>> > Hi Mario,
>>> >
>>> > On 18 April 2018 at 02:35, Mario Six <mario.six@gdsys.cc> wrote:
>>> >> Hi Simon,
>>> >>
>>> >> On Thu, Apr 12, 2018 at 6:37 PM, Simon Glass <sjg@chromium.org> wrote:
>>> >>> Hi Mario,
>>> >>>
>>> >>> On 11 April 2018 at 00:39, Mario Six <mario.six@gdsys.cc> wrote:
>>> >>>> Hi Simon,
>>> >>>>
>>> >>>> On Fri, Mar 30, 2018 at 10:41 AM, Simon Glass <sjg@chromium.org> wrote:
>>> >>>>> Hi,
>>> >>>>>
>>> >>>>> On 28 March 2018 at 20:38, Mario Six <mario.six@gdsys.cc> wrote:
>>> >>>>>> Add a cpu_print_info function to the CPU uclass to emulate the behavior
>>> >>>>>> of some current non-DM drivers (e.g. MPC83xx) to print CPU information
>>> >>>>>> during startup.
>>> >>>>>>
>>> >>>>>> Signed-off-by: Mario Six <mario.six@gdsys.cc>
>>> >>>>>> ---
>>> >>>>>>  drivers/cpu/cpu-uclass.c | 10 ++++++++++
>>> >>>>>>  include/cpu.h            | 15 +++++++++++++++
>>> >>>>>>  2 files changed, 25 insertions(+)
>>> >>>>>>
>>> >>>>>
>>> >>>>> I really don't want drivers printing stuff. Can you use the existing
>>> >>>>> get_info() method?
>>> >>>>>
>>> >>>>
>>> >>>> I could, but I'm just emulating the behavior of the legacy code here, which
>>> >>>> prints some information when the CPU is initialized. I think that's pretty
>>> >>>> useful, and I can do that in our board file, but that would mean implementing
>>> >>>> the same routine in every MPC83xx board to get the legacy behavior back.
>>> >>>
>>> >>> Yes, but I don't want the legacy code creeping into the eclass. Can
>>> >>> you convert the board to use the CPU eclass instead?
>>> >>>
>>> >>
>>> >> That's what I did, and I just discovered DISPLAY_CPUINFO, which does exactly
>>> >> what is needed. I'll implement the print_cpuinfo function in the CPU driver, so
>>> >> I can get rid of the print function in the uclass (and still retain the
>>> >> information printing at bootup).
>>> >
>>> > OK I see. Ideally we would have a function (perhaps in board_f) which
>>> > prints out the CPU info after obtaining it from the uclass. So could
>>> > you move your print_cpuinfo() function into board_f? Would it be
>>> > possible to use that if CONFIG_CPU is defined?
>>> >
>>> > At some point print_cpuinfo() could be removed from various board files.
>>> >
>>>
>>> The function prints the following (example for our device):
>>>
>>> --- >8 ---
>>>
>>> Reset Status: External/Internal Soft, External/Internal Hard
>>>
>>> CPU:   e300c3, MPC8308, Rev: 1.1 at 400 MHz, CSB: 133.333 MHz
>>>
>>> --- >8 ---
>>>
>>> So there are some values that are very specific to the platform, such as the
>>> CSB (Coherent System Bus) frequency, or the reset status. While it's probably
>>> possible to put some of that into a generic info printing routine, lots of it
>>> is so MPC83xx-specific that it doesn't make much sense for other CPUs.
>>
>> Well you get to provide a string from get_desc() so you can add
>> whatever you like!
>>
>
> OK, I thought I was supposed to decode the cpu_info and print that in the
> function. If i can use get_desc(), then it's fine. :-)
>
>>>
>>> Any idea how to tackle this? I don't really want to get rid of the Reset Status
>>> printing especially, since it's pretty useful information for debugging devices
>>> in the field.
>>
>> Re the reset status, shouldn't that come from the sysreset driver? I
>> wonder if we should add an API call for that? Or is it something
>> printed by the board?
>>
>
> No, that's indeed printed on every MPC83xx board (see prt_83xx_rsr in
> arch/powerpc/cpu/mpc83xx/cpu_init.c). A sysreset driver would probably be a
> good canonical candidate for printing such a message, true. But since there is
> no real system reset on MPC83xx to speak of, that would (for now at least) be
> the only thing a MPC83xx sysreset driver did. Also, we'd need another function
> in board_f.c, and I don't really know if reset cause printing is very
> wide-spread on other platforms to justify that.

Well I've certainly printed this info myself so I think it is useful,
particularly things like whether it was a watchdog reset or user
reset.

Regards,
Simon

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [U-Boot] [PATCH 6/8] cpu: Add cpu_print_info function
  2018-04-26 14:40                   ` Simon Glass
@ 2018-04-27 12:16                     ` Mario Six
  0 siblings, 0 replies; 22+ messages in thread
From: Mario Six @ 2018-04-27 12:16 UTC (permalink / raw)
  To: u-boot

Hi Simon,

On Thu, Apr 26, 2018 at 4:40 PM, Simon Glass <sjg@chromium.org> wrote:
> Hi Mario,
>
> On 26 April 2018 at 00:07, Mario Six <mario.six@gdsys.cc> wrote:
>> Hi Simon,
>>
>> On Tue, Apr 24, 2018 at 11:53 PM, Simon Glass <sjg@chromium.org> wrote:
>>> Hi Mario,
>>>
>>> On 19 April 2018 at 01:50, Mario Six <mario.six@gdsys.cc> wrote:
>>>>
>>>> Hi Simon,
>>>>
>>>> On Wed, Apr 18, 2018 at 5:45 PM, Simon Glass <sjg@chromium.org> wrote:
>>>> > Hi Mario,
>>>> >
>>>> > On 18 April 2018 at 02:35, Mario Six <mario.six@gdsys.cc> wrote:
>>>> >> Hi Simon,
>>>> >>
>>>> >> On Thu, Apr 12, 2018 at 6:37 PM, Simon Glass <sjg@chromium.org> wrote:
>>>> >>> Hi Mario,
>>>> >>>
>>>> >>> On 11 April 2018 at 00:39, Mario Six <mario.six@gdsys.cc> wrote:
>>>> >>>> Hi Simon,
>>>> >>>>
>>>> >>>> On Fri, Mar 30, 2018 at 10:41 AM, Simon Glass <sjg@chromium.org> wrote:
>>>> >>>>> Hi,
>>>> >>>>>
>>>> >>>>> On 28 March 2018 at 20:38, Mario Six <mario.six@gdsys.cc> wrote:
>>>> >>>>>> Add a cpu_print_info function to the CPU uclass to emulate the behavior
>>>> >>>>>> of some current non-DM drivers (e.g. MPC83xx) to print CPU information
>>>> >>>>>> during startup.
>>>> >>>>>>
>>>> >>>>>> Signed-off-by: Mario Six <mario.six@gdsys.cc>
>>>> >>>>>> ---
>>>> >>>>>>  drivers/cpu/cpu-uclass.c | 10 ++++++++++
>>>> >>>>>>  include/cpu.h            | 15 +++++++++++++++
>>>> >>>>>>  2 files changed, 25 insertions(+)
>>>> >>>>>>
>>>> >>>>>
>>>> >>>>> I really don't want drivers printing stuff. Can you use the existing
>>>> >>>>> get_info() method?
>>>> >>>>>
>>>> >>>>
>>>> >>>> I could, but I'm just emulating the behavior of the legacy code here, which
>>>> >>>> prints some information when the CPU is initialized. I think that's pretty
>>>> >>>> useful, and I can do that in our board file, but that would mean implementing
>>>> >>>> the same routine in every MPC83xx board to get the legacy behavior back.
>>>> >>>
>>>> >>> Yes, but I don't want the legacy code creeping into the eclass. Can
>>>> >>> you convert the board to use the CPU eclass instead?
>>>> >>>
>>>> >>
>>>> >> That's what I did, and I just discovered DISPLAY_CPUINFO, which does exactly
>>>> >> what is needed. I'll implement the print_cpuinfo function in the CPU driver, so
>>>> >> I can get rid of the print function in the uclass (and still retain the
>>>> >> information printing at bootup).
>>>> >
>>>> > OK I see. Ideally we would have a function (perhaps in board_f) which
>>>> > prints out the CPU info after obtaining it from the uclass. So could
>>>> > you move your print_cpuinfo() function into board_f? Would it be
>>>> > possible to use that if CONFIG_CPU is defined?
>>>> >
>>>> > At some point print_cpuinfo() could be removed from various board files.
>>>> >
>>>>
>>>> The function prints the following (example for our device):
>>>>
>>>> --- >8 ---
>>>>
>>>> Reset Status: External/Internal Soft, External/Internal Hard
>>>>
>>>> CPU:   e300c3, MPC8308, Rev: 1.1 at 400 MHz, CSB: 133.333 MHz
>>>>
>>>> --- >8 ---
>>>>
>>>> So there are some values that are very specific to the platform, such as the
>>>> CSB (Coherent System Bus) frequency, or the reset status. While it's probably
>>>> possible to put some of that into a generic info printing routine, lots of it
>>>> is so MPC83xx-specific that it doesn't make much sense for other CPUs.
>>>
>>> Well you get to provide a string from get_desc() so you can add
>>> whatever you like!
>>>
>>
>> OK, I thought I was supposed to decode the cpu_info and print that in the
>> function. If i can use get_desc(), then it's fine. :-)
>>
>>>>
>>>> Any idea how to tackle this? I don't really want to get rid of the Reset Status
>>>> printing especially, since it's pretty useful information for debugging devices
>>>> in the field.
>>>
>>> Re the reset status, shouldn't that come from the sysreset driver? I
>>> wonder if we should add an API call for that? Or is it something
>>> printed by the board?
>>>
>>
>> No, that's indeed printed on every MPC83xx board (see prt_83xx_rsr in
>> arch/powerpc/cpu/mpc83xx/cpu_init.c). A sysreset driver would probably be a
>> good canonical candidate for printing such a message, true. But since there is
>> no real system reset on MPC83xx to speak of, that would (for now at least) be
>> the only thing a MPC83xx sysreset driver did. Also, we'd need another function
>> in board_f.c, and I don't really know if reset cause printing is very
>> wide-spread on other platforms to justify that.
>
> Well I've certainly printed this info myself so I think it is useful,
> particularly things like whether it was a watchdog reset or user
> reset.
>

OK, I'll write a sysreset driver for MPC83xx; shouldn't be too complicated.

> Regards,
> Simon
>

Best regards,
Mario

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2018-04-27 12:16 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-28 12:38 [U-Boot] [PATCH 1/8] core: Add uclass_{first,next}_device_compat Mario Six
2018-03-28 12:38 ` [U-Boot] [PATCH 2/8] test: Add tests for uclass_{first, next}_device_compat Mario Six
2018-03-28 12:38 ` [U-Boot] [PATCH 3/8] ram: Add driver for MPC83xx Mario Six
2018-03-28 12:38 ` [U-Boot] [PATCH 4/8] clk: Add MPC83xx clock driver Mario Six
2018-03-28 12:38 ` [U-Boot] [PATCH 5/8] timer: Add MPC83xx timer driver Mario Six
2018-03-28 12:38 ` [U-Boot] [PATCH 6/8] cpu: Add cpu_print_info function Mario Six
2018-03-30  8:41   ` Simon Glass
2018-04-11  6:39     ` Mario Six
2018-04-12 16:37       ` Simon Glass
2018-04-18  8:35         ` Mario Six
2018-04-18 15:45           ` Simon Glass
2018-04-19  7:50             ` Mario Six
2018-04-24 21:53               ` Simon Glass
2018-04-26  6:07                 ` Mario Six
2018-04-26 14:40                   ` Simon Glass
2018-04-27 12:16                     ` Mario Six
2018-03-28 12:38 ` [U-Boot] [PATCH 7/8] cpu: Add MPC83xx CPU driver Mario Six
2018-03-28 12:38 ` [U-Boot] [PATCH 8/8] misc: Add MPC83xx serdes driver Mario Six
2018-03-30  8:41 ` [U-Boot] [PATCH 1/8] core: Add uclass_{first, next}_device_compat Simon Glass
2018-04-11  7:15   ` Mario Six
2018-04-12 16:31     ` Simon Glass
2018-04-18  9:02       ` Mario Six

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.