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", ð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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201001311026.o0VAQUA1033412>