PERFORCE change 174000 for review
Rafal Jaworowski
raj at FreeBSD.org
Sun Jan 31 10:26:31 UTC 2010
http://p4web.freebsd.org/chv.cgi?CH=174000
Change 174000 by raj at 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", ð0_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", ®, sizeof(reg));
+ if (len <= 0)
+ return (EINVAL);
+
+ *base = fdt_data_get(®[0], addr_cells);
+ *size = fdt_data_get(®[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;
More information about the p4-projects
mailing list