Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 31 Jan 2010 10:26:30 GMT
From:      Rafal Jaworowski <raj@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 174000 for review
Message-ID:  <201001311026.o0VAQUA1033412@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/chv.cgi?CH=174000

Change 174000 by raj@raj_fdt on 2010/01/31 10:26:23

	Marvell SOC: integrate decode windows configuration layer with
	FDT-oriented approach.
	
	- Read out all necessary addressing data from the blob instead of
	  using #define'd values.
	- Overall improve validating sub-routines to return error codes in
	  a more natural way.

Affected files ...

.. //depot/projects/fdt/sys/arm/mv/common.c#2 edit
.. //depot/projects/fdt/sys/arm/mv/kirkwood/kirkwood.c#2 edit
.. //depot/projects/fdt/sys/arm/mv/mvvar.h#3 edit

Differences ...

==== //depot/projects/fdt/sys/arm/mv/common.c#2 (text+ko) ====

@@ -37,12 +37,29 @@
 #include <sys/bus.h>
 #include <sys/kernel.h>
 
+#include <dev/ofw/openfirm.h>
+
 #include <machine/bus.h>
 
 #include <arm/mv/mvreg.h>
 #include <arm/mv/mvvar.h>
 #include <arm/mv/mvwin.h>
 
+#include "../../contrib/dtc/libfdt/libfdt_env.h"
+#include "../../../sys/dev/fdt/fdt_common.h"
+
+#define MAX_CPU_WIN	5
+
+#define DEBUG
+#undef DEBUG
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
+    printf(fmt,##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
 static int win_eth_can_remap(int i);
 
 static int decode_win_cpu_valid(void);
@@ -54,15 +71,42 @@
 
 static void decode_win_cpu_setup(void);
 static void decode_win_usb_setup(void);
-static void decode_win_eth_setup(uint32_t base);
-static void decode_win_pcie_setup(uint32_t base);
+static void decode_win_eth_setup(uint32_t);
+static void decode_win_pcie_setup(uint32_t);
 static void decode_win_sata_setup(void);
 static void decode_win_cesa_setup(void);
 
 static void decode_win_cesa_dump(void);
 static void decode_win_usb_dump(void);
 
+static int fdt_get_ranges(const char *, void *, int, int *, int *);
+static int fdt_get_regsize(phandle_t, u_long *, u_long *);
+
+static int win_cpu_from_dt(void);
+static int win_soc_from_dt(void);
+
 static uint32_t used_cpu_wins;
+static int cpu_wins_no = 0;
+
+static struct decode_win cpu_win_tbl[MAX_CPU_WIN];
+
+u_long cesa_base = 0;
+u_long usb0_base = 0;
+u_long eth0_base = 0;
+
+static const struct decode_win *cpu_wins = cpu_win_tbl;
+
+struct soc_node_spec {
+	const char	*compat;
+	u_long		*base;
+};
+
+static struct soc_node_spec soc_nodes[] = {
+	{ "mrvl,cesa",		&cesa_base },
+	{ "mrvl,ge",		&eth0_base },
+	{ "mrvl,usb-ehci",	&usb0_base },
+	{ NULL, NULL },
+};
 
 static __inline int
 pm_is_disabled(uint32_t mask)
@@ -285,7 +329,7 @@
 soc_decode_win(void)
 {
 	uint32_t dev, rev;
-	int mask;
+	int mask, err;
 
 	mask = 0;
 	TUNABLE_INT_FETCH("hw.pm-disable-mask", &mask);
@@ -293,14 +337,21 @@
 	if (mask != 0)
 		pm_disable_device(mask);
 
+	/* Retrieve data about physical addresses from device tree. */
+	if ((err = win_cpu_from_dt()) != 0)
+		return (err);
+
+	if ((err = win_soc_from_dt()) != 0)
+		return (err);
+
 	/* Retrieve our ID: some windows facilities vary between SoC models */
 	soc_id(&dev, &rev);
 
-	if (decode_win_cpu_valid() != 1 || decode_win_usb_valid() != 1 ||
-	    decode_win_eth_valid() != 1 || decode_win_idma_valid() != 1 ||
-	    decode_win_pcie_valid() != 1 || decode_win_sata_valid() != 1 ||
-	    decode_win_cesa_valid() != 1)
-		return(-1);
+	if (!decode_win_cpu_valid() || !decode_win_usb_valid() ||
+	    !decode_win_eth_valid() || !decode_win_idma_valid() ||
+	    !decode_win_pcie_valid() || !decode_win_sata_valid() ||
+	    !decode_win_cesa_valid())
+		return (EINVAL);
 
 	decode_win_cpu_setup();
 	decode_win_usb_setup();
@@ -332,6 +383,19 @@
 	return (0);
 }
 
+/*
+ * XXX Redefine macros. This is needed to avoid destroying compatibility with
+ * macros to be removed in the future (but currently used elsewhere). This
+ * will not be neccessary when fdtbus will be functioning.
+ */
+#undef MV_USB0_BASE
+#undef MV_CESA_BASE
+#undef MV_ETH0_BASE
+
+#define MV_USB0_BASE	(MV_BASE + usb0_base)
+#define MV_CESA_BASE	(MV_BASE + cesa_base)
+#define MV_ETH0_BASE	(MV_BASE + eth0_base)
+
 /**************************************************************************
  * Decode windows registers accessors
  **************************************************************************/
@@ -509,7 +573,7 @@
 
 	if (cpu_wins_no > MV_WIN_CPU_MAX) {
 		printf("CPU windows: too many entries: %d\n", cpu_wins_no);
-		return (-1);
+		return (0);
 	}
 
 	rv = 1;
@@ -562,7 +626,7 @@
 	int win;
 
 	if (used_cpu_wins >= MV_WIN_CPU_MAX)
-		return (-1);
+		return (0);
 
 	win = used_cpu_wins++;
 
@@ -1070,7 +1134,7 @@
 
 	if (idma_wins_no > MV_WIN_IDMA_MAX) {
 		printf("IDMA windows: too many entries: %d\n", idma_wins_no);
-		return (-1);
+		return (0);
 	}
 	for (i = 0, c = 0; i < MV_WIN_DDR_MAX; i++)
 		if (ddr_is_active(i))
@@ -1079,7 +1143,7 @@
 	if (idma_wins_no > (MV_WIN_IDMA_MAX - c)) {
 		printf("IDMA windows: too many entries: %d, available: %d\n",
 		    idma_wins_no, MV_WIN_IDMA_MAX - c);
-		return (-1);
+		return (0);
 	}
 
 	wintab = idma_wins;
@@ -1353,7 +1417,7 @@
 
 	if (xor_wins_no > MV_WIN_XOR_MAX) {
 		printf("XOR windows: too many entries: %d\n", xor_wins_no);
-		return (-1);
+		return (0);
 	}
 	for (i = 0, c = 0; i < MV_WIN_DDR_MAX; i++)
 		if (ddr_is_active(i))
@@ -1362,7 +1426,7 @@
 	if (xor_wins_no > (MV_WIN_XOR_MAX - c)) {
 		printf("XOR windows: too many entries: %d, available: %d\n",
 		    xor_wins_no, MV_WIN_IDMA_MAX - c);
-		return (-1);
+		return (0);
 	}
 
 	wintab = xor_wins;
@@ -1585,3 +1649,165 @@
 
 	return (decode_win_can_cover_ddr(MV_WIN_SATA_MAX));
 }
+
+/**************************************************************************
+ * FDT parsing routines.
+ **************************************************************************/
+
+static int
+fdt_get_ranges(const char *nodename, void *buf, int size, int *tuples,
+    int *tuplesize)
+{
+	phandle_t node;
+	pcell_t addr_cells, par_addr_cells, size_cells;
+	int len, tuple_size, tuples_count;
+
+	node = OF_finddevice(nodename);
+	if (node <= 0)
+		return (EINVAL);
+
+	if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0)
+		return (ENXIO);
+
+	par_addr_cells = fdt_parent_addr_cells(node);
+	if (par_addr_cells > 2)
+		return (ERANGE);
+
+	tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells +
+	    size_cells);
+
+	/* Note the OF_getprop_alloc() cannot be used at this early stage. */
+	len = OF_getprop(node, "ranges", buf, size);
+
+	/*
+	 * XXX this does not handle the empty 'ranges;' case, which is
+	 * legitimate and should be allowed.
+	 */
+	tuples_count = len / tuple_size;
+	if (tuples_count <= 0)
+		return (ERANGE);
+
+	if (fdt_ranges_verify(buf, tuples_count, par_addr_cells,
+	    addr_cells, size_cells) != 0)
+		return (ERANGE);
+
+	*tuples = tuples_count;
+	*tuplesize = tuple_size;
+	return (0);
+}
+
+static int
+fdt_get_regsize(phandle_t node, u_long *base, u_long *size)
+{
+	pcell_t reg[4];
+	int addr_cells, len, size_cells;
+
+	if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells))
+		return (ENXIO);
+
+	if ((sizeof(pcell_t) * (addr_cells + size_cells)) > sizeof(reg))
+		return (ENOMEM);
+
+	len = OF_getprop(node, "reg", &reg, sizeof(reg));
+	if (len <= 0)
+		return (EINVAL);
+
+	*base = fdt_data_get(&reg[0], addr_cells);
+	*size = fdt_data_get(&reg[addr_cells], size_cells);
+	return (0);
+}
+
+static int
+win_soc_from_dt(void)
+{
+	phandle_t node, child;
+	struct soc_node_spec *soc_node;
+	u_long size;
+	int err, i;
+
+	node = OF_finddevice("/");
+	if (node == 0)
+		panic("win_soc_from_dt: no root node");
+
+	node = fdt_find_compatible(node, "simple-bus");
+	if (node == 0)
+		return (ENXIO);
+
+	/*
+	 * Traverse through all children of simple-bus node, and retrieve
+	 * decode windows data for devices (if applicable).
+	 */
+	for (child = OF_child(node); child != 0; child = OF_peer(child))
+		for (i = 0; soc_nodes[i].compat != NULL; i++) {
+
+			soc_node = &soc_nodes[i];
+
+			if (!fdt_is_compatible(child, soc_node->compat))
+				continue;
+			if (soc_node->base == NULL)
+				continue;
+
+			err = fdt_get_regsize(child, soc_node->base, &size);
+			if (err != 0)
+				return (err);
+		}
+
+	return (0);
+}
+
+static int
+win_cpu_from_dt(void)
+{
+	pcell_t ranges[48];
+	u_long sram_base, sram_size;
+	phandle_t node;
+	int i, entry_size, err, t, tuple_size, tuples;
+
+	/* Retrieve 'ranges' property of '/localbus' node. */
+	if ((err = fdt_get_ranges("/localbus", ranges, sizeof(ranges),
+	    &tuples, &tuple_size)) != 0)
+		return (err);
+
+	/*
+	 * Fill CPU decode windows table.
+	 */
+	bzero((void *)&cpu_win_tbl, sizeof(cpu_win_tbl));
+
+	entry_size = tuple_size / sizeof(pcell_t);
+	cpu_wins_no = tuples;
+
+	for (i = 0, t = 0; t < tuples; i += entry_size, t++) {
+		cpu_win_tbl[t].target = 1;
+		cpu_win_tbl[t].attr = fdt32_to_cpu(ranges[i + 1]);
+		cpu_win_tbl[t].base = fdt32_to_cpu(ranges[i + 2]);
+		cpu_win_tbl[t].size = fdt32_to_cpu(ranges[i + 3]);
+		cpu_win_tbl[t].remap = -1;
+		debugf("target = 0x%0x attr = 0x%0x base = 0x%0x "
+		    "size = 0x%0x remap = %d\n", cpu_win_tbl[t].target,
+		    cpu_win_tbl[t].attr, cpu_win_tbl[t].base,
+		    cpu_win_tbl[t].size, cpu_win_tbl[t].remap);
+	}
+
+	/*
+	 * Retrieve CESA SRAM data.
+	 */
+	if ((node = OF_finddevice("/sram")) == 0)
+		/* SRAM block is not always present. */
+		return (0);
+
+	sram_base = sram_size = 0;
+	if (fdt_get_regsize(node, &sram_base, &sram_size) != 0)
+		return (EINVAL);
+
+	/*
+	 * XXX Need to handle different CESA SRAM target ID accross SOCs.
+	 */
+	cpu_win_tbl[++t].target = 4;
+	cpu_win_tbl[t].attr = 0;
+	cpu_win_tbl[t].base = sram_base;
+	cpu_win_tbl[t].size = sram_size;
+	cpu_win_tbl[t].remap = -1;
+	debugf("/sram: base = 0x%0lx size = 0x%0lx\n", sram_base, sram_size);
+
+	return (0);
+}

==== //depot/projects/fdt/sys/arm/mv/kirkwood/kirkwood.c#2 (text+ko) ====

@@ -141,26 +141,6 @@
 	{ -1, 0 }
 };
 
-const struct decode_win cpu_win_tbl[] = {
-	/* Device bus BOOT */
-	{ 1, 0x0f, MV_DEV_BOOT_PHYS_BASE, MV_DEV_BOOT_SIZE, -1 },
-
-	/* Device bus CS0 */
-	{ 1, 0x1e, MV_DEV_CS0_PHYS_BASE, MV_DEV_CS0_SIZE, -1 },
-
-	/* Device bus CS1 */
-	{ 1, 0x1d, MV_DEV_CS1_PHYS_BASE, MV_DEV_CS1_SIZE, -1 },
-
-	/* Device bus CS2 */
-	{ 1, 0x1b, MV_DEV_CS2_PHYS_BASE, MV_DEV_CS2_SIZE, -1 },
-
-	/* CESA */
-	{ 3, 0x00, MV_CESA_SRAM_PHYS_BASE, MV_CESA_SRAM_SIZE, -1 },
-
-};
-const struct decode_win *cpu_wins = cpu_win_tbl;
-int cpu_wins_no = sizeof(cpu_win_tbl) / sizeof(struct decode_win);
-
 const struct decode_win xor_win_tbl[] = {
 	/* PCIE MEM */
 	{ 4, 0xE8, MV_PCIE_MEM_PHYS_BASE, MV_PCIE_MEM_SIZE, -1 },

==== //depot/projects/fdt/sys/arm/mv/mvvar.h#3 (text+ko) ====

@@ -113,10 +113,8 @@
 extern const struct gpio_config mv_gpio_config[];
 extern bus_space_tag_t obio_tag;
 extern struct obio_device obio_devices[];
-extern const struct decode_win *cpu_wins;
 extern const struct decode_win *idma_wins;
 extern const struct decode_win *xor_wins;
-extern int cpu_wins_no;
 extern int idma_wins_no;
 extern int xor_wins_no;
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201001311026.o0VAQUA1033412>