/*-
* Copyright (C) 1998 Internet Research Institute, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by
* Internet Research Institute, Inc.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE)
switch (PCI_PRODUCT(pa->pa_id)) {
case PCI_PRODUCT_APPLE_GC:
case PCI_PRODUCT_APPLE_OHARE:
case PCI_PRODUCT_APPLE_HEATHROW:
case PCI_PRODUCT_APPLE_PADDINGTON:
case PCI_PRODUCT_APPLE_KEYLARGO:
case PCI_PRODUCT_APPLE_PANGEA_MACIO:
case PCI_PRODUCT_APPLE_INTREPID:
case PCI_PRODUCT_APPLE_K2:
case PCI_PRODUCT_APPLE_SHASTA:
return 1;
}
return 0;
}
/*
* Attach all the sub-devices we can find
*/
void
obio_attach(device_t parent, device_t self, void *aux)
{
struct obio_softc *sc = device_private(self);
struct pci_attach_args *pa = aux;
struct confargs ca;
bus_space_handle_t bsh;
int node, child, namelen, error;
u_int reg[20];
int intr[6], parent_intr = 0, parent_nintr = 0;
int map_size = 0x1000;
char name[32];
char compat[32];
case PCI_PRODUCT_APPLE_GC:
case PCI_PRODUCT_APPLE_OHARE:
case PCI_PRODUCT_APPLE_HEATHROW:
case PCI_PRODUCT_APPLE_PADDINGTON:
case PCI_PRODUCT_APPLE_KEYLARGO:
case PCI_PRODUCT_APPLE_PANGEA_MACIO:
case PCI_PRODUCT_APPLE_INTREPID:
node = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag);
if (node == -1)
node = OF_finddevice("mac-io");
if (node == -1)
node = OF_finddevice("/pci/mac-io");
break;
case PCI_PRODUCT_APPLE_K2:
case PCI_PRODUCT_APPLE_SHASTA:
node = OF_finddevice("mac-io");
map_size = 0x10000;
break;
default:
node = -1;
break;
}
if (node == -1)
panic("macio not found or unknown");
sc->sc_node = node;
#if defined (PMAC_G5)
if (OF_getprop(node, "assigned-addresses", reg, sizeof(reg)) < 20)
{
return;
}
#else
if (OF_getprop(node, "assigned-addresses", reg, sizeof(reg)) < 12)
return;
#endif /* PMAC_G5 */
/*
* XXX
* This relies on the primary obio always attaching first which is
* true on the PowerBook 3400c and similar machines but may or may
* not work on others. We can't rely on the node name since Apple
* didn't follow anything remotely resembling a consistent naming
* scheme.
*/
if (obio0 == NULL)
obio0 = sc;
/* now look for voltage and bus speed gpios */
use_dfs = 0;
for (child = OF_child(node); child; child = OF_peer(child)) {
if (OF_getprop(child, "name", name, sizeof(name)) < 1)
continue;
if (OF_getprop(child, "reg", reg, sizeof(reg)) < 4)
continue;
/*
* These register offsets either have to be added to the obio
* base address or to the gpio base address. This differs
* even in the same OF-tree! So we guess the offset is
* based on obio when it is larger than the gpio_base.
*/
if (reg[0] >= gpio_base)
reg[0] -= gpio_base;
if (strcmp(name, "frequency-gpio") == 0) {
DPRINTF("found frequency_gpio at %02x\n", reg[0]);
sc->sc_busspeed = gpio_base + reg[0];
}
if (strcmp(name, "voltage-gpio") == 0) {
DPRINTF("found voltage_gpio at %02x\n", reg[0]);
sc->sc_voltage = gpio_base + reg[0];
}
if (strcmp(name, "cpu-vcore-select") == 0) {
DPRINTF("found cpu-vcore-select at %02x\n", reg[0]);
sc->sc_voltage = gpio_base + reg[0];
/* frequency gpio is not needed, we use cpu's DFS */
use_dfs = 1;
}
}
/* support cpufreq */
snprintf(cf->cf_name, CPUFREQ_NAME_MAX, "Intrepid");
cf->cf_state[0].cfs_freq = sc->sc_spd_hi;
cf->cf_state[1].cfs_freq = sc->sc_spd_lo;
cf->cf_state_count = 2;
cf->cf_mp = FALSE;
cf->cf_cookie = sc;
cf->cf_get_freq = obio_get_freq;
cf->cf_set_freq = obio_set_freq;
/*
* XXX
* cpufreq_register() calls xc_broadcast() which relies on kthreads
* running so we need to postpone it
*/
config_interrupts(sc->sc_dev, obio_setup_cpufreq);
}
static void
obio_set_cpu_speed(struct obio_softc *sc, int fast)
{
if (sc->sc_voltage < 0)
return;
if (sc->sc_busspeed >= 0) {
/* set voltage and speed via gpio */
if (fast) {
bus_space_write_1(sc->sc_tag, sc->sc_bh,
sc->sc_voltage, 5);
bus_space_write_1(sc->sc_tag, sc->sc_bh,
sc->sc_busspeed, 5);
} else {
bus_space_write_1(sc->sc_tag, sc->sc_bh,
sc->sc_busspeed, 4);
bus_space_write_1(sc->sc_tag, sc->sc_bh,
sc->sc_voltage, 4);
}
}
else {
/* set voltage via gpio and speed via the 7447A's DFS bit */
if (fast) {
bus_space_write_1(sc->sc_tag, sc->sc_bh,
sc->sc_voltage, 5);
DELAY(1000);
}
/* set DFS for all cpus */
cpu_set_dfs(fast ? 1 : 2);
DELAY(100);