Ejemplo n.º 1
0
static int
nf10bmac_attach_fdt(device_t dev)
{
	struct nf10bmac_softc *sc;
	int error;

	sc = device_get_softc(dev);
	sc->nf10bmac_dev = dev;
	sc->nf10bmac_unit = device_get_unit(dev);

	/*
	 * FDT lists our resources.  For convenience we use three different
	 * mappings.  We need to attach them in the oder specified in .dts:
	 * LOOP (size 0x1f), TX (0x2f), RX (0x2f), INTR (0xf).
	 */

	/*
	 * LOOP memory region (this could be a general control region).
	 * 0x00: 32/64bit register to enable a Y-"lopback".
	 */
        sc->nf10bmac_ctrl_rid = 0;
        sc->nf10bmac_ctrl_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
            &sc->nf10bmac_ctrl_rid, RF_ACTIVE);
        if (sc->nf10bmac_ctrl_res == NULL) {
                device_printf(dev, "failed to map memory for CTRL region\n");
                error = ENXIO;
                goto err;
        } 
        if (bootverbose)
                device_printf(sc->nf10bmac_dev, "CTRL region at mem %p-%p\n",
                    (void *)rman_get_start(sc->nf10bmac_ctrl_res),
                    (void *)(rman_get_start(sc->nf10bmac_ctrl_res) + 
                    rman_get_size(sc->nf10bmac_ctrl_res)));

        /*
         * TX and TX metadata FIFO memory region.
         * 0x00: 32/64bit FIFO data,
	 * 0x08: 32/64bit FIFO metadata,
         * 0x10: 32/64bit packet length.
         */
        sc->nf10bmac_tx_mem_rid = 1;
        sc->nf10bmac_tx_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
            &sc->nf10bmac_tx_mem_rid, RF_ACTIVE);
        if (sc->nf10bmac_tx_mem_res == NULL) {
                device_printf(dev, "failed to map memory for TX FIFO\n");
                error = ENXIO;
                goto err;
        }
        if (bootverbose)
                device_printf(sc->nf10bmac_dev, "TX FIFO at mem %p-%p\n",
                    (void *)rman_get_start(sc->nf10bmac_tx_mem_res),
                    (void *)(rman_get_start(sc->nf10bmac_tx_mem_res) +
                    rman_get_size(sc->nf10bmac_tx_mem_res)));

        /*
         * RX and RXC metadata FIFO memory region.
         * 0x00: 32/64bit FIFO data,
	 * 0x08: 32/64bit FIFO metadata,
         * 0x10: 32/64bit packet length.
         */
        sc->nf10bmac_rx_mem_rid = 2;
        sc->nf10bmac_rx_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
            &sc->nf10bmac_rx_mem_rid, RF_ACTIVE);
        if (sc->nf10bmac_rx_mem_res == NULL) {
                device_printf(dev, "failed to map memory for RX FIFO\n");
                error = ENXIO;
                goto err;
        } 
        if (bootverbose)
                device_printf(sc->nf10bmac_dev, "RX FIFO at mem %p-%p\n",
                    (void *)rman_get_start(sc->nf10bmac_rx_mem_res),
                    (void *)(rman_get_start(sc->nf10bmac_rx_mem_res) + 
                    rman_get_size(sc->nf10bmac_rx_mem_res)));

	/*
	 * Interrupt handling registers.
	 * 0x00: 32/64bit register to clear (and disable) the RX interrupt.
	 * 0x08: 32/64bit register to enable or disable the RX interrupt.
	 */
        sc->nf10bmac_intr_rid = 3;
        sc->nf10bmac_intr_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
            &sc->nf10bmac_intr_rid, RF_ACTIVE);
        if (sc->nf10bmac_intr_res == NULL) {
                device_printf(dev, "failed to map memory for INTR region\n");
                error = ENXIO;
                goto err;
        } 
        if (bootverbose)
                device_printf(sc->nf10bmac_dev, "INTR region at mem %p-%p\n",
                    (void *)rman_get_start(sc->nf10bmac_intr_res),
                    (void *)(rman_get_start(sc->nf10bmac_intr_res) + 
                    rman_get_size(sc->nf10bmac_intr_res)));

	/* (Optional) RX and TX IRQ. */
	sc->nf10bmac_rx_irq_rid = 0;
	sc->nf10bmac_rx_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
	    &sc->nf10bmac_rx_irq_rid, RF_ACTIVE | RF_SHAREABLE);

	error = nf10bmac_attach(dev);
	if (error)
		goto err;

	return (0);

err:
	/* Cleanup. */
	nf10bmac_detach_resources(dev);

	return (error);
}
Ejemplo n.º 2
0
static int
ata_macio_attach(device_t dev)
{
	struct ata_macio_softc *sc = device_get_softc(dev);
	uint32_t timingreg;
	struct ata_channel *ch;
	int rid, i;

	/*
	 * Allocate resources
	 */

	rid = 0;
	ch = &sc->sc_ch.sc_ch;
	sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 
	    RF_ACTIVE);
	if (sc->sc_mem == NULL) {
		device_printf(dev, "could not allocate memory\n");
		return (ENXIO);
	}

	/*
	 * Set up the resource vectors
	 */
	for (i = ATA_DATA; i <= ATA_COMMAND; i++) {
		ch->r_io[i].res = sc->sc_mem;
		ch->r_io[i].offset = i * ATA_MACIO_REGGAP;
	}
	ch->r_io[ATA_CONTROL].res = sc->sc_mem;
	ch->r_io[ATA_CONTROL].offset = ATA_MACIO_ALTOFFSET;
	ata_default_registers(dev);

	ch->unit = 0;
	ch->flags |= ATA_USE_16BIT | ATA_NO_ATAPI_DMA;
	ata_generic_hw(dev);

#if USE_DBDMA_IRQ
	int dbdma_irq_rid = 1;
	struct resource *dbdma_irq;
	void *cookie;
#endif

	/* Init DMA engine */

	sc->sc_ch.dbdma_rid = 1;
	sc->sc_ch.dbdma_regs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 
	    &sc->sc_ch.dbdma_rid, RF_ACTIVE); 

	ata_dbdma_dmainit(dev);

	/* Configure initial timings */
	timingreg = bus_read_4(sc->sc_mem, ATA_MACIO_TIMINGREG);
	if (sc->rev == 4) {
		sc->udmaconf[0] = sc->udmaconf[1] = timingreg & 0x1ff00000;
		sc->wdmaconf[0] = sc->wdmaconf[1] = timingreg & 0x001ffc00;
		sc->pioconf[0]  = sc->pioconf[1]  = timingreg & 0x000003ff;
	} else {
		sc->udmaconf[0] = sc->udmaconf[1] = 0;
		sc->wdmaconf[0] = sc->wdmaconf[1] = timingreg & 0xfffff800;
		sc->pioconf[0]  = sc->pioconf[1]  = timingreg & 0x000007ff;
	}

#if USE_DBDMA_IRQ
	/* Bind to DBDMA interrupt as well */

	if ((dbdma_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
	    &dbdma_irq_rid, RF_SHAREABLE | RF_ACTIVE)) != NULL) {
		bus_setup_intr(dev, dbdma_irq, ATA_INTR_FLAGS, NULL,
			(driver_intr_t *)ata_interrupt, sc,&cookie);
	} 
#endif

	/* Set begin_transaction */
	sc->sc_ch.sc_ch.hw.begin_transaction = ata_macio_begin_transaction;

	return ata_attach(dev);
}
Ejemplo n.º 3
0
static int
sbni_attach_isa(device_t dev)
{
	struct sbni_softc *sc;
	struct sbni_flags flags;
	int error;
   
	sc = device_get_softc(dev);
	sc->dev = dev;

	sc->irq_res = bus_alloc_resource_any(
	    dev, SYS_RES_IRQ, &sc->irq_rid, RF_ACTIVE);

#ifndef SBNI_DUAL_COMPOUND

	if (sc->irq_res == NULL) {
		device_printf(dev, "irq conflict!\n");
		sbni_release_resources(sc);
		return (ENOENT);
	}

#else	/* SBNI_DUAL_COMPOUND */

	if (sc->irq_res) {
		sbni_add(sc);
	} else {
		struct sbni_softc  *master;

		if ((master = connect_to_master(sc)) == 0) {
			device_printf(dev, "failed to alloc irq\n");
			sbni_release_resources(sc);
			return (ENXIO);
		} else {
			device_printf(dev, "shared irq with %s\n",
			       master->ifp->if_xname);
		}
	} 
#endif	/* SBNI_DUAL_COMPOUND */

	*(u_int32_t*)&flags = device_get_flags(dev);

	error = sbni_attach(sc, device_get_unit(dev) * 2, flags);
	if (error) {
		device_printf(dev, "cannot initialize driver\n");
		sbni_release_resources(sc);
		return (error);
	}

	if (sc->irq_res) {
		error = bus_setup_intr(
		    dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE,
		    NULL, sbni_intr, sc, &sc->irq_handle);
		if (error) {
			device_printf(dev, "bus_setup_intr\n");
			sbni_detach(sc);
			sbni_release_resources(sc);
			return (error);
		}
	}

	return (0);
}
Ejemplo n.º 4
0
/********************************************************************************
 * Allocate resources, initialise the controller.
 */
static int
twe_attach(device_t dev)
{
    struct twe_softc	*sc;
    struct sysctl_oid	*sysctl_tree;
    int			rid, error;

    debug_called(4);

    /*
     * Initialise the softc structure.
     */
    sc = device_get_softc(dev);
    sc->twe_dev = dev;
    mtx_init(&sc->twe_io_lock, "twe I/O", NULL, MTX_DEF);
    sx_init(&sc->twe_config_lock, "twe config");

    /*
     * XXX: This sysctl tree must stay at hw.tweX rather than using
     * the device_get_sysctl_tree() created by new-bus because
     * existing 3rd party binary tools such as tw_cli and 3dm2 use the
     * existence of this sysctl node to discover controllers.
     */
    sysctl_tree = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev),
	SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
	device_get_nameunit(dev), CTLFLAG_RD, 0, "");
    if (sysctl_tree == NULL) {
	twe_printf(sc, "cannot add sysctl tree node\n");
	return (ENXIO);
    }
    SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(sysctl_tree),
	OID_AUTO, "driver_version", CTLFLAG_RD, TWE_DRIVER_VERSION_STRING, 0,
	"TWE driver version");

    /*
     * Force the busmaster enable bit on, in case the BIOS forgot.
     */
    pci_enable_busmaster(dev);

    /*
     * Allocate the PCI register window.
     */
    rid = TWE_IO_CONFIG_REG;
    if ((sc->twe_io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 
        RF_ACTIVE)) == NULL) {
	twe_printf(sc, "can't allocate register window\n");
	twe_free(sc);
	return(ENXIO);
    }

    /*
     * Allocate the parent bus DMA tag appropriate for PCI.
     */
    if (bus_dma_tag_create(bus_get_dma_tag(dev),		/* PCI parent */
			   1, 0, 				/* alignment, boundary */
			   BUS_SPACE_MAXADDR_32BIT, 		/* lowaddr */
			   BUS_SPACE_MAXADDR, 			/* highaddr */
			   NULL, NULL, 				/* filter, filterarg */
			   MAXBSIZE, TWE_MAX_SGL_LENGTH,	/* maxsize, nsegments */
			   BUS_SPACE_MAXSIZE_32BIT,		/* maxsegsize */
			   0,					/* flags */
			   NULL,				/* lockfunc */
			   NULL,				/* lockarg */
			   &sc->twe_parent_dmat)) {
	twe_printf(sc, "can't allocate parent DMA tag\n");
	twe_free(sc);
	return(ENOMEM);
    }

    /* 
     * Allocate and connect our interrupt.
     */
    rid = 0;
    if ((sc->twe_irq = bus_alloc_resource_any(sc->twe_dev, SYS_RES_IRQ,
        &rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
	twe_printf(sc, "can't allocate interrupt\n");
	twe_free(sc);
	return(ENXIO);
    }
    if (bus_setup_intr(sc->twe_dev, sc->twe_irq, INTR_TYPE_BIO | INTR_ENTROPY | INTR_MPSAFE,  
		       NULL, twe_pci_intr, sc, &sc->twe_intr)) {
	twe_printf(sc, "can't set up interrupt\n");
	twe_free(sc);
	return(ENXIO);
    }

    /*
     * Create DMA tag for mapping command's into controller-addressable space.
     */
    if (bus_dma_tag_create(sc->twe_parent_dmat, 	/* parent */
			   1, 0, 			/* alignment, boundary */
			   BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
			   BUS_SPACE_MAXADDR, 		/* highaddr */
			   NULL, NULL, 			/* filter, filterarg */
			   sizeof(TWE_Command) *
			   TWE_Q_LENGTH, 1,		/* maxsize, nsegments */
			   BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
			   0,				/* flags */
			   NULL,			/* lockfunc */
			   NULL,			/* lockarg */
			   &sc->twe_cmd_dmat)) {
	twe_printf(sc, "can't allocate data buffer DMA tag\n");
	twe_free(sc);
	return(ENOMEM);
    }
    /*
     * Allocate memory and make it available for DMA.
     */
    if (bus_dmamem_alloc(sc->twe_cmd_dmat, (void **)&sc->twe_cmd,
			 BUS_DMA_NOWAIT, &sc->twe_cmdmap)) {
	twe_printf(sc, "can't allocate command memory\n");
	return(ENOMEM);
    }
    bus_dmamap_load(sc->twe_cmd_dmat, sc->twe_cmdmap, sc->twe_cmd,
		    sizeof(TWE_Command) * TWE_Q_LENGTH,
		    twe_setup_request_dmamap, sc, 0);
    bzero(sc->twe_cmd, sizeof(TWE_Command) * TWE_Q_LENGTH);

    /*
     * Create DMA tag for mapping objects into controller-addressable space.
     */
    if (bus_dma_tag_create(sc->twe_parent_dmat, 	/* parent */
			   1, 0, 			/* alignment, boundary */
			   BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
			   BUS_SPACE_MAXADDR, 		/* highaddr */
			   NULL, NULL, 			/* filter, filterarg */
			   MAXBSIZE, TWE_MAX_SGL_LENGTH,/* maxsize, nsegments */
			   BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
			   BUS_DMA_ALLOCNOW,		/* flags */
			   busdma_lock_mutex,		/* lockfunc */
			   &sc->twe_io_lock,		/* lockarg */
			   &sc->twe_buffer_dmat)) {
	twe_printf(sc, "can't allocate data buffer DMA tag\n");
	twe_free(sc);
	return(ENOMEM);
    }

    /*
     * Create DMA tag for mapping objects into controller-addressable space.
     */
    if (bus_dma_tag_create(sc->twe_parent_dmat, 	/* parent */
			   1, 0, 			/* alignment, boundary */
			   BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
			   BUS_SPACE_MAXADDR, 		/* highaddr */
			   NULL, NULL, 			/* filter, filterarg */
			   MAXBSIZE, 1,			/* maxsize, nsegments */
			   BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
			   0,				/* flags */
			   NULL,			/* lockfunc */
			   NULL,			/* lockarg */
			   &sc->twe_immediate_dmat)) {
	twe_printf(sc, "can't allocate data buffer DMA tag\n");
	twe_free(sc);
	return(ENOMEM);
    }
    /*
     * Allocate memory for requests which cannot sleep or support continuation.
     */
     if (bus_dmamem_alloc(sc->twe_immediate_dmat, (void **)&sc->twe_immediate,
			  BUS_DMA_NOWAIT, &sc->twe_immediate_map)) {
	twe_printf(sc, "can't allocate memory for immediate requests\n");
	return(ENOMEM);
     }

    /*
     * Initialise the controller and driver core.
     */
    if ((error = twe_setup(sc))) {
	twe_free(sc);
	return(error);
    }

    /*
     * Print some information about the controller and configuration.
     */
    twe_describe_controller(sc);

    /*
     * Create the control device.
     */
    sc->twe_dev_t = make_dev(&twe_cdevsw, device_get_unit(sc->twe_dev), UID_ROOT, GID_OPERATOR,
			     S_IRUSR | S_IWUSR, "twe%d", device_get_unit(sc->twe_dev));
    sc->twe_dev_t->si_drv1 = sc;
    /*
     * Schedule ourselves to bring the controller up once interrupts are available.
     * This isn't strictly necessary, since we disable interrupts while probing the
     * controller, but it is more in keeping with common practice for other disk 
     * devices.
     */
    sc->twe_ich.ich_func = twe_intrhook;
    sc->twe_ich.ich_arg = sc;
    if (config_intrhook_establish(&sc->twe_ich) != 0) {
	twe_printf(sc, "can't establish configuration hook\n");
	twe_free(sc);
	return(ENXIO);
    }

    return(0);
}
Ejemplo n.º 5
0
/*
 * Standard attach entry point.
 *
 * Called when the driver is loaded.  It allocates needed resources,
 * and initializes the "hardware" and software.
 */
static int
netvsc_attach(device_t dev)
{
	struct hv_device *device_ctx = vmbus_get_devctx(dev);
	netvsc_device_info device_info;
	hn_softc_t *sc;
	int unit = device_get_unit(dev);
	struct ifnet *ifp;
	int ret;

	netvsc_init();

	sc = device_get_softc(dev);
	if (sc == NULL) {
		return (ENOMEM);
	}

	bzero(sc, sizeof(hn_softc_t));
	sc->hn_unit = unit;
	sc->hn_dev = dev;

	NV_LOCK_INIT(sc, "NetVSCLock");

	sc->hn_dev_obj = device_ctx;

	ifp = sc->hn_ifp = sc->arpcom.ac_ifp = if_alloc(IFT_ETHER);
	ifp->if_softc = sc;

	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
	ifp->if_dunit = unit;
	ifp->if_dname = NETVSC_DEVNAME;

	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
	ifp->if_ioctl = hn_ioctl;
	ifp->if_start = hn_start;
	ifp->if_init = hn_ifinit;
	/* needed by hv_rf_on_device_add() code */
	ifp->if_mtu = ETHERMTU;
	IFQ_SET_MAXLEN(&ifp->if_snd, 512);
	ifp->if_snd.ifq_drv_maxlen = 511;
	IFQ_SET_READY(&ifp->if_snd);

	/*
	 * Tell upper layers that we support full VLAN capability.
	 */
	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
	ifp->if_capenable |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;

	ret = hv_rf_on_device_add(device_ctx, &device_info);
	if (ret != 0) {
		if_free(ifp);

		return (ret);
	}
	if (device_info.link_state == 0) {
		sc->hn_carrier = 1;
	}

	ether_ifattach(ifp, device_info.mac_addr);

	return (0);
}
Ejemplo n.º 6
0
static int
at91_attach(device_t dev)
{
	struct at91_pmc_clock *clk;
	struct at91sam9_softc *sc = device_get_softc(dev);
	int i;

	struct at91_softc *at91sc = device_get_softc(device_get_parent(dev));

	sc->sc_st = at91sc->sc_st;
	sc->sc_sh = at91sc->sc_sh;
	sc->dev = dev;

	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9260_SYS_BASE,
	    AT91SAM9260_SYS_SIZE, &sc->sc_sys_sh) != 0)
		panic("Enable to map system registers");

	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9260_DBGU_BASE,
	    AT91SAM9260_DBGU_SIZE, &sc->sc_dbg_sh) != 0)
		panic("Enable to map DBGU registers");

	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9260_AIC_BASE,
	    AT91SAM9260_AIC_SIZE, &sc->sc_aic_sh) != 0)
		panic("Enable to map system registers");

	/* XXX Hack to tell atmelarm about the AIC */
	at91sc->sc_aic_sh = sc->sc_aic_sh;
	at91sc->sc_irq_system = AT91SAM9260_IRQ_SYSTEM;

	for (i = 0; i < 32; i++) {
		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SVR +
		    i * 4, i);
		/* Priority. */
		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SMR + i * 4,
		    at91_irq_prio[i]);
		if (i < 8)
			bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_EOICR,
			    1);
	}

	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SPU, 32);
	/* No debug. */
	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_DCR, 0);
	/* Disable and clear all interrupts. */
	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 0xffffffff);
	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_ICCR, 0xffffffff);

	/* Disable all interrupts for DBGU */
	bus_space_write_4(sc->sc_st, sc->sc_dbg_sh, 0x0c, 0xffffffff);

	if (bus_space_subregion(sc->sc_st, sc->sc_sh,
	    AT91SAM9260_MATRIX_BASE, AT91SAM9260_MATRIX_SIZE,
	    &sc->sc_matrix_sh) != 0)
		panic("Enable to map matrix registers");

	/* activate NAND*/
	i = bus_space_read_4(sc->sc_st, sc->sc_matrix_sh,
	    AT91SAM9260_EBICSA);
	bus_space_write_4(sc->sc_st, sc->sc_matrix_sh,
	    AT91SAM9260_EBICSA,
	    i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);

	/* Update USB device port clock info */
	clk = at91_pmc_clock_ref("udpck");
	clk->pmc_mask  = PMC_SCER_UDP_SAM9;
	at91_pmc_clock_deref(clk);

	/* Update USB host port clock info */
	clk = at91_pmc_clock_ref("uhpck");
	clk->pmc_mask  = PMC_SCER_UHP_SAM9;
	at91_pmc_clock_deref(clk);

	/* Each SOC has different PLL contraints */
	clk = at91_pmc_clock_ref("plla");
	clk->pll_min_in    = SAM9260_PLL_A_MIN_IN_FREQ;		/*   1 MHz */
	clk->pll_max_in    = SAM9260_PLL_A_MAX_IN_FREQ;		/*  32 MHz */
	clk->pll_min_out   = SAM9260_PLL_A_MIN_OUT_FREQ;	/*  80 MHz */
	clk->pll_max_out   = SAM9260_PLL_A_MAX_OUT_FREQ;	/* 240 MHz */
	clk->pll_mul_shift = SAM9260_PLL_A_MUL_SHIFT;
	clk->pll_mul_mask  = SAM9260_PLL_A_MUL_MASK;
	clk->pll_div_shift = SAM9260_PLL_A_DIV_SHIFT;
	clk->pll_div_mask  = SAM9260_PLL_A_DIV_MASK;
	clk->set_outb      = at91_pll_outa;
	at91_pmc_clock_deref(clk);

	/*
	 * Fudge MAX pll in frequence down below 3.0 MHz to ensure
	 * PMC alogrithm choose the divisor that causes the input clock
	 * to be near the optimal 2 MHz per datasheet.  We know
	 * we are going to be using this for the USB clock at 96 MHz.
	 * Causes no extra frequency deviation for all recomended crystal
	 * values.
	 */
	clk = at91_pmc_clock_ref("pllb");
	clk->pll_min_in    = SAM9260_PLL_B_MIN_IN_FREQ;		/*   1 MHz */
	clk->pll_max_in    = SAM9260_PLL_B_MAX_IN_FREQ;		/*   5 MHz */
	clk->pll_max_in    = 2999999;				/*  ~3 MHz */
	clk->pll_min_out   = SAM9260_PLL_B_MIN_OUT_FREQ;	/*  70 MHz */
	clk->pll_max_out   = SAM9260_PLL_B_MAX_OUT_FREQ;	/* 130 MHz */
	clk->pll_mul_shift = SAM9260_PLL_B_MUL_SHIFT;
	clk->pll_mul_mask  = SAM9260_PLL_B_MUL_MASK;
	clk->pll_div_shift = SAM9260_PLL_B_DIV_SHIFT;
	clk->pll_div_mask  = SAM9260_PLL_B_DIV_MASK;
	clk->set_outb      = at91_pll_outb;
	at91_pmc_clock_deref(clk);
	return (0);
}
Ejemplo n.º 7
0
static int
at91_udp_detach(device_t dev)
{
    struct at91_udp_softc *sc = device_get_softc(dev);
    device_t bdev;
    int err;

    if (sc->sc_dci.sc_bus.bdev) {
        bdev = sc->sc_dci.sc_bus.bdev;
        device_detach(bdev);
        device_delete_child(dev, bdev);
    }
    /* during module unload there are lots of children leftover */
    device_delete_all_children(dev);

    /* disable Transceiver */
    AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_TXVC, AT91_UDP_TXVC_DIS);

    /* disable and clear all interrupts */
    AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_IDR, 0xFFFFFFFF);
    AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_ICR, 0xFFFFFFFF);

    /* disable VBUS interrupt */
    at91_pio_gpio_set_interrupt(VBUS_BASE, VBUS_MASK, 0);

    if (sc->sc_vbus_irq_res && sc->sc_vbus_intr_hdl) {
        err = bus_teardown_intr(dev, sc->sc_vbus_irq_res,
                                sc->sc_vbus_intr_hdl);
        sc->sc_vbus_intr_hdl = NULL;
    }
    if (sc->sc_vbus_irq_res) {
        bus_release_resource(dev, SYS_RES_IRQ, 1,
                             sc->sc_vbus_irq_res);
        sc->sc_vbus_irq_res = NULL;
    }
    if (sc->sc_dci.sc_irq_res && sc->sc_dci.sc_intr_hdl) {
        /*
         * only call at91_udp_uninit() after at91_udp_init()
         */
        at91dci_uninit(&sc->sc_dci);

        err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res,
                                sc->sc_dci.sc_intr_hdl);
        sc->sc_dci.sc_intr_hdl = NULL;
    }
    if (sc->sc_dci.sc_irq_res) {
        bus_release_resource(dev, SYS_RES_IRQ, 0,
                             sc->sc_dci.sc_irq_res);
        sc->sc_dci.sc_irq_res = NULL;
    }
    if (sc->sc_dci.sc_io_res) {
        bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID,
                             sc->sc_dci.sc_io_res);
        sc->sc_dci.sc_io_res = NULL;
    }
    usb_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL);

    /* disable clocks */
    at91_pmc_clock_disable(sc->sc_iclk);
    at91_pmc_clock_disable(sc->sc_fclk);
    at91_pmc_clock_deref(sc->sc_fclk);
    at91_pmc_clock_deref(sc->sc_iclk);

    return (0);
}
Ejemplo n.º 8
0
static int
ehci_pci_attach(device_t self)
{
	ehci_softc_t *sc = device_get_softc(self);
	int err;
	int rid;

	/* initialise some bus fields */
	sc->sc_bus.parent = self;
	sc->sc_bus.devices = sc->sc_devices;
	sc->sc_bus.devices_max = EHCI_MAX_DEVICES;

	/* get all DMA memory */
	if (usb_bus_mem_alloc_all(&sc->sc_bus,
	    USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) {
		return (ENOMEM);
	}

	pci_enable_busmaster(self);

	switch (pci_read_config(self, PCI_USBREV, 1) & PCI_USB_REV_MASK) {
	case PCI_USB_REV_PRE_1_0:
	case PCI_USB_REV_1_0:
	case PCI_USB_REV_1_1:
		/*
		 * NOTE: some EHCI USB controllers have the wrong USB
		 * revision number. It appears those controllers are
		 * fully compliant so we just ignore this value in
		 * some common cases.
		 */
		device_printf(self, "pre-2.0 USB revision (ignored)\n");
		/* fallthrough */
	case PCI_USB_REV_2_0:
		break;
	default:
		/* Quirk for Parallels Desktop 4.0 */
		device_printf(self, "USB revision is unknown. Assuming v2.0.\n");
		break;
	}

	rid = PCI_CBMEM;
	sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid,
	    RF_ACTIVE);
	if (!sc->sc_io_res) {
		device_printf(self, "Could not map memory\n");
		goto error;
	}
	sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
	sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
	sc->sc_io_size = rman_get_size(sc->sc_io_res);

	rid = 0;
	sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid,
	    RF_SHAREABLE | RF_ACTIVE);
	if (sc->sc_irq_res == NULL) {
		device_printf(self, "Could not allocate irq\n");
		goto error;
	}
	sc->sc_bus.bdev = device_add_child(self, "usbus", -1);
	if (!sc->sc_bus.bdev) {
		device_printf(self, "Could not add USB device\n");
		goto error;
	}
	device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);

	/*
	 * ehci_pci_match will never return NULL if ehci_pci_probe
	 * succeeded
	 */
	device_set_desc(sc->sc_bus.bdev, ehci_pci_match(self));
	switch (pci_get_vendor(self)) {
	case PCI_EHCI_VENDORID_ACERLABS:
		sprintf(sc->sc_vendor, "AcerLabs");
		break;
	case PCI_EHCI_VENDORID_AMD:
		sprintf(sc->sc_vendor, "AMD");
		break;
	case PCI_EHCI_VENDORID_APPLE:
		sprintf(sc->sc_vendor, "Apple");
		break;
	case PCI_EHCI_VENDORID_ATI:
		sprintf(sc->sc_vendor, "ATI");
		break;
	case PCI_EHCI_VENDORID_CMDTECH:
		sprintf(sc->sc_vendor, "CMDTECH");
		break;
	case PCI_EHCI_VENDORID_INTEL:
		sprintf(sc->sc_vendor, "Intel");
		break;
	case PCI_EHCI_VENDORID_NEC:
		sprintf(sc->sc_vendor, "NEC");
		break;
	case PCI_EHCI_VENDORID_OPTI:
		sprintf(sc->sc_vendor, "OPTi");
		break;
	case PCI_EHCI_VENDORID_PHILIPS:
		sprintf(sc->sc_vendor, "Philips");
		break;
	case PCI_EHCI_VENDORID_SIS:
		sprintf(sc->sc_vendor, "SiS");
		break;
	case PCI_EHCI_VENDORID_NVIDIA:
	case PCI_EHCI_VENDORID_NVIDIA2:
		sprintf(sc->sc_vendor, "nVidia");
		break;
	case PCI_EHCI_VENDORID_VIA:
		sprintf(sc->sc_vendor, "VIA");
		break;
	default:
		if (bootverbose)
			device_printf(self, "(New EHCI DeviceId=0x%08x)\n",
			    pci_get_devid(self));
		sprintf(sc->sc_vendor, "(0x%04x)", pci_get_vendor(self));
	}

#if (__FreeBSD_version >= 700031)
	err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
	    NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl);
#else
	err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
	    (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl);
#endif
	if (err) {
		device_printf(self, "Could not setup irq, %d\n", err);
		sc->sc_intr_hdl = NULL;
		goto error;
	}
	ehci_pci_take_controller(self);

	/* Undocumented quirks taken from Linux */

	switch (pci_get_vendor(self)) {
	case PCI_EHCI_VENDORID_ATI:
		/* SB600 and SB700 EHCI quirk */
		switch (pci_get_device(self)) {
		case 0x4386:
			ehci_pci_ati_quirk(self, 0);
			break;
		case 0x4396:
			ehci_pci_ati_quirk(self, 1);
			break;
		default:
			break;
		}
		break;

	case PCI_EHCI_VENDORID_VIA:
		ehci_pci_via_quirk(self);
		break;

	default:
		break;
	}

	/* Dropped interrupts workaround */
	switch (pci_get_vendor(self)) {
	case PCI_EHCI_VENDORID_ATI:
	case PCI_EHCI_VENDORID_VIA:
		sc->sc_flags |= EHCI_SCFLG_LOSTINTRBUG;
		if (bootverbose)
			device_printf(self,
			    "Dropped interrupts workaround enabled\n");
		break;
	default:
		break;
	}

	/* Doorbell feature workaround */
	switch (pci_get_vendor(self)) {
	case PCI_EHCI_VENDORID_NVIDIA:
	case PCI_EHCI_VENDORID_NVIDIA2:
		sc->sc_flags |= EHCI_SCFLG_IAADBUG;
		if (bootverbose)
			device_printf(self,
			    "Doorbell workaround enabled\n");
		break;
	default:
		break;
	}

	err = ehci_init(sc);
	if (!err) {
		err = device_probe_and_attach(sc->sc_bus.bdev);
	}
	if (err) {
		device_printf(self, "USB init failed err=%d\n", err);
		goto error;
	}
	return (0);

error:
	ehci_pci_detach(self);
	return (ENXIO);
}
Ejemplo n.º 9
0
static int
pl310_attach(device_t dev)
{
	struct pl310_softc *sc = device_get_softc(dev);
	int rid;
	uint32_t cache_id, debug_ctrl;
	phandle_t node;

	sc->sc_dev = dev;
	rid = 0;
	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
	    RF_ACTIVE);
	if (sc->sc_mem_res == NULL)
		panic("%s: Cannot map registers", device_get_name(dev));

	/* Allocate an IRQ resource */
	rid = 0;
	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
	                                        RF_ACTIVE | RF_SHAREABLE);
	if (sc->sc_irq_res == NULL) {
		device_printf(dev, "cannot allocate IRQ, not using interrupt\n");
	}

	pl310_softc = sc;
	mtx_init(&sc->sc_mtx, "pl310lock", NULL, MTX_SPIN);

	cache_id = pl310_read4(sc, PL310_CACHE_ID);
	sc->sc_rtl_revision = (cache_id >> CACHE_ID_RELEASE_SHIFT) &
	    CACHE_ID_RELEASE_MASK;
	device_printf(dev, "Part number: 0x%x, release: 0x%x\n",
	    (cache_id >> CACHE_ID_PARTNUM_SHIFT) & CACHE_ID_PARTNUM_MASK,
	    (cache_id >> CACHE_ID_RELEASE_SHIFT) & CACHE_ID_RELEASE_MASK);

	/*
	 * Test for "arm,io-coherent" property and disable sync operation if
	 * platform is I/O coherent. Outer sync operations are not needed
	 * on coherent platform and may be harmful in certain situations.
	 */
	node = ofw_bus_get_node(dev);
	if (OF_hasprop(node, "arm,io-coherent"))
		sc->sc_io_coherent = true;

	/*
	 * If L2 cache is already enabled then something has violated the rules,
	 * because caches are supposed to be off at kernel entry.  The cache
	 * must be disabled to write the configuration registers without
	 * triggering an access error (SLVERR), but there's no documented safe
	 * procedure for disabling the L2 cache in the manual.  So we'll try to
	 * invent one:
	 *  - Use the debug register to force write-through mode and prevent
	 *    linefills (allocation of new lines on read); now anything we do
	 *    will not cause new data to come into the L2 cache.
	 *  - Writeback and invalidate the current contents.
	 *  - Disable the controller.
	 *  - Restore the original debug settings.
	 */
	if (pl310_read4(sc, PL310_CTRL) & CTRL_ENABLED) {
		device_printf(dev, "Warning: L2 Cache should not already be "
		    "active; trying to de-activate and re-initialize...\n");
		sc->sc_enabled = 1;
		debug_ctrl = pl310_read4(sc, PL310_DEBUG_CTRL);
		platform_pl310_write_debug(sc, debug_ctrl |
		    DEBUG_CTRL_DISABLE_WRITEBACK | DEBUG_CTRL_DISABLE_LINEFILL);
		pl310_set_way_sizes(sc);
		pl310_wbinv_all();
		platform_pl310_write_ctrl(sc, CTRL_DISABLED);
		platform_pl310_write_debug(sc, debug_ctrl);
	}
	sc->sc_enabled = pl310_enabled;

	if (sc->sc_enabled) {
		platform_pl310_init(sc);
		pl310_set_way_sizes(sc); /* platform init might change these */
		pl310_write4(pl310_softc, PL310_INV_WAY, 0xffff);
		pl310_wait_background_op(PL310_INV_WAY, 0xffff);
		platform_pl310_write_ctrl(sc, CTRL_ENABLED);
		device_printf(dev, "L2 Cache enabled: %uKB/%dB %d ways\n",
		    (g_l2cache_size / 1024), g_l2cache_line_size, g_ways_assoc);
		if (bootverbose)
			pl310_print_config(sc);
	} else {
		if (sc->sc_irq_res != NULL) {
			sc->sc_ich = malloc(sizeof(*sc->sc_ich), M_DEVBUF, M_WAITOK);
			sc->sc_ich->ich_func = pl310_config_intr;
			sc->sc_ich->ich_arg = sc;
			if (config_intrhook_establish(sc->sc_ich) != 0) {
				device_printf(dev,
				    "config_intrhook_establish failed\n");
				free(sc->sc_ich, M_DEVBUF);
				return(ENXIO);
			}
		}

		device_printf(dev, "L2 Cache disabled\n");
	}

	/* Set the l2 functions in the set of cpufuncs */
	cpufuncs.cf_l2cache_wbinv_all = pl310_wbinv_all;
	cpufuncs.cf_l2cache_wbinv_range = pl310_wbinv_range;
	cpufuncs.cf_l2cache_inv_range = pl310_inv_range;
	cpufuncs.cf_l2cache_wb_range = pl310_wb_range;
	cpufuncs.cf_l2cache_drain_writebuf = pl310_drain_writebuf;

	return (0);
}
Ejemplo n.º 10
0
static int
clkbrd_attach(device_t dev)
{
	struct clkbrd_softc *sc;
	int i, slots;
	uint8_t r;

	sc = device_get_softc(dev);
	sc->sc_dev = dev;

	for (i = CLKBRD_CF; i <= CLKBRD_CLKVER; i++) {
		sc->sc_rid[i] = i;
		sc->sc_res[i] = bus_alloc_resource_any(sc->sc_dev,
		    SYS_RES_MEMORY, &sc->sc_rid[i], RF_ACTIVE);
		if (sc->sc_res[i] == NULL) {
			if (i != CLKBRD_CLKVER) {
				device_printf(sc->sc_dev,
				    "could not allocate resource %d\n", i);
				goto fail;
			}
			continue;
		}
		sc->sc_bt[i] = rman_get_bustag(sc->sc_res[i]);
		sc->sc_bh[i] = rman_get_bushandle(sc->sc_res[i]);
		if (i == CLKBRD_CLKVER)
			sc->sc_flags |= CLKBRD_HAS_CLKVER;
	}

	slots = 4;
	r = bus_space_read_1(sc->sc_bt[CLKBRD_CLK], sc->sc_bh[CLKBRD_CLK],
	    CLK_STS1);
	switch (r & CLK_STS1_SLOTS_MASK) {
	case CLK_STS1_SLOTS_16:
		slots = 16;
		break;
	case CLK_STS1_SLOTS_8:
		slots = 8;
		break;
	case CLK_STS1_SLOTS_4:
		if (sc->sc_flags & CLKBRD_HAS_CLKVER) {
			r = bus_space_read_1(sc->sc_bt[CLKBRD_CLKVER],
			    sc->sc_bh[CLKBRD_CLKVER], CLKVER_SLOTS);
			if (r != 0 &&
			    (r & CLKVER_SLOTS_MASK) == CLKVER_SLOTS_PLUS)
				slots = 5;
		}
	}

	device_printf(sc->sc_dev, "Sun Enterprise Exx00 machine: %d slots\n",
	    slots);

	sc->sc_clk_ctrl = bus_space_read_1(sc->sc_bt[CLKBRD_CLK],
	    sc->sc_bh[CLKBRD_CLK], CLK_CTRL);
	sc->sc_led_dev = led_create(clkbrd_led_func, sc, "clockboard");

	return (0);

 fail:
	clkbrd_free_resources(sc);

	return (ENXIO);
}
Ejemplo n.º 11
0
static int
i2c_start(device_t dev, u_char slave, int timeout)
{
	struct i2c_softc *sc;
	int error;
	int reg;

	sc = device_get_softc(dev);

	DPRINTF("i2c start\n");

	mtx_lock(&sc->mutex);

#if 0
	DPRINTF("I2CCON == 0x%08x\n", READ1(sc, I2CCON));
	DPRINTF("I2CSTAT == 0x%08x\n", READ1(sc, I2CSTAT));
#endif

	if (slave & 1) {
		slave &= ~(1);
		slave <<= 1;
		slave |= 1;
	} else {
		slave <<= 1;
	}

	error = wait_for_nibb(sc);
	if (error) {
		mtx_unlock(&sc->mutex);
		DPRINTF("cant i2c start: IIC_EBUSERR\n");
		return (IIC_EBUSERR);
	}

	reg = READ1(sc, I2CCON);
	reg |= (IRQ_EN | ACKGEN);
	WRITE1(sc, I2CCON, reg);

	WRITE1(sc, I2CDS, slave);
	DELAY(50);

	reg = (RXTX_EN);
	reg |= I2C_START_STOP;
	reg |= (I2CMODE_MT << I2CMODE_S);
	WRITE1(sc, I2CSTAT, reg);

	error = wait_for_iif(sc);
	if (error) {
		DPRINTF("cant i2c start: iif error\n");

		mtx_unlock(&sc->mutex);
		return (error);
	}

	if (!is_ack(sc)) {
		DPRINTF("cant i2c start: no ack\n");

		mtx_unlock(&sc->mutex);
		return (IIC_ENOACK);
	};

	mtx_unlock(&sc->mutex);
	return (IIC_NOERR);
}
Ejemplo n.º 12
0
int
cfi_attach(device_t dev)
{
    struct cfi_softc *sc;
    u_int blksz, blocks;
    u_int r, u;

    sc = device_get_softc(dev);
    sc->sc_dev = dev;

    sc->sc_rid = 0;
    sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
                                        RF_ACTIVE);
    if (sc->sc_res == NULL)
        return (ENXIO);

    sc->sc_tag = rman_get_bustag(sc->sc_res);
    sc->sc_handle = rman_get_bushandle(sc->sc_res);

    /* Get time-out values for erase and write. */
    sc->sc_write_timeout = 1 << cfi_read_qry(sc, CFI_QRY_TTO_WRITE);
    sc->sc_erase_timeout = 1 << cfi_read_qry(sc, CFI_QRY_TTO_ERASE);
    sc->sc_write_timeout *= 1 << cfi_read_qry(sc, CFI_QRY_MTO_WRITE);
    sc->sc_erase_timeout *= 1 << cfi_read_qry(sc, CFI_QRY_MTO_ERASE);

    /* Get erase regions. */
    sc->sc_regions = cfi_read_qry(sc, CFI_QRY_NREGIONS);
    sc->sc_region = malloc(sc->sc_regions * sizeof(struct cfi_region),
                           M_TEMP, M_WAITOK | M_ZERO);
    for (r = 0; r < sc->sc_regions; r++) {
        blocks = cfi_read_qry(sc, CFI_QRY_REGION(r)) |
                 (cfi_read_qry(sc, CFI_QRY_REGION(r) + 1) << 8);
        sc->sc_region[r].r_blocks = blocks + 1;

        blksz = cfi_read_qry(sc, CFI_QRY_REGION(r) + 2) |
                (cfi_read_qry(sc, CFI_QRY_REGION(r) + 3) << 8);
        sc->sc_region[r].r_blksz = (blksz == 0) ? 128 :
                                   blksz * 256;
    }

    /* Reset the device to a default state. */
    cfi_write(sc, 0, CFI_BCS_CLEAR_STATUS);

    if (bootverbose) {
        device_printf(dev, "[");
        for (r = 0; r < sc->sc_regions; r++) {
            printf("%ux%s%s", sc->sc_region[r].r_blocks,
                   cfi_fmtsize(sc->sc_region[r].r_blksz),
                   (r == sc->sc_regions - 1) ? "]\n" : ",");
        }
    }

    u = device_get_unit(dev);
    sc->sc_nod = make_dev(&cfi_cdevsw, u, UID_ROOT, GID_WHEEL, 0600,
                          "%s%u", cfi_driver_name, u);
    sc->sc_nod->si_drv1 = sc;

    device_add_child(dev, "cfid", -1);
    bus_generic_attach(dev);

    return (0);
}
Ejemplo n.º 13
0
int
cfi_probe(device_t dev)
{
    char desc[80];
    struct cfi_softc *sc;
    char *vend_str;
    int error;
    uint16_t iface, vend;

    sc = device_get_softc(dev);
    sc->sc_dev = dev;

    sc->sc_rid = 0;
    sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
                                        RF_ACTIVE);
    if (sc->sc_res == NULL)
        return (ENXIO);

    sc->sc_tag = rman_get_bustag(sc->sc_res);
    sc->sc_handle = rman_get_bushandle(sc->sc_res);

    if (sc->sc_width == 0) {
        sc->sc_width = 1;
        while (sc->sc_width <= 4) {
            if (cfi_read_qry(sc, CFI_QRY_IDENT) == 'Q')
                break;
            sc->sc_width <<= 1;
        }
    } else if (cfi_read_qry(sc, CFI_QRY_IDENT) != 'Q') {
        error = ENXIO;
        goto out;
    }
    if (sc->sc_width > 4) {
        error = ENXIO;
        goto out;
    }

    /* We got a Q. Check if we also have the R and the Y. */
    if (cfi_read_qry(sc, CFI_QRY_IDENT + 1) != 'R' ||
            cfi_read_qry(sc, CFI_QRY_IDENT + 2) != 'Y') {
        error = ENXIO;
        goto out;
    }

    /* Get the vendor and command set. */
    vend = cfi_read_qry(sc, CFI_QRY_VEND) |
           (cfi_read_qry(sc, CFI_QRY_VEND + 1) << 8);

    sc->sc_cmdset = vend;

    switch (vend) {
    case CFI_VEND_AMD_ECS:
    case CFI_VEND_AMD_SCS:
        vend_str = "AMD/Fujitsu";
        break;
    case CFI_VEND_INTEL_ECS:
        vend_str = "Intel/Sharp";
        break;
    case CFI_VEND_INTEL_SCS:
        vend_str = "Intel";
        break;
    case CFI_VEND_MITSUBISHI_ECS:
    case CFI_VEND_MITSUBISHI_SCS:
        vend_str = "Mitsubishi";
        break;
    default:
        vend_str = "Unknown vendor";
        break;
    }

    /* Get the device size. */
    sc->sc_size = 1U << cfi_read_qry(sc, CFI_QRY_SIZE);

    /* Sanity-check the I/F */
    iface = cfi_read_qry(sc, CFI_QRY_IFACE) |
            (cfi_read_qry(sc, CFI_QRY_IFACE + 1) << 8);

    /*
     * Adding 1 to iface will give us a bit-wise "switch"
     * that allows us to test for the interface width by
     * testing a single bit.
     */
    iface++;

    error = (iface & sc->sc_width) ? 0 : EINVAL;
    if (error)
        goto out;

    snprintf(desc, sizeof(desc), "%s - %s", vend_str,
             cfi_fmtsize(sc->sc_size));
    device_set_desc_copy(dev, desc);

out:
    bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res);
    return (error);
}
Ejemplo n.º 14
0
static int
usie_attach(device_t self)
{
	struct usie_softc *sc = device_get_softc(self);
	struct usb_attach_arg *uaa = device_get_ivars(self);
	struct ifnet *ifp;
	struct usb_interface *iface;
	struct usb_interface_descriptor *id;
	struct usb_device_request req;
	int err;
	uint16_t fwattr;
	uint8_t iface_index;
	uint8_t ifidx;
	uint8_t start;

	device_set_usb_desc(self);
	sc->sc_udev = uaa->device;
	sc->sc_dev = self;

	mtx_init(&sc->sc_mtx, "usie", MTX_NETWORK_LOCK, MTX_DEF);
	ucom_ref(&sc->sc_super_ucom);

	TASK_INIT(&sc->sc_if_status_task, 0, usie_if_status_cb, sc);
	TASK_INIT(&sc->sc_if_sync_task, 0, usie_if_sync_cb, sc);

	usb_callout_init_mtx(&sc->sc_if_sync_ch, &sc->sc_mtx, 0);

	mtx_lock(&sc->sc_mtx);

	/* set power mode to D0 */
	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
	req.bRequest = USIE_POWER;
	USETW(req.wValue, 0);
	USETW(req.wIndex, 0);
	USETW(req.wLength, 0);
	if (usie_do_request(sc, &req, NULL)) {
		mtx_unlock(&sc->sc_mtx);
		goto detach;
	}
	/* read fw attr */
	fwattr = 0;
	req.bmRequestType = UT_READ_VENDOR_DEVICE;
	req.bRequest = USIE_FW_ATTR;
	USETW(req.wValue, 0);
	USETW(req.wIndex, 0);
	USETW(req.wLength, sizeof(fwattr));
	if (usie_do_request(sc, &req, &fwattr)) {
		mtx_unlock(&sc->sc_mtx);
		goto detach;
	}
	mtx_unlock(&sc->sc_mtx);

	/* check DHCP supports */
	DPRINTF("fwattr=%x\n", fwattr);
	if (!(fwattr & USIE_FW_DHCP)) {
		device_printf(self, "DHCP is not supported. A firmware upgrade might be needed.\n");
	}

	/* find available interfaces */
	sc->sc_nucom = 0;
	for (ifidx = 0; ifidx < USIE_IFACE_MAX; ifidx++) {
		iface = usbd_get_iface(uaa->device, ifidx);
		if (iface == NULL)
			break;

		id = usbd_get_interface_descriptor(iface);
		if ((id == NULL) || (id->bInterfaceClass != UICLASS_VENDOR))
			continue;

		/* setup Direct IP transfer */
		if (id->bInterfaceNumber >= 7 && id->bNumEndpoints == 3) {
			sc->sc_if_ifnum = id->bInterfaceNumber;
			iface_index = ifidx;

			DPRINTF("ifnum=%d, ifidx=%d\n",
			    sc->sc_if_ifnum, ifidx);

			err = usbd_transfer_setup(uaa->device,
			    &iface_index, sc->sc_if_xfer, usie_if_config,
			    USIE_IF_N_XFER, sc, &sc->sc_mtx);

			if (err == 0)
				continue;

			device_printf(self,
			    "could not allocate USB transfers on "
			    "iface_index=%d, err=%s\n",
			    iface_index, usbd_errstr(err));
			goto detach;
		}

		/* setup ucom */
		if (sc->sc_nucom >= USIE_UCOM_MAX)
			continue;

		usbd_set_parent_iface(uaa->device, ifidx,
		    uaa->info.bIfaceIndex);

		DPRINTF("NumEndpoints=%d bInterfaceNumber=%d\n",
		    id->bNumEndpoints, id->bInterfaceNumber);

		if (id->bNumEndpoints == 2) {
			sc->sc_uc_xfer[sc->sc_nucom][0] = NULL;
			start = 1;
		} else
			start = 0;

		err = usbd_transfer_setup(uaa->device, &ifidx,
		    sc->sc_uc_xfer[sc->sc_nucom] + start,
		    usie_uc_config + start, USIE_UC_N_XFER - start,
		    &sc->sc_ucom[sc->sc_nucom], &sc->sc_mtx);

		if (err != 0) {
			DPRINTF("usbd_transfer_setup error=%s\n", usbd_errstr(err));
			continue;
		}

		mtx_lock(&sc->sc_mtx);
		for (; start < USIE_UC_N_XFER; start++)
			usbd_xfer_set_stall(sc->sc_uc_xfer[sc->sc_nucom][start]);
		mtx_unlock(&sc->sc_mtx);

		sc->sc_uc_ifnum[sc->sc_nucom] = id->bInterfaceNumber;

		sc->sc_nucom++;		/* found a port */
	}

	if (sc->sc_nucom == 0) {
		device_printf(self, "no comports found\n");
		goto detach;
	}

	err = ucom_attach(&sc->sc_super_ucom, sc->sc_ucom,
	    sc->sc_nucom, sc, &usie_uc_callback, &sc->sc_mtx);

	if (err != 0) {
		DPRINTF("ucom_attach failed\n");
		goto detach;
	}
	DPRINTF("Found %d interfaces.\n", sc->sc_nucom);

	/* setup ifnet (Direct IP) */
	sc->sc_ifp = ifp = if_alloc(IFT_OTHER);

	if (ifp == NULL) {
		device_printf(self, "Could not allocate a network interface\n");
		goto detach;
	}
	if_initname(ifp, "usie", device_get_unit(self));

	ifp->if_softc = sc;
	ifp->if_mtu = USIE_MTU_MAX;
	ifp->if_flags |= IFF_NOARP;
	ifp->if_init = usie_if_init;
	ifp->if_ioctl = usie_if_ioctl;
	ifp->if_start = usie_if_start;
	ifp->if_output = usie_if_output;
	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
	IFQ_SET_READY(&ifp->if_snd);

	if_attach(ifp);
	bpfattach(ifp, DLT_RAW, 0);

	if (fwattr & USIE_PM_AUTO) {
		usbd_set_power_mode(uaa->device, USB_POWER_MODE_SAVE);
		DPRINTF("enabling automatic suspend and resume\n");
	} else {
		usbd_set_power_mode(uaa->device, USB_POWER_MODE_ON);
		DPRINTF("USB power is always ON\n");
	}

	DPRINTF("device attached\n");
	return (0);

detach:
	usie_detach(self);
	return (ENOMEM);
}
Ejemplo n.º 15
0
static void 
acd_strategy(struct bio *bp)
{
    device_t dev = bp->bio_to->geom->softc;
    struct ata_device *atadev = device_get_softc(dev);
    struct acd_softc *cdp = device_get_ivars(dev);
    struct ata_request *request;
    u_int32_t lba, lastlba, count;
    int8_t ccb[16];
    int track, blocksize;

    /* reject all queued entries if media changed */
    if (atadev->flags & ATA_D_MEDIA_CHANGED) {
	g_io_deliver(bp, EIO);
	return;
    }

    bzero(ccb, sizeof(ccb));

    track = bp->bio_to->index;

    if (track) {
	blocksize = (cdp->toc.tab[track - 1].control & 4) ? 2048 : 2352;
	lastlba = ntohl(cdp->toc.tab[track].addr.lba);
	lba = bp->bio_offset / blocksize;
	lba += ntohl(cdp->toc.tab[track - 1].addr.lba);
    }
    else {
	blocksize = cdp->block_size;
	lastlba = cdp->disk_size;
	lba = bp->bio_offset / blocksize;
    }

    count = bp->bio_length / blocksize;

    if (bp->bio_cmd == BIO_READ) {
	/* if transfer goes beyond range adjust it to be within limits */
	if (lba + count > lastlba) {
	    /* if we are entirely beyond EOM return EOF */
	    if (lastlba <= lba) {
		g_io_deliver(bp, 0);
		return;
	    }
	    count = lastlba - lba;
	}
	switch (blocksize) {
	case 2048:
	    ccb[0] = ATAPI_READ_BIG;
	    break;

	case 2352: 
	    ccb[0] = ATAPI_READ_CD;
	    ccb[9] = 0xf8;
	    break;

	default:
	    ccb[0] = ATAPI_READ_CD;
	    ccb[9] = 0x10;
	}
    }
    else
	ccb[0] = ATAPI_WRITE_BIG;
    
    ccb[1] = 0;
    ccb[2] = lba>>24;
    ccb[3] = lba>>16;
    ccb[4] = lba>>8;
    ccb[5] = lba;
    ccb[6] = count>>16;
    ccb[7] = count>>8;
    ccb[8] = count;

    if (!(request = ata_alloc_request())) {
	g_io_deliver(bp, ENOMEM);
	return;
    }
    request->dev = dev;
    request->bio = bp;
    bcopy(ccb, request->u.atapi.ccb, 16);
    request->data = bp->bio_data;
    request->bytecount = count * blocksize;
    request->transfersize = min(request->bytecount, 65534);
    request->timeout = (ccb[0] == ATAPI_WRITE_BIG) ? 60 : 30;
    request->retries = 2;
    request->callback = acd_done;
    request->flags = ATA_R_ATAPI;
    if (atadev->mode >= ATA_DMA)
	request->flags |= ATA_R_DMA;
    switch (bp->bio_cmd) {
    case BIO_READ:
	request->flags |= ATA_R_READ;
	break;
    case BIO_WRITE:
	request->flags |= ATA_R_WRITE;
	break;
    default:
	device_printf(dev, "unknown BIO operation\n");
	ata_free_request(request);
	g_io_deliver(bp, EIO);
	return;
    }
    ata_queue_request(request);
}
Ejemplo n.º 16
0
static int
ata_via_chipinit(device_t dev)
{
    struct ata_pci_controller *ctlr = device_get_softc(dev);

    if (ata_setup_interrupt(dev, ata_generic_intr))
	return ENXIO;

    /* AHCI SATA */
    if (ctlr->chip->cfg2 & VIAAHCI) {
	if (ata_ahci_chipinit(dev) != ENXIO)
	    return (0);
    }
    /* 2 SATA without SATA registers on first channel + 1 PATA on second */
    if (ctlr->chip->cfg2 & VIASATA) {
	ctlr->ch_attach = ata_via_sata_ch_attach;
	ctlr->setmode = ata_via_sata_setmode;
	ctlr->getrev = ata_via_sata_getrev;
	return 0;
    }
    /* Legacy SATA/SATA+PATA with SATA registers in BAR(5). */
    if (ctlr->chip->max_dma >= ATA_SA150) {
	ctlr->r_type2 = SYS_RES_IOPORT;
	ctlr->r_rid2 = PCIR_BAR(5);
	if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
						   &ctlr->r_rid2, RF_ACTIVE))) {
	    ctlr->ch_attach = ata_via_ch_attach;
	    ctlr->ch_detach = ata_via_ch_detach;
	    ctlr->reset = ata_via_reset;
	}
	if (ctlr->chip->cfg2 & VIABAR) {
	    ctlr->channels = 3;
	    ctlr->setmode = ata_via_new_setmode;
	} else
	    ctlr->setmode = ata_sata_setmode;
	ctlr->getrev = ata_sata_getrev;
	return 0;
    }

    /* prepare for ATA-66 on the 82C686a and 82C596b */
    if (ctlr->chip->cfg2 & VIACLK)
	pci_write_config(dev, 0x50, 0x030b030b, 4);       

    /* the southbridge might need the data corruption fix */
    if (ctlr->chip->cfg2 & VIABUG)
	ata_via_southbridge_fixup(dev);

    /* set fifo configuration half'n'half */
    pci_write_config(dev, 0x43, 
		     (pci_read_config(dev, 0x43, 1) & 0x90) | 0x2a, 1);

    /* set status register read retry */
    pci_write_config(dev, 0x44, pci_read_config(dev, 0x44, 1) | 0x08, 1);

    /* set DMA read & end-of-sector fifo flush */
    pci_write_config(dev, 0x46, 
		     (pci_read_config(dev, 0x46, 1) & 0x0c) | 0xf0, 1);

    /* set sector size */
    pci_write_config(dev, 0x60, DEV_BSIZE, 2);
    pci_write_config(dev, 0x68, DEV_BSIZE, 2);

    ctlr->setmode = ata_via_old_setmode;
    return 0;
}
Ejemplo n.º 17
0
static void 
acd_read_toc(device_t dev)
{
    struct ata_device *atadev = device_get_softc(dev);
    struct acd_softc *cdp = device_get_ivars(dev);
    struct g_provider *pp;
    u_int32_t sizes[2];
    int8_t ccb[16];
    int track, ntracks, len;

    atadev->flags &= ~ATA_D_MEDIA_CHANGED;
    bzero(&cdp->toc, sizeof(cdp->toc));
    cdp->disk_size = -1;                        /* hack for GEOM SOS */

    if (acd_test_ready(dev))
	return;

    bzero(ccb, sizeof(ccb));
    len = sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry);
    ccb[0] = ATAPI_READ_TOC;
    ccb[7] = len>>8;
    ccb[8] = len;
    if (ata_atapicmd(dev, ccb, (caddr_t)&cdp->toc, len,
		     ATA_R_READ | ATA_R_QUIET, 30)) {
	bzero(&cdp->toc, sizeof(cdp->toc));
	return;
    }
    ntracks = cdp->toc.hdr.ending_track - cdp->toc.hdr.starting_track + 1;
    if (ntracks <= 0 || ntracks > MAXTRK) {
	bzero(&cdp->toc, sizeof(cdp->toc));
	return;
    }

    len = sizeof(struct ioc_toc_header)+(ntracks+1)*sizeof(struct cd_toc_entry);
    bzero(ccb, sizeof(ccb));
    ccb[0] = ATAPI_READ_TOC;
    ccb[7] = len>>8;
    ccb[8] = len;
    if (ata_atapicmd(dev, ccb, (caddr_t)&cdp->toc, len,
		     ATA_R_READ | ATA_R_QUIET, 30)) {
	bzero(&cdp->toc, sizeof(cdp->toc));
	return;
    }
    cdp->toc.hdr.len = ntohs(cdp->toc.hdr.len);

    cdp->block_size = (cdp->toc.tab[0].control & 4) ? 2048 : 2352;
    acd_set_ioparm(dev);
    bzero(ccb, sizeof(ccb));
    ccb[0] = ATAPI_READ_CAPACITY;
    if (ata_atapicmd(dev, ccb, (caddr_t)sizes, sizeof(sizes),
		     ATA_R_READ | ATA_R_QUIET, 30)) {
	bzero(&cdp->toc, sizeof(cdp->toc));
	return;
    }
    cdp->disk_size = ntohl(sizes[0]) + 1;

    for (track = 1; track <= ntracks; track ++) {
	if (cdp->pp[track] != NULL)
	    continue;
	pp = g_new_providerf(cdp->gp, "acd%dt%02d", device_get_unit(dev),track);
	pp->index = track;
	cdp->pp[track] = pp;
	g_error_provider(pp, 0);
    }
    for (; track < MAXTRK; track ++) {
	if (cdp->pp[track] == NULL)
	    continue;
	cdp->pp[track]->flags |= G_PF_WITHER;
	g_orphan_provider(cdp->pp[track], ENXIO);
	cdp->pp[track] = NULL;
    }

#ifdef ACD_DEBUG
    if (cdp->disk_size && cdp->toc.hdr.ending_track) {
	device_printf(dev, "(%d sectors (%d bytes)), %d tracks ", 
		      cdp->disk_size, cdp->block_size,
		      cdp->toc.hdr.ending_track-cdp->toc.hdr.starting_track+1);
	if (cdp->toc.tab[0].control & 4)
	    printf("%dMB\n", cdp->disk_size * cdp->block_size / 1048576);
	else
	    printf("%d:%d audio\n",
		   cdp->disk_size / 75 / 60, cdp->disk_size / 75 % 60);
    }
#endif
}
Ejemplo n.º 18
0
/*
 * PCI attach: scan Open Firmware child nodes, and attach these as children
 * of the macio bus
 */
static int 
macio_attach(device_t dev)
{
	struct macio_softc *sc;
        struct macio_devinfo *dinfo;
        phandle_t  root;
	phandle_t  child;
	phandle_t  subchild;
        device_t cdev;
        u_int reg[3];
	int error, quirks;

	sc = device_get_softc(dev);
	root = sc->sc_node = ofw_bus_get_node(dev);
	
	/*
	 * Locate the device node and it's base address
	 */
	if (OF_getprop(root, "assigned-addresses", 
		       reg, sizeof(reg)) < sizeof(reg)) {
		return (ENXIO);
	}

	sc->sc_base = reg[2];
	sc->sc_size = MACIO_REG_SIZE;

	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
	sc->sc_mem_rman.rm_descr = "MacIO Device Memory";
	error = rman_init(&sc->sc_mem_rman);
	if (error) {
		device_printf(dev, "rman_init() failed. error = %d\n", error);
		return (error);
	}
	error = rman_manage_region(&sc->sc_mem_rman, 0, sc->sc_size);	
	if (error) {
		device_printf(dev,
		    "rman_manage_region() failed. error = %d\n", error);
		return (error);
	}

	/*
	 * Iterate through the sub-devices
	 */
	for (child = OF_child(root); child != 0; child = OF_peer(child)) {
		dinfo = malloc(sizeof(*dinfo), M_MACIO, M_WAITOK | M_ZERO);
		if (ofw_bus_gen_setup_devinfo(&dinfo->mdi_obdinfo, child) !=
		    0) {
			free(dinfo, M_MACIO);
			continue;
		}
		quirks = macio_get_quirks(dinfo->mdi_obdinfo.obd_name);
		if ((quirks & MACIO_QUIRK_IGNORE) != 0) {
			ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo);
			free(dinfo, M_MACIO);
			continue;
		}
		resource_list_init(&dinfo->mdi_resources);
		dinfo->mdi_ninterrupts = 0;
		macio_add_intr(child, dinfo);
		if ((quirks & MACIO_QUIRK_USE_CHILD_REG) != 0)
			macio_add_reg(OF_child(child), dinfo);
		else
			macio_add_reg(child, dinfo);
		if ((quirks & MACIO_QUIRK_CHILD_HAS_INTR) != 0)
			for (subchild = OF_child(child); subchild != 0;
			    subchild = OF_peer(subchild))
				macio_add_intr(subchild, dinfo);
		cdev = device_add_child(dev, NULL, -1);
		if (cdev == NULL) {
			device_printf(dev, "<%s>: device_add_child failed\n",
			    dinfo->mdi_obdinfo.obd_name);
			resource_list_free(&dinfo->mdi_resources);
			ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo);
			free(dinfo, M_MACIO);
			continue;
		}
		device_set_ivars(cdev, dinfo);
	}

	return (bus_generic_attach(dev));
}
Ejemplo n.º 19
0
static int
at91_udp_attach(device_t dev)
{
    struct at91_udp_softc *sc = device_get_softc(dev);
    int err;
    int rid;

    /* setup AT9100 USB device controller interface softc */

    sc->sc_dci.sc_clocks_on = &at91_udp_clocks_on;
    sc->sc_dci.sc_clocks_off = &at91_udp_clocks_off;
    sc->sc_dci.sc_clocks_arg = sc;
    sc->sc_dci.sc_pull_up = &at91_udp_pull_up;
    sc->sc_dci.sc_pull_down = &at91_udp_pull_down;
    sc->sc_dci.sc_pull_arg = sc;

    /* initialise some bus fields */
    sc->sc_dci.sc_bus.parent = dev;
    sc->sc_dci.sc_bus.devices = sc->sc_dci.sc_devices;
    sc->sc_dci.sc_bus.devices_max = AT91_MAX_DEVICES;

    /* get all DMA memory */
    if (usb_bus_mem_alloc_all(&sc->sc_dci.sc_bus,
                              USB_GET_DMA_TAG(dev), NULL)) {
        return (ENOMEM);
    }
    /*
     * configure VBUS input pin, enable deglitch and enable
     * interrupt :
     */
    at91_pio_use_gpio(VBUS_BASE, VBUS_MASK);
    at91_pio_gpio_input(VBUS_BASE, VBUS_MASK);
    at91_pio_gpio_set_deglitch(VBUS_BASE, VBUS_MASK, 1);
    at91_pio_gpio_set_interrupt(VBUS_BASE, VBUS_MASK, 1);

    /*
     * configure PULLUP output pin :
     */
    at91_pio_use_gpio(PULLUP_BASE, PULLUP_MASK);
    at91_pio_gpio_output(PULLUP_BASE, PULLUP_MASK, 0);

    at91_udp_pull_down(sc);

    /* wait 10ms for pulldown to stabilise */
    usb_pause_mtx(NULL, hz / 100);

    sc->sc_iclk = at91_pmc_clock_ref("udc_clk");
    sc->sc_fclk = at91_pmc_clock_ref("udpck");

    rid = MEM_RID;
    sc->sc_dci.sc_io_res =
        bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);

    if (!(sc->sc_dci.sc_io_res)) {
        err = ENOMEM;
        goto error;
    }
    sc->sc_dci.sc_io_tag = rman_get_bustag(sc->sc_dci.sc_io_res);
    sc->sc_dci.sc_io_hdl = rman_get_bushandle(sc->sc_dci.sc_io_res);
    sc->sc_dci.sc_io_size = rman_get_size(sc->sc_dci.sc_io_res);

    rid = 0;
    sc->sc_dci.sc_irq_res =
        bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
    if (!(sc->sc_dci.sc_irq_res)) {
        goto error;
    }
    rid = 1;
    sc->sc_vbus_irq_res =
        bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
    if (!(sc->sc_vbus_irq_res)) {
        goto error;
    }
    sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1);
    if (!(sc->sc_dci.sc_bus.bdev)) {
        goto error;
    }
    device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus);

#if (__FreeBSD_version >= 700031)
    err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
                         NULL, (driver_intr_t *)at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl);
#else
    err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
                         (driver_intr_t *)at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl);
#endif
    if (err) {
        sc->sc_dci.sc_intr_hdl = NULL;
        goto error;
    }
#if (__FreeBSD_version >= 700031)
    err = bus_setup_intr(dev, sc->sc_vbus_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
                         NULL, (driver_intr_t *)at91_vbus_poll, sc, &sc->sc_vbus_intr_hdl);
#else
    err = bus_setup_intr(dev, sc->sc_vbus_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
                         (driver_intr_t *)at91_vbus_poll, sc, &sc->sc_vbus_intr_hdl);
#endif
    if (err) {
        sc->sc_vbus_intr_hdl = NULL;
        goto error;
    }
    err = at91dci_init(&sc->sc_dci);
    if (!err) {
        err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev);
    }
    if (err) {
        goto error;
    } else {
        /* poll VBUS one time */
        at91_vbus_poll(sc);
    }
    return (0);

error:
    at91_udp_detach(dev);
    return (ENXIO);
}
Ejemplo n.º 20
0
static struct resource *
macio_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		macio_softc *sc;
	int		needactivate;
	struct		resource *rv;
	struct		rman *rm;
	u_long		adjstart, adjend, adjcount;
	struct		macio_devinfo *dinfo;
	struct		resource_list_entry *rle;

	sc = device_get_softc(bus);
	dinfo = device_get_ivars(child);

	needactivate = flags & RF_ACTIVE;
	flags &= ~RF_ACTIVE;

	switch (type) {
	case SYS_RES_MEMORY:
	case SYS_RES_IOPORT:
		rle = resource_list_find(&dinfo->mdi_resources, SYS_RES_MEMORY,
		    *rid);
		if (rle == NULL) {
			device_printf(bus, "no rle for %s memory %d\n",
			    device_get_nameunit(child), *rid);
			return (NULL);
		}

		if (start < rle->start)
			adjstart = rle->start;
		else if (start > rle->end)
			adjstart = rle->end;
		else
			adjstart = start;

		if (end < rle->start)
			adjend = rle->start;
		else if (end > rle->end)
			adjend = rle->end;
		else
			adjend = end;

		adjcount = adjend - adjstart;

		rm = &sc->sc_mem_rman;
		break;

	case SYS_RES_IRQ:
		/* Check for passthrough from subattachments like macgpio */
		if (device_get_parent(child) != bus)
			return BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
			    type, rid, start, end, count, flags);

		rle = resource_list_find(&dinfo->mdi_resources, SYS_RES_IRQ,
		    *rid);
		if (rle == NULL) {
			if (dinfo->mdi_ninterrupts >= 6) {
				device_printf(bus,
				    "%s has more than 6 interrupts\n",
				    device_get_nameunit(child));
				return (NULL);
			}
			resource_list_add(&dinfo->mdi_resources, SYS_RES_IRQ,
			    dinfo->mdi_ninterrupts, start, start, 1);

			dinfo->mdi_interrupts[dinfo->mdi_ninterrupts] = start;
			dinfo->mdi_ninterrupts++;
		}

		return (resource_list_alloc(&dinfo->mdi_resources, bus, child,
		    type, rid, start, end, count, flags));

	default:
		device_printf(bus, "unknown resource request from %s\n",
			      device_get_nameunit(child));
		return (NULL);
	}

	rv = rman_reserve_resource(rm, adjstart, adjend, adjcount, flags,
	    child);
	if (rv == NULL) {
		device_printf(bus,
		    "failed to reserve resource %#lx - %#lx (%#lx) for %s\n",
		    adjstart, adjend, adjcount, device_get_nameunit(child));
		return (NULL);
	}

	rman_set_rid(rv, *rid);

	if (needactivate) {
		if (bus_activate_resource(child, type, *rid, rv) != 0) {
                        device_printf(bus,
				      "failed to activate resource for %s\n",
				      device_get_nameunit(child));
			rman_release_resource(rv);
			return (NULL);
                }
        }

	return (rv);
}
Ejemplo n.º 21
0
/*
 * ppb_MS_microseq()
 *
 * Interprete a microsequence. Some microinstructions are executed at adapter
 * level to avoid function call overhead between ppbus and the adapter
 */
int
ppb_MS_microseq(device_t bus, device_t dev, struct ppb_microseq *msq, int *ret)
{
	struct ppb_data *ppb = (struct ppb_data *)device_get_softc(bus);
	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);

	struct ppb_microseq *mi;		/* current microinstruction */
	int error;

	struct ppb_xfer *xfer;

	/* microsequence executed to initialize the transfer */
	struct ppb_microseq initxfer[] = {
		MS_PTR(MS_UNKNOWN), 	/* set ptr to buffer */
		MS_SET(MS_UNKNOWN),	/* set transfer size */
		MS_RET(0)
	};

	if (ppb->ppb_owner != dev)
		return (EACCES);

#define INCR_PC (mi ++)

	mi = msq;
	for (;;) {
		switch (mi->opcode) {                                           
		case MS_OP_PUT:
		case MS_OP_GET:

			/* attempt to choose the best mode for the device */
			xfer = mode2xfer(bus, ppbdev, mi->opcode);

			/* figure out if we should use ieee1284 code */
			if (!xfer->loop) {
				if (mi->opcode == MS_OP_PUT) {
					if ((error = PPBUS_WRITE(
						device_get_parent(bus),
						(char *)mi->arg[0].p,
						mi->arg[1].i, 0)))
							goto error;

					INCR_PC;
					continue;
				} else {
					panic("%s: IEEE1284 read not supported", __func__);
				}
			}

			/* XXX should use ppb_MS_init_msq() */
			initxfer[0].arg[0].p = mi->arg[0].p;
			initxfer[1].arg[0].i = mi->arg[1].i;

			/* initialize transfer */
			ppb_MS_microseq(bus, dev, initxfer, &error);

			if (error)
				goto error;

			/* the xfer microsequence should not contain any
			 * MS_OP_PUT or MS_OP_GET!
			 */
			ppb_MS_microseq(bus, dev, xfer->loop, &error);

			if (error)
				goto error;

			INCR_PC;
			break;

                case MS_OP_RET:
			if (ret)
				*ret = mi->arg[0].i;	/* return code */
			return (0);
                        break;

		default:
			/* executing microinstructions at ppc level is
			 * faster. This is the default if the microinstr
			 * is unknown here
			 */
			if ((error = PPBUS_EXEC_MICROSEQ(
						device_get_parent(bus), &mi)))
				goto error;
			break;
		}
	}
error:
	return (error);
}
Ejemplo n.º 22
0
static int
at91_rst_attach(device_t dev)
{
	struct at91_rst_softc *sc;
	const char *cause;
	int rid, err;

	at91_rst_sc = sc = device_get_softc(dev);
	sc->sc_dev = dev;

	callout_init(&sc->tick_ch, 0);

	rid = 0;
	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
	    RF_ACTIVE);
	if (sc->mem_res == NULL) {
		device_printf(dev, "could not allocate memory resources.\n");
		err = ENOMEM;
		goto out;
	}
	rid = 0;
	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
	    RF_ACTIVE | RF_SHAREABLE);
	if (sc->irq_res == NULL) {
		device_printf(dev, "could not allocate interrupt resources.\n");
		err = ENOMEM;
		goto out;
	}

	/* Activate the interrupt. */
	err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
	    at91_rst_intr, NULL, sc, &sc->intrhand);
	if (err)
		device_printf(dev, "could not establish interrupt handler.\n");

	WR4(at91_rst_sc, RST_MR, RST_MR_ERSTL(0xd) | RST_MR_URSIEN | RST_MR_KEY);

	switch (RD4(sc, RST_SR) & RST_SR_RST_MASK) {
		case	RST_SR_RST_POW:
			cause = "Power On";
			break;
		case	RST_SR_RST_WAKE:
			cause = "Wake Up";
			break;
		case	RST_SR_RST_WDT:
			cause = "Watchdog";
			break;
		case	RST_SR_RST_SOFT:
			cause = "Software Request";
			break;
		case	RST_SR_RST_USR:
			cause = "External (User)";
			break;
		default:
			cause = "Unknown";
			break;
	}

	device_printf(dev, "Reset cause: %s.\n", cause);
out:
	return (err);
}
Ejemplo n.º 23
0
static void
acpi_cmbat_get_bif(void *arg)
{
    struct acpi_cmbat_softc *sc;
    ACPI_STATUS	as;
    ACPI_OBJECT	*res;
    ACPI_HANDLE	h;
    ACPI_BUFFER	bif_buffer;
    device_t dev;

    ACPI_SERIAL_ASSERT(cmbat);

    dev = arg;
    sc = device_get_softc(dev);
    h = acpi_get_handle(dev);
    bif_buffer.Pointer = NULL;
    bif_buffer.Length = ACPI_ALLOCATE_BUFFER;

    as = AcpiEvaluateObject(h, "_BIF", NULL, &bif_buffer);
    if (ACPI_FAILURE(as)) {
	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
		    "error fetching current battery info -- %s\n",
		    AcpiFormatException(as));
	goto end;
    }

    res = (ACPI_OBJECT *)bif_buffer.Pointer;
    if (!ACPI_PKG_VALID(res, 13)) {
	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
		    "battery info corrupted\n");
	goto end;
    }

    if (acpi_PkgInt32(res, 0, &sc->bif.units) != 0)
	goto end;
    if (acpi_PkgInt32(res, 1, &sc->bif.dcap) != 0)
	goto end;
    if (acpi_PkgInt32(res, 2, &sc->bif.lfcap) != 0)
	goto end;
    if (acpi_PkgInt32(res, 3, &sc->bif.btech) != 0)
	goto end;
    if (acpi_PkgInt32(res, 4, &sc->bif.dvol) != 0)
	goto end;
    if (acpi_PkgInt32(res, 5, &sc->bif.wcap) != 0)
	goto end;
    if (acpi_PkgInt32(res, 6, &sc->bif.lcap) != 0)
	goto end;
    if (acpi_PkgInt32(res, 7, &sc->bif.gra1) != 0)
	goto end;
    if (acpi_PkgInt32(res, 8, &sc->bif.gra2) != 0)
	goto end;
    if (acpi_PkgStr(res,  9, sc->bif.model, ACPI_CMBAT_MAXSTRLEN) != 0)
	goto end;
    if (acpi_PkgStr(res, 10, sc->bif.serial, ACPI_CMBAT_MAXSTRLEN) != 0)
	goto end;
    if (acpi_PkgStr(res, 11, sc->bif.type, ACPI_CMBAT_MAXSTRLEN) != 0)
	goto end;
    if (acpi_PkgStr(res, 12, sc->bif.oeminfo, ACPI_CMBAT_MAXSTRLEN) != 0)
	goto end;

end:
    if (bif_buffer.Pointer != NULL)
	AcpiOsFree(bif_buffer.Pointer);
}
Ejemplo n.º 24
0
static int
lbc_attach(device_t dev)
{
	struct lbc_softc *sc;
	struct lbc_devinfo *di;
	struct rman *rm;
	u_long offset, start, size;
	device_t cdev;
	phandle_t node, child;
	pcell_t *ranges, *rangesptr;
	int tuple_size, tuples;
	int par_addr_cells;
	int bank, error, i;

	sc = device_get_softc(dev);
	sc->sc_dev = dev;

	sc->sc_mrid = 0;
	sc->sc_mres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_mrid,
	    RF_ACTIVE);
	if (sc->sc_mres == NULL)
		return (ENXIO);

	sc->sc_bst = rman_get_bustag(sc->sc_mres);
	sc->sc_bsh = rman_get_bushandle(sc->sc_mres);

	for (bank = 0; bank < LBC_DEV_MAX; bank++) {
		bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_BR(bank), 0);
		bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_OR(bank), 0);
	}

	/*
	 * Initialize configuration register:
	 * - enable Local Bus
	 * - set data buffer control signal function
	 * - disable parity byte select
	 * - set ECC parity type
	 * - set bus monitor timing and timer prescale
	 */
	bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LBCR, 0);

	/*
	 * Initialize clock ratio register:
	 * - disable PLL bypass mode
	 * - configure LCLK delay cycles for the assertion of LALE
	 * - set system clock divider
	 */
	bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LCRR, 0x00030008);

	bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTEDR, 0);
	bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR, ~0);
	bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTEIR, 0x64080001);

	sc->sc_irid = 0;
	sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid,
	    RF_ACTIVE | RF_SHAREABLE);
	if (sc->sc_ires != NULL) {
		error = bus_setup_intr(dev, sc->sc_ires,
		    INTR_TYPE_MISC | INTR_MPSAFE, NULL, lbc_intr, sc,
		    &sc->sc_icookie);
		if (error) {
			device_printf(dev, "could not activate interrupt\n");
			bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
			    sc->sc_ires);
			sc->sc_ires = NULL;
		}
	}

	sc->sc_ltesr = ~0;

	rangesptr = NULL;

	rm = &sc->sc_rman;
	rm->rm_type = RMAN_ARRAY;
	rm->rm_descr = "Local Bus Space";
	rm->rm_start = 0UL;
	rm->rm_end = ~0UL;
	error = rman_init(rm);
	if (error)
		goto fail;

	error = rman_manage_region(rm, rm->rm_start, rm->rm_end);
	if (error) {
		rman_fini(rm);
		goto fail;
	}

	/*
	 * Process 'ranges' property.
	 */
	node = ofw_bus_get_node(dev);
	if ((fdt_addrsize_cells(node, &sc->sc_addr_cells,
	    &sc->sc_size_cells)) != 0) {
		error = ENXIO;
		goto fail;
	}

	par_addr_cells = fdt_parent_addr_cells(node);
	if (par_addr_cells > 2) {
		device_printf(dev, "unsupported parent #addr-cells\n");
		error = ERANGE;
		goto fail;
	}
	tuple_size = sizeof(pcell_t) * (sc->sc_addr_cells + par_addr_cells +
	    sc->sc_size_cells);

	tuples = OF_getprop_alloc(node, "ranges", tuple_size,
	    (void **)&ranges);
	if (tuples < 0) {
		device_printf(dev, "could not retrieve 'ranges' property\n");
		error = ENXIO;
		goto fail;
	}
	rangesptr = ranges;

	debugf("par addr_cells = %d, addr_cells = %d, size_cells = %d, "
	    "tuple_size = %d, tuples = %d\n", par_addr_cells,
	    sc->sc_addr_cells, sc->sc_size_cells, tuple_size, tuples);

	start = 0;
	size = 0;
	for (i = 0; i < tuples; i++) {

		/* The first cell is the bank (chip select) number. */
		bank = fdt_data_get((void *)ranges, 1);
		if (bank < 0 || bank > LBC_DEV_MAX) {
			device_printf(dev, "bank out of range: %d\n", bank);
			error = ERANGE;
			goto fail;
		}
		ranges += 1;

		/*
		 * Remaining cells of the child address define offset into
		 * this CS.
		 */
		offset = fdt_data_get((void *)ranges, sc->sc_addr_cells - 1);
		ranges += sc->sc_addr_cells - 1;

		/* Parent bus start address of this bank. */
		start = fdt_data_get((void *)ranges, par_addr_cells);
		ranges += par_addr_cells;

		size = fdt_data_get((void *)ranges, sc->sc_size_cells);
		ranges += sc->sc_size_cells;
		debugf("bank = %d, start = %lx, size = %lx\n", bank,
		    start, size);

		sc->sc_banks[bank].addr = start + offset;
		sc->sc_banks[bank].size = size;

		/*
		 * Attributes for the bank.
		 *
		 * XXX Note there are no DT bindings defined for them at the
		 * moment, so we need to provide some defaults.
		 */
		sc->sc_banks[bank].width = 16;
		sc->sc_banks[bank].msel = LBCRES_MSEL_GPCM;
		sc->sc_banks[bank].decc = LBCRES_DECC_DISABLED;
		sc->sc_banks[bank].atom = LBCRES_ATOM_DISABLED;
		sc->sc_banks[bank].wp = 0;
	}

	/*
	 * Initialize mem-mappings for the LBC banks (i.e. chip selects).
	 */
	error = lbc_banks_map(sc);
	if (error)
		goto fail;

	/*
	 * Walk the localbus and add direct subordinates as our children.
	 */
	for (child = OF_child(node); child != 0; child = OF_peer(child)) {

		di = malloc(sizeof(*di), M_LBC, M_WAITOK | M_ZERO);

		if (ofw_bus_gen_setup_devinfo(&di->di_ofw, child) != 0) {
			free(di, M_LBC);
			device_printf(dev, "could not set up devinfo\n");
			continue;
		}

		resource_list_init(&di->di_res);

		if (fdt_lbc_reg_decode(child, sc, di)) {
			device_printf(dev, "could not process 'reg' "
			    "property\n");
			ofw_bus_gen_destroy_devinfo(&di->di_ofw);
			free(di, M_LBC);
			continue;
		}

		fdt_lbc_fixup(child, sc, di);

		/* Add newbus device for this FDT node */
		cdev = device_add_child(dev, NULL, -1);
		if (cdev == 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_LBC);
			continue;
		}
		debugf("added child name='%s', node=%p\n", di->di_ofw.obd_name,
		    (void *)child);
		device_set_ivars(cdev, di);
	}

	/*
	 * Enable the LBC.
	 */
	lbc_banks_enable(sc);

	free(rangesptr, M_OFWPROP);
	return (bus_generic_attach(dev));

fail:
	free(rangesptr, M_OFWPROP);
	bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mrid, sc->sc_mres);
	return (error);
}
Ejemplo n.º 25
0
static int
pl310_attach(device_t dev)
{
	struct pl310_softc *sc = device_get_softc(dev);
	int rid = 0;
	uint32_t aux_value;
	uint32_t ctrl_value;
	uint32_t cache_id;

	sc->sc_dev = dev;
	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 
	    RF_ACTIVE);
	if (sc->sc_mem_res == NULL)
		panic("%s: Cannot map registers", device_get_name(dev));

	/* Allocate an IRQ resource */
	rid = 0;
	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
	                                        RF_ACTIVE | RF_SHAREABLE);
	if (sc->sc_irq_res == NULL) {
		panic("Cannot allocate IRQ\n");
	}

	pl310_softc = sc;
	mtx_init(&sc->sc_mtx, "pl310lock", NULL, MTX_SPIN);
	sc->sc_enabled = pl310_enabled;

	/* activate the interrupt */
	bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
				pl310_filter, NULL, sc, &sc->sc_irq_h);

	cache_id = pl310_read4(sc, PL310_CACHE_ID);
	sc->sc_rtl_revision = (cache_id >> CACHE_ID_RELEASE_SHIFT) &
	    CACHE_ID_RELEASE_MASK;
	device_printf(dev, "Part number: 0x%x, release: 0x%x\n",
	    (cache_id >> CACHE_ID_PARTNUM_SHIFT) & CACHE_ID_PARTNUM_MASK,
	    (cache_id >> CACHE_ID_RELEASE_SHIFT) & CACHE_ID_RELEASE_MASK);
	aux_value = pl310_read4(sc, PL310_AUX_CTRL);
	g_way_size = (aux_value & AUX_CTRL_WAY_SIZE_MASK) >>
	    AUX_CTRL_WAY_SIZE_SHIFT;
	g_way_size = 1 << (g_way_size + 13);
	if (aux_value & (1 << AUX_CTRL_ASSOCIATIVITY_SHIFT))
		g_ways_assoc = 16;
	else
		g_ways_assoc = 8;
	g_l2cache_way_mask = (1 << g_ways_assoc) - 1;
	g_l2cache_size = g_way_size * g_ways_assoc;
	/* Print the information */
	device_printf(dev, "L2 Cache: %uKB/%dB %d ways\n", (g_l2cache_size / 1024),
	       g_l2cache_line_size, g_ways_assoc);

	ctrl_value = pl310_read4(sc, PL310_CTRL);

	if (sc->sc_enabled && !(ctrl_value & CTRL_ENABLED)) {
		/* invalidate current content */
		pl310_write4(pl310_softc, PL310_INV_WAY, 0xffff);
		pl310_wait_background_op(PL310_INV_WAY, 0xffff);

		/* Enable the L2 cache if disabled */
		platform_pl310_write_ctrl(sc, CTRL_ENABLED);
		device_printf(dev, "L2 Cache enabled\n");
	} 

	if (!sc->sc_enabled && (ctrl_value & CTRL_ENABLED)) {
		/*
		 * Set counters so when cache event happens
		 * we'll get interrupt and be warned that something 
		 * is off
		 */

		/* Cache Line Eviction for Counter 0 */
		pl310_write4(sc, PL310_EVENT_COUNTER0_CONF, 
		    EVENT_COUNTER_CONF_INCR | EVENT_COUNTER_CONF_CO);
		/* Data Read Request for Counter 1 */
		pl310_write4(sc, PL310_EVENT_COUNTER1_CONF, 
		    EVENT_COUNTER_CONF_INCR | EVENT_COUNTER_CONF_DRREQ);

		/* Temporary switch on for final flush*/
		sc->sc_enabled = 1;
		pl310_wbinv_all();
		sc->sc_enabled = 0;
		platform_pl310_write_ctrl(sc, CTRL_DISABLED);

		/* Enable and clear pending interrupts */
		pl310_write4(sc, PL310_INTR_CLEAR, INTR_MASK_ECNTR);
		pl310_write4(sc, PL310_INTR_MASK, INTR_MASK_ALL);

		/* Enable counters and reset C0 and C1 */
		pl310_write4(sc, PL310_EVENT_COUNTER_CTRL, 
		    EVENT_COUNTER_CTRL_ENABLED | 
		    EVENT_COUNTER_CTRL_C0_RESET | 
		    EVENT_COUNTER_CTRL_C1_RESET);

		device_printf(dev, "L2 Cache disabled\n");
	}

	if (sc->sc_enabled)
		platform_pl310_init(sc);

	pl310_wbinv_all();

	/* Set the l2 functions in the set of cpufuncs */
	cpufuncs.cf_l2cache_wbinv_all = pl310_wbinv_all;
	cpufuncs.cf_l2cache_wbinv_range = pl310_wbinv_range;
	cpufuncs.cf_l2cache_inv_range = pl310_inv_range;
	cpufuncs.cf_l2cache_wb_range = pl310_wb_range;

	return (0);
}
Ejemplo n.º 26
0
static struct resource *
lbc_alloc_resource(device_t bus, device_t child, int type, int *rid,
    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
{
	struct lbc_softc *sc;
	struct lbc_devinfo *di;
	struct resource_list_entry *rle;
	struct resource *res;
	struct rman *rm;
	int needactivate;

	/* We only support default allocations. */
	if (!RMAN_IS_DEFAULT_RANGE(start, end))
		return (NULL);

	sc = device_get_softc(bus);
	if (type == SYS_RES_IRQ)
		return (bus_alloc_resource(bus, type, rid, start, end, count,
		    flags));

	/*
	 * Request for the default allocation with a given rid: use resource
	 * list stored in the local device info.
	 */
	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;
	count = rle->count;
	end = start + count - 1;

	sc = device_get_softc(bus);

	needactivate = flags & RF_ACTIVE;
	flags &= ~RF_ACTIVE;

	rm = &sc->sc_rman;

	res = rman_reserve_resource(rm, start, end, count, flags, child);
	if (res == NULL) {
		device_printf(bus, "failed to reserve resource %#lx - %#lx "
		    "(%#lx)\n", start, end, count);
		return (NULL);
	}

	rman_set_rid(res, *rid);
	rman_set_bustag(res, &bs_be_tag);
	rman_set_bushandle(res, rman_get_start(res));

	if (needactivate)
		if (bus_activate_resource(child, type, *rid, res)) {
			device_printf(child, "resource activation failed\n");
			rman_release_resource(res);
			return (NULL);
		}

	return (res);
}
Ejemplo n.º 27
0
static int
ata_macio_setmode(device_t dev, int target, int mode)
{
	struct ata_macio_softc *sc = device_get_softc(dev);

	int min_cycle = 0, min_active = 0;
        int cycle_tick = 0, act_tick = 0, inact_tick = 0, half_tick;

	mode = min(mode, sc->max_mode);

	if ((mode & ATA_DMA_MASK) == ATA_UDMA0) {
		min_cycle = udma_timings[mode & ATA_MODE_MASK].cycle;
		min_active = udma_timings[mode & ATA_MODE_MASK].active;
	
		cycle_tick = ATA_TIME_TO_TICK(sc->rev,min_cycle);
		act_tick = ATA_TIME_TO_TICK(sc->rev,min_active);

		/* mask: 0x1ff00000 */
		sc->udmaconf[target] =
		    (cycle_tick << 21) | (act_tick << 25) | 0x100000;
	} else if ((mode & ATA_DMA_MASK) == ATA_WDMA0) {
		min_cycle = dma_timings[mode & ATA_MODE_MASK].cycle;
		min_active = dma_timings[mode & ATA_MODE_MASK].active;
	
		cycle_tick = ATA_TIME_TO_TICK(sc->rev,min_cycle);
		act_tick = ATA_TIME_TO_TICK(sc->rev,min_active);

		if (sc->rev == 4) {
			inact_tick = cycle_tick - act_tick;
			/* mask: 0x001ffc00 */
			sc->wdmaconf[target] = 
			    (act_tick << 10) | (inact_tick << 15);
		} else {
			inact_tick = cycle_tick - act_tick - DMA_REC_OFFSET;
			if (inact_tick < DMA_REC_MIN)
				inact_tick = DMA_REC_MIN;
			half_tick = 0;  /* XXX */

			/* mask: 0xfffff800 */
			sc->wdmaconf[target] = (half_tick << 21) 
			    | (inact_tick << 16) | (act_tick << 11);
		}
	} else {
		min_cycle = 
		    pio_timings[(mode & ATA_MODE_MASK) - ATA_PIO0].cycle;
		min_active = 
		    pio_timings[(mode & ATA_MODE_MASK) - ATA_PIO0].active;
	
		cycle_tick = ATA_TIME_TO_TICK(sc->rev,min_cycle);
		act_tick = ATA_TIME_TO_TICK(sc->rev,min_active);

		if (sc->rev == 4) {
			inact_tick = cycle_tick - act_tick;

			/* mask: 0x000003ff */
			sc->pioconf[target] =
			    (inact_tick << 5) | act_tick;
		} else {
			if (act_tick < PIO_ACT_MIN)
				act_tick = PIO_ACT_MIN;

			inact_tick = cycle_tick - act_tick - PIO_REC_OFFSET;
			if (inact_tick < PIO_REC_MIN)
				inact_tick = PIO_REC_MIN;

			/* mask: 0x000007ff */
			sc->pioconf[target] = 
			    (inact_tick << 5) | act_tick;
		}
	}

	return (mode);
}
Ejemplo n.º 28
0
static int 
acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct thread *td)
{
    device_t dev = pp->geom->softc;
    struct ata_device *atadev = device_get_softc(dev);
    struct acd_softc *cdp = device_get_ivars(dev);
    int error = 0, nocopyout = 0;

    if (!cdp)
	return ENXIO;

    if (atadev->flags & ATA_D_MEDIA_CHANGED) {
	switch (cmd) {
	case CDIOCRESET:
	    acd_test_ready(dev);
	    break;
	   
	default:
	    acd_read_toc(dev);
	    acd_prevent_allow(dev, 1);
	    cdp->flags |= F_LOCKED;
	    break;
	}
    }

    switch (cmd) {

    case CDIOCRESUME:
	error = acd_pause_resume(dev, 1);
	break;

    case CDIOCPAUSE:
	error = acd_pause_resume(dev, 0);
	break;

    case CDIOCSTART:
	error = acd_start_stop(dev, 1);
	break;

    case CDIOCSTOP:
	error = acd_start_stop(dev, 0);
	break;

    case CDIOCALLOW:
	error = acd_prevent_allow(dev, 0);
	cdp->flags &= ~F_LOCKED;
	break;

    case CDIOCPREVENT:
	error = acd_prevent_allow(dev, 1);
	cdp->flags |= F_LOCKED;
	break;

    /*
     * XXXRW: Why does this require privilege?
     */
    case CDIOCRESET:
	error = priv_check(td, PRIV_DRIVER);
	if (error)
	    break;
	error = acd_test_ready(dev);
	break;

    case CDIOCEJECT:
	if (pp->acr != 1) {
	    error = EBUSY;
	    break;
	}
	error = acd_tray(dev, 0);
	break;

    case CDIOCCLOSE:
	if (pp->acr != 1)
	    break;
	error = acd_tray(dev, 1);
	break;

    case CDIOREADTOCHEADER:
	if (!cdp->toc.hdr.ending_track) {
	    error = EIO;
	    break;
	}
	bcopy(&cdp->toc.hdr, addr, sizeof(cdp->toc.hdr));
	break;

    case CDIOREADTOCENTRYS:
	{
	    struct ioc_read_toc_entry *te = (struct ioc_read_toc_entry *)addr;
	    struct toc *toc = &cdp->toc;
	    int starting_track = te->starting_track;
	    int len;

	    if (!toc->hdr.ending_track) {
		error = EIO;
		break;
	    }

	    if (te->data_len < sizeof(toc->tab[0]) || 
		(te->data_len % sizeof(toc->tab[0])) != 0 || 
		(te->address_format != CD_MSF_FORMAT &&
		te->address_format != CD_LBA_FORMAT)) {
		error = EINVAL;
		break;
	    }

	    if (!starting_track)
		starting_track = toc->hdr.starting_track;
	    else if (starting_track == 170) 
		starting_track = toc->hdr.ending_track + 1;
	    else if (starting_track < toc->hdr.starting_track ||
		     starting_track > toc->hdr.ending_track + 1) {
		error = EINVAL;
		break;
	    }

	    len = ((toc->hdr.ending_track + 1 - starting_track) + 1) *
		  sizeof(toc->tab[0]);
	    if (te->data_len < len)
		len = te->data_len;
	    if (len > sizeof(toc->tab)) {
		error = EINVAL;
		break;
	    }

	    if (te->address_format == CD_MSF_FORMAT) {
		struct cd_toc_entry *entry;

		if (!(toc = malloc(sizeof(struct toc), M_ACD, M_NOWAIT))) {
		    error = ENOMEM;
		    break;
		}
		bcopy(&cdp->toc, toc, sizeof(struct toc));
		entry = toc->tab + (toc->hdr.ending_track + 1 -
			toc->hdr.starting_track) + 1;
		while (--entry >= toc->tab) {
		    lba2msf(ntohl(entry->addr.lba), &entry->addr.msf.minute,
			    &entry->addr.msf.second, &entry->addr.msf.frame);
		    entry->addr_type = CD_MSF_FORMAT;
		}
	    }
	    error = copyout(toc->tab + starting_track - toc->hdr.starting_track,
			    te->data, len);
	    if (te->address_format == CD_MSF_FORMAT)
		free(toc, M_ACD);
	}
	break;

    case CDIOREADTOCENTRY:
	{
	    struct ioc_read_toc_single_entry *te =
		(struct ioc_read_toc_single_entry *)addr;
	    struct toc *toc = &cdp->toc;
	    u_char track = te->track;

	    if (!toc->hdr.ending_track) {
		error = EIO;
		break;
	    }

	    if (te->address_format != CD_MSF_FORMAT && 
		te->address_format != CD_LBA_FORMAT) {
		error = EINVAL;
		break;
	    }

	    if (!track)
		track = toc->hdr.starting_track;
	    else if (track == 170)
		track = toc->hdr.ending_track + 1;
	    else if (track < toc->hdr.starting_track ||
		     track > toc->hdr.ending_track + 1) {
		error = EINVAL;
		break;
	    }

	    if (te->address_format == CD_MSF_FORMAT) {
		struct cd_toc_entry *entry;

		if (!(toc = malloc(sizeof(struct toc), M_ACD, M_NOWAIT))) {
		    error = ENOMEM;
		    break;
		}
		bcopy(&cdp->toc, toc, sizeof(struct toc));
		entry = toc->tab + (track - toc->hdr.starting_track);
		lba2msf(ntohl(entry->addr.lba), &entry->addr.msf.minute,
			&entry->addr.msf.second, &entry->addr.msf.frame);
	    }
	    bcopy(toc->tab + track - toc->hdr.starting_track,
		  &te->entry, sizeof(struct cd_toc_entry));
	    if (te->address_format == CD_MSF_FORMAT)
		free(toc, M_ACD);
	}
	break;

#if __FreeBSD_version > 600008
    case CDIOCREADSUBCHANNEL_SYSSPACE:
	nocopyout = 1;
	/* FALLTHROUGH */

#endif
    case CDIOCREADSUBCHANNEL:
	{
	    struct ioc_read_subchannel *args =
		(struct ioc_read_subchannel *)addr;
	    u_int8_t format;
	    int8_t ccb[16] = { ATAPI_READ_SUBCHANNEL, 0, 0x40, 1, 0, 0, 0,
			       sizeof(cdp->subchan)>>8, sizeof(cdp->subchan),
			       0, 0, 0, 0, 0, 0, 0 };

	    if (args->data_len > sizeof(struct cd_sub_channel_info) ||
		args->data_len < sizeof(struct cd_sub_channel_header)) {
		error = EINVAL;
		break;
	    }

	    format = args->data_format;
	    if ((format != CD_CURRENT_POSITION) &&
		(format != CD_MEDIA_CATALOG) && (format != CD_TRACK_INFO)) {
		error = EINVAL;
		break;
	    }

	    ccb[1] = args->address_format & CD_MSF_FORMAT;

	    if ((error = ata_atapicmd(dev, ccb, (caddr_t)&cdp->subchan,
				      sizeof(cdp->subchan), ATA_R_READ, 10)))
		break;

	    if ((format == CD_MEDIA_CATALOG) || (format == CD_TRACK_INFO)) {
		if (cdp->subchan.header.audio_status == 0x11) {
		    error = EINVAL;
		    break;
		}

		ccb[3] = format;
		if (format == CD_TRACK_INFO)
		    ccb[6] = args->track;

		if ((error = ata_atapicmd(dev, ccb, (caddr_t)&cdp->subchan, 
					  sizeof(cdp->subchan),ATA_R_READ,10))){
		    break;
		}
	    }
	    if (nocopyout == 0) {
		error = copyout(&cdp->subchan, args->data, args->data_len);
	    } else {
		error = 0;
		bcopy(&cdp->subchan, args->data, args->data_len);
	    }
	}
	break;

    case CDIOCPLAYMSF:
	{
	    struct ioc_play_msf *args = (struct ioc_play_msf *)addr;

	    error = 
		acd_play(dev, 
			 msf2lba(args->start_m, args->start_s, args->start_f),
			 msf2lba(args->end_m, args->end_s, args->end_f));
	}
	break;

    case CDIOCPLAYBLOCKS:
	{
	    struct ioc_play_blocks *args = (struct ioc_play_blocks *)addr;

	    error = acd_play(dev, args->blk, args->blk + args->len);
	}
	break;

    case CDIOCPLAYTRACKS:
	{
	    struct ioc_play_track *args = (struct ioc_play_track *)addr;
	    int t1, t2;

	    if (!cdp->toc.hdr.ending_track) {
		error = EIO;
		break;
	    }
	    if (args->end_track < cdp->toc.hdr.ending_track + 1)
		++args->end_track;
	    if (args->end_track > cdp->toc.hdr.ending_track + 1)
		args->end_track = cdp->toc.hdr.ending_track + 1;
	    t1 = args->start_track - cdp->toc.hdr.starting_track;
	    t2 = args->end_track - cdp->toc.hdr.starting_track;
	    if (t1 < 0 || t2 < 0 ||
		t1 > (cdp->toc.hdr.ending_track-cdp->toc.hdr.starting_track)) {
		error = EINVAL;
		break;
	    }
	    error = acd_play(dev, ntohl(cdp->toc.tab[t1].addr.lba),
			     ntohl(cdp->toc.tab[t2].addr.lba));
	}
	break;

    case CDIOCGETVOL:
	{
	    struct ioc_vol *arg = (struct ioc_vol *)addr;

	    if ((error = acd_mode_sense(dev, ATAPI_CDROM_AUDIO_PAGE,
					(caddr_t)&cdp->au, sizeof(cdp->au))))
		break;

	    if (cdp->au.page_code != ATAPI_CDROM_AUDIO_PAGE) {
		error = EIO;
		break;
	    }
	    arg->vol[0] = cdp->au.port[0].volume;
	    arg->vol[1] = cdp->au.port[1].volume;
	    arg->vol[2] = cdp->au.port[2].volume;
	    arg->vol[3] = cdp->au.port[3].volume;
	}
	break;

    case CDIOCSETVOL:
	{
	    struct ioc_vol *arg = (struct ioc_vol *)addr;

	    if ((error = acd_mode_sense(dev, ATAPI_CDROM_AUDIO_PAGE,
					(caddr_t)&cdp->au, sizeof(cdp->au))))
		break;
	    if (cdp->au.page_code != ATAPI_CDROM_AUDIO_PAGE) {
		error = EIO;
		break;
	    }
	    if ((error = acd_mode_sense(dev, ATAPI_CDROM_AUDIO_PAGE_MASK,
					(caddr_t)&cdp->aumask,
					sizeof(cdp->aumask))))
		break;
	    cdp->au.data_length = 0;
	    cdp->au.port[0].channels = CHANNEL_0;
	    cdp->au.port[1].channels = CHANNEL_1;
	    cdp->au.port[0].volume = arg->vol[0] & cdp->aumask.port[0].volume;
	    cdp->au.port[1].volume = arg->vol[1] & cdp->aumask.port[1].volume;
	    cdp->au.port[2].volume = arg->vol[2] & cdp->aumask.port[2].volume;
	    cdp->au.port[3].volume = arg->vol[3] & cdp->aumask.port[3].volume;
	    error =  acd_mode_select(dev, (caddr_t)&cdp->au, sizeof(cdp->au));
	}
	break;

    case CDIOCSETPATCH:
	{
	    struct ioc_patch *arg = (struct ioc_patch *)addr;

	    error = acd_setchan(dev, arg->patch[0], arg->patch[1],
				arg->patch[2], arg->patch[3]);
	}
	break;

    case CDIOCSETMONO:
	error = acd_setchan(dev, CHANNEL_0|CHANNEL_1, CHANNEL_0|CHANNEL_1, 0,0);
	break;

    case CDIOCSETSTEREO:
	error = acd_setchan(dev, CHANNEL_0, CHANNEL_1, 0, 0);
	break;

    case CDIOCSETMUTE:
	error = acd_setchan(dev, 0, 0, 0, 0);
	break;

    case CDIOCSETLEFT:
	error = acd_setchan(dev, CHANNEL_0, CHANNEL_0, 0, 0);
	break;

    case CDIOCSETRIGHT:
	error = acd_setchan(dev, CHANNEL_1, CHANNEL_1, 0, 0);
	break;

    case CDRIOCBLANK:
	error = acd_blank(dev, (*(int *)addr));
	break;

    case CDRIOCNEXTWRITEABLEADDR:
	{
	    struct acd_track_info track_info;

	    if ((error = acd_read_track_info(dev, 0xff, &track_info)))
		break;

	    if (!track_info.nwa_valid) {
		error = EINVAL;
		break;
	    }
	    *(int*)addr = track_info.next_writeable_addr;
	}
	break;
 
    case CDRIOCINITWRITER:
	error = acd_init_writer(dev, (*(int *)addr));
	break;

    case CDRIOCINITTRACK:
	error = acd_init_track(dev, (struct cdr_track *)addr);
	break;

    case CDRIOCFLUSH:
	error = acd_flush(dev);
	break;

    case CDRIOCFIXATE:
	error = acd_fixate(dev, (*(int *)addr));
	break;

    case CDRIOCREADSPEED:
	{
	    int speed = *(int *)addr;

	    /* Preserve old behavior: units in multiples of CDROM speed */
	    if (speed < 177)
		speed *= 177;
	    error = acd_set_speed(dev, speed, CDR_MAX_SPEED);
	}
	break;

    case CDRIOCWRITESPEED:
	{
	    int speed = *(int *)addr;

	    if (speed < 177)
		speed *= 177;
	    error = acd_set_speed(dev, CDR_MAX_SPEED, speed);
	}
	break;

    case CDRIOCGETBLOCKSIZE:
	*(int *)addr = cdp->block_size;
	break;

    case CDRIOCSETBLOCKSIZE:
	cdp->block_size = *(int *)addr;
	pp->sectorsize = cdp->block_size;       /* hack for GEOM SOS */
	acd_set_ioparm(dev);
	break;

    case CDRIOCGETPROGRESS:
	error = acd_get_progress(dev, (int *)addr);
	break;

    case CDRIOCSENDCUE:
	error = acd_send_cue(dev, (struct cdr_cuesheet *)addr);
	break;

    case CDRIOCREADFORMATCAPS:
	error = acd_read_format_caps(dev, (struct cdr_format_capacities *)addr);
	break;

    case CDRIOCFORMAT:
	error = acd_format(dev, (struct cdr_format_params *)addr);
	break;

    case DVDIOCREPORTKEY:
	if (cdp->cap.media & MST_READ_DVDROM)
	    error = acd_report_key(dev, (struct dvd_authinfo *)addr);
	else
	    error = EINVAL;
	break;

    case DVDIOCSENDKEY:
	if (cdp->cap.media & MST_READ_DVDROM)
	    error = acd_send_key(dev, (struct dvd_authinfo *)addr);
	else
	    error = EINVAL;
	break;

    case DVDIOCREADSTRUCTURE:
	if (cdp->cap.media & MST_READ_DVDROM)
	    error = acd_read_structure(dev, (struct dvd_struct *)addr);
	else
	    error = EINVAL;
	break;

    default:
	error = ata_device_ioctl(dev, cmd, addr);
    }
    return error;
}

static int
acd_geom_access(struct g_provider *pp, int dr, int dw, int de)
{
    device_t dev = pp->geom->softc;
    struct acd_softc *cdp = device_get_ivars(dev);
    struct ata_request *request;
    int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0,
		       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    int timeout = 60, track;

    if (!(request = ata_alloc_request()))
	return ENOMEM;

    /* wait if drive is not finished loading the medium */
    while (timeout--) {
	request->dev = dev;
	bcopy(ccb, request->u.atapi.ccb, 16);
	request->flags = ATA_R_ATAPI;
	request->timeout = ATA_REQUEST_TIMEOUT;
	ata_queue_request(request);
	if (!request->error &&
	    (request->u.atapi.sense.key == 2 ||
	     request->u.atapi.sense.key == 7) &&
	    request->u.atapi.sense.asc == 4 &&
	    request->u.atapi.sense.ascq == 1)
	    pause("acdld", hz / 2);
	else
	    break;
    }
    ata_free_request(request);

    if (pp->acr == 0) {
	acd_prevent_allow(dev, 1);
	cdp->flags |= F_LOCKED;
	acd_read_toc(dev);
    }

    if (dr + pp->acr == 0) {
	acd_prevent_allow(dev, 0);
	cdp->flags &= ~F_LOCKED;
    }

    if ((track = pp->index)) {
	pp->sectorsize = (cdp->toc.tab[track - 1].control & 4) ? 2048 : 2352;
	pp->mediasize = ntohl(cdp->toc.tab[track].addr.lba) -
			ntohl(cdp->toc.tab[track - 1].addr.lba);
    }
    else {
	pp->sectorsize = cdp->block_size;
	pp->mediasize = cdp->disk_size;
    }
    pp->mediasize *= pp->sectorsize;

    return 0;
}
Ejemplo n.º 29
0
static int
ohci_obio_attach(device_t self)
{
	ohci_softc_t *sc = device_get_softc(self);
	uint32_t reg;
	int err;
	int rid;

	/* setup controller interface softc */
	reg = rt305x_sysctl_get(SYSCTL_SYSCFG1);
	reg |= SYSCTL_SYSCFG1_USB0_HOST_MODE;
	rt305x_sysctl_set(SYSCTL_SYSCFG1, reg);

	reg = rt305x_sysctl_get(SYSCTL_CLKCFG1);
	reg |= SYSCTL_CLKCFG1_UPHY0_CLK_EN;
#ifdef MT7620
	reg |= SYSCTL_CLKCFG1_UPHY1_CLK_EN;
#endif
	rt305x_sysctl_set(SYSCTL_CLKCFG1, reg);

	reg = rt305x_sysctl_get(SYSCTL_RSTCTRL);
	reg |= SYSCTL_RSTCTRL_UPHY0 | SYSCTL_RSTCTRL_UPHY1;
	rt305x_sysctl_set(SYSCTL_RSTCTRL, reg);
	reg &= ~(SYSCTL_RSTCTRL_UPHY0 | SYSCTL_RSTCTRL_UPHY1);
	DELAY(100000);
	rt305x_sysctl_set(SYSCTL_RSTCTRL, reg);
	DELAY(100000);

	/* initialise some bus fields */
	sc->sc_bus.parent = self;
	sc->sc_bus.devices = sc->sc_devices;
	sc->sc_bus.devices_max = OHCI_MAX_DEVICES;
	sc->sc_bus.dma_bits = 32;

	/* get all DMA memory */
	if (usb_bus_mem_alloc_all(&sc->sc_bus,
	    USB_GET_DMA_TAG(self), &ohci_iterate_hw_softc)) {
		printf("No mem\n");
		return (ENOMEM);
	}

	rid = 0;
	sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid,
				RF_ACTIVE);
	if (!sc->sc_io_res) {
		device_printf(self, "Could not map memory\n");
		goto error;
	}
	sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
	sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
	sc->sc_io_size = rman_get_size(sc->sc_io_res);

	rid = 0;
	sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid,
		RF_SHAREABLE | RF_ACTIVE);
	if (sc->sc_irq_res == NULL) {
		device_printf(self, "Could not allocate irq\n");
		goto error;
	}

	sc->sc_bus.bdev = device_add_child(self, "usbus", -1);
	if (!(sc->sc_bus.bdev)) {
		device_printf(self, "Could not add USB device\n");
		goto error;
	}
	device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
	device_set_desc(sc->sc_bus.bdev, OHCI_HC_DEVSTR);

	sprintf(sc->sc_vendor, "Ralink");

	err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
		NULL, (driver_intr_t *)ohci_interrupt, sc, &sc->sc_intr_hdl);
	if (err) {
		device_printf(self, "Could not setup irq, %d\n", err);
		sc->sc_intr_hdl = NULL;
		goto error;
	}

	err = ohci_init(sc);
	if (!err) {
		err = device_probe_and_attach(sc->sc_bus.bdev);
	}
	if (err) {
		device_printf(self, "USB init failed err=%d\n", err);
		goto error;
	}
	return (0);

error:
	ohci_obio_detach(self);
	return (ENXIO);
}
Ejemplo n.º 30
0
int
rk_cru_attach(device_t dev)
{
	struct rk_cru_softc *sc;
	phandle_t node;
	int	i;

	sc = device_get_softc(dev);
	sc->dev = dev;

	node = ofw_bus_get_node(dev);

	if (bus_alloc_resources(dev, rk_cru_spec, &sc->res) != 0) {
		device_printf(dev, "cannot allocate resources for device\n");
		return (ENXIO);
	}

	mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);

	sc->clkdom = clkdom_create(dev);
	if (sc->clkdom == NULL)
		panic("Cannot create clkdom\n");

	for (i = 0; i < sc->nclks; i++) {
		switch (sc->clks[i].type) {
		case RK_CLK_UNDEFINED:
			break;
		case RK_CLK_PLL:
			rk_clk_pll_register(sc->clkdom, sc->clks[i].clk.pll);
			break;
		case RK_CLK_COMPOSITE:
			rk_clk_composite_register(sc->clkdom,
			    sc->clks[i].clk.composite);
			break;
		case RK_CLK_MUX:
			rk_clk_mux_register(sc->clkdom, sc->clks[i].clk.mux);
			break;
		case RK_CLK_ARMCLK:
			rk_clk_armclk_register(sc->clkdom, sc->clks[i].clk.armclk);
			break;
		default:
			device_printf(dev, "Unknown clock type\n");
			return (ENXIO);
			break;
		}
	}
	if (sc->gates)
		rk_cru_register_gates(sc);

	if (clkdom_finit(sc->clkdom) != 0)
		panic("cannot finalize clkdom initialization\n");

	if (bootverbose)
		clkdom_dump(sc->clkdom);

	clk_set_assigned(dev, node);

	/* If we have resets, register our self as a reset provider */
	if (sc->resets)
		hwreset_register_ofw_provider(dev);

	return (0);
}