Index: head/sys/arm/include/fdt.h =================================================================== --- head/sys/arm/include/fdt.h (revision 281086) +++ head/sys/arm/include/fdt.h (revision 281087) @@ -1,58 +1,54 @@ /*- * Copyright (c) 2010 The FreeBSD Foundation * All rights reserved. * * This software was developed by Semihalf under sponsorship from * the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _MACHINE_FDT_H_ #define _MACHINE_FDT_H_ #include #include #include #include #include /* Max interrupt number */ #define FDT_INTR_MAX NIRQ /* Map phandle/intpin pair to global IRQ number */ #define FDT_MAP_IRQ(node, pin) (pin) /* * Bus space tag. XXX endianess info needs to be derived from the blob. */ extern bus_space_tag_t fdtbus_bs_tag; -struct arm_devmap_entry; - -int fdt_localbus_devmap(phandle_t, struct arm_devmap_entry *, int, int *); - #endif /* _MACHINE_FDT_H_ */ Index: head/sys/arm/mv/mv_localbus.c =================================================================== --- head/sys/arm/mv/mv_localbus.c (revision 281086) +++ head/sys/arm/mv/mv_localbus.c (revision 281087) @@ -1,493 +1,494 @@ /*- * Copyright (c) 2012 Semihalf. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dev/fdt/fdt_common.h" #include "ofw_bus_if.h" +#include #include #ifdef DEBUG #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ printf(fmt,##args); } while (0) #else #define debugf(fmt, args...) #endif #define MV_LOCALBUS_MAX_BANKS 8 #define MV_LOCALBUS_MAX_BANK_CELLS 4 static MALLOC_DEFINE(M_LOCALBUS, "localbus", "localbus devices information"); struct localbus_bank { vm_offset_t va; /* VA of the bank */ vm_paddr_t pa; /* physical address of the bank */ vm_size_t size; /* bank size */ uint8_t mapped; /* device memory has mapping */ }; struct localbus_softc { device_t sc_dev; bus_space_handle_t sc_bsh; bus_space_tag_t sc_bst; int sc_rid; struct localbus_bank *sc_banks; }; struct localbus_devinfo { struct ofw_bus_devinfo di_ofw; struct resource_list di_res; int di_bank; }; struct localbus_va_entry { int8_t bank; vm_offset_t va; vm_size_t size; }; /* * Prototypes. */ static int localbus_probe(device_t); static int localbus_attach(device_t); static int localbus_print_child(device_t, device_t); static struct resource *localbus_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); static struct resource_list *localbus_get_resource_list(device_t, device_t); static ofw_bus_get_devinfo_t localbus_get_devinfo; /* * Bus interface definition. */ static device_method_t localbus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, localbus_probe), DEVMETHOD(device_attach, localbus_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, localbus_print_child), DEVMETHOD(bus_alloc_resource, localbus_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_get_resource_list, localbus_get_resource_list), /* OFW bus interface */ DEVMETHOD(ofw_bus_get_devinfo, localbus_get_devinfo), DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), { 0, 0 } }; static driver_t localbus_driver = { "localbus", localbus_methods, sizeof(struct localbus_softc) }; const struct localbus_va_entry localbus_virtmap[] = { { 0, MV_DEV_BOOT_BASE, MV_DEV_BOOT_SIZE }, { 1, MV_DEV_CS0_BASE, MV_DEV_CS0_SIZE }, { 2, MV_DEV_CS1_BASE, MV_DEV_CS1_SIZE }, { 3, MV_DEV_CS2_BASE, MV_DEV_CS2_SIZE }, { -1, 0, 0 } }; static struct localbus_bank localbus_banks[MV_LOCALBUS_MAX_BANKS]; devclass_t localbus_devclass; DRIVER_MODULE(localbus, ofwbus, localbus_driver, localbus_devclass, 0, 0); static int fdt_localbus_reg_decode(phandle_t node, struct localbus_softc *sc, struct localbus_devinfo *di) { u_long start, end, count; pcell_t *reg, *regptr; pcell_t addr_cells, size_cells; int tuple_size, tuples; int i, rv, bank; if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0) return (ENXIO); tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)®); debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells); debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size); if (tuples <= 0) /* No 'reg' property in this node. */ return (0); regptr = reg; for (i = 0; i < tuples; i++) { bank = fdt_data_get((void *)regptr, 1); if (bank >= MV_LOCALBUS_MAX_BANKS) { device_printf(sc->sc_dev, "bank number [%d] out of " "range\n", bank); continue; } /* * If device doesn't have virtual to physical mapping don't add * resources */ if (!(sc->sc_banks[bank].mapped)) { device_printf(sc->sc_dev, "device [%d]: missing memory " "mapping\n", bank); continue; } di->di_bank = bank; regptr += 1; /* Get address/size. */ rv = fdt_data_to_res(regptr, addr_cells - 1, size_cells, &start, &count); if (rv != 0) { resource_list_free(&di->di_res); goto out; } /* Check if enough amount of memory is mapped */ if (sc->sc_banks[bank].size < count) { device_printf(sc->sc_dev, "device [%d]: not enough " "memory reserved\n", bank); continue; } regptr += addr_cells - 1 + size_cells; /* Calculate address range relative to VA base. */ start = sc->sc_banks[bank].va + start; end = start + count - 1; debugf("reg addr bank = %d, start = %lx, end = %lx, " "count = %lx\n", bank, start, end, count); /* Use bank (CS) cell as rid. */ resource_list_add(&di->di_res, SYS_RES_MEMORY, di->di_bank, start, end, count); } rv = 0; out: free(reg, M_OFWPROP); return (rv); } static int localbus_probe(device_t dev) { if (!ofw_bus_is_compatible_strict(dev, "mrvl,lbc")) return (ENXIO); device_set_desc(dev, "Marvell device bus"); return (BUS_PROBE_DEFAULT); } static int localbus_attach(device_t dev) { device_t dev_child; struct localbus_softc *sc; struct localbus_devinfo *di; phandle_t dt_node, dt_child; sc = device_get_softc(dev); sc->sc_dev = dev; sc->sc_banks = localbus_banks; /* * Walk localbus and add direct subordinates as our children. */ dt_node = ofw_bus_get_node(dev); for (dt_child = OF_child(dt_node); dt_child != 0; dt_child = OF_peer(dt_child)) { /* Check and process 'status' property. */ if (!(fdt_is_enabled(dt_child))) continue; if (!(fdt_pm_is_enabled(dt_child))) continue; di = malloc(sizeof(*di), M_LOCALBUS, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&di->di_ofw, dt_child) != 0) { free(di, M_LOCALBUS); device_printf(dev, "could not set up devinfo\n"); continue; } resource_list_init(&di->di_res); if (fdt_localbus_reg_decode(dt_child, sc, di)) { device_printf(dev, "could not process 'reg' " "property\n"); ofw_bus_gen_destroy_devinfo(&di->di_ofw); free(di, M_LOCALBUS); continue; } /* Add newbus device for this FDT node */ dev_child = device_add_child(dev, NULL, -1); if (dev_child == NULL) { device_printf(dev, "could not add child: %s\n", di->di_ofw.obd_name); resource_list_free(&di->di_res); ofw_bus_gen_destroy_devinfo(&di->di_ofw); free(di, M_LOCALBUS); continue; } #ifdef DEBUG device_printf(dev, "added child: %s\n\n", di->di_ofw.obd_name); #endif device_set_ivars(dev_child, di); } return (bus_generic_attach(dev)); } static int localbus_print_child(device_t dev, device_t child) { struct localbus_devinfo *di; struct resource_list *rl; int rv; di = device_get_ivars(child); rl = &di->di_res; rv = 0; rv += bus_print_child_header(dev, child); rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); rv += bus_print_child_footer(dev, child); return (rv); } static struct resource * localbus_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct localbus_devinfo *di; struct resource_list_entry *rle; /* * Request for the default allocation with a given rid: use resource * list stored in the local device info. */ if ((start == 0UL) && (end == ~0UL)) { if ((di = device_get_ivars(child)) == NULL) return (NULL); if (type == SYS_RES_IOPORT) type = SYS_RES_MEMORY; rid = &di->di_bank; rle = resource_list_find(&di->di_res, type, *rid); if (rle == NULL) { device_printf(bus, "no default resources for " "rid = %d, type = %d\n", *rid, type); return (NULL); } start = rle->start; end = rle->end; count = rle->count; } return (bus_generic_alloc_resource(bus, child, type, rid, start, end, count, flags)); } static struct resource_list * localbus_get_resource_list(device_t bus, device_t child) { struct localbus_devinfo *di; di = device_get_ivars(child); return (&di->di_res); } static const struct ofw_bus_devinfo * localbus_get_devinfo(device_t bus, device_t child) { struct localbus_devinfo *di; di = device_get_ivars(child); return (&di->di_ofw); } int fdt_localbus_devmap(phandle_t dt_node, struct arm_devmap_entry *fdt_devmap, int banks_max_num, int *banks_added) { pcell_t ranges[MV_LOCALBUS_MAX_BANKS * MV_LOCALBUS_MAX_BANK_CELLS]; pcell_t *rangesptr; uint32_t tuple_size, bank; vm_paddr_t offset; vm_size_t size; int dev_num, addr_cells, size_cells, par_addr_cells, va_index, i, j, k; if ((fdt_addrsize_cells(dt_node, &addr_cells, &size_cells)) != 0) return (EINVAL); par_addr_cells = fdt_parent_addr_cells(dt_node); if (par_addr_cells > 2) { /* * Localbus devmap initialization error: unsupported parent * #addr-cells */ return (ERANGE); } tuple_size = (addr_cells + par_addr_cells + size_cells); if (tuple_size > MV_LOCALBUS_MAX_BANK_CELLS) return (ERANGE); tuple_size *= sizeof(pcell_t); dev_num = OF_getprop(dt_node, "ranges", ranges, sizeof(ranges)); if (dev_num <= 0) return (EINVAL); /* Calculate number of devices attached to bus */ dev_num = dev_num / tuple_size; /* * If number of ranges > max number of localbus devices, * additional entries will not be processed */ dev_num = MIN(dev_num, banks_max_num); rangesptr = &ranges[0]; j = 0; /* Process data from FDT */ for (i = 0; i < dev_num; i++) { /* First field is bank number */ bank = fdt_data_get((void *)rangesptr, 1); rangesptr += 1; if (bank > MV_LOCALBUS_MAX_BANKS) { /* Bank out of range */ rangesptr += ((addr_cells - 1) + par_addr_cells + size_cells); continue; } /* Find virtmap entry for this bank */ va_index = -1; for (k = 0; localbus_virtmap[k].bank >= 0; k++) { if (localbus_virtmap[k].bank == bank) { va_index = k; break; } } /* Check if virtmap entry was found */ if (va_index == -1) { rangesptr += ((addr_cells - 1) + par_addr_cells + size_cells); continue; } /* Remaining child's address fields are unused */ rangesptr += (addr_cells - 1); /* Parent address offset */ offset = fdt_data_get((void *)rangesptr, par_addr_cells); rangesptr += par_addr_cells; /* Last field is size */ size = fdt_data_get((void *)rangesptr, size_cells); rangesptr += size_cells; if (size > localbus_virtmap[va_index].size) { /* Not enough space reserved in virtual memory map */ continue; } fdt_devmap[j].pd_va = localbus_virtmap[va_index].va; fdt_devmap[j].pd_pa = offset; fdt_devmap[j].pd_size = size; fdt_devmap[j].pd_prot = VM_PROT_READ | VM_PROT_WRITE; fdt_devmap[j].pd_cache = PTE_DEVICE; /* Copy data to structure used by localbus driver */ localbus_banks[bank].va = fdt_devmap[j].pd_va; localbus_banks[bank].pa = fdt_devmap[j].pd_pa; localbus_banks[bank].size = fdt_devmap[j].pd_size; localbus_banks[bank].mapped = 1; j++; } *banks_added = j; return (0); } Index: head/sys/arm/mv/mvvar.h =================================================================== --- head/sys/arm/mv/mvvar.h (revision 281086) +++ head/sys/arm/mv/mvvar.h (revision 281087) @@ -1,144 +1,145 @@ /*- * Copyright (c) 2002, 2003 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0var.h, rev 1 * * $FreeBSD$ */ #ifndef _MVVAR_H_ #define _MVVAR_H_ #include #include #include #include #include #include #define MV_TYPE_PCI 0 #define MV_TYPE_PCIE 1 #define MV_MODE_ENDPOINT 0 #define MV_MODE_ROOT 1 struct gpio_config { int gc_gpio; /* GPIO number */ uint32_t gc_flags; /* GPIO flags */ int gc_output; /* GPIO output value */ }; struct decode_win { int target; /* Mbus unit ID */ int attr; /* Attributes of the target interface */ vm_paddr_t base; /* Physical base addr */ uint32_t size; vm_paddr_t remap; }; extern const struct gpio_config mv_gpio_config[]; extern const struct decode_win *cpu_wins; extern const struct decode_win *idma_wins; extern const struct decode_win *xor_wins; extern int idma_wins_no; extern int xor_wins_no; /* Function prototypes */ int mv_gpio_setup_intrhandler(const char *name, driver_filter_t *filt, void (*hand)(void *), void *arg, int pin, int flags, void **cookiep); void mv_gpio_intr_mask(int pin); void mv_gpio_intr_unmask(int pin); void mv_gpio_out(uint32_t pin, uint8_t val, uint8_t enable); uint8_t mv_gpio_in(uint32_t pin); int soc_decode_win(void); void soc_id(uint32_t *dev, uint32_t *rev); void soc_dump_decode_win(void); uint32_t soc_power_ctrl_get(uint32_t mask); void soc_power_ctrl_set(uint32_t mask); uint64_t get_sar_value(void); int decode_win_cpu_set(int target, int attr, vm_paddr_t base, uint32_t size, vm_paddr_t remap); int decode_win_overlap(int, int, const struct decode_win *); int win_cpu_can_remap(int); void decode_win_pcie_setup(u_long); void ddr_disable(int i); int ddr_is_active(int i); uint32_t ddr_base(int i); uint32_t ddr_size(int i); uint32_t ddr_attr(int i); uint32_t ddr_target(int i); uint32_t cpu_extra_feat(void); uint32_t get_tclk(void); uint32_t get_l2clk(void); uint32_t read_cpu_ctrl(uint32_t); void write_cpu_ctrl(uint32_t, uint32_t); #if defined(SOC_MV_ARMADAXP) uint32_t read_cpu_mp_clocks(uint32_t reg); void write_cpu_mp_clocks(uint32_t reg, uint32_t val); uint32_t read_cpu_misc(uint32_t reg); void write_cpu_misc(uint32_t reg, uint32_t val); #endif int mv_pcib_bar_win_set(device_t dev, uint32_t base, uint32_t size, uint32_t remap, int winno, int busno); int mv_pcib_cpu_win_remap(device_t dev, uint32_t remap, uint32_t size); void mv_mask_endpoint_irq(uintptr_t nb, int unit); void mv_unmask_endpoint_irq(uintptr_t nb, int unit); int mv_drbl_get_next_irq(int dir, int unit); void mv_drbl_mask_all(int unit); void mv_drbl_mask_irq(uint32_t irq, int dir, int unit); void mv_drbl_unmask_irq(uint32_t irq, int dir, int unit); void mv_drbl_set_mask(uint32_t val, int dir, int unit); uint32_t mv_drbl_get_mask(int dir, int unit); void mv_drbl_set_cause(uint32_t val, int dir, int unit); uint32_t mv_drbl_get_cause(int dir, int unit); void mv_drbl_set_msg(uint32_t val, int mnr, int dir, int unit); uint32_t mv_drbl_get_msg(int mnr, int dir, int unit); int mv_msi_data(int irq, uint64_t *addr, uint32_t *data); struct arm_devmap_entry; int mv_pci_devmap(phandle_t, struct arm_devmap_entry *, vm_offset_t, vm_offset_t); +int fdt_localbus_devmap(phandle_t, struct arm_devmap_entry *, int, int *); #endif /* _MVVAR_H_ */