1*3db86aabSstevel /* 2*3db86aabSstevel * CDDL HEADER START 3*3db86aabSstevel * 4*3db86aabSstevel * The contents of this file are subject to the terms of the 5*3db86aabSstevel * Common Development and Distribution License (the "License"). 6*3db86aabSstevel * You may not use this file except in compliance with the License. 7*3db86aabSstevel * 8*3db86aabSstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*3db86aabSstevel * or http://www.opensolaris.org/os/licensing. 10*3db86aabSstevel * See the License for the specific language governing permissions 11*3db86aabSstevel * and limitations under the License. 12*3db86aabSstevel * 13*3db86aabSstevel * When distributing Covered Code, include this CDDL HEADER in each 14*3db86aabSstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*3db86aabSstevel * If applicable, add the following below this CDDL HEADER, with the 16*3db86aabSstevel * fields enclosed by brackets "[]" replaced with your own identifying 17*3db86aabSstevel * information: Portions Copyright [yyyy] [name of copyright owner] 18*3db86aabSstevel * 19*3db86aabSstevel * CDDL HEADER END 20*3db86aabSstevel */ 21*3db86aabSstevel 22*3db86aabSstevel /* 23*3db86aabSstevel * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*3db86aabSstevel * Use is subject to license terms. 25*3db86aabSstevel */ 26*3db86aabSstevel 27*3db86aabSstevel #pragma ident "%Z%%M% %I% %E% SMI" 28*3db86aabSstevel 29*3db86aabSstevel /* 30*3db86aabSstevel * PCIC device/interrupt handler 31*3db86aabSstevel * The "pcic" driver handles the Intel 82365SL, Cirrus Logic 32*3db86aabSstevel * and Toshiba (and possibly other clones) PCMCIA adapter chip 33*3db86aabSstevel * sets. It implements a subset of Socket Services as defined 34*3db86aabSstevel * in the Solaris PCMCIA design documents 35*3db86aabSstevel */ 36*3db86aabSstevel 37*3db86aabSstevel /* 38*3db86aabSstevel * currently defined "properties" 39*3db86aabSstevel * 40*3db86aabSstevel * clock-frequency bus clock frequency 41*3db86aabSstevel * smi system management interrupt override 42*3db86aabSstevel * need-mult-irq need status IRQ for each pair of sockets 43*3db86aabSstevel * disable-audio don't route audio signal to speaker 44*3db86aabSstevel */ 45*3db86aabSstevel 46*3db86aabSstevel 47*3db86aabSstevel #include <sys/types.h> 48*3db86aabSstevel #include <sys/inttypes.h> 49*3db86aabSstevel #include <sys/param.h> 50*3db86aabSstevel #include <sys/systm.h> 51*3db86aabSstevel #include <sys/user.h> 52*3db86aabSstevel #include <sys/buf.h> 53*3db86aabSstevel #include <sys/file.h> 54*3db86aabSstevel #include <sys/uio.h> 55*3db86aabSstevel #include <sys/conf.h> 56*3db86aabSstevel #include <sys/stat.h> 57*3db86aabSstevel #include <sys/autoconf.h> 58*3db86aabSstevel #include <sys/vtoc.h> 59*3db86aabSstevel #include <sys/dkio.h> 60*3db86aabSstevel #include <sys/ddi.h> 61*3db86aabSstevel #include <sys/sunddi.h> 62*3db86aabSstevel #include <sys/sunndi.h> 63*3db86aabSstevel #include <sys/var.h> 64*3db86aabSstevel #include <sys/callb.h> 65*3db86aabSstevel #include <sys/open.h> 66*3db86aabSstevel #include <sys/ddidmareq.h> 67*3db86aabSstevel #include <sys/dma_engine.h> 68*3db86aabSstevel #include <sys/kstat.h> 69*3db86aabSstevel #include <sys/kmem.h> 70*3db86aabSstevel #include <sys/modctl.h> 71*3db86aabSstevel #include <sys/pci.h> 72*3db86aabSstevel #include <sys/pci_impl.h> 73*3db86aabSstevel 74*3db86aabSstevel #include <sys/pctypes.h> 75*3db86aabSstevel #include <sys/pcmcia.h> 76*3db86aabSstevel #include <sys/sservice.h> 77*3db86aabSstevel 78*3db86aabSstevel #include <sys/note.h> 79*3db86aabSstevel 80*3db86aabSstevel #include <sys/pcic_reg.h> 81*3db86aabSstevel #include <sys/pcic_var.h> 82*3db86aabSstevel 83*3db86aabSstevel #if defined(__sparc) 84*3db86aabSstevel #include <sys/pci/pci_nexus.h> 85*3db86aabSstevel #endif 86*3db86aabSstevel 87*3db86aabSstevel #include <sys/syshw.h> 88*3db86aabSstevel #include "cardbus/cardbus.h" 89*3db86aabSstevel 90*3db86aabSstevel #define SOFTC_SIZE (sizeof (anp_t)) 91*3db86aabSstevel 92*3db86aabSstevel static int pcic_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 93*3db86aabSstevel static int pcic_attach(dev_info_t *, ddi_attach_cmd_t); 94*3db86aabSstevel static int pcic_detach(dev_info_t *, ddi_detach_cmd_t); 95*3db86aabSstevel static uint_t pcic_intr(caddr_t, caddr_t); 96*3db86aabSstevel static int pcic_do_io_intr(pcicdev_t *, uint32_t); 97*3db86aabSstevel static int pcic_probe(dev_info_t *); 98*3db86aabSstevel 99*3db86aabSstevel static int pcic_open(dev_t *, int, int, cred_t *); 100*3db86aabSstevel static int pcic_close(dev_t, int, int, cred_t *); 101*3db86aabSstevel static int pcic_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 102*3db86aabSstevel 103*3db86aabSstevel typedef struct pcm_regs pcm_regs_t; 104*3db86aabSstevel 105*3db86aabSstevel static void pcic_init_assigned(dev_info_t *); 106*3db86aabSstevel static int pcic_apply_avail_ranges(dev_info_t *, pcm_regs_t *, 107*3db86aabSstevel pci_regspec_t *, int); 108*3db86aabSstevel int pci_resource_setup_avail(dev_info_t *, pci_regspec_t *, int); 109*3db86aabSstevel 110*3db86aabSstevel /* 111*3db86aabSstevel * On x86 platforms the ddi_iobp_alloc(9F) and ddi_mem_alloc(9F) calls 112*3db86aabSstevel * are xlated into DMA ctlops. To make this nexus work on x86, we 113*3db86aabSstevel * need to have the default ddi_dma_mctl ctlops in the bus_ops 114*3db86aabSstevel * structure, just to pass the request to the parent. The correct 115*3db86aabSstevel * ctlops should be ddi_no_dma_mctl because so far we don't do DMA. 116*3db86aabSstevel */ 117*3db86aabSstevel static 118*3db86aabSstevel struct bus_ops pcmciabus_ops = { 119*3db86aabSstevel BUSO_REV, 120*3db86aabSstevel pcmcia_bus_map, 121*3db86aabSstevel NULL, 122*3db86aabSstevel NULL, 123*3db86aabSstevel NULL, 124*3db86aabSstevel i_ddi_map_fault, 125*3db86aabSstevel ddi_no_dma_map, 126*3db86aabSstevel ddi_no_dma_allochdl, 127*3db86aabSstevel ddi_no_dma_freehdl, 128*3db86aabSstevel ddi_no_dma_bindhdl, 129*3db86aabSstevel ddi_no_dma_unbindhdl, 130*3db86aabSstevel ddi_no_dma_flush, 131*3db86aabSstevel ddi_no_dma_win, 132*3db86aabSstevel ddi_dma_mctl, 133*3db86aabSstevel pcmcia_ctlops, 134*3db86aabSstevel pcmcia_prop_op, 135*3db86aabSstevel NULL, /* (*bus_get_eventcookie)(); */ 136*3db86aabSstevel NULL, /* (*bus_add_eventcall)(); */ 137*3db86aabSstevel NULL, /* (*bus_remove_eventcall)(); */ 138*3db86aabSstevel NULL, /* (*bus_post_event)(); */ 139*3db86aabSstevel NULL, /* (*bus_intr_ctl)(); */ 140*3db86aabSstevel NULL, /* (*bus_config)(); */ 141*3db86aabSstevel NULL, /* (*bus_unconfig)(); */ 142*3db86aabSstevel NULL, /* (*bus_fm_init)(); */ 143*3db86aabSstevel NULL, /* (*bus_fm_fini)(); */ 144*3db86aabSstevel NULL, /* (*bus_enter)() */ 145*3db86aabSstevel NULL, /* (*bus_exit)() */ 146*3db86aabSstevel NULL, /* (*bus_power)() */ 147*3db86aabSstevel pcmcia_intr_ops /* (*bus_intr_op)(); */ 148*3db86aabSstevel }; 149*3db86aabSstevel 150*3db86aabSstevel static struct cb_ops pcic_cbops = { 151*3db86aabSstevel pcic_open, 152*3db86aabSstevel pcic_close, 153*3db86aabSstevel nodev, 154*3db86aabSstevel nodev, 155*3db86aabSstevel nodev, 156*3db86aabSstevel nodev, 157*3db86aabSstevel nodev, 158*3db86aabSstevel pcic_ioctl, 159*3db86aabSstevel nodev, 160*3db86aabSstevel nodev, 161*3db86aabSstevel nodev, 162*3db86aabSstevel nochpoll, 163*3db86aabSstevel ddi_prop_op, 164*3db86aabSstevel NULL, 165*3db86aabSstevel #ifdef CARDBUS 166*3db86aabSstevel D_NEW | D_MP | D_HOTPLUG 167*3db86aabSstevel #else 168*3db86aabSstevel D_NEW | D_MP 169*3db86aabSstevel #endif 170*3db86aabSstevel }; 171*3db86aabSstevel 172*3db86aabSstevel static struct dev_ops pcic_devops = { 173*3db86aabSstevel DEVO_REV, 174*3db86aabSstevel 0, 175*3db86aabSstevel pcic_getinfo, 176*3db86aabSstevel nulldev, 177*3db86aabSstevel pcic_probe, 178*3db86aabSstevel pcic_attach, 179*3db86aabSstevel pcic_detach, 180*3db86aabSstevel nulldev, 181*3db86aabSstevel &pcic_cbops, 182*3db86aabSstevel &pcmciabus_ops, 183*3db86aabSstevel NULL 184*3db86aabSstevel }; 185*3db86aabSstevel 186*3db86aabSstevel void *pcic_soft_state_p = NULL; 187*3db86aabSstevel static int pcic_maxinst = -1; 188*3db86aabSstevel static timeout_id_t pcic_delayed_resume_toid; 189*3db86aabSstevel 190*3db86aabSstevel int pcic_do_insertion = 1; 191*3db86aabSstevel int pcic_do_removal = 1; 192*3db86aabSstevel 193*3db86aabSstevel struct irqmap { 194*3db86aabSstevel int irq; 195*3db86aabSstevel int count; 196*3db86aabSstevel } pcic_irq_map[16]; 197*3db86aabSstevel 198*3db86aabSstevel 199*3db86aabSstevel int pcic_debug = 0x0; 200*3db86aabSstevel static void pcic_err(dev_info_t *dip, int level, const char *fmt, ...); 201*3db86aabSstevel extern void cardbus_dump_pci_config(dev_info_t *dip); 202*3db86aabSstevel extern void cardbus_dump_socket(dev_info_t *dip); 203*3db86aabSstevel extern int cardbus_validate_iline(dev_info_t *dip, ddi_acc_handle_t handle); 204*3db86aabSstevel static void pcic_dump_debqueue(char *msg); 205*3db86aabSstevel 206*3db86aabSstevel #if defined(PCIC_DEBUG) 207*3db86aabSstevel static void xxdmp_all_regs(pcicdev_t *, int, uint32_t); 208*3db86aabSstevel 209*3db86aabSstevel #define pcic_mutex_enter(a) \ 210*3db86aabSstevel { \ 211*3db86aabSstevel pcic_err(NULL, 10, "Set lock at %d\n", __LINE__); \ 212*3db86aabSstevel mutex_enter(a); \ 213*3db86aabSstevel }; 214*3db86aabSstevel 215*3db86aabSstevel #define pcic_mutex_exit(a) \ 216*3db86aabSstevel { \ 217*3db86aabSstevel pcic_err(NULL, 10, "Clear lock at %d\n", __LINE__); \ 218*3db86aabSstevel mutex_exit(a); \ 219*3db86aabSstevel }; 220*3db86aabSstevel 221*3db86aabSstevel #else 222*3db86aabSstevel #define pcic_mutex_enter(a) mutex_enter(a) 223*3db86aabSstevel #define pcic_mutex_exit(a) mutex_exit(a) 224*3db86aabSstevel #endif 225*3db86aabSstevel 226*3db86aabSstevel #define PCIC_VCC_3VLEVEL 1 227*3db86aabSstevel #define PCIC_VCC_5VLEVEL 2 228*3db86aabSstevel #define PCIC_VCC_12LEVEL 3 229*3db86aabSstevel 230*3db86aabSstevel /* bit patterns to select voltage levels */ 231*3db86aabSstevel int pcic_vpp_levels[13] = { 232*3db86aabSstevel 0, 0, 0, 233*3db86aabSstevel 1, /* 3.3V */ 234*3db86aabSstevel 0, 235*3db86aabSstevel 1, /* 5V */ 236*3db86aabSstevel 0, 0, 0, 0, 0, 0, 237*3db86aabSstevel 2 /* 12V */ 238*3db86aabSstevel }; 239*3db86aabSstevel 240*3db86aabSstevel uint8_t pcic_cbv_levels[13] = { 241*3db86aabSstevel 0, 0, 0, 242*3db86aabSstevel 3, /* 3.3V */ 243*3db86aabSstevel 0, 244*3db86aabSstevel 2, /* 5V */ 245*3db86aabSstevel 0, 0, 0, 0, 0, 0, 246*3db86aabSstevel 1 /* 12V */ 247*3db86aabSstevel }; 248*3db86aabSstevel 249*3db86aabSstevel struct power_entry pcic_power[4] = { 250*3db86aabSstevel { 251*3db86aabSstevel 0, VCC|VPP1|VPP2 252*3db86aabSstevel }, 253*3db86aabSstevel { 254*3db86aabSstevel 33, /* 3.3Volt */ 255*3db86aabSstevel VCC|VPP1|VPP2 256*3db86aabSstevel }, 257*3db86aabSstevel { 258*3db86aabSstevel 5*10, /* 5Volt */ 259*3db86aabSstevel VCC|VPP1|VPP2 /* currently only know about this */ 260*3db86aabSstevel }, 261*3db86aabSstevel { 262*3db86aabSstevel 12*10, /* 12Volt */ 263*3db86aabSstevel VPP1|VPP2 264*3db86aabSstevel } 265*3db86aabSstevel }; 266*3db86aabSstevel 267*3db86aabSstevel /* 268*3db86aabSstevel * Base used to allocate ranges of PCI memory on x86 systems 269*3db86aabSstevel * Each instance gets a chunk above the base that is used to map 270*3db86aabSstevel * in the memory and I/O windows for that device. 271*3db86aabSstevel * Pages below the base are also allocated for the EXCA registers, 272*3db86aabSstevel * one per instance. 273*3db86aabSstevel */ 274*3db86aabSstevel #define PCIC_PCI_MEMCHUNK 0x1000000 275*3db86aabSstevel 276*3db86aabSstevel static int pcic_wait_insert_time = 5000000; /* In micro-seconds */ 277*3db86aabSstevel static int pcic_debounce_time = 200000; /* In micro-seconds */ 278*3db86aabSstevel 279*3db86aabSstevel struct debounce { 280*3db86aabSstevel pcic_socket_t *pcs; 281*3db86aabSstevel clock_t expire; 282*3db86aabSstevel struct debounce *next; 283*3db86aabSstevel }; 284*3db86aabSstevel 285*3db86aabSstevel static syshw_t pcic_syshw = { 286*3db86aabSstevel 0, "PC Card Socket 0", SH_CONNECTION, 287*3db86aabSstevel SYSHW_CAN_SIGNAL_CHANGE|SYSHW_STATE_VALID|SYSHW_VAL0_VALID, 288*3db86aabSstevel B_FALSE, {2, 0, 0, 0} 289*3db86aabSstevel }; 290*3db86aabSstevel 291*3db86aabSstevel static struct debounce *pcic_deb_queue = NULL; 292*3db86aabSstevel static kmutex_t pcic_deb_mtx; 293*3db86aabSstevel static kcondvar_t pcic_deb_cv; 294*3db86aabSstevel static kthread_t *pcic_deb_threadid; 295*3db86aabSstevel 296*3db86aabSstevel static inthandler_t *pcic_handlers; 297*3db86aabSstevel 298*3db86aabSstevel static void pcic_setup_adapter(pcicdev_t *); 299*3db86aabSstevel static int pcic_change(pcicdev_t *, int); 300*3db86aabSstevel static int pcic_ll_reset(pcicdev_t *, int); 301*3db86aabSstevel static void pcic_mswait(pcicdev_t *, int, int); 302*3db86aabSstevel static boolean_t pcic_check_ready(pcicdev_t *, int); 303*3db86aabSstevel static void pcic_set_cdtimers(pcicdev_t *, int, uint32_t, int); 304*3db86aabSstevel static void pcic_ready_wait(pcicdev_t *, int); 305*3db86aabSstevel extern int pcmcia_get_intr(dev_info_t *, int); 306*3db86aabSstevel extern int pcmcia_return_intr(dev_info_t *, int); 307*3db86aabSstevel 308*3db86aabSstevel static int pcic_callback(dev_info_t *, int (*)(), int); 309*3db86aabSstevel static int pcic_inquire_adapter(dev_info_t *, inquire_adapter_t *); 310*3db86aabSstevel static int pcic_get_adapter(dev_info_t *, get_adapter_t *); 311*3db86aabSstevel static int pcic_get_page(dev_info_t *, get_page_t *); 312*3db86aabSstevel static int pcic_get_socket(dev_info_t *, get_socket_t *); 313*3db86aabSstevel static int pcic_get_status(dev_info_t *, get_ss_status_t *); 314*3db86aabSstevel static int pcic_get_window(dev_info_t *, get_window_t *); 315*3db86aabSstevel static int pcic_inquire_socket(dev_info_t *, inquire_socket_t *); 316*3db86aabSstevel static int pcic_inquire_window(dev_info_t *, inquire_window_t *); 317*3db86aabSstevel static int pcic_reset_socket(dev_info_t *, int, int); 318*3db86aabSstevel static int pcic_set_page(dev_info_t *, set_page_t *); 319*3db86aabSstevel static int pcic_set_window(dev_info_t *, set_window_t *); 320*3db86aabSstevel static int pcic_set_socket(dev_info_t *, set_socket_t *); 321*3db86aabSstevel static int pcic_set_interrupt(dev_info_t *, set_irq_handler_t *); 322*3db86aabSstevel static int pcic_clear_interrupt(dev_info_t *, clear_irq_handler_t *); 323*3db86aabSstevel static void pcic_pm_detection(void *); 324*3db86aabSstevel static void pcic_iomem_pci_ctl(ddi_acc_handle_t, uchar_t *, unsigned); 325*3db86aabSstevel static int clext_reg_read(pcicdev_t *, int, uchar_t); 326*3db86aabSstevel static void clext_reg_write(pcicdev_t *, int, uchar_t, uchar_t); 327*3db86aabSstevel static int pcic_calc_speed(pcicdev_t *, uint32_t); 328*3db86aabSstevel static int pcic_card_state(pcicdev_t *, pcic_socket_t *); 329*3db86aabSstevel static int pcic_find_pci_type(pcicdev_t *); 330*3db86aabSstevel static void pcic_82092_smiirq_ctl(pcicdev_t *, int, int, int); 331*3db86aabSstevel static void pcic_handle_cd_change(pcicdev_t *, pcic_socket_t *, uint8_t); 332*3db86aabSstevel static uint_t pcic_cd_softint(caddr_t, caddr_t); 333*3db86aabSstevel static uint8_t pcic_getb(pcicdev_t *, int, int); 334*3db86aabSstevel static void pcic_putb(pcicdev_t *, int, int, int8_t); 335*3db86aabSstevel static int pcic_set_vcc_level(pcicdev_t *, set_socket_t *); 336*3db86aabSstevel static uint_t pcic_softintr(caddr_t, caddr_t); 337*3db86aabSstevel 338*3db86aabSstevel static void pcic_debounce(pcic_socket_t *); 339*3db86aabSstevel static void pcic_delayed_resume(void *); 340*3db86aabSstevel static void *pcic_add_debqueue(pcic_socket_t *, int); 341*3db86aabSstevel static void pcic_rm_debqueue(void *); 342*3db86aabSstevel static void pcic_deb_thread(); 343*3db86aabSstevel 344*3db86aabSstevel static boolean_t pcic_load_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp); 345*3db86aabSstevel static void pcic_unload_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp); 346*3db86aabSstevel static uint32_t pcic_getcb(pcicdev_t *pcic, int reg); 347*3db86aabSstevel static void pcic_putcb(pcicdev_t *pcic, int reg, uint32_t value); 348*3db86aabSstevel static void pcic_cb_enable_intr(dev_info_t *); 349*3db86aabSstevel static void pcic_cb_disable_intr(dev_info_t *); 350*3db86aabSstevel static void pcic_enable_io_intr(pcicdev_t *pcic, int socket, int irq); 351*3db86aabSstevel static void pcic_disable_io_intr(pcicdev_t *pcic, int socket); 352*3db86aabSstevel 353*3db86aabSstevel static cb_nexus_cb_t pcic_cbnexus_ops = { 354*3db86aabSstevel pcic_cb_enable_intr, 355*3db86aabSstevel pcic_cb_disable_intr 356*3db86aabSstevel }; 357*3db86aabSstevel 358*3db86aabSstevel static int pcic_exca_powerctl(pcicdev_t *pcic, int socket, int powerlevel); 359*3db86aabSstevel static int pcic_cbus_powerctl(pcicdev_t *pcic, int socket); 360*3db86aabSstevel 361*3db86aabSstevel static void pcic_syshw_cardstate(syshw_t *, void *); 362*3db86aabSstevel 363*3db86aabSstevel #if defined(__sparc) 364*3db86aabSstevel static int pcic_fault(enum pci_fault_ops op, void *arg); 365*3db86aabSstevel #endif 366*3db86aabSstevel 367*3db86aabSstevel /* 368*3db86aabSstevel * Default to support for Voyager IIi if sparc is defined. 369*3db86aabSstevel * Appart from the PCI base addresses this only effect the TI1250. 370*3db86aabSstevel */ 371*3db86aabSstevel #if defined(sparc) 372*3db86aabSstevel #define VOYAGER 373*3db86aabSstevel #endif 374*3db86aabSstevel 375*3db86aabSstevel 376*3db86aabSstevel /* 377*3db86aabSstevel * pcmcia_attach() uses 0 and 128 upwards for the initpcmcia and devctl 378*3db86aabSstevel * interfaces so we use 254. 379*3db86aabSstevel */ 380*3db86aabSstevel #define SYSHW_MINOR 254 381*3db86aabSstevel 382*3db86aabSstevel /* 383*3db86aabSstevel * Forward declarations for syshw interface (See end of file). 384*3db86aabSstevel */ 385*3db86aabSstevel static void syshw_attach(pcicdev_t *); 386*3db86aabSstevel static void syshw_detach(pcicdev_t *); 387*3db86aabSstevel static void syshw_resume(pcicdev_t *); 388*3db86aabSstevel 389*3db86aabSstevel #ifdef VOYAGER 390*3db86aabSstevel static uint_t syshw_intr(caddr_t); 391*3db86aabSstevel static uint_t syshw_intr_hi(pcicdev_t *); 392*3db86aabSstevel #endif 393*3db86aabSstevel 394*3db86aabSstevel static int syshw_open(dev_t *, int, int, cred_t *); 395*3db86aabSstevel static int syshw_close(dev_t, int, int, cred_t *); 396*3db86aabSstevel static int syshw_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 397*3db86aabSstevel static uint32_t syshw_add2map(syshw_t *, void (*)(syshw_t *, void *), void *); 398*3db86aabSstevel static void syshw_send_signal(int); 399*3db86aabSstevel 400*3db86aabSstevel /* 401*3db86aabSstevel * pcmcia interface operations structure 402*3db86aabSstevel * this is the private interface that is exported to the nexus 403*3db86aabSstevel */ 404*3db86aabSstevel pcmcia_if_t pcic_if_ops = { 405*3db86aabSstevel PCIF_MAGIC, 406*3db86aabSstevel PCIF_VERSION, 407*3db86aabSstevel pcic_callback, 408*3db86aabSstevel pcic_get_adapter, 409*3db86aabSstevel pcic_get_page, 410*3db86aabSstevel pcic_get_socket, 411*3db86aabSstevel pcic_get_status, 412*3db86aabSstevel pcic_get_window, 413*3db86aabSstevel pcic_inquire_adapter, 414*3db86aabSstevel pcic_inquire_socket, 415*3db86aabSstevel pcic_inquire_window, 416*3db86aabSstevel pcic_reset_socket, 417*3db86aabSstevel pcic_set_page, 418*3db86aabSstevel pcic_set_window, 419*3db86aabSstevel pcic_set_socket, 420*3db86aabSstevel pcic_set_interrupt, 421*3db86aabSstevel pcic_clear_interrupt, 422*3db86aabSstevel NULL, 423*3db86aabSstevel }; 424*3db86aabSstevel 425*3db86aabSstevel /* 426*3db86aabSstevel * chip type identification routines 427*3db86aabSstevel * this list of functions is searched until one of them succeeds 428*3db86aabSstevel * or all fail. i82365SL is assumed if failed. 429*3db86aabSstevel */ 430*3db86aabSstevel static int pcic_ci_cirrus(pcicdev_t *); 431*3db86aabSstevel static int pcic_ci_vadem(pcicdev_t *); 432*3db86aabSstevel static int pcic_ci_ricoh(pcicdev_t *); 433*3db86aabSstevel 434*3db86aabSstevel int (*pcic_ci_funcs[])(pcicdev_t *) = { 435*3db86aabSstevel pcic_ci_cirrus, 436*3db86aabSstevel pcic_ci_vadem, 437*3db86aabSstevel pcic_ci_ricoh, 438*3db86aabSstevel NULL 439*3db86aabSstevel }; 440*3db86aabSstevel 441*3db86aabSstevel static struct modldrv modldrv = { 442*3db86aabSstevel &mod_driverops, /* Type of module. This one is a driver */ 443*3db86aabSstevel "PCIC PCMCIA adapter driver %I%", /* Name of the module. */ 444*3db86aabSstevel &pcic_devops, /* driver ops */ 445*3db86aabSstevel }; 446*3db86aabSstevel 447*3db86aabSstevel static struct modlinkage modlinkage = { 448*3db86aabSstevel MODREV_1, (void *)&modldrv, NULL 449*3db86aabSstevel }; 450*3db86aabSstevel 451*3db86aabSstevel int 452*3db86aabSstevel _init() 453*3db86aabSstevel { 454*3db86aabSstevel int stat; 455*3db86aabSstevel 456*3db86aabSstevel /* Allocate soft state */ 457*3db86aabSstevel if ((stat = ddi_soft_state_init(&pcic_soft_state_p, 458*3db86aabSstevel SOFTC_SIZE, 2)) != DDI_SUCCESS) 459*3db86aabSstevel return (stat); 460*3db86aabSstevel 461*3db86aabSstevel if ((stat = mod_install(&modlinkage)) != 0) 462*3db86aabSstevel ddi_soft_state_fini(&pcic_soft_state_p); 463*3db86aabSstevel 464*3db86aabSstevel return (stat); 465*3db86aabSstevel } 466*3db86aabSstevel 467*3db86aabSstevel int 468*3db86aabSstevel _fini() 469*3db86aabSstevel { 470*3db86aabSstevel int stat = 0; 471*3db86aabSstevel 472*3db86aabSstevel if ((stat = mod_remove(&modlinkage)) != 0) 473*3db86aabSstevel return (stat); 474*3db86aabSstevel 475*3db86aabSstevel if (pcic_deb_threadid) { 476*3db86aabSstevel mutex_enter(&pcic_deb_mtx); 477*3db86aabSstevel pcic_deb_threadid = 0; 478*3db86aabSstevel while (!pcic_deb_threadid) 479*3db86aabSstevel cv_wait(&pcic_deb_cv, &pcic_deb_mtx); 480*3db86aabSstevel pcic_deb_threadid = 0; 481*3db86aabSstevel mutex_exit(&pcic_deb_mtx); 482*3db86aabSstevel 483*3db86aabSstevel mutex_destroy(&pcic_deb_mtx); 484*3db86aabSstevel cv_destroy(&pcic_deb_cv); 485*3db86aabSstevel } 486*3db86aabSstevel 487*3db86aabSstevel ddi_soft_state_fini(&pcic_soft_state_p); 488*3db86aabSstevel 489*3db86aabSstevel return (stat); 490*3db86aabSstevel } 491*3db86aabSstevel 492*3db86aabSstevel int 493*3db86aabSstevel _info(struct modinfo *modinfop) 494*3db86aabSstevel { 495*3db86aabSstevel return (mod_info(&modlinkage, modinfop)); 496*3db86aabSstevel } 497*3db86aabSstevel 498*3db86aabSstevel /* 499*3db86aabSstevel * pcic_getinfo() 500*3db86aabSstevel * provide instance/device information about driver 501*3db86aabSstevel */ 502*3db86aabSstevel /*ARGSUSED*/ 503*3db86aabSstevel static int 504*3db86aabSstevel pcic_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 505*3db86aabSstevel { 506*3db86aabSstevel anp_t *anp; 507*3db86aabSstevel int error = DDI_SUCCESS; 508*3db86aabSstevel minor_t minor; 509*3db86aabSstevel 510*3db86aabSstevel switch (cmd) { 511*3db86aabSstevel case DDI_INFO_DEVT2DEVINFO: 512*3db86aabSstevel minor = getminor((dev_t)arg); 513*3db86aabSstevel if (minor == SYSHW_MINOR) 514*3db86aabSstevel minor = 0; 515*3db86aabSstevel else 516*3db86aabSstevel minor &= 0x7f; 517*3db86aabSstevel if (!(anp = ddi_get_soft_state(pcic_soft_state_p, minor))) 518*3db86aabSstevel *result = NULL; 519*3db86aabSstevel else 520*3db86aabSstevel *result = anp->an_dip; 521*3db86aabSstevel break; 522*3db86aabSstevel case DDI_INFO_DEVT2INSTANCE: 523*3db86aabSstevel minor = getminor((dev_t)arg); 524*3db86aabSstevel if (minor == SYSHW_MINOR) 525*3db86aabSstevel minor = 0; 526*3db86aabSstevel else 527*3db86aabSstevel minor &= 0x7f; 528*3db86aabSstevel *result = (void *)((long)minor); 529*3db86aabSstevel break; 530*3db86aabSstevel default: 531*3db86aabSstevel error = DDI_FAILURE; 532*3db86aabSstevel break; 533*3db86aabSstevel } 534*3db86aabSstevel return (error); 535*3db86aabSstevel } 536*3db86aabSstevel 537*3db86aabSstevel static int 538*3db86aabSstevel pcic_probe(dev_info_t *dip) 539*3db86aabSstevel { 540*3db86aabSstevel int value; 541*3db86aabSstevel ddi_device_acc_attr_t attr; 542*3db86aabSstevel ddi_acc_handle_t handle; 543*3db86aabSstevel uchar_t *index, *data; 544*3db86aabSstevel 545*3db86aabSstevel if (ddi_dev_is_sid(dip) == DDI_SUCCESS) 546*3db86aabSstevel return (DDI_PROBE_DONTCARE); 547*3db86aabSstevel 548*3db86aabSstevel /* 549*3db86aabSstevel * find a PCIC device (any vendor) 550*3db86aabSstevel * while there can be up to 4 such devices in 551*3db86aabSstevel * a system, we currently only look for 1 552*3db86aabSstevel * per probe. There will be up to 2 chips per 553*3db86aabSstevel * instance since they share I/O space 554*3db86aabSstevel */ 555*3db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 556*3db86aabSstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 557*3db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 558*3db86aabSstevel 559*3db86aabSstevel if (ddi_regs_map_setup(dip, PCIC_ISA_CONTROL_REG_NUM, 560*3db86aabSstevel (caddr_t *)&index, 561*3db86aabSstevel PCIC_ISA_CONTROL_REG_OFFSET, 562*3db86aabSstevel PCIC_ISA_CONTROL_REG_LENGTH, 563*3db86aabSstevel &attr, &handle) != DDI_SUCCESS) 564*3db86aabSstevel return (DDI_PROBE_FAILURE); 565*3db86aabSstevel 566*3db86aabSstevel data = index + 1; 567*3db86aabSstevel 568*3db86aabSstevel #if defined(PCIC_DEBUG) 569*3db86aabSstevel if (pcic_debug) 570*3db86aabSstevel cmn_err(CE_CONT, "pcic_probe: entered\n"); 571*3db86aabSstevel if (pcic_debug) 572*3db86aabSstevel cmn_err(CE_CONT, "\tindex=%p\n", (void *)index); 573*3db86aabSstevel #endif 574*3db86aabSstevel ddi_put8(handle, index, PCIC_CHIP_REVISION); 575*3db86aabSstevel ddi_put8(handle, data, 0); 576*3db86aabSstevel value = ddi_get8(handle, data); 577*3db86aabSstevel #if defined(PCIC_DEBUG) 578*3db86aabSstevel if (pcic_debug) 579*3db86aabSstevel cmn_err(CE_CONT, "\tchip revision register = %x\n", value); 580*3db86aabSstevel #endif 581*3db86aabSstevel if ((value & PCIC_REV_MASK) >= PCIC_REV_LEVEL_LOW && 582*3db86aabSstevel (value & 0x30) == 0) { 583*3db86aabSstevel /* 584*3db86aabSstevel * we probably have a PCIC chip in the system 585*3db86aabSstevel * do a little more checking. If we find one, 586*3db86aabSstevel * reset everything in case of softboot 587*3db86aabSstevel */ 588*3db86aabSstevel ddi_put8(handle, index, PCIC_MAPPING_ENABLE); 589*3db86aabSstevel ddi_put8(handle, data, 0); 590*3db86aabSstevel value = ddi_get8(handle, data); 591*3db86aabSstevel #if defined(PCIC_DEBUG) 592*3db86aabSstevel if (pcic_debug) 593*3db86aabSstevel cmn_err(CE_CONT, "\tzero test = %x\n", value); 594*3db86aabSstevel #endif 595*3db86aabSstevel /* should read back as zero */ 596*3db86aabSstevel if (value == 0) { 597*3db86aabSstevel /* 598*3db86aabSstevel * we do have one and it is off the bus 599*3db86aabSstevel */ 600*3db86aabSstevel #if defined(PCIC_DEBUG) 601*3db86aabSstevel if (pcic_debug) 602*3db86aabSstevel cmn_err(CE_CONT, "pcic_probe: success\n"); 603*3db86aabSstevel #endif 604*3db86aabSstevel ddi_regs_map_free(&handle); 605*3db86aabSstevel return (DDI_PROBE_SUCCESS); 606*3db86aabSstevel } 607*3db86aabSstevel } 608*3db86aabSstevel #if defined(PCIC_DEBUG) 609*3db86aabSstevel if (pcic_debug) 610*3db86aabSstevel cmn_err(CE_CONT, "pcic_probe: failed\n"); 611*3db86aabSstevel #endif 612*3db86aabSstevel ddi_regs_map_free(&handle); 613*3db86aabSstevel return (DDI_PROBE_FAILURE); 614*3db86aabSstevel } 615*3db86aabSstevel 616*3db86aabSstevel /* 617*3db86aabSstevel * These are just defaults they can also be changed via a property in the 618*3db86aabSstevel * conf file. 619*3db86aabSstevel */ 620*3db86aabSstevel static int pci_config_reg_num = PCIC_PCI_CONFIG_REG_NUM; 621*3db86aabSstevel static int pci_control_reg_num = PCIC_PCI_CONTROL_REG_NUM; 622*3db86aabSstevel static int pcic_do_pcmcia_sr = 0; 623*3db86aabSstevel static int pcic_use_cbpwrctl = PCF_CBPWRCTL; 624*3db86aabSstevel 625*3db86aabSstevel /* 626*3db86aabSstevel * enable insertion/removal interrupt for 32bit cards 627*3db86aabSstevel */ 628*3db86aabSstevel static int 629*3db86aabSstevel cardbus_enable_cd_intr(dev_info_t *dip) 630*3db86aabSstevel { 631*3db86aabSstevel ddi_acc_handle_t iohandle; 632*3db86aabSstevel caddr_t ioaddr; 633*3db86aabSstevel ddi_device_acc_attr_t attr; 634*3db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 635*3db86aabSstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 636*3db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 637*3db86aabSstevel (void) ddi_regs_map_setup(dip, 1, 638*3db86aabSstevel (caddr_t *)&ioaddr, 639*3db86aabSstevel 0, 640*3db86aabSstevel 4096, 641*3db86aabSstevel &attr, &iohandle); 642*3db86aabSstevel 643*3db86aabSstevel /* CSC Interrupt: Card detect interrupt on */ 644*3db86aabSstevel ddi_put32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_MASK), 645*3db86aabSstevel ddi_get32(iohandle, 646*3db86aabSstevel (uint32_t *)(ioaddr+CB_STATUS_MASK)) | CB_SE_CCDMASK); 647*3db86aabSstevel 648*3db86aabSstevel ddi_put32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT), 649*3db86aabSstevel ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT))); 650*3db86aabSstevel 651*3db86aabSstevel ddi_regs_map_free(&iohandle); 652*3db86aabSstevel return (1); 653*3db86aabSstevel } 654*3db86aabSstevel 655*3db86aabSstevel /* 656*3db86aabSstevel * pcic_attach() 657*3db86aabSstevel * attach the PCIC (Intel 82365SL/CirrusLogic/Toshiba) driver 658*3db86aabSstevel * to the system. This is a child of "sysbus" since that is where 659*3db86aabSstevel * the hardware lives, but it provides services to the "pcmcia" 660*3db86aabSstevel * nexus driver. It gives a pointer back via its private data 661*3db86aabSstevel * structure which contains both the dip and socket services entry 662*3db86aabSstevel * points 663*3db86aabSstevel */ 664*3db86aabSstevel static int 665*3db86aabSstevel pcic_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 666*3db86aabSstevel { 667*3db86aabSstevel anp_t *pcic_nexus; 668*3db86aabSstevel pcicdev_t *pcic; 669*3db86aabSstevel int irqlevel, value; 670*3db86aabSstevel int pci_cfrn, pci_ctrn; 671*3db86aabSstevel int i, j, smi, actual; 672*3db86aabSstevel char *typename; 673*3db86aabSstevel char bus_type[16] = "(unknown)"; 674*3db86aabSstevel int len = sizeof (bus_type); 675*3db86aabSstevel ddi_device_acc_attr_t attr; 676*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 677*3db86aabSstevel uint_t pri; 678*3db86aabSstevel syshw_t *shwp; 679*3db86aabSstevel 680*3db86aabSstevel #if defined(PCIC_DEBUG) 681*3db86aabSstevel if (pcic_debug) { 682*3db86aabSstevel cmn_err(CE_CONT, "pcic_attach: entered\n"); 683*3db86aabSstevel } 684*3db86aabSstevel #endif 685*3db86aabSstevel switch (cmd) { 686*3db86aabSstevel case DDI_ATTACH: 687*3db86aabSstevel break; 688*3db86aabSstevel case DDI_RESUME: 689*3db86aabSstevel pcic = anp->an_private; 690*3db86aabSstevel /* 691*3db86aabSstevel * for now, this is a simulated resume. 692*3db86aabSstevel * a real one may need different things. 693*3db86aabSstevel */ 694*3db86aabSstevel if (pcic != NULL && pcic->pc_flags & PCF_SUSPENDED) { 695*3db86aabSstevel mutex_enter(&pcic->pc_lock); 696*3db86aabSstevel /* should probe for new sockets showing up */ 697*3db86aabSstevel pcic_setup_adapter(pcic); 698*3db86aabSstevel syshw_resume(pcic); 699*3db86aabSstevel pcic->pc_flags &= ~PCF_SUSPENDED; 700*3db86aabSstevel mutex_exit(&pcic->pc_lock); 701*3db86aabSstevel (void) pcmcia_begin_resume(dip); 702*3db86aabSstevel /* 703*3db86aabSstevel * this will do the CARD_INSERTION 704*3db86aabSstevel * due to needing time for threads to 705*3db86aabSstevel * run, it must be delayed for a short amount 706*3db86aabSstevel * of time. pcmcia_wait_insert checks for all 707*3db86aabSstevel * children to be removed and then triggers insert. 708*3db86aabSstevel */ 709*3db86aabSstevel /* 710*3db86aabSstevel * The reason for having a single timeout here 711*3db86aabSstevel * rather than seperate timeout()s for each instance 712*3db86aabSstevel * is due to the limited number (2) of callout threads 713*3db86aabSstevel * available in Solaris 2.6. A single 1250A ends up 714*3db86aabSstevel * as two instances of the interface with one slot each. 715*3db86aabSstevel * The pcic_delayed_resume() function ends by calling 716*3db86aabSstevel * pcmcia_wait_insert() which at one point does a 717*3db86aabSstevel * delay(). delay() is implemented with a timeout() 718*3db86aabSstevel * call so you end up with both the callout() 719*3db86aabSstevel * threads waiting to be woken up by another callout(). 720*3db86aabSstevel * This situation locks up the machine hence the 721*3db86aabSstevel * convolution here to only use one timeout. 722*3db86aabSstevel */ 723*3db86aabSstevel if (!pcic_delayed_resume_toid) 724*3db86aabSstevel pcic_delayed_resume_toid = 725*3db86aabSstevel timeout(pcic_delayed_resume, (caddr_t)0, 726*3db86aabSstevel drv_usectohz(pcic_wait_insert_time)); 727*3db86aabSstevel 728*3db86aabSstevel /* 729*3db86aabSstevel * for complete implementation need END_RESUME (later) 730*3db86aabSstevel */ 731*3db86aabSstevel return (DDI_SUCCESS); 732*3db86aabSstevel 733*3db86aabSstevel } 734*3db86aabSstevel return (DDI_SUCCESS); 735*3db86aabSstevel default: 736*3db86aabSstevel return (DDI_FAILURE); 737*3db86aabSstevel } 738*3db86aabSstevel 739*3db86aabSstevel /* 740*3db86aabSstevel * Allocate soft state associated with this instance. 741*3db86aabSstevel */ 742*3db86aabSstevel if (ddi_soft_state_zalloc(pcic_soft_state_p, 743*3db86aabSstevel ddi_get_instance(dip)) != DDI_SUCCESS) { 744*3db86aabSstevel cmn_err(CE_CONT, "pcic%d: Unable to alloc state\n", 745*3db86aabSstevel ddi_get_instance(dip)); 746*3db86aabSstevel return (DDI_FAILURE); 747*3db86aabSstevel } 748*3db86aabSstevel 749*3db86aabSstevel pcic_nexus = ddi_get_soft_state(pcic_soft_state_p, 750*3db86aabSstevel ddi_get_instance(dip)); 751*3db86aabSstevel 752*3db86aabSstevel pcic = kmem_zalloc(sizeof (pcicdev_t), KM_SLEEP); 753*3db86aabSstevel 754*3db86aabSstevel pcic->dip = dip; 755*3db86aabSstevel pcic_nexus->an_dip = dip; 756*3db86aabSstevel pcic_nexus->an_if = &pcic_if_ops; 757*3db86aabSstevel pcic_nexus->an_private = pcic; 758*3db86aabSstevel pcic->pc_numpower = sizeof (pcic_power)/sizeof (pcic_power[0]); 759*3db86aabSstevel pcic->pc_power = pcic_power; 760*3db86aabSstevel 761*3db86aabSstevel pci_ctrn = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP, 762*3db86aabSstevel "pci-control-reg-number", pci_control_reg_num); 763*3db86aabSstevel pci_cfrn = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP, 764*3db86aabSstevel "pci-config-reg-number", pci_config_reg_num); 765*3db86aabSstevel 766*3db86aabSstevel ddi_set_driver_private(dip, pcic_nexus); 767*3db86aabSstevel 768*3db86aabSstevel /* 769*3db86aabSstevel * pcic->pc_irq is really the IPL level we want to run at 770*3db86aabSstevel * set the default values here and override from intr spec 771*3db86aabSstevel */ 772*3db86aabSstevel pcic->pc_irq = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP, 773*3db86aabSstevel "interrupt-priorities", -1); 774*3db86aabSstevel 775*3db86aabSstevel if (pcic->pc_irq == -1) { 776*3db86aabSstevel int actual; 777*3db86aabSstevel uint_t pri; 778*3db86aabSstevel ddi_intr_handle_t hdl; 779*3db86aabSstevel 780*3db86aabSstevel /* see if intrspec tells us different */ 781*3db86aabSstevel if (ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED, 782*3db86aabSstevel 0, 1, &actual, DDI_INTR_ALLOC_NORMAL) == DDI_SUCCESS) { 783*3db86aabSstevel if (ddi_intr_get_pri(hdl, &pri) == DDI_SUCCESS) 784*3db86aabSstevel pcic->pc_irq = pri; 785*3db86aabSstevel else 786*3db86aabSstevel pcic->pc_irq = LOCK_LEVEL + 1; 787*3db86aabSstevel (void) ddi_intr_free(hdl); 788*3db86aabSstevel } 789*3db86aabSstevel } 790*3db86aabSstevel pcic_nexus->an_ipl = pcic->pc_irq; 791*3db86aabSstevel 792*3db86aabSstevel /* 793*3db86aabSstevel * Check our parent bus type. We do different things based on which 794*3db86aabSstevel * bus we're on. 795*3db86aabSstevel */ 796*3db86aabSstevel if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip), 797*3db86aabSstevel PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP, 798*3db86aabSstevel "device_type", (caddr_t)&bus_type[0], &len) != 799*3db86aabSstevel DDI_PROP_SUCCESS) { 800*3db86aabSstevel if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip), 801*3db86aabSstevel PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP, 802*3db86aabSstevel "bus-type", (caddr_t)&bus_type[0], &len) != 803*3db86aabSstevel DDI_PROP_SUCCESS) { 804*3db86aabSstevel 805*3db86aabSstevel cmn_err(CE_CONT, 806*3db86aabSstevel "pcic%d: can't find parent bus type\n", 807*3db86aabSstevel ddi_get_instance(dip)); 808*3db86aabSstevel 809*3db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 810*3db86aabSstevel return (DDI_FAILURE); 811*3db86aabSstevel } 812*3db86aabSstevel } /* ddi_prop_op("device_type") */ 813*3db86aabSstevel 814*3db86aabSstevel if (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0) { 815*3db86aabSstevel pcic->pc_flags = PCF_PCIBUS; 816*3db86aabSstevel } else { 817*3db86aabSstevel #if defined(__sparc) 818*3db86aabSstevel cmn_err(CE_CONT, "pcic%d: unsupported parent bus type: [%s]\n", 819*3db86aabSstevel ddi_get_instance(dip), bus_type); 820*3db86aabSstevel 821*3db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 822*3db86aabSstevel return (DDI_FAILURE); 823*3db86aabSstevel #else 824*3db86aabSstevel pcic->pc_flags = 0; 825*3db86aabSstevel #endif 826*3db86aabSstevel } 827*3db86aabSstevel 828*3db86aabSstevel if ((pcic->bus_speed = ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip), 829*3db86aabSstevel DDI_PROP_CANSLEEP, 830*3db86aabSstevel "clock-frequency", 0)) == 0) { 831*3db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS) 832*3db86aabSstevel pcic->bus_speed = PCIC_PCI_DEF_SYSCLK; 833*3db86aabSstevel else 834*3db86aabSstevel pcic->bus_speed = PCIC_ISA_DEF_SYSCLK; 835*3db86aabSstevel } else { 836*3db86aabSstevel /* 837*3db86aabSstevel * OBP can declare the speed in Hz... 838*3db86aabSstevel */ 839*3db86aabSstevel if (pcic->bus_speed > 1000000) 840*3db86aabSstevel pcic->bus_speed /= 1000000; 841*3db86aabSstevel } /* ddi_prop_op("clock-frequency") */ 842*3db86aabSstevel 843*3db86aabSstevel pcic->pc_io_type = PCIC_IO_TYPE_82365SL; /* default mode */ 844*3db86aabSstevel 845*3db86aabSstevel #ifdef PCIC_DEBUG 846*3db86aabSstevel if (pcic_debug) { 847*3db86aabSstevel cmn_err(CE_CONT, 848*3db86aabSstevel "pcic%d: parent bus type = [%s], speed = %d MHz\n", 849*3db86aabSstevel ddi_get_instance(dip), 850*3db86aabSstevel bus_type, pcic->bus_speed); 851*3db86aabSstevel } 852*3db86aabSstevel #endif 853*3db86aabSstevel 854*3db86aabSstevel /* 855*3db86aabSstevel * The reg properties on a PCI node are different than those 856*3db86aabSstevel * on a non-PCI node. Handle that difference here. 857*3db86aabSstevel * If it turns out to be a CardBus chip, we have even more 858*3db86aabSstevel * differences. 859*3db86aabSstevel */ 860*3db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS) { 861*3db86aabSstevel int class_code; 862*3db86aabSstevel #if defined(__i386) || defined(__amd64) 863*3db86aabSstevel pcic->pc_base = 0x1000000; 864*3db86aabSstevel pcic->pc_bound = (uint32_t)~0; 865*3db86aabSstevel pcic->pc_iobase = 0x1000; 866*3db86aabSstevel pcic->pc_iobound = 0xefff; 867*3db86aabSstevel #elif defined(__sparc) 868*3db86aabSstevel pcic->pc_base = 0x0; 869*3db86aabSstevel pcic->pc_bound = (uint32_t)~0; 870*3db86aabSstevel pcic->pc_iobase = 0x00000; 871*3db86aabSstevel pcic->pc_iobound = 0xffff; 872*3db86aabSstevel #endif 873*3db86aabSstevel 874*3db86aabSstevel /* usually need to get at config space so map first */ 875*3db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 876*3db86aabSstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 877*3db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 878*3db86aabSstevel 879*3db86aabSstevel if (ddi_regs_map_setup(dip, pci_cfrn, 880*3db86aabSstevel (caddr_t *)&pcic->cfgaddr, 881*3db86aabSstevel PCIC_PCI_CONFIG_REG_OFFSET, 882*3db86aabSstevel PCIC_PCI_CONFIG_REG_LENGTH, 883*3db86aabSstevel &attr, 884*3db86aabSstevel &pcic->cfg_handle) != 885*3db86aabSstevel DDI_SUCCESS) { 886*3db86aabSstevel cmn_err(CE_CONT, 887*3db86aabSstevel "pcic%d: unable to map config space" 888*3db86aabSstevel "regs\n", 889*3db86aabSstevel ddi_get_instance(dip)); 890*3db86aabSstevel 891*3db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 892*3db86aabSstevel return (DDI_FAILURE); 893*3db86aabSstevel } /* ddi_regs_map_setup */ 894*3db86aabSstevel 895*3db86aabSstevel class_code = ddi_getprop(DDI_DEV_T_ANY, dip, 896*3db86aabSstevel DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS, 897*3db86aabSstevel "class-code", -1); 898*3db86aabSstevel #ifdef PCIC_DEBUG 899*3db86aabSstevel if (pcic_debug) { 900*3db86aabSstevel cmn_err(CE_CONT, "pcic_attach class_code=%x\n", 901*3db86aabSstevel class_code); 902*3db86aabSstevel } 903*3db86aabSstevel #endif 904*3db86aabSstevel 905*3db86aabSstevel switch (class_code) { 906*3db86aabSstevel case PCIC_PCI_CARDBUS: 907*3db86aabSstevel pcic->pc_flags |= PCF_CARDBUS; 908*3db86aabSstevel pcic->pc_io_type = PCIC_IO_TYPE_YENTA; 909*3db86aabSstevel /* 910*3db86aabSstevel * Get access to the adapter registers on the 911*3db86aabSstevel * PCI bus. A 4K memory page 912*3db86aabSstevel */ 913*3db86aabSstevel #if defined(PCIC_DEBUG) 914*3db86aabSstevel pcic_err(dip, 8, "Is Cardbus device\n"); 915*3db86aabSstevel if (pcic_debug) { 916*3db86aabSstevel int nr; 917*3db86aabSstevel long rs; 918*3db86aabSstevel (void) ddi_dev_nregs(dip, &nr); 919*3db86aabSstevel pcic_err(dip, 9, "\tdev, cfgaddr 0x%p," 920*3db86aabSstevel "cfghndl 0x%p nregs %d", 921*3db86aabSstevel (void *)pcic->cfgaddr, 922*3db86aabSstevel (void *)pcic->cfg_handle, nr); 923*3db86aabSstevel 924*3db86aabSstevel (void) ddi_dev_regsize(dip, 925*3db86aabSstevel PCIC_PCI_CONTROL_REG_NUM, &rs); 926*3db86aabSstevel 927*3db86aabSstevel pcic_err(dip, 9, "\tsize of reg %d is 0x%x\n", 928*3db86aabSstevel PCIC_PCI_CONTROL_REG_NUM, (int)rs); 929*3db86aabSstevel } 930*3db86aabSstevel #endif 931*3db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 932*3db86aabSstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 933*3db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 934*3db86aabSstevel 935*3db86aabSstevel if (ddi_regs_map_setup(dip, pci_ctrn, 936*3db86aabSstevel (caddr_t *)&pcic->ioaddr, 937*3db86aabSstevel PCIC_PCI_CONTROL_REG_OFFSET, 938*3db86aabSstevel PCIC_CB_CONTROL_REG_LENGTH, 939*3db86aabSstevel &attr, &pcic->handle) != 940*3db86aabSstevel DDI_SUCCESS) { 941*3db86aabSstevel cmn_err(CE_CONT, 942*3db86aabSstevel "pcic%d: unable to map PCI regs\n", 943*3db86aabSstevel ddi_get_instance(dip)); 944*3db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle); 945*3db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 946*3db86aabSstevel return (DDI_FAILURE); 947*3db86aabSstevel } /* ddi_regs_map_setup */ 948*3db86aabSstevel 949*3db86aabSstevel /* 950*3db86aabSstevel * Find out the chip type - If we're on a PCI bus, 951*3db86aabSstevel * the adapter has that information in the PCI 952*3db86aabSstevel * config space. 953*3db86aabSstevel * Note that we call pcic_find_pci_type here since 954*3db86aabSstevel * it needs a valid mapped pcic->handle to 955*3db86aabSstevel * access some of the adapter registers in 956*3db86aabSstevel * some cases. 957*3db86aabSstevel */ 958*3db86aabSstevel if (pcic_find_pci_type(pcic) != DDI_SUCCESS) { 959*3db86aabSstevel ddi_regs_map_free(&pcic->handle); 960*3db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle); 961*3db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 962*3db86aabSstevel cmn_err(CE_WARN, "pcic: %s: unsupported " 963*3db86aabSstevel "bridge\n", 964*3db86aabSstevel ddi_get_name_addr(dip)); 965*3db86aabSstevel return (DDI_FAILURE); 966*3db86aabSstevel } 967*3db86aabSstevel break; 968*3db86aabSstevel 969*3db86aabSstevel default: 970*3db86aabSstevel case PCIC_PCI_PCMCIA: 971*3db86aabSstevel /* 972*3db86aabSstevel * Get access to the adapter IO registers on the 973*3db86aabSstevel * PCI bus config space. 974*3db86aabSstevel */ 975*3db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 976*3db86aabSstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 977*3db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 978*3db86aabSstevel 979*3db86aabSstevel /* 980*3db86aabSstevel * We need a default mapping to the adapter's IO 981*3db86aabSstevel * control register space. For most adapters 982*3db86aabSstevel * that are of class PCIC_PCI_PCMCIA (or of 983*3db86aabSstevel * a default class) the control registers 984*3db86aabSstevel * will be using the 82365-type control/data 985*3db86aabSstevel * format. 986*3db86aabSstevel */ 987*3db86aabSstevel if (ddi_regs_map_setup(dip, pci_ctrn, 988*3db86aabSstevel (caddr_t *)&pcic->ioaddr, 989*3db86aabSstevel PCIC_PCI_CONTROL_REG_OFFSET, 990*3db86aabSstevel PCIC_PCI_CONTROL_REG_LENGTH, 991*3db86aabSstevel &attr, 992*3db86aabSstevel &pcic->handle) != DDI_SUCCESS) { 993*3db86aabSstevel cmn_err(CE_CONT, 994*3db86aabSstevel "pcic%d: unable to map PCI regs\n", 995*3db86aabSstevel ddi_get_instance(dip)); 996*3db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle); 997*3db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 998*3db86aabSstevel return (DDI_FAILURE); 999*3db86aabSstevel } /* ddi_regs_map_setup */ 1000*3db86aabSstevel 1001*3db86aabSstevel /* 1002*3db86aabSstevel * Find out the chip type - If we're on a PCI bus, 1003*3db86aabSstevel * the adapter has that information in the PCI 1004*3db86aabSstevel * config space. 1005*3db86aabSstevel * Note that we call pcic_find_pci_type here since 1006*3db86aabSstevel * it needs a valid mapped pcic->handle to 1007*3db86aabSstevel * access some of the adapter registers in 1008*3db86aabSstevel * some cases. 1009*3db86aabSstevel */ 1010*3db86aabSstevel if (pcic_find_pci_type(pcic) != DDI_SUCCESS) { 1011*3db86aabSstevel ddi_regs_map_free(&pcic->handle); 1012*3db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle); 1013*3db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 1014*3db86aabSstevel cmn_err(CE_WARN, "pcic: %s: unsupported " 1015*3db86aabSstevel "bridge\n", 1016*3db86aabSstevel ddi_get_name_addr(dip)); 1017*3db86aabSstevel return (DDI_FAILURE); 1018*3db86aabSstevel } 1019*3db86aabSstevel 1020*3db86aabSstevel /* 1021*3db86aabSstevel * Some PCI-PCMCIA(R2) adapters are Yenta-compliant 1022*3db86aabSstevel * for extended registers even though they are 1023*3db86aabSstevel * not CardBus adapters. For those adapters, 1024*3db86aabSstevel * re-map pcic->handle to be large enough to 1025*3db86aabSstevel * encompass the Yenta registers. 1026*3db86aabSstevel */ 1027*3db86aabSstevel switch (pcic->pc_type) { 1028*3db86aabSstevel case PCIC_TI_PCI1031: 1029*3db86aabSstevel ddi_regs_map_free(&pcic->handle); 1030*3db86aabSstevel 1031*3db86aabSstevel if (ddi_regs_map_setup(dip, 1032*3db86aabSstevel PCIC_PCI_CONTROL_REG_NUM, 1033*3db86aabSstevel (caddr_t *)&pcic->ioaddr, 1034*3db86aabSstevel PCIC_PCI_CONTROL_REG_OFFSET, 1035*3db86aabSstevel PCIC_CB_CONTROL_REG_LENGTH, 1036*3db86aabSstevel &attr, 1037*3db86aabSstevel &pcic->handle) != DDI_SUCCESS) { 1038*3db86aabSstevel cmn_err(CE_CONT, 1039*3db86aabSstevel "pcic%d: unable to map " 1040*3db86aabSstevel "PCI regs\n", 1041*3db86aabSstevel ddi_get_instance(dip)); 1042*3db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle); 1043*3db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 1044*3db86aabSstevel return (DDI_FAILURE); 1045*3db86aabSstevel } /* ddi_regs_map_setup */ 1046*3db86aabSstevel break; 1047*3db86aabSstevel default: 1048*3db86aabSstevel break; 1049*3db86aabSstevel } /* switch (pcic->pc_type) */ 1050*3db86aabSstevel break; 1051*3db86aabSstevel } /* switch (class_code) */ 1052*3db86aabSstevel } else { 1053*3db86aabSstevel /* 1054*3db86aabSstevel * We're not on a PCI bus, so assume an ISA bus type 1055*3db86aabSstevel * register property. Get access to the adapter IO 1056*3db86aabSstevel * registers on a non-PCI bus. 1057*3db86aabSstevel */ 1058*3db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 1059*3db86aabSstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 1060*3db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 1061*3db86aabSstevel pcic->mem_reg_num = PCIC_ISA_MEM_REG_NUM; 1062*3db86aabSstevel pcic->io_reg_num = PCIC_ISA_IO_REG_NUM; 1063*3db86aabSstevel 1064*3db86aabSstevel if (ddi_regs_map_setup(dip, PCIC_ISA_CONTROL_REG_NUM, 1065*3db86aabSstevel (caddr_t *)&pcic->ioaddr, 1066*3db86aabSstevel PCIC_ISA_CONTROL_REG_OFFSET, 1067*3db86aabSstevel PCIC_ISA_CONTROL_REG_LENGTH, 1068*3db86aabSstevel &attr, 1069*3db86aabSstevel &pcic->handle) != DDI_SUCCESS) { 1070*3db86aabSstevel cmn_err(CE_CONT, 1071*3db86aabSstevel "pcic%d: unable to map ISA registers\n", 1072*3db86aabSstevel ddi_get_instance(dip)); 1073*3db86aabSstevel 1074*3db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 1075*3db86aabSstevel return (DDI_FAILURE); 1076*3db86aabSstevel } /* ddi_regs_map_setup */ 1077*3db86aabSstevel 1078*3db86aabSstevel /* ISA bus is limited to 24-bits, but not first 640K */ 1079*3db86aabSstevel pcic->pc_base = 0xd0000; 1080*3db86aabSstevel pcic->pc_bound = (uint32_t)~0; 1081*3db86aabSstevel pcic->pc_iobase = 0x1000; 1082*3db86aabSstevel pcic->pc_iobound = 0xefff; 1083*3db86aabSstevel } /* !PCF_PCIBUS */ 1084*3db86aabSstevel 1085*3db86aabSstevel #ifdef PCIC_DEBUG 1086*3db86aabSstevel if (pcic_debug) { 1087*3db86aabSstevel cmn_err(CE_CONT, "pcic_attach pc_flags=%x pc_type=%x\n", 1088*3db86aabSstevel pcic->pc_flags, pcic->pc_type); 1089*3db86aabSstevel } 1090*3db86aabSstevel #endif 1091*3db86aabSstevel 1092*3db86aabSstevel /* 1093*3db86aabSstevel * Setup various adapter registers for the PCI case. For the 1094*3db86aabSstevel * non-PCI case, find out the chip type. 1095*3db86aabSstevel */ 1096*3db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS) { 1097*3db86aabSstevel int iline; 1098*3db86aabSstevel #if defined(__sparc) 1099*3db86aabSstevel iline = 0; 1100*3db86aabSstevel #else 1101*3db86aabSstevel iline = cardbus_validate_iline(dip, pcic->cfg_handle); 1102*3db86aabSstevel #endif 1103*3db86aabSstevel 1104*3db86aabSstevel /* set flags and socket counts based on chip type */ 1105*3db86aabSstevel switch (pcic->pc_type) { 1106*3db86aabSstevel uint32_t cfg; 1107*3db86aabSstevel case PCIC_INTEL_i82092: 1108*3db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 1109*3db86aabSstevel pcic->cfgaddr + PCIC_82092_PCICON); 1110*3db86aabSstevel /* we can only support 4 Socket version */ 1111*3db86aabSstevel if (cfg & PCIC_82092_4_SOCKETS) { 1112*3db86aabSstevel pcic->pc_numsockets = 4; 1113*3db86aabSstevel pcic->pc_type = PCIC_INTEL_i82092; 1114*3db86aabSstevel if (iline != 0xFF) 1115*3db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1; 1116*3db86aabSstevel else 1117*3db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_ISA; 1118*3db86aabSstevel } else { 1119*3db86aabSstevel cmn_err(CE_CONT, 1120*3db86aabSstevel "pcic%d: Intel 82092 adapter " 1121*3db86aabSstevel "in unsupported configuration: 0x%x", 1122*3db86aabSstevel ddi_get_instance(pcic->dip), cfg); 1123*3db86aabSstevel pcic->pc_numsockets = 0; 1124*3db86aabSstevel } /* PCIC_82092_4_SOCKETS */ 1125*3db86aabSstevel break; 1126*3db86aabSstevel case PCIC_CL_PD6730: 1127*3db86aabSstevel case PCIC_CL_PD6729: 1128*3db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1; 1129*3db86aabSstevel cfg = ddi_getprop(DDI_DEV_T_ANY, dip, 1130*3db86aabSstevel DDI_PROP_CANSLEEP, 1131*3db86aabSstevel "interrupts", 0); 1132*3db86aabSstevel /* if not interrupt pin then must use ISA style IRQs */ 1133*3db86aabSstevel if (cfg == 0 || iline == 0xFF) 1134*3db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_ISA; 1135*3db86aabSstevel else { 1136*3db86aabSstevel /* 1137*3db86aabSstevel * we have the option to use PCI interrupts. 1138*3db86aabSstevel * this might not be optimal but in some cases 1139*3db86aabSstevel * is the only thing possible (sparc case). 1140*3db86aabSstevel * we now deterine what is possible. 1141*3db86aabSstevel */ 1142*3db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1; 1143*3db86aabSstevel } 1144*3db86aabSstevel pcic->pc_numsockets = 2; 1145*3db86aabSstevel pcic->pc_flags |= PCF_IO_REMAP; 1146*3db86aabSstevel break; 1147*3db86aabSstevel case PCIC_TI_PCI1031: 1148*3db86aabSstevel /* this chip doesn't do CardBus but looks like one */ 1149*3db86aabSstevel pcic->pc_flags &= ~PCF_CARDBUS; 1150*3db86aabSstevel /* FALLTHROUGH */ 1151*3db86aabSstevel default: 1152*3db86aabSstevel pcic->pc_flags |= PCF_IO_REMAP; 1153*3db86aabSstevel /* FALLTHROUGH */ 1154*3db86aabSstevel /* indicate feature even if not supported */ 1155*3db86aabSstevel pcic->pc_flags |= PCF_DMA | PCF_ZV; 1156*3db86aabSstevel /* Not sure if these apply to all these chips */ 1157*3db86aabSstevel pcic->pc_flags |= (PCF_VPPX|PCF_33VCAP); 1158*3db86aabSstevel pcic->pc_flags |= pcic_use_cbpwrctl; 1159*3db86aabSstevel 1160*3db86aabSstevel pcic->pc_numsockets = 1; /* one per function */ 1161*3db86aabSstevel if (iline != 0xFF) { 1162*3db86aabSstevel uint8_t cfg; 1163*3db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1; 1164*3db86aabSstevel 1165*3db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 1166*3db86aabSstevel (pcic->cfgaddr + PCIC_BRIDGE_CTL_REG)); 1167*3db86aabSstevel cfg &= (~PCIC_FUN_INT_MOD_ISA); 1168*3db86aabSstevel ddi_put8(pcic->cfg_handle, (pcic->cfgaddr + 1169*3db86aabSstevel PCIC_BRIDGE_CTL_REG), cfg); 1170*3db86aabSstevel } 1171*3db86aabSstevel else 1172*3db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_ISA; 1173*3db86aabSstevel pcic->pc_io_type = PCIC_IOTYPE_YENTA; 1174*3db86aabSstevel break; 1175*3db86aabSstevel } 1176*3db86aabSstevel } else { 1177*3db86aabSstevel /* 1178*3db86aabSstevel * We're not on a PCI bus so do some more 1179*3db86aabSstevel * checking for adapter type here. 1180*3db86aabSstevel * For the non-PCI bus case: 1181*3db86aabSstevel * It could be any one of a number of different chips 1182*3db86aabSstevel * If we can't determine anything else, it is assumed 1183*3db86aabSstevel * to be an Intel 82365SL. The Cirrus Logic PD6710 1184*3db86aabSstevel * has an extension register that provides unique 1185*3db86aabSstevel * identification. Toshiba chip isn't detailed as yet. 1186*3db86aabSstevel */ 1187*3db86aabSstevel 1188*3db86aabSstevel /* Init the CL id mode */ 1189*3db86aabSstevel pcic_putb(pcic, 0, PCIC_CHIP_INFO, 0); 1190*3db86aabSstevel value = pcic_getb(pcic, 0, PCIC_CHIP_INFO); 1191*3db86aabSstevel 1192*3db86aabSstevel /* default to Intel i82365SL and then refine */ 1193*3db86aabSstevel pcic->pc_type = PCIC_I82365SL; 1194*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_I82365SL; 1195*3db86aabSstevel for (value = 0; pcic_ci_funcs[value] != NULL; value++) { 1196*3db86aabSstevel /* go until one succeeds or none left */ 1197*3db86aabSstevel if (pcic_ci_funcs[value](pcic)) 1198*3db86aabSstevel break; 1199*3db86aabSstevel } 1200*3db86aabSstevel 1201*3db86aabSstevel /* any chip specific flags get set here */ 1202*3db86aabSstevel switch (pcic->pc_type) { 1203*3db86aabSstevel case PCIC_CL_PD6722: 1204*3db86aabSstevel pcic->pc_flags |= PCF_DMA; 1205*3db86aabSstevel } 1206*3db86aabSstevel 1207*3db86aabSstevel for (i = 0; i < PCIC_MAX_SOCKETS; i++) { 1208*3db86aabSstevel /* 1209*3db86aabSstevel * look for total number of sockets. 1210*3db86aabSstevel * basically check each possible socket for 1211*3db86aabSstevel * presence like in probe 1212*3db86aabSstevel */ 1213*3db86aabSstevel 1214*3db86aabSstevel /* turn all windows off */ 1215*3db86aabSstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0); 1216*3db86aabSstevel value = pcic_getb(pcic, i, PCIC_MAPPING_ENABLE); 1217*3db86aabSstevel 1218*3db86aabSstevel /* 1219*3db86aabSstevel * if a zero is read back, then this socket 1220*3db86aabSstevel * might be present. It would be except for 1221*3db86aabSstevel * some systems that map the secondary PCIC 1222*3db86aabSstevel * chip space back to the first. 1223*3db86aabSstevel */ 1224*3db86aabSstevel if (value != 0) { 1225*3db86aabSstevel /* definitely not so skip */ 1226*3db86aabSstevel /* note: this is for Compaq support */ 1227*3db86aabSstevel continue; 1228*3db86aabSstevel } 1229*3db86aabSstevel 1230*3db86aabSstevel /* further tests */ 1231*3db86aabSstevel value = pcic_getb(pcic, i, PCIC_CHIP_REVISION) & 1232*3db86aabSstevel PCIC_REV_MASK; 1233*3db86aabSstevel if (!(value >= PCIC_REV_LEVEL_LOW && 1234*3db86aabSstevel value <= PCIC_REV_LEVEL_HI)) 1235*3db86aabSstevel break; 1236*3db86aabSstevel 1237*3db86aabSstevel pcic_putb(pcic, i, PCIC_SYSMEM_0_STARTLOW, 0xaa); 1238*3db86aabSstevel pcic_putb(pcic, i, PCIC_SYSMEM_1_STARTLOW, 0x55); 1239*3db86aabSstevel value = pcic_getb(pcic, i, PCIC_SYSMEM_0_STARTLOW); 1240*3db86aabSstevel 1241*3db86aabSstevel j = pcic_getb(pcic, i, PCIC_SYSMEM_1_STARTLOW); 1242*3db86aabSstevel if (value != 0xaa || j != 0x55) 1243*3db86aabSstevel break; 1244*3db86aabSstevel 1245*3db86aabSstevel /* 1246*3db86aabSstevel * at this point we know if we have hardware 1247*3db86aabSstevel * of some type and not just the bus holding 1248*3db86aabSstevel * a pattern for us. We still have to determine 1249*3db86aabSstevel * the case where more than 2 sockets are 1250*3db86aabSstevel * really the same due to peculiar mappings of 1251*3db86aabSstevel * hardware. 1252*3db86aabSstevel */ 1253*3db86aabSstevel j = pcic->pc_numsockets++; 1254*3db86aabSstevel pcic->pc_sockets[j].pcs_flags = 0; 1255*3db86aabSstevel pcic->pc_sockets[j].pcs_io = pcic->ioaddr; 1256*3db86aabSstevel pcic->pc_sockets[j].pcs_socket = i; 1257*3db86aabSstevel 1258*3db86aabSstevel /* put PC Card into RESET, just in case */ 1259*3db86aabSstevel value = pcic_getb(pcic, i, PCIC_INTERRUPT); 1260*3db86aabSstevel pcic_putb(pcic, i, PCIC_INTERRUPT, 1261*3db86aabSstevel value & ~PCIC_RESET); 1262*3db86aabSstevel } 1263*3db86aabSstevel 1264*3db86aabSstevel #if defined(PCIC_DEBUG) 1265*3db86aabSstevel if (pcic_debug) 1266*3db86aabSstevel cmn_err(CE_CONT, "num sockets = %d\n", 1267*3db86aabSstevel pcic->pc_numsockets); 1268*3db86aabSstevel #endif 1269*3db86aabSstevel if (pcic->pc_numsockets == 0) { 1270*3db86aabSstevel ddi_regs_map_free(&pcic->handle); 1271*3db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 1272*3db86aabSstevel return (DDI_FAILURE); 1273*3db86aabSstevel } 1274*3db86aabSstevel 1275*3db86aabSstevel /* 1276*3db86aabSstevel * need to think this through again in light of 1277*3db86aabSstevel * Compaq not following the model that all the 1278*3db86aabSstevel * chip vendors recommend. IBM 755 seems to be 1279*3db86aabSstevel * afflicted as well. Basically, if the vendor 1280*3db86aabSstevel * wired things wrong, socket 0 responds for socket 2 1281*3db86aabSstevel * accesses, etc. 1282*3db86aabSstevel */ 1283*3db86aabSstevel if (pcic->pc_numsockets > 2) { 1284*3db86aabSstevel int count = pcic->pc_numsockets / 4; 1285*3db86aabSstevel for (i = 0; i < count; i++) { 1286*3db86aabSstevel /* put pattern into socket 0 */ 1287*3db86aabSstevel pcic_putb(pcic, i, 1288*3db86aabSstevel PCIC_SYSMEM_0_STARTLOW, 0x11); 1289*3db86aabSstevel 1290*3db86aabSstevel /* put pattern into socket 2 */ 1291*3db86aabSstevel pcic_putb(pcic, i + 2, 1292*3db86aabSstevel PCIC_SYSMEM_0_STARTLOW, 0x33); 1293*3db86aabSstevel 1294*3db86aabSstevel /* read back socket 0 */ 1295*3db86aabSstevel value = pcic_getb(pcic, i, 1296*3db86aabSstevel PCIC_SYSMEM_0_STARTLOW); 1297*3db86aabSstevel 1298*3db86aabSstevel /* read back chip 1 socket 0 */ 1299*3db86aabSstevel j = pcic_getb(pcic, i + 2, 1300*3db86aabSstevel PCIC_SYSMEM_0_STARTLOW); 1301*3db86aabSstevel if (j == value) { 1302*3db86aabSstevel pcic->pc_numsockets -= 2; 1303*3db86aabSstevel } 1304*3db86aabSstevel } 1305*3db86aabSstevel } 1306*3db86aabSstevel 1307*3db86aabSstevel smi = 0xff; /* no more override */ 1308*3db86aabSstevel 1309*3db86aabSstevel if (ddi_getprop(DDI_DEV_T_NONE, dip, 1310*3db86aabSstevel DDI_PROP_DONTPASS, "need-mult-irq", 1311*3db86aabSstevel 0xffff) != 0xffff) 1312*3db86aabSstevel pcic->pc_flags |= PCF_MULT_IRQ; 1313*3db86aabSstevel 1314*3db86aabSstevel } /* !PCF_PCIBUS */ 1315*3db86aabSstevel 1316*3db86aabSstevel /* 1317*3db86aabSstevel * some platforms/busses need to have resources setup 1318*3db86aabSstevel * this is temporary until a real resource allocator is 1319*3db86aabSstevel * implemented. 1320*3db86aabSstevel */ 1321*3db86aabSstevel 1322*3db86aabSstevel pcic_init_assigned(dip); 1323*3db86aabSstevel 1324*3db86aabSstevel typename = pcic->pc_chipname; 1325*3db86aabSstevel 1326*3db86aabSstevel #ifdef PCIC_DEBUG 1327*3db86aabSstevel if (pcic_debug) { 1328*3db86aabSstevel int nregs, nintrs; 1329*3db86aabSstevel 1330*3db86aabSstevel if (ddi_dev_nregs(dip, &nregs) != DDI_SUCCESS) 1331*3db86aabSstevel nregs = 0; 1332*3db86aabSstevel 1333*3db86aabSstevel if (ddi_dev_nintrs(dip, &nintrs) != DDI_SUCCESS) 1334*3db86aabSstevel nintrs = 0; 1335*3db86aabSstevel 1336*3db86aabSstevel cmn_err(CE_CONT, 1337*3db86aabSstevel "pcic%d: %d register sets, %d interrupts\n", 1338*3db86aabSstevel ddi_get_instance(dip), nregs, nintrs); 1339*3db86aabSstevel 1340*3db86aabSstevel nintrs = 0; 1341*3db86aabSstevel while (nregs--) { 1342*3db86aabSstevel off_t size; 1343*3db86aabSstevel 1344*3db86aabSstevel if (ddi_dev_regsize(dip, nintrs, &size) == 1345*3db86aabSstevel DDI_SUCCESS) { 1346*3db86aabSstevel cmn_err(CE_CONT, 1347*3db86aabSstevel "\tregnum %d size %ld (0x%lx)" 1348*3db86aabSstevel "bytes", 1349*3db86aabSstevel nintrs, size, size); 1350*3db86aabSstevel if (nintrs == 1351*3db86aabSstevel (pcic->pc_io_type == PCIC_IO_TYPE_82365SL ? 1352*3db86aabSstevel PCIC_ISA_CONTROL_REG_NUM : 1353*3db86aabSstevel PCIC_PCI_CONTROL_REG_NUM)) 1354*3db86aabSstevel cmn_err(CE_CONT, 1355*3db86aabSstevel " mapped at: 0x%p\n", 1356*3db86aabSstevel (void *)pcic->ioaddr); 1357*3db86aabSstevel else 1358*3db86aabSstevel cmn_err(CE_CONT, "\n"); 1359*3db86aabSstevel } else { 1360*3db86aabSstevel cmn_err(CE_CONT, 1361*3db86aabSstevel "\tddi_dev_regsize(rnumber" 1362*3db86aabSstevel "= %d) returns DDI_FAILURE\n", 1363*3db86aabSstevel nintrs); 1364*3db86aabSstevel } 1365*3db86aabSstevel nintrs++; 1366*3db86aabSstevel } /* while */ 1367*3db86aabSstevel } /* if (pcic_debug) */ 1368*3db86aabSstevel #endif 1369*3db86aabSstevel 1370*3db86aabSstevel cv_init(&pcic->pm_cv, NULL, CV_DRIVER, NULL); 1371*3db86aabSstevel 1372*3db86aabSstevel if (!ddi_getprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 1373*3db86aabSstevel "disable-audio", 0)) 1374*3db86aabSstevel pcic->pc_flags |= PCF_AUDIO; 1375*3db86aabSstevel 1376*3db86aabSstevel if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP, 1377*3db86aabSstevel "disable-cardbus", 0)) 1378*3db86aabSstevel pcic->pc_flags &= ~PCF_CARDBUS; 1379*3db86aabSstevel 1380*3db86aabSstevel (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, PCICPROP_CTL, 1381*3db86aabSstevel typename); 1382*3db86aabSstevel 1383*3db86aabSstevel /* 1384*3db86aabSstevel * Init all socket SMI levels to 0 (no SMI) 1385*3db86aabSstevel */ 1386*3db86aabSstevel for (i = 0; i < PCIC_MAX_SOCKETS; i++) { 1387*3db86aabSstevel pcic->pc_sockets[i].pcs_smi = 0; 1388*3db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id = 0; 1389*3db86aabSstevel pcic->pc_sockets[i].pcs_pcic = pcic; 1390*3db86aabSstevel } 1391*3db86aabSstevel pcic->pc_lastreg = -1; /* just to make sure we are in sync */ 1392*3db86aabSstevel 1393*3db86aabSstevel /* 1394*3db86aabSstevel * Setup the IRQ handler(s) 1395*3db86aabSstevel */ 1396*3db86aabSstevel switch (pcic->pc_intr_mode) { 1397*3db86aabSstevel int xx; 1398*3db86aabSstevel case PCIC_INTR_MODE_ISA: 1399*3db86aabSstevel /* 1400*3db86aabSstevel * On a non-PCI bus, we just use whatever SMI IRQ level was 1401*3db86aabSstevel * specified above, and the IO IRQ levels are allocated 1402*3db86aabSstevel * dynamically. 1403*3db86aabSstevel */ 1404*3db86aabSstevel for (xx = 15, smi = 0; xx >= 0; xx--) { 1405*3db86aabSstevel if (PCIC_IRQ(xx) & 1406*3db86aabSstevel PCIC_AVAIL_IRQS) { 1407*3db86aabSstevel smi = pcmcia_get_intr(dip, xx); 1408*3db86aabSstevel if (smi >= 0) 1409*3db86aabSstevel break; 1410*3db86aabSstevel } 1411*3db86aabSstevel } 1412*3db86aabSstevel #if defined(PCIC_DEBUG) 1413*3db86aabSstevel if (pcic_debug) 1414*3db86aabSstevel cmn_err(CE_NOTE, "\tselected IRQ %d as SMI\n", smi); 1415*3db86aabSstevel #endif 1416*3db86aabSstevel /* init to same so share is easy */ 1417*3db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) 1418*3db86aabSstevel pcic->pc_sockets[i].pcs_smi = smi; 1419*3db86aabSstevel /* any special handling of IRQ levels */ 1420*3db86aabSstevel if (pcic->pc_flags & PCF_MULT_IRQ) { 1421*3db86aabSstevel for (i = 2; i < pcic->pc_numsockets; i++) { 1422*3db86aabSstevel if ((i & 1) == 0) { 1423*3db86aabSstevel int xx; 1424*3db86aabSstevel for (xx = 15, smi = 0; xx >= 0; xx--) { 1425*3db86aabSstevel if (PCIC_IRQ(xx) & 1426*3db86aabSstevel PCIC_AVAIL_IRQS) { 1427*3db86aabSstevel smi = 1428*3db86aabSstevel pcmcia_get_intr(dip, 1429*3db86aabSstevel xx); 1430*3db86aabSstevel if (smi >= 0) 1431*3db86aabSstevel break; 1432*3db86aabSstevel } 1433*3db86aabSstevel } 1434*3db86aabSstevel } 1435*3db86aabSstevel if (smi >= 0) 1436*3db86aabSstevel pcic->pc_sockets[i].pcs_smi = smi; 1437*3db86aabSstevel } 1438*3db86aabSstevel } 1439*3db86aabSstevel pcic->pc_intr_htblp = kmem_alloc(pcic->pc_numsockets * 1440*3db86aabSstevel sizeof (ddi_intr_handle_t), KM_SLEEP); 1441*3db86aabSstevel for (i = 0, irqlevel = -1; i < pcic->pc_numsockets; i++) { 1442*3db86aabSstevel struct intrspec *ispecp; 1443*3db86aabSstevel struct ddi_parent_private_data *pdp; 1444*3db86aabSstevel 1445*3db86aabSstevel if (irqlevel == pcic->pc_sockets[i].pcs_smi) 1446*3db86aabSstevel continue; 1447*3db86aabSstevel else { 1448*3db86aabSstevel irqlevel = pcic->pc_sockets[i].pcs_smi; 1449*3db86aabSstevel } 1450*3db86aabSstevel /* 1451*3db86aabSstevel * now convert the allocated IRQ into an intrspec 1452*3db86aabSstevel * and ask our parent to add it. Don't use 1453*3db86aabSstevel * the ddi_add_intr since we don't have a 1454*3db86aabSstevel * default intrspec in all cases. 1455*3db86aabSstevel * 1456*3db86aabSstevel * note: this sort of violates DDI but we don't 1457*3db86aabSstevel * get hardware intrspecs for many of the devices. 1458*3db86aabSstevel * at the same time, we know how to allocate them 1459*3db86aabSstevel * so we do the right thing. 1460*3db86aabSstevel */ 1461*3db86aabSstevel if (ddi_intr_alloc(dip, &pcic->pc_intr_htblp[i], 1462*3db86aabSstevel DDI_INTR_TYPE_FIXED, 0, 1, &actual, 1463*3db86aabSstevel DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) { 1464*3db86aabSstevel cmn_err(CE_WARN, "%s: ddi_intr_alloc failed", 1465*3db86aabSstevel ddi_get_name(dip)); 1466*3db86aabSstevel goto isa_exit1; 1467*3db86aabSstevel } 1468*3db86aabSstevel 1469*3db86aabSstevel /* 1470*3db86aabSstevel * See earlier note: 1471*3db86aabSstevel * Since some devices don't have 'intrspec' 1472*3db86aabSstevel * we make one up in rootnex. 1473*3db86aabSstevel * 1474*3db86aabSstevel * However, it is not properly initialized as 1475*3db86aabSstevel * the data it needs is present in this driver 1476*3db86aabSstevel * and there is no interface to pass that up. 1477*3db86aabSstevel * Specially 'irqlevel' is very important and 1478*3db86aabSstevel * it is part of pcic struct. 1479*3db86aabSstevel * 1480*3db86aabSstevel * Set 'intrspec' up here; otherwise adding the 1481*3db86aabSstevel * interrupt will fail. 1482*3db86aabSstevel */ 1483*3db86aabSstevel pdp = ddi_get_parent_data(dip); 1484*3db86aabSstevel ispecp = (struct intrspec *)&pdp->par_intr[0]; 1485*3db86aabSstevel ispecp->intrspec_vec = irqlevel; 1486*3db86aabSstevel ispecp->intrspec_pri = pcic->pc_irq; 1487*3db86aabSstevel 1488*3db86aabSstevel /* Stay compatible w/ PCMCIA */ 1489*3db86aabSstevel pcic->pc_pri = (ddi_iblock_cookie_t) 1490*3db86aabSstevel (uintptr_t)pcic->pc_irq; 1491*3db86aabSstevel pcic->pc_dcookie.idev_priority = 1492*3db86aabSstevel (uintptr_t)pcic->pc_pri; 1493*3db86aabSstevel pcic->pc_dcookie.idev_vector = (ushort_t)irqlevel; 1494*3db86aabSstevel 1495*3db86aabSstevel (void) ddi_intr_set_pri(pcic->pc_intr_htblp[i], 1496*3db86aabSstevel pcic->pc_irq); 1497*3db86aabSstevel 1498*3db86aabSstevel if (i == 0) { 1499*3db86aabSstevel mutex_init(&pcic->intr_lock, NULL, MUTEX_DRIVER, 1500*3db86aabSstevel DDI_INTR_PRI(pcic->pc_irq)); 1501*3db86aabSstevel mutex_init(&pcic->pc_lock, NULL, MUTEX_DRIVER, 1502*3db86aabSstevel NULL); 1503*3db86aabSstevel } 1504*3db86aabSstevel 1505*3db86aabSstevel if (ddi_intr_add_handler(pcic->pc_intr_htblp[i], 1506*3db86aabSstevel pcic_intr, (caddr_t)pcic, NULL)) { 1507*3db86aabSstevel cmn_err(CE_WARN, 1508*3db86aabSstevel "%s: ddi_intr_add_handler failed", 1509*3db86aabSstevel ddi_get_name(dip)); 1510*3db86aabSstevel goto isa_exit2; 1511*3db86aabSstevel } 1512*3db86aabSstevel 1513*3db86aabSstevel if (ddi_intr_enable(pcic->pc_intr_htblp[i])) { 1514*3db86aabSstevel cmn_err(CE_WARN, "%s: ddi_intr_enable failed", 1515*3db86aabSstevel ddi_get_name(dip)); 1516*3db86aabSstevel for (j = i; j < 0; j--) 1517*3db86aabSstevel (void) ddi_intr_remove_handler( 1518*3db86aabSstevel pcic->pc_intr_htblp[j]); 1519*3db86aabSstevel goto isa_exit2; 1520*3db86aabSstevel } 1521*3db86aabSstevel } 1522*3db86aabSstevel break; 1523*3db86aabSstevel case PCIC_INTR_MODE_PCI_1: 1524*3db86aabSstevel case PCIC_INTR_MODE_PCI: 1525*3db86aabSstevel /* 1526*3db86aabSstevel * If we're on a PCI bus, we route all interrupts, both SMI 1527*3db86aabSstevel * and IO interrupts, through a single interrupt line. 1528*3db86aabSstevel * Assign the SMI IRQ level to the IO IRQ level here. 1529*3db86aabSstevel */ 1530*3db86aabSstevel pcic->pc_pci_intr_hdlp = kmem_alloc(sizeof (ddi_intr_handle_t), 1531*3db86aabSstevel KM_SLEEP); 1532*3db86aabSstevel if (ddi_intr_alloc(dip, pcic->pc_pci_intr_hdlp, 1533*3db86aabSstevel DDI_INTR_TYPE_FIXED, 0, 1, &actual, 1534*3db86aabSstevel DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) 1535*3db86aabSstevel goto pci_exit1; 1536*3db86aabSstevel 1537*3db86aabSstevel if (ddi_intr_get_pri(pcic->pc_pci_intr_hdlp[0], 1538*3db86aabSstevel &pri) != DDI_SUCCESS) { 1539*3db86aabSstevel (void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]); 1540*3db86aabSstevel goto pci_exit1; 1541*3db86aabSstevel } 1542*3db86aabSstevel 1543*3db86aabSstevel pcic->pc_pri = (void *)(uintptr_t)pri; 1544*3db86aabSstevel mutex_init(&pcic->intr_lock, NULL, MUTEX_DRIVER, pcic->pc_pri); 1545*3db86aabSstevel mutex_init(&pcic->pc_lock, NULL, MUTEX_DRIVER, NULL); 1546*3db86aabSstevel 1547*3db86aabSstevel if (ddi_intr_add_handler(pcic->pc_pci_intr_hdlp[0], 1548*3db86aabSstevel pcic_intr, (caddr_t)pcic, NULL)) 1549*3db86aabSstevel goto pci_exit2; 1550*3db86aabSstevel 1551*3db86aabSstevel if (ddi_intr_enable(pcic->pc_pci_intr_hdlp[0])) { 1552*3db86aabSstevel (void) ddi_intr_remove_handler( 1553*3db86aabSstevel pcic->pc_pci_intr_hdlp[0]); 1554*3db86aabSstevel goto pci_exit2; 1555*3db86aabSstevel } 1556*3db86aabSstevel 1557*3db86aabSstevel /* Stay compatible w/ PCMCIA */ 1558*3db86aabSstevel pcic->pc_dcookie.idev_priority = (ushort_t)pri; 1559*3db86aabSstevel 1560*3db86aabSstevel /* init to same (PCI) so share is easy */ 1561*3db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) 1562*3db86aabSstevel pcic->pc_sockets[i].pcs_smi = 0xF; /* any valid */ 1563*3db86aabSstevel break; 1564*3db86aabSstevel } 1565*3db86aabSstevel 1566*3db86aabSstevel /* 1567*3db86aabSstevel * Setup the adapter hardware to some reasonable defaults. 1568*3db86aabSstevel */ 1569*3db86aabSstevel mutex_enter(&pcic->pc_lock); 1570*3db86aabSstevel /* mark the driver state as attached */ 1571*3db86aabSstevel pcic->pc_flags |= PCF_ATTACHED; 1572*3db86aabSstevel pcic_setup_adapter(pcic); 1573*3db86aabSstevel 1574*3db86aabSstevel for (j = 0; j < pcic->pc_numsockets; j++) 1575*3db86aabSstevel if (ddi_intr_add_softint(dip, 1576*3db86aabSstevel &pcic->pc_sockets[j].pcs_cd_softint_hdl, 1577*3db86aabSstevel PCIC_SOFTINT_PRI_VAL, pcic_cd_softint, 1578*3db86aabSstevel (caddr_t)&pcic->pc_sockets[j]) != DDI_SUCCESS) 1579*3db86aabSstevel goto pci_exit2; 1580*3db86aabSstevel 1581*3db86aabSstevel #if defined(PCIC_DEBUG) 1582*3db86aabSstevel if (pcic_debug) 1583*3db86aabSstevel cmn_err(CE_CONT, "type = %s sockets = %d\n", typename, 1584*3db86aabSstevel pcic->pc_numsockets); 1585*3db86aabSstevel #endif 1586*3db86aabSstevel 1587*3db86aabSstevel pcic_nexus->an_iblock = &pcic->pc_pri; 1588*3db86aabSstevel pcic_nexus->an_idev = &pcic->pc_dcookie; 1589*3db86aabSstevel 1590*3db86aabSstevel mutex_exit(&pcic->pc_lock); 1591*3db86aabSstevel 1592*3db86aabSstevel #ifdef CARDBUS 1593*3db86aabSstevel (void) cardbus_enable_cd_intr(dip); 1594*3db86aabSstevel if (pcic_debug) { 1595*3db86aabSstevel 1596*3db86aabSstevel cardbus_dump_pci_config(dip); 1597*3db86aabSstevel cardbus_dump_socket(dip); 1598*3db86aabSstevel } 1599*3db86aabSstevel 1600*3db86aabSstevel /* 1601*3db86aabSstevel * Give the Cardbus misc module a chance to do it's per-adapter 1602*3db86aabSstevel * instance setup. Note that there is no corresponding detach() 1603*3db86aabSstevel * call. 1604*3db86aabSstevel */ 1605*3db86aabSstevel if (pcic->pc_flags & PCF_CARDBUS) 1606*3db86aabSstevel if (cardbus_attach(dip, &pcic_cbnexus_ops) != DDI_SUCCESS) { 1607*3db86aabSstevel cmn_err(CE_CONT, 1608*3db86aabSstevel "pcic_attach: cardbus_attach failed\n"); 1609*3db86aabSstevel goto pci_exit2; 1610*3db86aabSstevel } 1611*3db86aabSstevel #endif 1612*3db86aabSstevel 1613*3db86aabSstevel /* 1614*3db86aabSstevel * Give the PCMCIA misc module a chance to do it's per-adapter 1615*3db86aabSstevel * instance setup. 1616*3db86aabSstevel */ 1617*3db86aabSstevel if ((i = pcmcia_attach(dip, pcic_nexus)) != DDI_SUCCESS) 1618*3db86aabSstevel goto pci_exit2; 1619*3db86aabSstevel 1620*3db86aabSstevel syshw_attach(pcic); 1621*3db86aabSstevel if (pcic_maxinst == -1) { 1622*3db86aabSstevel /* This assumes that all instances run at the same IPL. */ 1623*3db86aabSstevel mutex_init(&pcic_deb_mtx, NULL, MUTEX_DRIVER, NULL); 1624*3db86aabSstevel cv_init(&pcic_deb_cv, NULL, CV_DRIVER, NULL); 1625*3db86aabSstevel pcic_deb_threadid = thread_create((caddr_t)NULL, 0, 1626*3db86aabSstevel pcic_deb_thread, (caddr_t)NULL, 0, &p0, TS_RUN, 1627*3db86aabSstevel v.v_maxsyspri - 2); 1628*3db86aabSstevel } 1629*3db86aabSstevel pcic_maxinst = max(pcic_maxinst, ddi_get_instance(dip)); 1630*3db86aabSstevel /* 1631*3db86aabSstevel * Setup a debounce timeout to do an initial card detect 1632*3db86aabSstevel * and enable interrupts. 1633*3db86aabSstevel */ 1634*3db86aabSstevel for (j = 0; j < pcic->pc_numsockets; j++) { 1635*3db86aabSstevel shwp = kmem_alloc(sizeof (syshw_t), KM_SLEEP); 1636*3db86aabSstevel if (shwp) { 1637*3db86aabSstevel bcopy(&pcic_syshw, shwp, sizeof (pcic_syshw)); 1638*3db86aabSstevel pcic_syshw.id_string[15]++; 1639*3db86aabSstevel pcic->pc_sockets[j].pcs_syshwsig = 1640*3db86aabSstevel syshw_add2map(shwp, pcic_syshw_cardstate, 1641*3db86aabSstevel &pcic->pc_sockets[j]); 1642*3db86aabSstevel } 1643*3db86aabSstevel pcic->pc_sockets[j].pcs_debounce_id = 1644*3db86aabSstevel pcic_add_debqueue(&pcic->pc_sockets[j], 1645*3db86aabSstevel drv_usectohz(pcic_debounce_time)); 1646*3db86aabSstevel } 1647*3db86aabSstevel 1648*3db86aabSstevel return (i); 1649*3db86aabSstevel 1650*3db86aabSstevel isa_exit2: 1651*3db86aabSstevel mutex_destroy(&pcic->intr_lock); 1652*3db86aabSstevel mutex_destroy(&pcic->pc_lock); 1653*3db86aabSstevel for (j = i; j < 0; j--) 1654*3db86aabSstevel (void) ddi_intr_free(pcic->pc_intr_htblp[j]); 1655*3db86aabSstevel isa_exit1: 1656*3db86aabSstevel (void) pcmcia_return_intr(dip, pcic->pc_sockets[i].pcs_smi); 1657*3db86aabSstevel ddi_regs_map_free(&pcic->handle); 1658*3db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS) 1659*3db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle); 1660*3db86aabSstevel kmem_free(pcic->pc_intr_htblp, pcic->pc_numsockets * 1661*3db86aabSstevel sizeof (ddi_intr_handle_t)); 1662*3db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 1663*3db86aabSstevel return (DDI_FAILURE); 1664*3db86aabSstevel 1665*3db86aabSstevel pci_exit2: 1666*3db86aabSstevel mutex_destroy(&pcic->intr_lock); 1667*3db86aabSstevel mutex_destroy(&pcic->pc_lock); 1668*3db86aabSstevel (void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]); 1669*3db86aabSstevel pci_exit1: 1670*3db86aabSstevel ddi_regs_map_free(&pcic->handle); 1671*3db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS) 1672*3db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle); 1673*3db86aabSstevel kmem_free(pcic->pc_pci_intr_hdlp, sizeof (ddi_intr_handle_t)); 1674*3db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 1675*3db86aabSstevel return (DDI_FAILURE); 1676*3db86aabSstevel } 1677*3db86aabSstevel 1678*3db86aabSstevel /* 1679*3db86aabSstevel * pcic_detach() 1680*3db86aabSstevel * request to detach from the system 1681*3db86aabSstevel */ 1682*3db86aabSstevel static int 1683*3db86aabSstevel pcic_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 1684*3db86aabSstevel { 1685*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 1686*3db86aabSstevel pcicdev_t *pcic = anp->an_private; 1687*3db86aabSstevel int i; 1688*3db86aabSstevel 1689*3db86aabSstevel switch (cmd) { 1690*3db86aabSstevel case DDI_DETACH: 1691*3db86aabSstevel /* don't detach if the nexus still talks to us */ 1692*3db86aabSstevel if (pcic->pc_callback != NULL) 1693*3db86aabSstevel return (DDI_FAILURE); 1694*3db86aabSstevel syshw_detach(pcic); 1695*3db86aabSstevel 1696*3db86aabSstevel /* kill off the pm simulation */ 1697*3db86aabSstevel if (pcic->pc_pmtimer) 1698*3db86aabSstevel (void) untimeout(pcic->pc_pmtimer); 1699*3db86aabSstevel 1700*3db86aabSstevel /* turn everything off for all sockets and chips */ 1701*3db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) { 1702*3db86aabSstevel if (pcic->pc_sockets[i].pcs_debounce_id) 1703*3db86aabSstevel pcic_rm_debqueue( 1704*3db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id); 1705*3db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id = 0; 1706*3db86aabSstevel 1707*3db86aabSstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0); 1708*3db86aabSstevel pcic_putb(pcic, i, PCIC_CARD_DETECT, 0); 1709*3db86aabSstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0); 1710*3db86aabSstevel /* disable interrupts and put card into RESET */ 1711*3db86aabSstevel pcic_putb(pcic, i, PCIC_INTERRUPT, 0); 1712*3db86aabSstevel } 1713*3db86aabSstevel (void) ddi_intr_disable(pcic->pc_pci_intr_hdlp[0]); 1714*3db86aabSstevel (void) ddi_intr_remove_handler(pcic->pc_pci_intr_hdlp[0]); 1715*3db86aabSstevel (void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]); 1716*3db86aabSstevel kmem_free(pcic->pc_pci_intr_hdlp, sizeof (ddi_intr_handle_t)); 1717*3db86aabSstevel pcic->pc_flags = 0; 1718*3db86aabSstevel mutex_destroy(&pcic->pc_lock); 1719*3db86aabSstevel mutex_destroy(&pcic->intr_lock); 1720*3db86aabSstevel cv_destroy(&pcic->pm_cv); 1721*3db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS) 1722*3db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle); 1723*3db86aabSstevel if (pcic->handle) 1724*3db86aabSstevel ddi_regs_map_free(&pcic->handle); 1725*3db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 1726*3db86aabSstevel ddi_soft_state_free(pcic_soft_state_p, ddi_get_instance(dip)); 1727*3db86aabSstevel return (DDI_SUCCESS); 1728*3db86aabSstevel 1729*3db86aabSstevel case DDI_SUSPEND: 1730*3db86aabSstevel case DDI_PM_SUSPEND: 1731*3db86aabSstevel /* 1732*3db86aabSstevel * we got a suspend event (either real or imagined) 1733*3db86aabSstevel * so notify the nexus proper that all existing cards 1734*3db86aabSstevel * should go away. 1735*3db86aabSstevel */ 1736*3db86aabSstevel mutex_enter(&pcic->pc_lock); 1737*3db86aabSstevel #ifdef CARDBUS 1738*3db86aabSstevel if (pcic->pc_flags & PCF_CARDBUS) 1739*3db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) 1740*3db86aabSstevel if ((pcic->pc_sockets[i].pcs_flags & 1741*3db86aabSstevel (PCS_CARD_PRESENT|PCS_CARD_ISCARDBUS)) == 1742*3db86aabSstevel (PCS_CARD_PRESENT|PCS_CARD_ISCARDBUS)) 1743*3db86aabSstevel if (!cardbus_can_suspend(dip)) { 1744*3db86aabSstevel mutex_exit(&pcic->pc_lock); 1745*3db86aabSstevel cmn_err(CE_WARN, 1746*3db86aabSstevel "Please unconfigure all " 1747*3db86aabSstevel "CardBus devices before " 1748*3db86aabSstevel "attempting to suspend\n"); 1749*3db86aabSstevel return (DDI_FAILURE); 1750*3db86aabSstevel } 1751*3db86aabSstevel #endif 1752*3db86aabSstevel /* turn everything off for all sockets and chips */ 1753*3db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) { 1754*3db86aabSstevel if (pcic->pc_sockets[i].pcs_debounce_id) 1755*3db86aabSstevel pcic_rm_debqueue( 1756*3db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id); 1757*3db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id = 0; 1758*3db86aabSstevel 1759*3db86aabSstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0); 1760*3db86aabSstevel pcic_putb(pcic, i, PCIC_CARD_DETECT, 0); 1761*3db86aabSstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0); 1762*3db86aabSstevel /* disable interrupts and put card into RESET */ 1763*3db86aabSstevel pcic_putb(pcic, i, PCIC_INTERRUPT, 0); 1764*3db86aabSstevel pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0); 1765*3db86aabSstevel if (pcic->pc_flags & PCF_CBPWRCTL) 1766*3db86aabSstevel pcic_putcb(pcic, CB_CONTROL, 0); 1767*3db86aabSstevel 1768*3db86aabSstevel if (pcic->pc_sockets[i].pcs_flags & PCS_CARD_PRESENT) { 1769*3db86aabSstevel pcic->pc_sockets[i].pcs_flags = PCS_STARTING; 1770*3db86aabSstevel /* 1771*3db86aabSstevel * Because we are half way through a save 1772*3db86aabSstevel * all this does is schedule a removal event 1773*3db86aabSstevel * to cs for when the system comes back. 1774*3db86aabSstevel * This doesn't actually matter. 1775*3db86aabSstevel */ 1776*3db86aabSstevel if (!pcic_do_pcmcia_sr && pcic_do_removal && 1777*3db86aabSstevel pcic->pc_callback) { 1778*3db86aabSstevel PC_CALLBACK(pcic->dip, pcic->pc_cb_arg, 1779*3db86aabSstevel PCE_CARD_REMOVAL, 1780*3db86aabSstevel pcic->pc_sockets[i].pcs_socket); 1781*3db86aabSstevel } 1782*3db86aabSstevel } 1783*3db86aabSstevel } 1784*3db86aabSstevel 1785*3db86aabSstevel pcic->pc_flags |= PCF_SUSPENDED; 1786*3db86aabSstevel mutex_exit(&pcic->pc_lock); 1787*3db86aabSstevel pcic_delayed_resume_toid = 0; 1788*3db86aabSstevel 1789*3db86aabSstevel /* 1790*3db86aabSstevel * when true power management exists, save the adapter 1791*3db86aabSstevel * state here to enable a recovery. For the emulation 1792*3db86aabSstevel * condition, the state is gone 1793*3db86aabSstevel */ 1794*3db86aabSstevel return (DDI_SUCCESS); 1795*3db86aabSstevel 1796*3db86aabSstevel default: 1797*3db86aabSstevel return (EINVAL); 1798*3db86aabSstevel } 1799*3db86aabSstevel } 1800*3db86aabSstevel 1801*3db86aabSstevel static uint32_t pcic_tisysctl_onbits = ((1<<27) | (1<<15) | (1<<14)); 1802*3db86aabSstevel static uint32_t pcic_tisysctl_offbits = 0; 1803*3db86aabSstevel static uint32_t pcic_default_latency = 0x40; 1804*3db86aabSstevel 1805*3db86aabSstevel static void 1806*3db86aabSstevel pcic_setup_adapter(pcicdev_t *pcic) 1807*3db86aabSstevel { 1808*3db86aabSstevel int i; 1809*3db86aabSstevel int value, flags; 1810*3db86aabSstevel 1811*3db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS) { 1812*3db86aabSstevel /* 1813*3db86aabSstevel * all PCI-to-PCMCIA bus bridges need memory and I/O enabled 1814*3db86aabSstevel */ 1815*3db86aabSstevel flags = (PCIC_ENABLE_IO | PCIC_ENABLE_MEM); 1816*3db86aabSstevel pcic_iomem_pci_ctl(pcic->cfg_handle, pcic->cfgaddr, flags); 1817*3db86aabSstevel } 1818*3db86aabSstevel /* enable each socket */ 1819*3db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) { 1820*3db86aabSstevel pcic->pc_sockets[i].pcs_flags = 0; 1821*3db86aabSstevel /* find out the socket capabilities (I/O vs memory) */ 1822*3db86aabSstevel value = pcic_getb(pcic, i, 1823*3db86aabSstevel PCIC_CHIP_REVISION) & PCIC_REV_ID_MASK; 1824*3db86aabSstevel if (value == PCIC_REV_ID_IO || value == PCIC_REV_ID_BOTH) 1825*3db86aabSstevel pcic->pc_sockets[i].pcs_flags |= PCS_SOCKET_IO; 1826*3db86aabSstevel 1827*3db86aabSstevel /* disable all windows just in case */ 1828*3db86aabSstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0); 1829*3db86aabSstevel 1830*3db86aabSstevel switch (pcic->pc_type) { 1831*3db86aabSstevel uint32_t cfg32; 1832*3db86aabSstevel uint16_t cfg16; 1833*3db86aabSstevel uint8_t cfg; 1834*3db86aabSstevel 1835*3db86aabSstevel /* enable extended registers for Vadem */ 1836*3db86aabSstevel case PCIC_VADEM_VG469: 1837*3db86aabSstevel case PCIC_VADEM: 1838*3db86aabSstevel 1839*3db86aabSstevel /* enable card status change interrupt for socket */ 1840*3db86aabSstevel break; 1841*3db86aabSstevel 1842*3db86aabSstevel case PCIC_I82365SL: 1843*3db86aabSstevel break; 1844*3db86aabSstevel 1845*3db86aabSstevel case PCIC_CL_PD6710: 1846*3db86aabSstevel pcic_putb(pcic, 0, PCIC_MISC_CTL_2, PCIC_LED_ENABLE); 1847*3db86aabSstevel break; 1848*3db86aabSstevel 1849*3db86aabSstevel /* 1850*3db86aabSstevel * On the CL_6730, we need to set up the interrupt 1851*3db86aabSstevel * signalling mode (PCI mode) and set the SMI and 1852*3db86aabSstevel * IRQ interrupt lines to PCI/level-mode. 1853*3db86aabSstevel */ 1854*3db86aabSstevel case PCIC_CL_PD6730: 1855*3db86aabSstevel switch (pcic->pc_intr_mode) { 1856*3db86aabSstevel case PCIC_INTR_MODE_PCI_1: 1857*3db86aabSstevel clext_reg_write(pcic, i, PCIC_CLEXT_MISC_CTL_3, 1858*3db86aabSstevel ((clext_reg_read(pcic, i, 1859*3db86aabSstevel PCIC_CLEXT_MISC_CTL_3) & 1860*3db86aabSstevel ~PCIC_CLEXT_INT_PCI) | 1861*3db86aabSstevel PCIC_CLEXT_INT_PCI)); 1862*3db86aabSstevel clext_reg_write(pcic, i, PCIC_CLEXT_EXT_CTL_1, 1863*3db86aabSstevel (PCIC_CLEXT_IRQ_LVL_MODE | 1864*3db86aabSstevel PCIC_CLEXT_SMI_LVL_MODE)); 1865*3db86aabSstevel cfg = PCIC_CL_LP_DYN_MODE; 1866*3db86aabSstevel pcic_putb(pcic, i, PCIC_MISC_CTL_2, cfg); 1867*3db86aabSstevel break; 1868*3db86aabSstevel case PCIC_INTR_MODE_ISA: 1869*3db86aabSstevel break; 1870*3db86aabSstevel } 1871*3db86aabSstevel break; 1872*3db86aabSstevel /* 1873*3db86aabSstevel * On the CL_6729, we set the SMI and IRQ interrupt 1874*3db86aabSstevel * lines to PCI/level-mode. as well as program the 1875*3db86aabSstevel * correct clock speed divider bit. 1876*3db86aabSstevel */ 1877*3db86aabSstevel case PCIC_CL_PD6729: 1878*3db86aabSstevel switch (pcic->pc_intr_mode) { 1879*3db86aabSstevel case PCIC_INTR_MODE_PCI_1: 1880*3db86aabSstevel clext_reg_write(pcic, i, PCIC_CLEXT_EXT_CTL_1, 1881*3db86aabSstevel (PCIC_CLEXT_IRQ_LVL_MODE | 1882*3db86aabSstevel PCIC_CLEXT_SMI_LVL_MODE)); 1883*3db86aabSstevel 1884*3db86aabSstevel break; 1885*3db86aabSstevel case PCIC_INTR_MODE_ISA: 1886*3db86aabSstevel break; 1887*3db86aabSstevel } 1888*3db86aabSstevel if (pcic->bus_speed > PCIC_PCI_25MHZ && i == 0) { 1889*3db86aabSstevel cfg = 0; 1890*3db86aabSstevel cfg |= PCIC_CL_TIMER_CLK_DIV; 1891*3db86aabSstevel pcic_putb(pcic, i, PCIC_MISC_CTL_2, cfg); 1892*3db86aabSstevel } 1893*3db86aabSstevel break; 1894*3db86aabSstevel case PCIC_INTEL_i82092: 1895*3db86aabSstevel cfg = PCIC_82092_EN_TIMING; 1896*3db86aabSstevel if (pcic->bus_speed < PCIC_SYSCLK_33MHZ) 1897*3db86aabSstevel cfg |= PCIC_82092_PCICLK_25MHZ; 1898*3db86aabSstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr + 1899*3db86aabSstevel PCIC_82092_PCICON, cfg); 1900*3db86aabSstevel break; 1901*3db86aabSstevel case PCIC_TI_PCI1130: 1902*3db86aabSstevel case PCIC_TI_PCI1131: 1903*3db86aabSstevel case PCIC_TI_PCI1250: 1904*3db86aabSstevel case PCIC_TI_PCI1031: 1905*3db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 1906*3db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG); 1907*3db86aabSstevel cfg &= ~PCIC_DEVCTL_INTR_MASK; 1908*3db86aabSstevel switch (pcic->pc_intr_mode) { 1909*3db86aabSstevel case PCIC_INTR_MODE_ISA: 1910*3db86aabSstevel cfg |= PCIC_DEVCTL_INTR_ISA; 1911*3db86aabSstevel break; 1912*3db86aabSstevel } 1913*3db86aabSstevel #ifdef PCIC_DEBUG 1914*3db86aabSstevel if (pcic_debug) { 1915*3db86aabSstevel cmn_err(CE_CONT, "pcic_setup_adapter: " 1916*3db86aabSstevel "write reg 0x%x=%x \n", 1917*3db86aabSstevel PCIC_DEVCTL_REG, cfg); 1918*3db86aabSstevel } 1919*3db86aabSstevel #endif 1920*3db86aabSstevel ddi_put8(pcic->cfg_handle, 1921*3db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG, 1922*3db86aabSstevel cfg); 1923*3db86aabSstevel 1924*3db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 1925*3db86aabSstevel pcic->cfgaddr + PCIC_CRDCTL_REG); 1926*3db86aabSstevel cfg &= ~(PCIC_CRDCTL_PCIINTR|PCIC_CRDCTL_PCICSC| 1927*3db86aabSstevel PCIC_CRDCTL_PCIFUNC); 1928*3db86aabSstevel switch (pcic->pc_intr_mode) { 1929*3db86aabSstevel case PCIC_INTR_MODE_PCI_1: 1930*3db86aabSstevel cfg |= PCIC_CRDCTL_PCIINTR | 1931*3db86aabSstevel PCIC_CRDCTL_PCICSC | 1932*3db86aabSstevel PCIC_CRDCTL_PCIFUNC; 1933*3db86aabSstevel pcic->pc_flags |= PCF_USE_SMI; 1934*3db86aabSstevel break; 1935*3db86aabSstevel } 1936*3db86aabSstevel #ifdef PCIC_DEBUG 1937*3db86aabSstevel if (pcic_debug) { 1938*3db86aabSstevel cmn_err(CE_CONT, "pcic_setup_adapter: " 1939*3db86aabSstevel " write reg 0x%x=%x \n", 1940*3db86aabSstevel PCIC_CRDCTL_REG, cfg); 1941*3db86aabSstevel } 1942*3db86aabSstevel #endif 1943*3db86aabSstevel ddi_put8(pcic->cfg_handle, 1944*3db86aabSstevel pcic->cfgaddr + PCIC_CRDCTL_REG, 1945*3db86aabSstevel cfg); 1946*3db86aabSstevel break; 1947*3db86aabSstevel case PCIC_TI_PCI1221: 1948*3db86aabSstevel case PCIC_TI_PCI1225: 1949*3db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 1950*3db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG); 1951*3db86aabSstevel cfg |= (PCIC_DEVCTL_INTR_DFLT | PCIC_DEVCTL_3VCAPABLE); 1952*3db86aabSstevel #ifdef PCIC_DEBUG 1953*3db86aabSstevel if (pcic_debug) { 1954*3db86aabSstevel cmn_err(CE_CONT, "pcic_setup_adapter: " 1955*3db86aabSstevel " write reg 0x%x=%x \n", 1956*3db86aabSstevel PCIC_DEVCTL_REG, cfg); 1957*3db86aabSstevel } 1958*3db86aabSstevel #endif 1959*3db86aabSstevel ddi_put8(pcic->cfg_handle, 1960*3db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG, cfg); 1961*3db86aabSstevel 1962*3db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 1963*3db86aabSstevel pcic->cfgaddr + PCIC_DIAG_REG); 1964*3db86aabSstevel if (pcic->pc_type == PCIC_TI_PCI1225) { 1965*3db86aabSstevel cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC); 1966*3db86aabSstevel } else { 1967*3db86aabSstevel cfg |= PCIC_DIAG_ASYNC; 1968*3db86aabSstevel } 1969*3db86aabSstevel pcic->pc_flags |= PCF_USE_SMI; 1970*3db86aabSstevel #ifdef PCIC_DEBUG 1971*3db86aabSstevel if (pcic_debug) { 1972*3db86aabSstevel cmn_err(CE_CONT, "pcic_setup_adapter: " 1973*3db86aabSstevel " write reg 0x%x=%x \n", 1974*3db86aabSstevel PCIC_DIAG_REG, cfg); 1975*3db86aabSstevel } 1976*3db86aabSstevel #endif 1977*3db86aabSstevel ddi_put8(pcic->cfg_handle, 1978*3db86aabSstevel pcic->cfgaddr + PCIC_DIAG_REG, cfg); 1979*3db86aabSstevel break; 1980*3db86aabSstevel case PCIC_TI_PCI1520: 1981*3db86aabSstevel case PCIC_TI_VENDOR: 1982*3db86aabSstevel if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) { 1983*3db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 1984*3db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG); 1985*3db86aabSstevel cfg |= PCIC_FUN_INT_MOD_ISA; 1986*3db86aabSstevel ddi_put8(pcic->cfg_handle, 1987*3db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG, 1988*3db86aabSstevel cfg); 1989*3db86aabSstevel } 1990*3db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 1991*3db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG); 1992*3db86aabSstevel cfg &= ~PCIC_DEVCTL_INTR_MASK; 1993*3db86aabSstevel if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) 1994*3db86aabSstevel cfg |= PCIC_DEVCTL_INTR_ISA; 1995*3db86aabSstevel ddi_put8(pcic->cfg_handle, 1996*3db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG, 1997*3db86aabSstevel cfg); 1998*3db86aabSstevel 1999*3db86aabSstevel /* tie INTA and INTB together */ 2000*3db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 2001*3db86aabSstevel (pcic->cfgaddr + PCIC_SYSCTL_REG + 3)); 2002*3db86aabSstevel cfg |= PCIC_SYSCTL_INTRTIE; 2003*3db86aabSstevel ddi_put8(pcic->cfg_handle, (pcic->cfgaddr + 2004*3db86aabSstevel PCIC_SYSCTL_REG + 3), cfg); 2005*3db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 2006*3db86aabSstevel pcic->cfgaddr + PCIC_DIAG_REG); 2007*3db86aabSstevel cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC); 2008*3db86aabSstevel ddi_put8(pcic->cfg_handle, 2009*3db86aabSstevel pcic->cfgaddr + PCIC_DIAG_REG, cfg); 2010*3db86aabSstevel break; 2011*3db86aabSstevel case PCIC_TI_PCI1410: 2012*3db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 2013*3db86aabSstevel pcic->cfgaddr + PCIC_DIAG_REG); 2014*3db86aabSstevel cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC); 2015*3db86aabSstevel ddi_put8(pcic->cfg_handle, 2016*3db86aabSstevel pcic->cfgaddr + PCIC_DIAG_REG, cfg); 2017*3db86aabSstevel break; 2018*3db86aabSstevel case PCIC_TOSHIBA_TOPIC100: 2019*3db86aabSstevel case PCIC_TOSHIBA_TOPIC95: 2020*3db86aabSstevel case PCIC_TOSHIBA_VENDOR: 2021*3db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, pcic->cfgaddr + 2022*3db86aabSstevel PCIC_TOSHIBA_SLOT_CTL_REG); 2023*3db86aabSstevel cfg |= (PCIC_TOSHIBA_SCR_SLOTON | 2024*3db86aabSstevel PCIC_TOSHIBA_SCR_SLOTEN); 2025*3db86aabSstevel cfg &= (~PCIC_TOSHIBA_SCR_PRT_MASK); 2026*3db86aabSstevel cfg |= PCIC_TOSHIBA_SCR_PRT_3E2; 2027*3db86aabSstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr + 2028*3db86aabSstevel PCIC_TOSHIBA_SLOT_CTL_REG, cfg); 2029*3db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, pcic->cfgaddr + 2030*3db86aabSstevel PCIC_TOSHIBA_INTR_CTL_REG); 2031*3db86aabSstevel switch (pcic->pc_intr_mode) { 2032*3db86aabSstevel case PCIC_INTR_MODE_ISA: 2033*3db86aabSstevel cfg &= ~PCIC_TOSHIBA_ICR_SRC; 2034*3db86aabSstevel ddi_put8(pcic->cfg_handle, 2035*3db86aabSstevel pcic->cfgaddr + 2036*3db86aabSstevel PCIC_TOSHIBA_INTR_CTL_REG, cfg); 2037*3db86aabSstevel 2038*3db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 2039*3db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG); 2040*3db86aabSstevel cfg |= PCIC_FUN_INT_MOD_ISA; 2041*3db86aabSstevel ddi_put8(pcic->cfg_handle, 2042*3db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG, 2043*3db86aabSstevel cfg); 2044*3db86aabSstevel break; 2045*3db86aabSstevel case PCIC_INTR_MODE_PCI_1: 2046*3db86aabSstevel cfg |= PCIC_TOSHIBA_ICR_SRC; 2047*3db86aabSstevel cfg &= (~PCIC_TOSHIBA_ICR_PIN_MASK); 2048*3db86aabSstevel cfg |= PCIC_TOSHIBA_ICR_PIN_INTA; 2049*3db86aabSstevel ddi_put8(pcic->cfg_handle, 2050*3db86aabSstevel pcic->cfgaddr + 2051*3db86aabSstevel PCIC_TOSHIBA_INTR_CTL_REG, cfg); 2052*3db86aabSstevel break; 2053*3db86aabSstevel } 2054*3db86aabSstevel break; 2055*3db86aabSstevel case PCIC_O2MICRO_VENDOR: 2056*3db86aabSstevel cfg32 = ddi_get32(pcic->cfg_handle, 2057*3db86aabSstevel (uint32_t *)(pcic->cfgaddr + 2058*3db86aabSstevel PCIC_O2MICRO_MISC_CTL)); 2059*3db86aabSstevel switch (pcic->pc_intr_mode) { 2060*3db86aabSstevel case PCIC_INTR_MODE_ISA: 2061*3db86aabSstevel cfg32 |= (PCIC_O2MICRO_ISA_LEGACY | 2062*3db86aabSstevel PCIC_O2MICRO_INT_MOD_PCI); 2063*3db86aabSstevel ddi_put32(pcic->cfg_handle, 2064*3db86aabSstevel (uint32_t *)(pcic->cfgaddr + 2065*3db86aabSstevel PCIC_O2MICRO_MISC_CTL), 2066*3db86aabSstevel cfg32); 2067*3db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 2068*3db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG); 2069*3db86aabSstevel cfg |= PCIC_FUN_INT_MOD_ISA; 2070*3db86aabSstevel ddi_put8(pcic->cfg_handle, 2071*3db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG, 2072*3db86aabSstevel cfg); 2073*3db86aabSstevel break; 2074*3db86aabSstevel case PCIC_INTR_MODE_PCI_1: 2075*3db86aabSstevel cfg32 &= ~PCIC_O2MICRO_ISA_LEGACY; 2076*3db86aabSstevel cfg32 |= PCIC_O2MICRO_INT_MOD_PCI; 2077*3db86aabSstevel ddi_put32(pcic->cfg_handle, 2078*3db86aabSstevel (uint32_t *)(pcic->cfgaddr + 2079*3db86aabSstevel PCIC_O2MICRO_MISC_CTL), 2080*3db86aabSstevel cfg32); 2081*3db86aabSstevel break; 2082*3db86aabSstevel } 2083*3db86aabSstevel break; 2084*3db86aabSstevel case PCIC_RICOH_VENDOR: 2085*3db86aabSstevel if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) { 2086*3db86aabSstevel cfg16 = ddi_get16(pcic->cfg_handle, 2087*3db86aabSstevel (uint16_t *)(pcic->cfgaddr + 2088*3db86aabSstevel PCIC_RICOH_MISC_CTL_2)); 2089*3db86aabSstevel cfg16 |= (PCIC_RICOH_CSC_INT_MOD | 2090*3db86aabSstevel PCIC_RICOH_FUN_INT_MOD); 2091*3db86aabSstevel ddi_put16(pcic->cfg_handle, 2092*3db86aabSstevel (uint16_t *)(pcic->cfgaddr + 2093*3db86aabSstevel PCIC_RICOH_MISC_CTL_2), 2094*3db86aabSstevel cfg16); 2095*3db86aabSstevel 2096*3db86aabSstevel cfg16 = ddi_get16(pcic->cfg_handle, 2097*3db86aabSstevel (uint16_t *)(pcic->cfgaddr + 2098*3db86aabSstevel PCIC_RICOH_MISC_CTL)); 2099*3db86aabSstevel cfg16 |= PCIC_RICOH_SIRQ_EN; 2100*3db86aabSstevel ddi_put16(pcic->cfg_handle, 2101*3db86aabSstevel (uint16_t *)(pcic->cfgaddr + 2102*3db86aabSstevel PCIC_RICOH_MISC_CTL), 2103*3db86aabSstevel cfg16); 2104*3db86aabSstevel 2105*3db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 2106*3db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG); 2107*3db86aabSstevel cfg |= PCIC_FUN_INT_MOD_ISA; 2108*3db86aabSstevel ddi_put8(pcic->cfg_handle, 2109*3db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG, 2110*3db86aabSstevel cfg); 2111*3db86aabSstevel } 2112*3db86aabSstevel break; 2113*3db86aabSstevel default: 2114*3db86aabSstevel break; 2115*3db86aabSstevel } /* switch */ 2116*3db86aabSstevel 2117*3db86aabSstevel /* setup general card status change interrupt */ 2118*3db86aabSstevel switch (pcic->pc_type) { 2119*3db86aabSstevel case PCIC_TI_PCI1225: 2120*3db86aabSstevel case PCIC_TI_PCI1221: 2121*3db86aabSstevel case PCIC_TI_PCI1031: 2122*3db86aabSstevel case PCIC_TI_PCI1520: 2123*3db86aabSstevel case PCIC_TI_PCI1410: 2124*3db86aabSstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 2125*3db86aabSstevel PCIC_CHANGE_DEFAULT); 2126*3db86aabSstevel break; 2127*3db86aabSstevel default: 2128*3db86aabSstevel if (pcic->pc_intr_mode == 2129*3db86aabSstevel PCIC_INTR_MODE_PCI_1) { 2130*3db86aabSstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 2131*3db86aabSstevel PCIC_CHANGE_DEFAULT); 2132*3db86aabSstevel break; 2133*3db86aabSstevel } else { 2134*3db86aabSstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 2135*3db86aabSstevel PCIC_CHANGE_DEFAULT | 2136*3db86aabSstevel (pcic->pc_sockets[i].pcs_smi << 4)); 2137*3db86aabSstevel break; 2138*3db86aabSstevel } 2139*3db86aabSstevel } 2140*3db86aabSstevel 2141*3db86aabSstevel pcic->pc_flags |= PCF_INTRENAB; 2142*3db86aabSstevel 2143*3db86aabSstevel /* take card out of RESET */ 2144*3db86aabSstevel pcic_putb(pcic, i, PCIC_INTERRUPT, PCIC_RESET); 2145*3db86aabSstevel /* turn power off and let CS do this */ 2146*3db86aabSstevel pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0); 2147*3db86aabSstevel 2148*3db86aabSstevel /* final chip specific initialization */ 2149*3db86aabSstevel switch (pcic->pc_type) { 2150*3db86aabSstevel case PCIC_VADEM: 2151*3db86aabSstevel pcic_putb(pcic, i, PCIC_VG_CONTROL, 2152*3db86aabSstevel PCIC_VC_DELAYENABLE); 2153*3db86aabSstevel pcic->pc_flags |= PCF_DEBOUNCE; 2154*3db86aabSstevel /* FALLTHROUGH */ 2155*3db86aabSstevel case PCIC_I82365SL: 2156*3db86aabSstevel pcic_putb(pcic, i, PCIC_GLOBAL_CONTROL, 2157*3db86aabSstevel PCIC_GC_CSC_WRITE); 2158*3db86aabSstevel /* clear any pending interrupts */ 2159*3db86aabSstevel value = pcic_getb(pcic, i, PCIC_CARD_STATUS_CHANGE); 2160*3db86aabSstevel pcic_putb(pcic, i, PCIC_CARD_STATUS_CHANGE, value); 2161*3db86aabSstevel break; 2162*3db86aabSstevel /* The 82092 uses PCI config space to enable interrupts */ 2163*3db86aabSstevel case PCIC_INTEL_i82092: 2164*3db86aabSstevel pcic_82092_smiirq_ctl(pcic, i, PCIC_82092_CTL_SMI, 2165*3db86aabSstevel PCIC_82092_INT_ENABLE); 2166*3db86aabSstevel break; 2167*3db86aabSstevel case PCIC_CL_PD6729: 2168*3db86aabSstevel if (pcic->bus_speed >= PCIC_PCI_DEF_SYSCLK && i == 0) { 2169*3db86aabSstevel value = pcic_getb(pcic, i, PCIC_MISC_CTL_2); 2170*3db86aabSstevel pcic_putb(pcic, i, PCIC_MISC_CTL_2, 2171*3db86aabSstevel value | PCIC_CL_TIMER_CLK_DIV); 2172*3db86aabSstevel } 2173*3db86aabSstevel break; 2174*3db86aabSstevel } /* switch */ 2175*3db86aabSstevel 2176*3db86aabSstevel #if defined(PCIC_DEBUG) 2177*3db86aabSstevel if (pcic_debug) 2178*3db86aabSstevel cmn_err(CE_CONT, 2179*3db86aabSstevel "socket %d value=%x, flags = %x (%s)\n", 2180*3db86aabSstevel i, value, pcic->pc_sockets[i].pcs_flags, 2181*3db86aabSstevel (pcic->pc_sockets[i].pcs_flags & 2182*3db86aabSstevel PCS_CARD_PRESENT) ? 2183*3db86aabSstevel "card present" : "no card"); 2184*3db86aabSstevel #endif 2185*3db86aabSstevel } 2186*3db86aabSstevel } 2187*3db86aabSstevel 2188*3db86aabSstevel /* 2189*3db86aabSstevel * pcic_intr(caddr_t, caddr_t) 2190*3db86aabSstevel * interrupt handler for the PCIC style adapter 2191*3db86aabSstevel * handles all basic interrupts and also checks 2192*3db86aabSstevel * for status changes and notifies the nexus if 2193*3db86aabSstevel * necessary 2194*3db86aabSstevel * 2195*3db86aabSstevel * On PCI bus adapters, also handles all card 2196*3db86aabSstevel * IO interrupts. 2197*3db86aabSstevel */ 2198*3db86aabSstevel /*ARGSUSED*/ 2199*3db86aabSstevel uint32_t 2200*3db86aabSstevel pcic_intr(caddr_t arg1, caddr_t arg2) 2201*3db86aabSstevel { 2202*3db86aabSstevel pcicdev_t *pcic = (pcicdev_t *)arg1; 2203*3db86aabSstevel int value = 0, i, ret = DDI_INTR_UNCLAIMED; 2204*3db86aabSstevel uint8_t status; 2205*3db86aabSstevel uint_t io_ints; 2206*3db86aabSstevel 2207*3db86aabSstevel #if defined(PCIC_DEBUG) 2208*3db86aabSstevel pcic_err(pcic->dip, 0xf, 2209*3db86aabSstevel "pcic_intr: enter pc_flags=0x%x PCF_ATTACHED=0x%x" 2210*3db86aabSstevel " pc_numsockets=%d \n", 2211*3db86aabSstevel pcic->pc_flags, PCF_ATTACHED, pcic->pc_numsockets); 2212*3db86aabSstevel #endif 2213*3db86aabSstevel 2214*3db86aabSstevel if (!(pcic->pc_flags & PCF_ATTACHED)) 2215*3db86aabSstevel return (DDI_INTR_UNCLAIMED); 2216*3db86aabSstevel 2217*3db86aabSstevel mutex_enter(&pcic->intr_lock); 2218*3db86aabSstevel 2219*3db86aabSstevel if (pcic->pc_flags & PCF_SUSPENDED) { 2220*3db86aabSstevel mutex_exit(&pcic->intr_lock); 2221*3db86aabSstevel return (ret); 2222*3db86aabSstevel } 2223*3db86aabSstevel 2224*3db86aabSstevel /* 2225*3db86aabSstevel * need to change to only ACK and touch the slot that 2226*3db86aabSstevel * actually caused the interrupt. Currently everything 2227*3db86aabSstevel * is acked 2228*3db86aabSstevel * 2229*3db86aabSstevel * we need to look at all known sockets to determine 2230*3db86aabSstevel * what might have happened, so step through the list 2231*3db86aabSstevel * of them 2232*3db86aabSstevel */ 2233*3db86aabSstevel #ifdef VOYAGER 2234*3db86aabSstevel ret = syshw_intr_hi(pcic); 2235*3db86aabSstevel #endif 2236*3db86aabSstevel 2237*3db86aabSstevel /* 2238*3db86aabSstevel * Set the bitmask for IO interrupts to initially include all sockets 2239*3db86aabSstevel */ 2240*3db86aabSstevel io_ints = (1 << pcic->pc_numsockets) - 1; 2241*3db86aabSstevel 2242*3db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) { 2243*3db86aabSstevel int card_type; 2244*3db86aabSstevel pcic_socket_t *sockp; 2245*3db86aabSstevel int value_cb = 0; 2246*3db86aabSstevel 2247*3db86aabSstevel sockp = &pcic->pc_sockets[i]; 2248*3db86aabSstevel /* get the socket's I/O addresses */ 2249*3db86aabSstevel 2250*3db86aabSstevel if (sockp->pcs_flags & PCS_WAITING) { 2251*3db86aabSstevel io_ints &= ~(1 << i); 2252*3db86aabSstevel continue; 2253*3db86aabSstevel } 2254*3db86aabSstevel 2255*3db86aabSstevel if (sockp->pcs_flags & PCS_CARD_IO) 2256*3db86aabSstevel card_type = IF_IO; 2257*3db86aabSstevel else 2258*3db86aabSstevel card_type = IF_MEMORY; 2259*3db86aabSstevel 2260*3db86aabSstevel if (pcic->pc_io_type == PCIC_IO_TYPE_YENTA) 2261*3db86aabSstevel value_cb = pcic_getcb(pcic, CB_STATUS_EVENT); 2262*3db86aabSstevel 2263*3db86aabSstevel value = pcic_change(pcic, i); 2264*3db86aabSstevel 2265*3db86aabSstevel if ((value != 0) || (value_cb != 0)) { 2266*3db86aabSstevel int x = pcic->pc_cb_arg; 2267*3db86aabSstevel 2268*3db86aabSstevel ret = DDI_INTR_CLAIMED; 2269*3db86aabSstevel 2270*3db86aabSstevel #if defined(PCIC_DEBUG) 2271*3db86aabSstevel pcic_err(pcic->dip, 0x9, 2272*3db86aabSstevel "card_type = %d, value_cb = 0x%x\n", 2273*3db86aabSstevel card_type, 2274*3db86aabSstevel value_cb ? value_cb : 2275*3db86aabSstevel pcic_getcb(pcic, CB_STATUS_EVENT)); 2276*3db86aabSstevel if (pcic_debug) 2277*3db86aabSstevel cmn_err(CE_CONT, 2278*3db86aabSstevel "\tchange on socket %d (%x)\n", i, 2279*3db86aabSstevel value); 2280*3db86aabSstevel #endif 2281*3db86aabSstevel /* find out what happened */ 2282*3db86aabSstevel status = pcic_getb(pcic, i, PCIC_INTERFACE_STATUS); 2283*3db86aabSstevel 2284*3db86aabSstevel /* acknowledge the interrupt */ 2285*3db86aabSstevel if (value_cb) 2286*3db86aabSstevel pcic_putcb(pcic, CB_STATUS_EVENT, value_cb); 2287*3db86aabSstevel 2288*3db86aabSstevel if (value) 2289*3db86aabSstevel pcic_putb(pcic, i, PCIC_CARD_STATUS_CHANGE, 2290*3db86aabSstevel value); 2291*3db86aabSstevel 2292*3db86aabSstevel if (pcic->pc_callback == NULL) { 2293*3db86aabSstevel /* if not callback handler, nothing to do */ 2294*3db86aabSstevel continue; 2295*3db86aabSstevel } 2296*3db86aabSstevel 2297*3db86aabSstevel /* Card Detect */ 2298*3db86aabSstevel if (value & PCIC_CD_DETECT || 2299*3db86aabSstevel value_cb & CB_PS_CCDMASK) { 2300*3db86aabSstevel uint8_t irq; 2301*3db86aabSstevel #if defined(PCIC_DEBUG) 2302*3db86aabSstevel if (pcic_debug) 2303*3db86aabSstevel cmn_err(CE_CONT, 2304*3db86aabSstevel "\tcd_detect: status=%x," 2305*3db86aabSstevel " flags=%x\n", 2306*3db86aabSstevel status, sockp->pcs_flags); 2307*3db86aabSstevel #else 2308*3db86aabSstevel #ifdef lint 2309*3db86aabSstevel if (status == 0) 2310*3db86aabSstevel status++; 2311*3db86aabSstevel #endif 2312*3db86aabSstevel #endif 2313*3db86aabSstevel /* 2314*3db86aabSstevel * Turn off all interrupts for this socket here. 2315*3db86aabSstevel */ 2316*3db86aabSstevel irq = pcic_getb(pcic, sockp->pcs_socket, 2317*3db86aabSstevel PCIC_MANAGEMENT_INT); 2318*3db86aabSstevel irq &= ~PCIC_CHANGE_MASK; 2319*3db86aabSstevel pcic_putb(pcic, sockp->pcs_socket, 2320*3db86aabSstevel PCIC_MANAGEMENT_INT, irq); 2321*3db86aabSstevel 2322*3db86aabSstevel pcic_putcb(pcic, CB_STATUS_MASK, 0x0); 2323*3db86aabSstevel 2324*3db86aabSstevel if (!sockp->pcs_cd_softint_flg) { 2325*3db86aabSstevel sockp->pcs_cd_softint_flg = 1; 2326*3db86aabSstevel (void) ddi_intr_trigger_softint( 2327*3db86aabSstevel sockp->pcs_cd_softint_hdl, NULL); 2328*3db86aabSstevel } 2329*3db86aabSstevel 2330*3db86aabSstevel io_ints &= ~(1 << i); 2331*3db86aabSstevel } /* PCIC_CD_DETECT */ 2332*3db86aabSstevel 2333*3db86aabSstevel /* Ready/Change Detect */ 2334*3db86aabSstevel sockp->pcs_state ^= SBM_RDYBSY; 2335*3db86aabSstevel if (card_type == IF_MEMORY && value & PCIC_RD_DETECT) { 2336*3db86aabSstevel sockp->pcs_flags |= PCS_READY; 2337*3db86aabSstevel PC_CALLBACK(pcic->dip, x, PCE_CARD_READY, i); 2338*3db86aabSstevel } 2339*3db86aabSstevel 2340*3db86aabSstevel /* Battery Warn Detect */ 2341*3db86aabSstevel if (card_type == IF_MEMORY && 2342*3db86aabSstevel value & PCIC_BW_DETECT && 2343*3db86aabSstevel !(sockp->pcs_state & SBM_BVD2)) { 2344*3db86aabSstevel sockp->pcs_state |= SBM_BVD2; 2345*3db86aabSstevel PC_CALLBACK(pcic->dip, x, 2346*3db86aabSstevel PCE_CARD_BATTERY_WARN, i); 2347*3db86aabSstevel } 2348*3db86aabSstevel 2349*3db86aabSstevel /* Battery Dead Detect */ 2350*3db86aabSstevel if (value & PCIC_BD_DETECT) { 2351*3db86aabSstevel /* 2352*3db86aabSstevel * need to work out event if RI not enabled 2353*3db86aabSstevel * and card_type == IF_IO 2354*3db86aabSstevel */ 2355*3db86aabSstevel if (card_type == IF_MEMORY && 2356*3db86aabSstevel !(sockp->pcs_state & SBM_BVD1)) { 2357*3db86aabSstevel sockp->pcs_state |= SBM_BVD1; 2358*3db86aabSstevel PC_CALLBACK(pcic->dip, x, 2359*3db86aabSstevel PCE_CARD_BATTERY_DEAD, 2360*3db86aabSstevel i); 2361*3db86aabSstevel } else { 2362*3db86aabSstevel /* 2363*3db86aabSstevel * information in pin replacement 2364*3db86aabSstevel * register if one is available 2365*3db86aabSstevel */ 2366*3db86aabSstevel PC_CALLBACK(pcic->dip, x, 2367*3db86aabSstevel PCE_CARD_STATUS_CHANGE, 2368*3db86aabSstevel i); 2369*3db86aabSstevel } /* IF_MEMORY */ 2370*3db86aabSstevel } /* PCIC_BD_DETECT */ 2371*3db86aabSstevel } /* if pcic_change */ 2372*3db86aabSstevel /* 2373*3db86aabSstevel * for any controllers that we can detect whether a socket 2374*3db86aabSstevel * had an interrupt for the PC Card, we should sort that out 2375*3db86aabSstevel * here. 2376*3db86aabSstevel */ 2377*3db86aabSstevel } /* for pc_numsockets */ 2378*3db86aabSstevel 2379*3db86aabSstevel /* 2380*3db86aabSstevel * If we're on a PCI bus, we may need to cycle through each IO 2381*3db86aabSstevel * interrupt handler that is registered since they all 2382*3db86aabSstevel * share the same interrupt line. 2383*3db86aabSstevel */ 2384*3db86aabSstevel 2385*3db86aabSstevel 2386*3db86aabSstevel #if defined(PCIC_DEBUG) 2387*3db86aabSstevel pcic_err(pcic->dip, 0xf, 2388*3db86aabSstevel "pcic_intr: pc_intr_mode=%d pc_type=%x io_ints=0x%x\n", 2389*3db86aabSstevel pcic->pc_intr_mode, pcic->pc_type, io_ints); 2390*3db86aabSstevel #endif 2391*3db86aabSstevel 2392*3db86aabSstevel switch (pcic->pc_intr_mode) { 2393*3db86aabSstevel case PCIC_INTR_MODE_PCI_1: 2394*3db86aabSstevel value = ~0; 2395*3db86aabSstevel /* fix value if adapter can tell us about I/O intrs */ 2396*3db86aabSstevel switch (pcic->pc_type) { 2397*3db86aabSstevel 2398*3db86aabSstevel case PCIC_TI_PCI1031: 2399*3db86aabSstevel case PCIC_TI_PCI1130: 2400*3db86aabSstevel case PCIC_TI_PCI1131: 2401*3db86aabSstevel case PCIC_TI_PCI1250: 2402*3db86aabSstevel case PCIC_TI_PCI1225: 2403*3db86aabSstevel case PCIC_TI_PCI1221: 2404*3db86aabSstevel case PCIC_TI_PCI1520: 2405*3db86aabSstevel case PCIC_TI_PCI1410: 2406*3db86aabSstevel case PCIC_TI_VENDOR: 2407*3db86aabSstevel i = ddi_get8(pcic->cfg_handle, 2408*3db86aabSstevel pcic->cfgaddr + PCIC_CRDCTL_REG); 2409*3db86aabSstevel if (i & PCIC_CRDCTL_IFG) 2410*3db86aabSstevel value = 1; 2411*3db86aabSstevel else 2412*3db86aabSstevel value = 0; 2413*3db86aabSstevel i |= PCIC_CRDCTL_IFG; 2414*3db86aabSstevel /* clear the condition */ 2415*3db86aabSstevel ddi_put8(pcic->cfg_handle, 2416*3db86aabSstevel pcic->cfgaddr + PCIC_CRDCTL_REG, i); 2417*3db86aabSstevel break; 2418*3db86aabSstevel case PCIC_TOSHIBA_TOPIC100: 2419*3db86aabSstevel case PCIC_TOSHIBA_TOPIC95: 2420*3db86aabSstevel case PCIC_TOSHIBA_VENDOR: 2421*3db86aabSstevel case PCIC_RICOH_VENDOR: 2422*3db86aabSstevel case PCIC_O2MICRO_VENDOR: 2423*3db86aabSstevel default: 2424*3db86aabSstevel value = 1; 2425*3db86aabSstevel break; 2426*3db86aabSstevel } 2427*3db86aabSstevel if (value && pcic_do_io_intr(pcic, value) == DDI_INTR_CLAIMED) 2428*3db86aabSstevel ret = DDI_INTR_CLAIMED; 2429*3db86aabSstevel break; 2430*3db86aabSstevel default: 2431*3db86aabSstevel break; 2432*3db86aabSstevel } 2433*3db86aabSstevel 2434*3db86aabSstevel mutex_exit(&pcic->intr_lock); 2435*3db86aabSstevel 2436*3db86aabSstevel #if defined(PCIC_DEBUG) 2437*3db86aabSstevel pcic_err(pcic->dip, 0xf, 2438*3db86aabSstevel "pcic_intr: ret=%d value=%d DDI_INTR_CLAIMED=%d\n", 2439*3db86aabSstevel ret, value, DDI_INTR_CLAIMED); 2440*3db86aabSstevel #endif 2441*3db86aabSstevel 2442*3db86aabSstevel return (ret); 2443*3db86aabSstevel } 2444*3db86aabSstevel 2445*3db86aabSstevel /* 2446*3db86aabSstevel * pcic_change() 2447*3db86aabSstevel * check to see if this socket had a change in state 2448*3db86aabSstevel * by checking the status change register 2449*3db86aabSstevel */ 2450*3db86aabSstevel static int 2451*3db86aabSstevel pcic_change(pcicdev_t *pcic, int socket) 2452*3db86aabSstevel { 2453*3db86aabSstevel return (pcic_getb(pcic, socket, PCIC_CARD_STATUS_CHANGE)); 2454*3db86aabSstevel } 2455*3db86aabSstevel 2456*3db86aabSstevel /* 2457*3db86aabSstevel * pcic_do_io_intr - calls client interrupt handlers 2458*3db86aabSstevel */ 2459*3db86aabSstevel static int 2460*3db86aabSstevel pcic_do_io_intr(pcicdev_t *pcic, uint32_t sockets) 2461*3db86aabSstevel { 2462*3db86aabSstevel inthandler_t *tmp; 2463*3db86aabSstevel int ret = DDI_INTR_UNCLAIMED; 2464*3db86aabSstevel 2465*3db86aabSstevel #if defined(PCIC_DEBUG) 2466*3db86aabSstevel pcic_err(pcic->dip, 0xf, 2467*3db86aabSstevel "pcic_do_io_intr: pcic=%p sockets=%d irq_top=%p\n", 2468*3db86aabSstevel (void *)pcic, (int)sockets, (void *)pcic->irq_top); 2469*3db86aabSstevel #endif 2470*3db86aabSstevel 2471*3db86aabSstevel if (pcic->irq_top != NULL) { 2472*3db86aabSstevel tmp = pcic->irq_current; 2473*3db86aabSstevel 2474*3db86aabSstevel do { 2475*3db86aabSstevel int cur = pcic->irq_current->socket; 2476*3db86aabSstevel pcic_socket_t *sockp = 2477*3db86aabSstevel &pcic->pc_sockets[cur]; 2478*3db86aabSstevel 2479*3db86aabSstevel #if defined(PCIC_DEBUG) 2480*3db86aabSstevel pcic_err(pcic->dip, 0xf, 2481*3db86aabSstevel "\t pcs_flags=0x%x PCS_CARD_PRESENT=0x%x\n", 2482*3db86aabSstevel sockp->pcs_flags, PCS_CARD_PRESENT); 2483*3db86aabSstevel pcic_err(pcic->dip, 0xf, 2484*3db86aabSstevel "\t sockets=%d cur=%d intr=%p arg1=%p " 2485*3db86aabSstevel "arg2=%p\n", 2486*3db86aabSstevel sockets, cur, (void *)pcic->irq_current->intr, 2487*3db86aabSstevel pcic->irq_current->arg1, 2488*3db86aabSstevel pcic->irq_current->arg2); 2489*3db86aabSstevel #endif 2490*3db86aabSstevel if (sockp->pcs_flags & PCS_CARD_PRESENT && 2491*3db86aabSstevel sockets & (1 << cur)) { 2492*3db86aabSstevel 2493*3db86aabSstevel if ((*pcic->irq_current->intr)(pcic->irq_current->arg1, 2494*3db86aabSstevel pcic->irq_current->arg2) == DDI_INTR_CLAIMED) 2495*3db86aabSstevel ret = DDI_INTR_CLAIMED; 2496*3db86aabSstevel 2497*3db86aabSstevel #if defined(PCIC_DEBUG) 2498*3db86aabSstevel pcic_err(pcic->dip, 0xf, 2499*3db86aabSstevel "\t ret=%d DDI_INTR_CLAIMED=%d\n", 2500*3db86aabSstevel ret, DDI_INTR_CLAIMED); 2501*3db86aabSstevel #endif 2502*3db86aabSstevel } 2503*3db86aabSstevel 2504*3db86aabSstevel 2505*3db86aabSstevel if ((pcic->irq_current = pcic->irq_current->next) == NULL) 2506*3db86aabSstevel pcic->irq_current = pcic->irq_top; 2507*3db86aabSstevel 2508*3db86aabSstevel } while (pcic->irq_current != tmp); 2509*3db86aabSstevel 2510*3db86aabSstevel if ((pcic->irq_current = pcic->irq_current->next) == NULL) 2511*3db86aabSstevel pcic->irq_current = pcic->irq_top; 2512*3db86aabSstevel 2513*3db86aabSstevel } else { 2514*3db86aabSstevel ret = DDI_INTR_UNCLAIMED; 2515*3db86aabSstevel } 2516*3db86aabSstevel 2517*3db86aabSstevel #if defined(PCIC_DEBUG) 2518*3db86aabSstevel pcic_err(pcic->dip, 0xf, 2519*3db86aabSstevel "pcic_do_io_intr: exit ret=%d DDI_INTR_CLAIMED=%d\n", 2520*3db86aabSstevel ret, DDI_INTR_CLAIMED); 2521*3db86aabSstevel #endif 2522*3db86aabSstevel 2523*3db86aabSstevel return (ret); 2524*3db86aabSstevel 2525*3db86aabSstevel } 2526*3db86aabSstevel 2527*3db86aabSstevel /* 2528*3db86aabSstevel * pcic_inquire_adapter() 2529*3db86aabSstevel * SocketServices InquireAdapter function 2530*3db86aabSstevel * get characteristics of the physical adapter 2531*3db86aabSstevel */ 2532*3db86aabSstevel /*ARGSUSED*/ 2533*3db86aabSstevel static int 2534*3db86aabSstevel pcic_inquire_adapter(dev_info_t *dip, inquire_adapter_t *config) 2535*3db86aabSstevel { 2536*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 2537*3db86aabSstevel pcicdev_t *pcic = anp->an_private; 2538*3db86aabSstevel 2539*3db86aabSstevel config->NumSockets = pcic->pc_numsockets; 2540*3db86aabSstevel config->NumWindows = pcic->pc_numsockets * PCIC_NUMWINSOCK; 2541*3db86aabSstevel config->NumEDCs = 0; 2542*3db86aabSstevel config->AdpCaps = 0; 2543*3db86aabSstevel config->ActiveHigh = 0; 2544*3db86aabSstevel config->ActiveLow = PCIC_AVAIL_IRQS; 2545*3db86aabSstevel config->NumPower = pcic->pc_numpower; 2546*3db86aabSstevel config->power_entry = pcic->pc_power; /* until we resolve this */ 2547*3db86aabSstevel #if defined(PCIC_DEBUG) 2548*3db86aabSstevel if (pcic_debug) { 2549*3db86aabSstevel cmn_err(CE_CONT, "pcic_inquire_adapter:\n"); 2550*3db86aabSstevel cmn_err(CE_CONT, "\tNumSockets=%d\n", config->NumSockets); 2551*3db86aabSstevel cmn_err(CE_CONT, "\tNumWindows=%d\n", config->NumWindows); 2552*3db86aabSstevel } 2553*3db86aabSstevel #endif 2554*3db86aabSstevel config->ResourceFlags = 0; 2555*3db86aabSstevel switch (pcic->pc_intr_mode) { 2556*3db86aabSstevel case PCIC_INTR_MODE_PCI_1: 2557*3db86aabSstevel config->ResourceFlags |= RES_OWN_IRQ | RES_IRQ_NEXUS | 2558*3db86aabSstevel RES_IRQ_SHAREABLE; 2559*3db86aabSstevel break; 2560*3db86aabSstevel } 2561*3db86aabSstevel return (SUCCESS); 2562*3db86aabSstevel } 2563*3db86aabSstevel 2564*3db86aabSstevel /* 2565*3db86aabSstevel * pcic_callback() 2566*3db86aabSstevel * The PCMCIA nexus calls us via this function 2567*3db86aabSstevel * in order to set the callback function we are 2568*3db86aabSstevel * to call the nexus with 2569*3db86aabSstevel */ 2570*3db86aabSstevel /*ARGSUSED*/ 2571*3db86aabSstevel static int 2572*3db86aabSstevel pcic_callback(dev_info_t *dip, int (*handler)(), int arg) 2573*3db86aabSstevel { 2574*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 2575*3db86aabSstevel pcicdev_t *pcic = anp->an_private; 2576*3db86aabSstevel 2577*3db86aabSstevel if (handler != NULL) { 2578*3db86aabSstevel pcic->pc_callback = handler; 2579*3db86aabSstevel pcic->pc_cb_arg = arg; 2580*3db86aabSstevel pcic->pc_flags |= PCF_CALLBACK; 2581*3db86aabSstevel } else { 2582*3db86aabSstevel pcic->pc_callback = NULL; 2583*3db86aabSstevel pcic->pc_cb_arg = 0; 2584*3db86aabSstevel pcic->pc_flags &= ~PCF_CALLBACK; 2585*3db86aabSstevel } 2586*3db86aabSstevel /* 2587*3db86aabSstevel * we're now registered with the nexus 2588*3db86aabSstevel * it is acceptable to do callbacks at this point. 2589*3db86aabSstevel * don't call back from here though since it could block 2590*3db86aabSstevel */ 2591*3db86aabSstevel return (PC_SUCCESS); 2592*3db86aabSstevel } 2593*3db86aabSstevel 2594*3db86aabSstevel /* 2595*3db86aabSstevel * pcic_calc_speed (pcicdev_t *pcic, uint32_t speed) 2596*3db86aabSstevel * calculate the speed bits from the specified memory speed 2597*3db86aabSstevel * there may be more to do here 2598*3db86aabSstevel */ 2599*3db86aabSstevel 2600*3db86aabSstevel static int 2601*3db86aabSstevel pcic_calc_speed(pcicdev_t *pcic, uint32_t speed) 2602*3db86aabSstevel { 2603*3db86aabSstevel uint32_t wspeed = 1; /* assume 1 wait state when unknown */ 2604*3db86aabSstevel uint32_t bspeed = PCIC_ISA_DEF_SYSCLK; 2605*3db86aabSstevel 2606*3db86aabSstevel switch (pcic->pc_type) { 2607*3db86aabSstevel case PCIC_I82365SL: 2608*3db86aabSstevel case PCIC_VADEM: 2609*3db86aabSstevel case PCIC_VADEM_VG469: 2610*3db86aabSstevel default: 2611*3db86aabSstevel /* Intel chip wants it in waitstates */ 2612*3db86aabSstevel wspeed = mhztons(PCIC_ISA_DEF_SYSCLK) * 3; 2613*3db86aabSstevel if (speed <= wspeed) 2614*3db86aabSstevel wspeed = 0; 2615*3db86aabSstevel else if (speed <= (wspeed += mhztons(bspeed))) 2616*3db86aabSstevel wspeed = 1; 2617*3db86aabSstevel else if (speed <= (wspeed += mhztons(bspeed))) 2618*3db86aabSstevel wspeed = 2; 2619*3db86aabSstevel else 2620*3db86aabSstevel wspeed = 3; 2621*3db86aabSstevel wspeed <<= 6; /* put in right bit positions */ 2622*3db86aabSstevel break; 2623*3db86aabSstevel 2624*3db86aabSstevel case PCIC_INTEL_i82092: 2625*3db86aabSstevel wspeed = SYSMEM_82092_80NS; 2626*3db86aabSstevel if (speed > 80) 2627*3db86aabSstevel wspeed = SYSMEM_82092_100NS; 2628*3db86aabSstevel if (speed > 100) 2629*3db86aabSstevel wspeed = SYSMEM_82092_150NS; 2630*3db86aabSstevel if (speed > 150) 2631*3db86aabSstevel wspeed = SYSMEM_82092_200NS; 2632*3db86aabSstevel if (speed > 200) 2633*3db86aabSstevel wspeed = SYSMEM_82092_250NS; 2634*3db86aabSstevel if (speed > 250) 2635*3db86aabSstevel wspeed = SYSMEM_82092_600NS; 2636*3db86aabSstevel wspeed <<= 5; /* put in right bit positions */ 2637*3db86aabSstevel break; 2638*3db86aabSstevel 2639*3db86aabSstevel } /* switch */ 2640*3db86aabSstevel 2641*3db86aabSstevel return (wspeed); 2642*3db86aabSstevel } 2643*3db86aabSstevel 2644*3db86aabSstevel /* 2645*3db86aabSstevel * These values are taken from the PC Card Standard Electrical Specification. 2646*3db86aabSstevel * Generally the larger value is taken if 2 are possible. 2647*3db86aabSstevel */ 2648*3db86aabSstevel static struct pcic_card_times { 2649*3db86aabSstevel uint16_t cycle; /* Speed as found in the atribute space of he card. */ 2650*3db86aabSstevel uint16_t setup; /* Corresponding address setup time. */ 2651*3db86aabSstevel uint16_t width; /* Corresponding width, OE or WE. */ 2652*3db86aabSstevel uint16_t hold; /* Corresponding data or address hold time. */ 2653*3db86aabSstevel } pcic_card_times[] = { 2654*3db86aabSstevel 2655*3db86aabSstevel /* 2656*3db86aabSstevel * Note: The rounded up times for 250, 200 & 150 have been increased 2657*3db86aabSstevel * due to problems with the 3-Com ethernet cards (pcelx) on UBIIi. 2658*3db86aabSstevel * See BugID 00663. 2659*3db86aabSstevel */ 2660*3db86aabSstevel 2661*3db86aabSstevel /* 2662*3db86aabSstevel * Rounded up times Original times from 2663*3db86aabSstevel * that add up to the the PCMCIA Spec. 2664*3db86aabSstevel * cycle time. 2665*3db86aabSstevel */ 2666*3db86aabSstevel {600, 180, 370, 140}, /* 100, 300, 70 */ 2667*3db86aabSstevel {400, 120, 300, 90}, /* Made this one up */ 2668*3db86aabSstevel {250, 100, 190, 70}, /* 30, 150, 30 */ 2669*3db86aabSstevel {200, 80, 170, 70}, /* 20, 120, 30 */ 2670*3db86aabSstevel {150, 50, 110, 40}, /* 20, 80, 20 */ 2671*3db86aabSstevel {100, 40, 80, 40}, /* 10, 60, 15 */ 2672*3db86aabSstevel {0, 10, 60, 15} /* 10, 60, 15 */ 2673*3db86aabSstevel }; 2674*3db86aabSstevel 2675*3db86aabSstevel /* 2676*3db86aabSstevel * pcic_set_cdtimers 2677*3db86aabSstevel * This is specific to several Cirrus Logic chips 2678*3db86aabSstevel */ 2679*3db86aabSstevel static void 2680*3db86aabSstevel pcic_set_cdtimers(pcicdev_t *pcic, int socket, uint32_t speed, int tset) 2681*3db86aabSstevel { 2682*3db86aabSstevel int cmd, set, rec, offset, clk_pulse; 2683*3db86aabSstevel struct pcic_card_times *ctp; 2684*3db86aabSstevel 2685*3db86aabSstevel if ((tset == IOMEM_CLTIMER_SET_1) || (tset == SYSMEM_CLTIMER_SET_1)) 2686*3db86aabSstevel offset = 3; 2687*3db86aabSstevel else 2688*3db86aabSstevel offset = 0; 2689*3db86aabSstevel 2690*3db86aabSstevel clk_pulse = mhztons(pcic->bus_speed); 2691*3db86aabSstevel for (ctp = pcic_card_times; speed < ctp->cycle; ctp++); 2692*3db86aabSstevel 2693*3db86aabSstevel /* 2694*3db86aabSstevel * Add (clk_pulse/2) and an extra 1 to account for rounding errors. 2695*3db86aabSstevel */ 2696*3db86aabSstevel set = ((ctp->setup + 10 + 1 + (clk_pulse/2))/clk_pulse) - 1; 2697*3db86aabSstevel if (set < 0) 2698*3db86aabSstevel set = 0; 2699*3db86aabSstevel 2700*3db86aabSstevel cmd = ((ctp->width + 10 + 1 + (clk_pulse/2))/clk_pulse) - 1; 2701*3db86aabSstevel if (cmd < 0) 2702*3db86aabSstevel cmd = 0; 2703*3db86aabSstevel 2704*3db86aabSstevel rec = ((ctp->hold + 10 + 1 + (clk_pulse/2))/clk_pulse) - 2; 2705*3db86aabSstevel if (rec < 0) 2706*3db86aabSstevel rec = 0; 2707*3db86aabSstevel 2708*3db86aabSstevel #if defined(PCIC_DEBUG) 2709*3db86aabSstevel pcic_err(pcic->dip, 8, "pcic_set_cdtimers(%d, Timer Set %d)\n" 2710*3db86aabSstevel "ct=%d, cp=%d, cmd=0x%x, setup=0x%x, rec=0x%x\n", 2711*3db86aabSstevel (unsigned)speed, offset == 3 ? 1 : 0, 2712*3db86aabSstevel ctp->cycle, clk_pulse, cmd, set, rec); 2713*3db86aabSstevel #endif 2714*3db86aabSstevel 2715*3db86aabSstevel pcic_putb(pcic, socket, PCIC_TIME_COMMAND_0 + offset, cmd); 2716*3db86aabSstevel pcic_putb(pcic, socket, PCIC_TIME_SETUP_0 + offset, set); 2717*3db86aabSstevel pcic_putb(pcic, socket, PCIC_TIME_RECOVER_0 + offset, rec); 2718*3db86aabSstevel } 2719*3db86aabSstevel 2720*3db86aabSstevel /* 2721*3db86aabSstevel * pcic_set_window 2722*3db86aabSstevel * essentially the same as the Socket Services specification 2723*3db86aabSstevel * We use socket and not adapter since they are identifiable 2724*3db86aabSstevel * but the rest is the same 2725*3db86aabSstevel * 2726*3db86aabSstevel * dip pcic driver's device information 2727*3db86aabSstevel * window parameters for the request 2728*3db86aabSstevel */ 2729*3db86aabSstevel static int 2730*3db86aabSstevel pcic_set_window(dev_info_t *dip, set_window_t *window) 2731*3db86aabSstevel { 2732*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 2733*3db86aabSstevel pcicdev_t *pcic = anp->an_private; 2734*3db86aabSstevel int select; 2735*3db86aabSstevel int socket, pages, which, ret; 2736*3db86aabSstevel pcic_socket_t *sockp = &pcic->pc_sockets[window->socket]; 2737*3db86aabSstevel ra_return_t res; 2738*3db86aabSstevel ndi_ra_request_t req; 2739*3db86aabSstevel uint32_t base = window->base; 2740*3db86aabSstevel 2741*3db86aabSstevel #if defined(PCIC_DEBUG) 2742*3db86aabSstevel if (pcic_debug) { 2743*3db86aabSstevel cmn_err(CE_CONT, "pcic_set_window: entered\n"); 2744*3db86aabSstevel cmn_err(CE_CONT, 2745*3db86aabSstevel "\twindow=%d, socket=%d, WindowSize=%d, speed=%d\n", 2746*3db86aabSstevel window->window, window->socket, window->WindowSize, 2747*3db86aabSstevel window->speed); 2748*3db86aabSstevel cmn_err(CE_CONT, 2749*3db86aabSstevel "\tbase=%x, state=%x\n", (unsigned)window->base, 2750*3db86aabSstevel (unsigned)window->state); 2751*3db86aabSstevel } 2752*3db86aabSstevel #endif 2753*3db86aabSstevel 2754*3db86aabSstevel /* 2755*3db86aabSstevel * do some basic sanity checking on what we support 2756*3db86aabSstevel * we don't do paged mode 2757*3db86aabSstevel */ 2758*3db86aabSstevel if (window->state & WS_PAGED) { 2759*3db86aabSstevel cmn_err(CE_WARN, "pcic_set_window: BAD_ATTRIBUTE\n"); 2760*3db86aabSstevel return (BAD_ATTRIBUTE); 2761*3db86aabSstevel } 2762*3db86aabSstevel 2763*3db86aabSstevel /* 2764*3db86aabSstevel * we don't care about previous mappings. 2765*3db86aabSstevel * Card Services will deal with that so don't 2766*3db86aabSstevel * even check 2767*3db86aabSstevel */ 2768*3db86aabSstevel 2769*3db86aabSstevel socket = window->socket; 2770*3db86aabSstevel 2771*3db86aabSstevel if (!(window->state & WS_IO)) { 2772*3db86aabSstevel int win, tmp; 2773*3db86aabSstevel pcs_memwin_t *memp; 2774*3db86aabSstevel #if defined(PCIC_DEBUG) 2775*3db86aabSstevel if (pcic_debug) 2776*3db86aabSstevel cmn_err(CE_CONT, "\twindow type is memory\n"); 2777*3db86aabSstevel #endif 2778*3db86aabSstevel /* this is memory window mapping */ 2779*3db86aabSstevel win = window->window % PCIC_NUMWINSOCK; 2780*3db86aabSstevel tmp = window->window / PCIC_NUMWINSOCK; 2781*3db86aabSstevel 2782*3db86aabSstevel /* only windows 2-6 can do memory mapping */ 2783*3db86aabSstevel if (tmp != window->socket || win < PCIC_IOWINDOWS) { 2784*3db86aabSstevel cmn_err(CE_CONT, 2785*3db86aabSstevel "\tattempt to map to non-mem window\n"); 2786*3db86aabSstevel return (BAD_WINDOW); 2787*3db86aabSstevel } 2788*3db86aabSstevel 2789*3db86aabSstevel if (window->WindowSize == 0) 2790*3db86aabSstevel window->WindowSize = MEM_MIN; 2791*3db86aabSstevel else if ((window->WindowSize & (PCIC_PAGE-1)) != 0) { 2792*3db86aabSstevel cmn_err(CE_WARN, "pcic_set_window: BAD_SIZE\n"); 2793*3db86aabSstevel return (BAD_SIZE); 2794*3db86aabSstevel } 2795*3db86aabSstevel 2796*3db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 2797*3db86aabSstevel 2798*3db86aabSstevel memp = &sockp->pcs_windows[win].mem; 2799*3db86aabSstevel memp->pcw_speed = window->speed; 2800*3db86aabSstevel 2801*3db86aabSstevel win -= PCIC_IOWINDOWS; /* put in right range */ 2802*3db86aabSstevel 2803*3db86aabSstevel if (window->WindowSize != memp->pcw_len) 2804*3db86aabSstevel which = memp->pcw_len; 2805*3db86aabSstevel else 2806*3db86aabSstevel which = 0; 2807*3db86aabSstevel 2808*3db86aabSstevel if (window->state & WS_ENABLED) { 2809*3db86aabSstevel uint32_t wspeed; 2810*3db86aabSstevel #if defined(PCIC_DEBUG) 2811*3db86aabSstevel if (pcic_debug) { 2812*3db86aabSstevel cmn_err(CE_CONT, 2813*3db86aabSstevel "\tbase=%x, win=%d\n", (unsigned)base, 2814*3db86aabSstevel win); 2815*3db86aabSstevel if (which) 2816*3db86aabSstevel cmn_err(CE_CONT, 2817*3db86aabSstevel "\tneed to remap window\n"); 2818*3db86aabSstevel } 2819*3db86aabSstevel #endif 2820*3db86aabSstevel 2821*3db86aabSstevel if (which && (memp->pcw_status & PCW_MAPPED)) { 2822*3db86aabSstevel ddi_regs_map_free(&memp->pcw_handle); 2823*3db86aabSstevel res.ra_addr_lo = memp->pcw_base; 2824*3db86aabSstevel res.ra_len = memp->pcw_len; 2825*3db86aabSstevel (void) pcmcia_free_mem(dip, &res); 2826*3db86aabSstevel memp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED); 2827*3db86aabSstevel memp->pcw_hostmem = NULL; 2828*3db86aabSstevel memp->pcw_base = NULL; 2829*3db86aabSstevel memp->pcw_len = 0; 2830*3db86aabSstevel } 2831*3db86aabSstevel 2832*3db86aabSstevel which = window->WindowSize >> PAGE_SHIFT; 2833*3db86aabSstevel 2834*3db86aabSstevel if (!(memp->pcw_status & PCW_MAPPED)) { 2835*3db86aabSstevel ret = 0; 2836*3db86aabSstevel 2837*3db86aabSstevel memp->pcw_base = base; 2838*3db86aabSstevel bzero(&req, sizeof (req)); 2839*3db86aabSstevel req.ra_len = which << PAGE_SHIFT; 2840*3db86aabSstevel req.ra_addr = (uint64_t)memp->pcw_base; 2841*3db86aabSstevel req.ra_boundbase = pcic->pc_base; 2842*3db86aabSstevel req.ra_boundlen = pcic->pc_bound; 2843*3db86aabSstevel req.ra_flags = (memp->pcw_base ? 2844*3db86aabSstevel NDI_RA_ALLOC_SPECIFIED : 0) | 2845*3db86aabSstevel NDI_RA_ALLOC_BOUNDED; 2846*3db86aabSstevel req.ra_align_mask = 2847*3db86aabSstevel (PAGESIZE - 1) | (PCIC_PAGE - 1); 2848*3db86aabSstevel #if defined(PCIC_DEBUG) 2849*3db86aabSstevel pcic_err(dip, 8, 2850*3db86aabSstevel "\tlen 0x%"PRIx64 2851*3db86aabSstevel "addr 0x%"PRIx64"bbase 0x%"PRIx64 2852*3db86aabSstevel " blen 0x%"PRIx64" flags 0x%x" 2853*3db86aabSstevel " algn 0x%"PRIx64"\n", 2854*3db86aabSstevel req.ra_len, req.ra_addr, 2855*3db86aabSstevel req.ra_boundbase, 2856*3db86aabSstevel req.ra_boundlen, req.ra_flags, 2857*3db86aabSstevel req.ra_align_mask); 2858*3db86aabSstevel #endif 2859*3db86aabSstevel 2860*3db86aabSstevel ret = pcmcia_alloc_mem(dip, &req, &res); 2861*3db86aabSstevel if (ret == DDI_FAILURE) { 2862*3db86aabSstevel mutex_exit(&pcic->pc_lock); 2863*3db86aabSstevel cmn_err(CE_WARN, 2864*3db86aabSstevel "\tpcmcia_alloc_mem() failed\n"); 2865*3db86aabSstevel return (BAD_SIZE); 2866*3db86aabSstevel } 2867*3db86aabSstevel memp->pcw_base = res.ra_addr_lo; 2868*3db86aabSstevel base = memp->pcw_base; 2869*3db86aabSstevel 2870*3db86aabSstevel #if defined(PCIC_DEBUG) 2871*3db86aabSstevel if (pcic_debug) 2872*3db86aabSstevel cmn_err(CE_CONT, 2873*3db86aabSstevel "\tsetwindow: new base=%x\n", 2874*3db86aabSstevel (unsigned)memp->pcw_base); 2875*3db86aabSstevel #endif 2876*3db86aabSstevel memp->pcw_len = window->WindowSize; 2877*3db86aabSstevel 2878*3db86aabSstevel which = pcmcia_map_reg(pcic->dip, 2879*3db86aabSstevel window->child, 2880*3db86aabSstevel &res, 2881*3db86aabSstevel (uint32_t)(window->state & 2882*3db86aabSstevel 0xffff) | 2883*3db86aabSstevel (window->socket << 16), 2884*3db86aabSstevel (caddr_t *)&memp->pcw_hostmem, 2885*3db86aabSstevel &memp->pcw_handle, 2886*3db86aabSstevel &window->attr, NULL); 2887*3db86aabSstevel 2888*3db86aabSstevel if (which != DDI_SUCCESS) { 2889*3db86aabSstevel 2890*3db86aabSstevel cmn_err(CE_WARN, "\tpcmcia_map_reg() " 2891*3db86aabSstevel "failed\n"); 2892*3db86aabSstevel 2893*3db86aabSstevel res.ra_addr_lo = memp->pcw_base; 2894*3db86aabSstevel res.ra_len = memp->pcw_len; 2895*3db86aabSstevel (void) pcmcia_free_mem(pcic->dip, &res); 2896*3db86aabSstevel 2897*3db86aabSstevel mutex_exit(&pcic->pc_lock); 2898*3db86aabSstevel 2899*3db86aabSstevel return (BAD_WINDOW); 2900*3db86aabSstevel } 2901*3db86aabSstevel memp->pcw_status |= PCW_MAPPED; 2902*3db86aabSstevel #if defined(PCIC_DEBUG) 2903*3db86aabSstevel if (pcic_debug) 2904*3db86aabSstevel cmn_err(CE_CONT, 2905*3db86aabSstevel "\tmap=%x, hostmem=%p\n", 2906*3db86aabSstevel which, 2907*3db86aabSstevel (void *)memp->pcw_hostmem); 2908*3db86aabSstevel #endif 2909*3db86aabSstevel } else { 2910*3db86aabSstevel base = memp->pcw_base; 2911*3db86aabSstevel } 2912*3db86aabSstevel 2913*3db86aabSstevel /* report the handle back to caller */ 2914*3db86aabSstevel window->handle = memp->pcw_handle; 2915*3db86aabSstevel 2916*3db86aabSstevel #if defined(PCIC_DEBUG) 2917*3db86aabSstevel if (pcic_debug) { 2918*3db86aabSstevel cmn_err(CE_CONT, 2919*3db86aabSstevel "\twindow mapped to %x@%x len=%d\n", 2920*3db86aabSstevel (unsigned)window->base, 2921*3db86aabSstevel (unsigned)memp->pcw_base, 2922*3db86aabSstevel memp->pcw_len); 2923*3db86aabSstevel } 2924*3db86aabSstevel #endif 2925*3db86aabSstevel 2926*3db86aabSstevel /* find the register set offset */ 2927*3db86aabSstevel select = win * PCIC_MEM_1_OFFSET; 2928*3db86aabSstevel #if defined(PCIC_DEBUG) 2929*3db86aabSstevel if (pcic_debug) 2930*3db86aabSstevel cmn_err(CE_CONT, "\tselect=%x\n", select); 2931*3db86aabSstevel #endif 2932*3db86aabSstevel 2933*3db86aabSstevel /* 2934*3db86aabSstevel * at this point, the register window indicator has 2935*3db86aabSstevel * been converted to be an offset from the first 2936*3db86aabSstevel * set of registers that are used for programming 2937*3db86aabSstevel * the window mapping and the offset used to select 2938*3db86aabSstevel * the correct set of registers to access the 2939*3db86aabSstevel * specified socket. This allows basing everything 2940*3db86aabSstevel * off the _0 window 2941*3db86aabSstevel */ 2942*3db86aabSstevel 2943*3db86aabSstevel /* map the physical page base address */ 2944*3db86aabSstevel which = (window->state & WS_16BIT) ? SYSMEM_DATA_16 : 0; 2945*3db86aabSstevel which |= (window->speed <= MEM_SPEED_MIN) ? 2946*3db86aabSstevel SYSMEM_ZERO_WAIT : 0; 2947*3db86aabSstevel 2948*3db86aabSstevel /* need to select register set */ 2949*3db86aabSstevel select = PCIC_MEM_1_OFFSET * win; 2950*3db86aabSstevel 2951*3db86aabSstevel pcic_putb(pcic, socket, 2952*3db86aabSstevel PCIC_SYSMEM_0_STARTLOW + select, 2953*3db86aabSstevel SYSMEM_LOW(base)); 2954*3db86aabSstevel pcic_putb(pcic, socket, 2955*3db86aabSstevel PCIC_SYSMEM_0_STARTHI + select, 2956*3db86aabSstevel SYSMEM_HIGH(base) | which); 2957*3db86aabSstevel 2958*3db86aabSstevel /* 2959*3db86aabSstevel * Some adapters can decode window addresses greater 2960*3db86aabSstevel * than 16-bits worth, so handle them here. 2961*3db86aabSstevel */ 2962*3db86aabSstevel switch (pcic->pc_type) { 2963*3db86aabSstevel case PCIC_INTEL_i82092: 2964*3db86aabSstevel pcic_putb(pcic, socket, 2965*3db86aabSstevel PCIC_82092_CPAGE, 2966*3db86aabSstevel SYSMEM_EXT(base)); 2967*3db86aabSstevel break; 2968*3db86aabSstevel case PCIC_CL_PD6729: 2969*3db86aabSstevel case PCIC_CL_PD6730: 2970*3db86aabSstevel clext_reg_write(pcic, socket, 2971*3db86aabSstevel PCIC_CLEXT_MMAP0_UA + win, 2972*3db86aabSstevel SYSMEM_EXT(base)); 2973*3db86aabSstevel break; 2974*3db86aabSstevel case PCIC_TI_PCI1130: 2975*3db86aabSstevel /* 2976*3db86aabSstevel * Note that the TI chip has one upper byte 2977*3db86aabSstevel * per socket so all windows get bound to a 2978*3db86aabSstevel * 16MB segment. This must be detected and 2979*3db86aabSstevel * handled appropriately. We can detect that 2980*3db86aabSstevel * it is done by seeing if the pc_base has 2981*3db86aabSstevel * changed and changing when the register 2982*3db86aabSstevel * is first set. This will force the bounds 2983*3db86aabSstevel * to be correct. 2984*3db86aabSstevel */ 2985*3db86aabSstevel if (pcic->pc_bound == 0xffffffff) { 2986*3db86aabSstevel pcic_putb(pcic, socket, 2987*3db86aabSstevel PCIC_TI_WINDOW_PAGE_PCI, 2988*3db86aabSstevel SYSMEM_EXT(base)); 2989*3db86aabSstevel pcic->pc_base = SYSMEM_EXT(base) << 24; 2990*3db86aabSstevel pcic->pc_bound = 0x1000000; 2991*3db86aabSstevel } 2992*3db86aabSstevel break; 2993*3db86aabSstevel case PCIC_TI_PCI1031: 2994*3db86aabSstevel case PCIC_TI_PCI1131: 2995*3db86aabSstevel case PCIC_TI_PCI1250: 2996*3db86aabSstevel case PCIC_TI_PCI1225: 2997*3db86aabSstevel case PCIC_TI_PCI1221: 2998*3db86aabSstevel case PCIC_SMC_34C90: 2999*3db86aabSstevel case PCIC_CL_PD6832: 3000*3db86aabSstevel case PCIC_RICOH_RL5C466: 3001*3db86aabSstevel case PCIC_TI_PCI1410: 3002*3db86aabSstevel case PCIC_ENE_1410: 3003*3db86aabSstevel case PCIC_TI_PCI1510: 3004*3db86aabSstevel case PCIC_TI_PCI1520: 3005*3db86aabSstevel case PCIC_O2_OZ6912: 3006*3db86aabSstevel case PCIC_TI_PCI1420: 3007*3db86aabSstevel case PCIC_ENE_1420: 3008*3db86aabSstevel case PCIC_TI_VENDOR: 3009*3db86aabSstevel case PCIC_TOSHIBA_TOPIC100: 3010*3db86aabSstevel case PCIC_TOSHIBA_TOPIC95: 3011*3db86aabSstevel case PCIC_TOSHIBA_VENDOR: 3012*3db86aabSstevel case PCIC_RICOH_VENDOR: 3013*3db86aabSstevel case PCIC_O2MICRO_VENDOR: 3014*3db86aabSstevel pcic_putb(pcic, socket, 3015*3db86aabSstevel PCIC_YENTA_MEM_PAGE + win, 3016*3db86aabSstevel SYSMEM_EXT(base)); 3017*3db86aabSstevel break; 3018*3db86aabSstevel default: 3019*3db86aabSstevel cmn_err(CE_NOTE, "pcic_set_window: unknown " 3020*3db86aabSstevel "cardbus vendor:0x%X\n", 3021*3db86aabSstevel pcic->pc_type); 3022*3db86aabSstevel pcic_putb(pcic, socket, 3023*3db86aabSstevel PCIC_YENTA_MEM_PAGE + win, 3024*3db86aabSstevel SYSMEM_EXT(base)); 3025*3db86aabSstevel 3026*3db86aabSstevel break; 3027*3db86aabSstevel } /* switch */ 3028*3db86aabSstevel 3029*3db86aabSstevel /* 3030*3db86aabSstevel * specify the length of the mapped range 3031*3db86aabSstevel * we convert to pages (rounding up) so that 3032*3db86aabSstevel * the hardware gets the right thing 3033*3db86aabSstevel */ 3034*3db86aabSstevel pages = (window->WindowSize+PCIC_PAGE-1)/PCIC_PAGE; 3035*3db86aabSstevel 3036*3db86aabSstevel /* 3037*3db86aabSstevel * Setup this window's timing. 3038*3db86aabSstevel */ 3039*3db86aabSstevel switch (pcic->pc_type) { 3040*3db86aabSstevel case PCIC_CL_PD6729: 3041*3db86aabSstevel case PCIC_CL_PD6730: 3042*3db86aabSstevel case PCIC_CL_PD6710: 3043*3db86aabSstevel case PCIC_CL_PD6722: 3044*3db86aabSstevel wspeed = SYSMEM_CLTIMER_SET_0; 3045*3db86aabSstevel pcic_set_cdtimers(pcic, socket, 3046*3db86aabSstevel window->speed, 3047*3db86aabSstevel wspeed); 3048*3db86aabSstevel break; 3049*3db86aabSstevel 3050*3db86aabSstevel case PCIC_INTEL_i82092: 3051*3db86aabSstevel default: 3052*3db86aabSstevel wspeed = pcic_calc_speed(pcic, window->speed); 3053*3db86aabSstevel break; 3054*3db86aabSstevel } /* switch */ 3055*3db86aabSstevel 3056*3db86aabSstevel #if defined(PCIC_DEBUG) 3057*3db86aabSstevel if (pcic_debug) 3058*3db86aabSstevel cmn_err(CE_CONT, 3059*3db86aabSstevel "\twindow %d speed bits = %x for " 3060*3db86aabSstevel "%dns\n", 3061*3db86aabSstevel win, (unsigned)wspeed, window->speed); 3062*3db86aabSstevel #endif 3063*3db86aabSstevel 3064*3db86aabSstevel pcic_putb(pcic, socket, PCIC_SYSMEM_0_STOPLOW + select, 3065*3db86aabSstevel SYSMEM_LOW(base + 3066*3db86aabSstevel (pages * PCIC_PAGE)-1)); 3067*3db86aabSstevel 3068*3db86aabSstevel wspeed |= SYSMEM_HIGH(base + (pages * PCIC_PAGE)-1); 3069*3db86aabSstevel pcic_putb(pcic, socket, PCIC_SYSMEM_0_STOPHI + select, 3070*3db86aabSstevel wspeed); 3071*3db86aabSstevel 3072*3db86aabSstevel /* 3073*3db86aabSstevel * now map the card's memory pages - we start with page 3074*3db86aabSstevel * 0 3075*3db86aabSstevel * we also default to AM -- set page might change it 3076*3db86aabSstevel */ 3077*3db86aabSstevel base = memp->pcw_base; 3078*3db86aabSstevel pcic_putb(pcic, socket, 3079*3db86aabSstevel PCIC_CARDMEM_0_LOW + select, 3080*3db86aabSstevel CARDMEM_LOW(0 - (uint32_t)base)); 3081*3db86aabSstevel 3082*3db86aabSstevel pcic_putb(pcic, socket, 3083*3db86aabSstevel PCIC_CARDMEM_0_HI + select, 3084*3db86aabSstevel CARDMEM_HIGH(0 - (uint32_t)base) | 3085*3db86aabSstevel CARDMEM_REG_ACTIVE); 3086*3db86aabSstevel 3087*3db86aabSstevel /* 3088*3db86aabSstevel * enable the window even though redundant 3089*3db86aabSstevel * and SetPage may do it again. 3090*3db86aabSstevel */ 3091*3db86aabSstevel select = pcic_getb(pcic, socket, 3092*3db86aabSstevel PCIC_MAPPING_ENABLE); 3093*3db86aabSstevel select |= SYSMEM_WINDOW(win); 3094*3db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, select); 3095*3db86aabSstevel memp->pcw_offset = 0; 3096*3db86aabSstevel memp->pcw_status |= PCW_ENABLED; 3097*3db86aabSstevel } else { 3098*3db86aabSstevel /* 3099*3db86aabSstevel * not only do we unmap the memory, the 3100*3db86aabSstevel * window has been turned off. 3101*3db86aabSstevel */ 3102*3db86aabSstevel if (which && memp->pcw_status & PCW_MAPPED) { 3103*3db86aabSstevel ddi_regs_map_free(&memp->pcw_handle); 3104*3db86aabSstevel res.ra_addr_lo = memp->pcw_base; 3105*3db86aabSstevel res.ra_len = memp->pcw_len; 3106*3db86aabSstevel (void) pcmcia_free_mem(pcic->dip, &res); 3107*3db86aabSstevel memp->pcw_hostmem = NULL; 3108*3db86aabSstevel memp->pcw_status &= ~PCW_MAPPED; 3109*3db86aabSstevel } 3110*3db86aabSstevel 3111*3db86aabSstevel /* disable current mapping */ 3112*3db86aabSstevel select = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE); 3113*3db86aabSstevel select &= ~SYSMEM_WINDOW(win); 3114*3db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, select); 3115*3db86aabSstevel memp->pcw_status &= ~PCW_ENABLED; 3116*3db86aabSstevel } 3117*3db86aabSstevel memp->pcw_len = window->WindowSize; 3118*3db86aabSstevel window->handle = memp->pcw_handle; 3119*3db86aabSstevel #if defined(PCIC_DEBUG) 3120*3db86aabSstevel if (pcic_debug) 3121*3db86aabSstevel xxdmp_all_regs(pcic, window->socket, -1); 3122*3db86aabSstevel #endif 3123*3db86aabSstevel } else { 3124*3db86aabSstevel /* 3125*3db86aabSstevel * This is a request for an IO window 3126*3db86aabSstevel */ 3127*3db86aabSstevel int win, tmp; 3128*3db86aabSstevel pcs_iowin_t *winp; 3129*3db86aabSstevel /* I/O windows */ 3130*3db86aabSstevel #if defined(PCIC_DEBUG) 3131*3db86aabSstevel if (pcic_debug) 3132*3db86aabSstevel cmn_err(CE_CONT, "\twindow type is I/O\n"); 3133*3db86aabSstevel #endif 3134*3db86aabSstevel 3135*3db86aabSstevel /* only windows 0 and 1 can do I/O */ 3136*3db86aabSstevel win = window->window % PCIC_NUMWINSOCK; 3137*3db86aabSstevel tmp = window->window / PCIC_NUMWINSOCK; 3138*3db86aabSstevel 3139*3db86aabSstevel if (win >= PCIC_IOWINDOWS || tmp != window->socket) { 3140*3db86aabSstevel cmn_err(CE_WARN, 3141*3db86aabSstevel "\twindow is out of range (%d)\n", 3142*3db86aabSstevel window->window); 3143*3db86aabSstevel return (BAD_WINDOW); 3144*3db86aabSstevel } 3145*3db86aabSstevel 3146*3db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 3147*3db86aabSstevel 3148*3db86aabSstevel winp = &sockp->pcs_windows[win].io; 3149*3db86aabSstevel winp->pcw_speed = window->speed; 3150*3db86aabSstevel if (window->WindowSize != 1 && window->WindowSize & 1) { 3151*3db86aabSstevel /* we don't want an odd-size window */ 3152*3db86aabSstevel window->WindowSize++; 3153*3db86aabSstevel } 3154*3db86aabSstevel winp->pcw_len = window->WindowSize; 3155*3db86aabSstevel 3156*3db86aabSstevel if (window->state & WS_ENABLED) { 3157*3db86aabSstevel if (winp->pcw_status & PCW_MAPPED) { 3158*3db86aabSstevel ddi_regs_map_free(&winp->pcw_handle); 3159*3db86aabSstevel res.ra_addr_lo = winp->pcw_base; 3160*3db86aabSstevel res.ra_len = winp->pcw_len; 3161*3db86aabSstevel (void) pcmcia_free_io(pcic->dip, &res); 3162*3db86aabSstevel winp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED); 3163*3db86aabSstevel } 3164*3db86aabSstevel 3165*3db86aabSstevel /* 3166*3db86aabSstevel * if the I/O address wasn't allocated, allocate 3167*3db86aabSstevel * it now. If it was allocated, it better 3168*3db86aabSstevel * be free to use. 3169*3db86aabSstevel * The winp->pcw_offset value is set and used 3170*3db86aabSstevel * later on if the particular adapter 3171*3db86aabSstevel * that we're running on has the ability 3172*3db86aabSstevel * to translate IO accesses to the card 3173*3db86aabSstevel * (such as some adapters in the Cirrus 3174*3db86aabSstevel * Logic family). 3175*3db86aabSstevel */ 3176*3db86aabSstevel winp->pcw_offset = 0; 3177*3db86aabSstevel 3178*3db86aabSstevel /* 3179*3db86aabSstevel * Setup the request parameters for the 3180*3db86aabSstevel * requested base and length. If 3181*3db86aabSstevel * we're on an adapter that has 3182*3db86aabSstevel * IO window offset registers, then 3183*3db86aabSstevel * we don't need a specific base 3184*3db86aabSstevel * address, just a length, and then 3185*3db86aabSstevel * we'll cause the correct IO address 3186*3db86aabSstevel * to be generated on the socket by 3187*3db86aabSstevel * setting up the IO window offset 3188*3db86aabSstevel * registers. 3189*3db86aabSstevel * For adapters that support this capability, we 3190*3db86aabSstevel * always use the IO window offset registers, 3191*3db86aabSstevel * even if the passed base/length would be in 3192*3db86aabSstevel * range. 3193*3db86aabSstevel */ 3194*3db86aabSstevel base = window->base; 3195*3db86aabSstevel bzero(&req, sizeof (req)); 3196*3db86aabSstevel req.ra_len = window->WindowSize; 3197*3db86aabSstevel 3198*3db86aabSstevel req.ra_addr = (uint64_t) 3199*3db86aabSstevel ((pcic->pc_flags & PCF_IO_REMAP) ? 0 : base); 3200*3db86aabSstevel req.ra_flags = (req.ra_addr) ? 3201*3db86aabSstevel NDI_RA_ALLOC_SPECIFIED : 0; 3202*3db86aabSstevel 3203*3db86aabSstevel req.ra_flags |= NDI_RA_ALIGN_SIZE; 3204*3db86aabSstevel /* need to rethink this */ 3205*3db86aabSstevel req.ra_boundbase = pcic->pc_iobase; 3206*3db86aabSstevel req.ra_boundlen = pcic->pc_iobound; 3207*3db86aabSstevel req.ra_flags |= NDI_RA_ALLOC_BOUNDED; 3208*3db86aabSstevel 3209*3db86aabSstevel #if defined(PCIC_DEBUG) 3210*3db86aabSstevel pcic_err(dip, 8, 3211*3db86aabSstevel "\tlen 0x%"PRIx64" addr 0x%"PRIx64 3212*3db86aabSstevel "bbase 0x%"PRIx64 3213*3db86aabSstevel "blen 0x%"PRIx64" flags 0x%x algn 0x%" 3214*3db86aabSstevel PRIx64"\n", 3215*3db86aabSstevel req.ra_len, (uint64_t)req.ra_addr, 3216*3db86aabSstevel req.ra_boundbase, 3217*3db86aabSstevel req.ra_boundlen, req.ra_flags, 3218*3db86aabSstevel req.ra_align_mask); 3219*3db86aabSstevel #endif 3220*3db86aabSstevel 3221*3db86aabSstevel /* 3222*3db86aabSstevel * Try to allocate the space. If we fail this, 3223*3db86aabSstevel * return the appropriate error depending 3224*3db86aabSstevel * on whether the caller specified a 3225*3db86aabSstevel * specific base address or not. 3226*3db86aabSstevel */ 3227*3db86aabSstevel if (pcmcia_alloc_io(dip, &req, &res) == DDI_FAILURE) { 3228*3db86aabSstevel winp->pcw_status &= ~PCW_ENABLED; 3229*3db86aabSstevel mutex_exit(&pcic->pc_lock); 3230*3db86aabSstevel cmn_err(CE_WARN, "Failed to alloc I/O:\n" 3231*3db86aabSstevel "\tlen 0x%" PRIx64 " addr 0x%" PRIx64 3232*3db86aabSstevel "bbase 0x%" PRIx64 3233*3db86aabSstevel "blen 0x%" PRIx64 "flags 0x%x" 3234*3db86aabSstevel "algn 0x%" PRIx64 "\n", 3235*3db86aabSstevel req.ra_len, req.ra_addr, 3236*3db86aabSstevel req.ra_boundbase, 3237*3db86aabSstevel req.ra_boundlen, req.ra_flags, 3238*3db86aabSstevel req.ra_align_mask); 3239*3db86aabSstevel 3240*3db86aabSstevel return (base?BAD_BASE:BAD_SIZE); 3241*3db86aabSstevel } /* pcmcia_alloc_io */ 3242*3db86aabSstevel 3243*3db86aabSstevel /* 3244*3db86aabSstevel * Don't change the original base. Either we use 3245*3db86aabSstevel * the offset registers below (PCF_IO_REMAP is set) 3246*3db86aabSstevel * or it was allocated correctly anyway. 3247*3db86aabSstevel */ 3248*3db86aabSstevel winp->pcw_base = res.ra_addr_lo; 3249*3db86aabSstevel 3250*3db86aabSstevel #if defined(PCIC_DEBUG) 3251*3db86aabSstevel pcic_err(dip, 8, 3252*3db86aabSstevel "\tsetwindow: new base=%x orig base 0x%x\n", 3253*3db86aabSstevel (unsigned)winp->pcw_base, base); 3254*3db86aabSstevel #endif 3255*3db86aabSstevel 3256*3db86aabSstevel if ((which = pcmcia_map_reg(pcic->dip, 3257*3db86aabSstevel window->child, 3258*3db86aabSstevel &res, 3259*3db86aabSstevel (uint32_t)(window->state & 3260*3db86aabSstevel 0xffff) | 3261*3db86aabSstevel (window->socket << 16), 3262*3db86aabSstevel (caddr_t *)&winp->pcw_hostmem, 3263*3db86aabSstevel &winp->pcw_handle, 3264*3db86aabSstevel &window->attr, 3265*3db86aabSstevel base)) != DDI_SUCCESS) { 3266*3db86aabSstevel 3267*3db86aabSstevel cmn_err(CE_WARN, "pcmcia_map_reg()" 3268*3db86aabSstevel "failed\n"); 3269*3db86aabSstevel 3270*3db86aabSstevel res.ra_addr_lo = winp->pcw_base; 3271*3db86aabSstevel res.ra_len = winp->pcw_len; 3272*3db86aabSstevel (void) pcmcia_free_io(pcic->dip, &res); 3273*3db86aabSstevel 3274*3db86aabSstevel mutex_exit(&pcic->pc_lock); 3275*3db86aabSstevel return (BAD_WINDOW); 3276*3db86aabSstevel } 3277*3db86aabSstevel 3278*3db86aabSstevel window->handle = winp->pcw_handle; 3279*3db86aabSstevel winp->pcw_status |= PCW_MAPPED; 3280*3db86aabSstevel 3281*3db86aabSstevel /* find the register set offset */ 3282*3db86aabSstevel select = win * PCIC_IO_OFFSET; 3283*3db86aabSstevel 3284*3db86aabSstevel #if defined(PCIC_DEBUG) 3285*3db86aabSstevel if (pcic_debug) { 3286*3db86aabSstevel cmn_err(CE_CONT, 3287*3db86aabSstevel "\tenable: window=%d, select=%x, " 3288*3db86aabSstevel "base=%x, handle=%p\n", 3289*3db86aabSstevel win, select, 3290*3db86aabSstevel (unsigned)window->base, 3291*3db86aabSstevel (void *)window->handle); 3292*3db86aabSstevel } 3293*3db86aabSstevel #endif 3294*3db86aabSstevel /* 3295*3db86aabSstevel * at this point, the register window indicator has 3296*3db86aabSstevel * been converted to be an offset from the first 3297*3db86aabSstevel * set of registers that are used for programming 3298*3db86aabSstevel * the window mapping and the offset used to select 3299*3db86aabSstevel * the correct set of registers to access the 3300*3db86aabSstevel * specified socket. This allows basing everything 3301*3db86aabSstevel * off the _0 window 3302*3db86aabSstevel */ 3303*3db86aabSstevel 3304*3db86aabSstevel /* map the I/O base in */ 3305*3db86aabSstevel pcic_putb(pcic, socket, 3306*3db86aabSstevel PCIC_IO_ADDR_0_STARTLOW + select, 3307*3db86aabSstevel LOW_BYTE((uint32_t)winp->pcw_base)); 3308*3db86aabSstevel pcic_putb(pcic, socket, 3309*3db86aabSstevel PCIC_IO_ADDR_0_STARTHI + select, 3310*3db86aabSstevel HIGH_BYTE((uint32_t)winp->pcw_base)); 3311*3db86aabSstevel 3312*3db86aabSstevel pcic_putb(pcic, socket, 3313*3db86aabSstevel PCIC_IO_ADDR_0_STOPLOW + select, 3314*3db86aabSstevel LOW_BYTE((uint32_t)winp->pcw_base + 3315*3db86aabSstevel window->WindowSize - 1)); 3316*3db86aabSstevel pcic_putb(pcic, socket, 3317*3db86aabSstevel PCIC_IO_ADDR_0_STOPHI + select, 3318*3db86aabSstevel HIGH_BYTE((uint32_t)winp->pcw_base + 3319*3db86aabSstevel window->WindowSize - 1)); 3320*3db86aabSstevel 3321*3db86aabSstevel /* 3322*3db86aabSstevel * We've got the requested IO space, now see if we 3323*3db86aabSstevel * need to adjust the IO window offset registers 3324*3db86aabSstevel * so that the correct IO address is generated 3325*3db86aabSstevel * at the socket. If this window doesn't have 3326*3db86aabSstevel * this capability, then we're all done setting 3327*3db86aabSstevel * up the IO resources. 3328*3db86aabSstevel */ 3329*3db86aabSstevel if (pcic->pc_flags & PCF_IO_REMAP) { 3330*3db86aabSstevel 3331*3db86aabSstevel 3332*3db86aabSstevel /* 3333*3db86aabSstevel * Note that only 16 bits are used to program 3334*3db86aabSstevel * the registers but leave 32 bits on pcw_offset 3335*3db86aabSstevel * so that we can generate the original base 3336*3db86aabSstevel * in get_window() 3337*3db86aabSstevel */ 3338*3db86aabSstevel winp->pcw_offset = (base - winp->pcw_base); 3339*3db86aabSstevel 3340*3db86aabSstevel pcic_putb(pcic, socket, 3341*3db86aabSstevel PCIC_IO_OFFSET_LOW + 3342*3db86aabSstevel (win * PCIC_IO_OFFSET_OFFSET), 3343*3db86aabSstevel winp->pcw_offset & 0x0ff); 3344*3db86aabSstevel pcic_putb(pcic, socket, 3345*3db86aabSstevel PCIC_IO_OFFSET_HI + 3346*3db86aabSstevel (win * PCIC_IO_OFFSET_OFFSET), 3347*3db86aabSstevel (winp->pcw_offset >> 8) & 0x0ff); 3348*3db86aabSstevel 3349*3db86aabSstevel } /* PCF_IO_REMAP */ 3350*3db86aabSstevel 3351*3db86aabSstevel /* now get the other details (size, etc) right */ 3352*3db86aabSstevel 3353*3db86aabSstevel /* 3354*3db86aabSstevel * Set the data size control bits here. Most of the 3355*3db86aabSstevel * adapters will ignore IOMEM_16BIT when 3356*3db86aabSstevel * IOMEM_IOCS16 is set, except for the Intel 3357*3db86aabSstevel * 82092, which only pays attention to the 3358*3db86aabSstevel * IOMEM_16BIT bit. Sigh... Intel can't even 3359*3db86aabSstevel * make a proper clone of their own chip. 3360*3db86aabSstevel * The 82092 also apparently can't set the timing 3361*3db86aabSstevel * of I/O windows. 3362*3db86aabSstevel */ 3363*3db86aabSstevel which = (window->state & WS_16BIT) ? 3364*3db86aabSstevel (IOMEM_16BIT | IOMEM_IOCS16) : 0; 3365*3db86aabSstevel 3366*3db86aabSstevel switch (pcic->pc_type) { 3367*3db86aabSstevel case PCIC_CL_PD6729: 3368*3db86aabSstevel case PCIC_CL_PD6730: 3369*3db86aabSstevel case PCIC_CL_PD6710: 3370*3db86aabSstevel case PCIC_CL_PD6722: 3371*3db86aabSstevel case PCIC_CL_PD6832: 3372*3db86aabSstevel /* 3373*3db86aabSstevel * Select Timer Set 1 - this will take 3374*3db86aabSstevel * effect when the PCIC_IO_CONTROL 3375*3db86aabSstevel * register is written to later on; 3376*3db86aabSstevel * the call to pcic_set_cdtimers 3377*3db86aabSstevel * just sets up the timer itself. 3378*3db86aabSstevel */ 3379*3db86aabSstevel which |= IOMEM_CLTIMER_SET_1; 3380*3db86aabSstevel pcic_set_cdtimers(pcic, socket, 3381*3db86aabSstevel window->speed, 3382*3db86aabSstevel IOMEM_CLTIMER_SET_1); 3383*3db86aabSstevel which |= IOMEM_IOCS16; 3384*3db86aabSstevel break; 3385*3db86aabSstevel case PCIC_TI_PCI1031: 3386*3db86aabSstevel 3387*3db86aabSstevel if (window->state & WS_16BIT) 3388*3db86aabSstevel which |= IOMEM_WAIT16; 3389*3db86aabSstevel 3390*3db86aabSstevel break; 3391*3db86aabSstevel case PCIC_TI_PCI1130: 3392*3db86aabSstevel 3393*3db86aabSstevel if (window->state & WS_16BIT) 3394*3db86aabSstevel which |= IOMEM_WAIT16; 3395*3db86aabSstevel 3396*3db86aabSstevel break; 3397*3db86aabSstevel case PCIC_INTEL_i82092: 3398*3db86aabSstevel break; 3399*3db86aabSstevel default: 3400*3db86aabSstevel if (window->speed > 3401*3db86aabSstevel mhztons(pcic->bus_speed) * 3) 3402*3db86aabSstevel which |= IOMEM_WAIT16; 3403*3db86aabSstevel #ifdef notdef 3404*3db86aabSstevel if (window->speed < 3405*3db86aabSstevel mhztons(pcic->bus_speed) * 6) 3406*3db86aabSstevel which |= IOMEM_ZERO_WAIT; 3407*3db86aabSstevel #endif 3408*3db86aabSstevel break; 3409*3db86aabSstevel } /* switch (pc_type) */ 3410*3db86aabSstevel 3411*3db86aabSstevel /* 3412*3db86aabSstevel * Setup the data width and timing 3413*3db86aabSstevel */ 3414*3db86aabSstevel select = pcic_getb(pcic, socket, PCIC_IO_CONTROL); 3415*3db86aabSstevel select &= ~(PCIC_IO_WIN_MASK << (win * 4)); 3416*3db86aabSstevel select |= IOMEM_SETWIN(win, which); 3417*3db86aabSstevel pcic_putb(pcic, socket, PCIC_IO_CONTROL, select); 3418*3db86aabSstevel 3419*3db86aabSstevel /* 3420*3db86aabSstevel * Enable the IO window 3421*3db86aabSstevel */ 3422*3db86aabSstevel select = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE); 3423*3db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, 3424*3db86aabSstevel select | IOMEM_WINDOW(win)); 3425*3db86aabSstevel 3426*3db86aabSstevel winp->pcw_status |= PCW_ENABLED; 3427*3db86aabSstevel 3428*3db86aabSstevel #if defined(PCIC_DEBUG) 3429*3db86aabSstevel if (pcic_debug) { 3430*3db86aabSstevel cmn_err(CE_CONT, 3431*3db86aabSstevel "\twhich = %x, select = %x (%x)\n", 3432*3db86aabSstevel which, select, 3433*3db86aabSstevel IOMEM_SETWIN(win, which)); 3434*3db86aabSstevel xxdmp_all_regs(pcic, window->socket * 0x40, 24); 3435*3db86aabSstevel } 3436*3db86aabSstevel #endif 3437*3db86aabSstevel } else { 3438*3db86aabSstevel /* 3439*3db86aabSstevel * not only do we unmap the IO space, the 3440*3db86aabSstevel * window has been turned off. 3441*3db86aabSstevel */ 3442*3db86aabSstevel if (winp->pcw_status & PCW_MAPPED) { 3443*3db86aabSstevel ddi_regs_map_free(&winp->pcw_handle); 3444*3db86aabSstevel res.ra_addr_lo = winp->pcw_base; 3445*3db86aabSstevel res.ra_len = winp->pcw_len; 3446*3db86aabSstevel (void) pcmcia_free_io(pcic->dip, &res); 3447*3db86aabSstevel winp->pcw_status &= ~PCW_MAPPED; 3448*3db86aabSstevel } 3449*3db86aabSstevel 3450*3db86aabSstevel /* disable current mapping */ 3451*3db86aabSstevel select = pcic_getb(pcic, socket, 3452*3db86aabSstevel PCIC_MAPPING_ENABLE); 3453*3db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, 3454*3db86aabSstevel select &= ~IOMEM_WINDOW(win)); 3455*3db86aabSstevel winp->pcw_status &= ~PCW_ENABLED; 3456*3db86aabSstevel 3457*3db86aabSstevel winp->pcw_base = 0; 3458*3db86aabSstevel winp->pcw_len = 0; 3459*3db86aabSstevel winp->pcw_offset = 0; 3460*3db86aabSstevel window->base = 0; 3461*3db86aabSstevel /* now make sure we don't accidentally re-enable */ 3462*3db86aabSstevel /* find the register set offset */ 3463*3db86aabSstevel select = win * PCIC_IO_OFFSET; 3464*3db86aabSstevel pcic_putb(pcic, socket, 3465*3db86aabSstevel PCIC_IO_ADDR_0_STARTLOW + select, 0); 3466*3db86aabSstevel pcic_putb(pcic, socket, 3467*3db86aabSstevel PCIC_IO_ADDR_0_STARTHI + select, 0); 3468*3db86aabSstevel pcic_putb(pcic, socket, 3469*3db86aabSstevel PCIC_IO_ADDR_0_STOPLOW + select, 0); 3470*3db86aabSstevel pcic_putb(pcic, socket, 3471*3db86aabSstevel PCIC_IO_ADDR_0_STOPHI + select, 0); 3472*3db86aabSstevel } 3473*3db86aabSstevel } 3474*3db86aabSstevel mutex_exit(&pcic->pc_lock); 3475*3db86aabSstevel 3476*3db86aabSstevel return (SUCCESS); 3477*3db86aabSstevel } 3478*3db86aabSstevel 3479*3db86aabSstevel /* 3480*3db86aabSstevel * pcic_card_state() 3481*3db86aabSstevel * compute the instantaneous Card State information 3482*3db86aabSstevel */ 3483*3db86aabSstevel static int 3484*3db86aabSstevel pcic_card_state(pcicdev_t *pcic, pcic_socket_t *sockp) 3485*3db86aabSstevel { 3486*3db86aabSstevel int value, result; 3487*3db86aabSstevel #if defined(PCIC_DEBUG) 3488*3db86aabSstevel int orig_value; 3489*3db86aabSstevel #endif 3490*3db86aabSstevel 3491*3db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 3492*3db86aabSstevel 3493*3db86aabSstevel value = pcic_getb(pcic, sockp->pcs_socket, PCIC_INTERFACE_STATUS); 3494*3db86aabSstevel 3495*3db86aabSstevel #if defined(PCIC_DEBUG) 3496*3db86aabSstevel orig_value = value; 3497*3db86aabSstevel if (pcic_debug >= 8) 3498*3db86aabSstevel cmn_err(CE_CONT, "pcic_card_state(%p) if status = %b for %d\n", 3499*3db86aabSstevel (void *)sockp, 3500*3db86aabSstevel value, 3501*3db86aabSstevel "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI", 3502*3db86aabSstevel sockp->pcs_socket); 3503*3db86aabSstevel #endif 3504*3db86aabSstevel /* 3505*3db86aabSstevel * Lie to socket services if we are not ready. 3506*3db86aabSstevel * This is when we are starting up or during debounce timeouts 3507*3db86aabSstevel * or if the card is a cardbus card. 3508*3db86aabSstevel */ 3509*3db86aabSstevel if (!(sockp->pcs_flags & (PCS_STARTING|PCS_CARD_ISCARDBUS)) && 3510*3db86aabSstevel !sockp->pcs_debounce_id && 3511*3db86aabSstevel (value & PCIC_ISTAT_CD_MASK) == PCIC_CD_PRESENT_OK) { 3512*3db86aabSstevel result = SBM_CD; 3513*3db86aabSstevel 3514*3db86aabSstevel if (value & PCIC_WRITE_PROTECT || !(value & PCIC_POWER_ON)) 3515*3db86aabSstevel result |= SBM_WP; 3516*3db86aabSstevel if (value & PCIC_POWER_ON) { 3517*3db86aabSstevel if (value & PCIC_READY) 3518*3db86aabSstevel result |= SBM_RDYBSY; 3519*3db86aabSstevel value = (~value) & (PCIC_BVD1 | PCIC_BVD2); 3520*3db86aabSstevel if (value & PCIC_BVD1) 3521*3db86aabSstevel result |= SBM_BVD1; 3522*3db86aabSstevel if (value & PCIC_BVD2) 3523*3db86aabSstevel result |= SBM_BVD2; 3524*3db86aabSstevel } 3525*3db86aabSstevel } else 3526*3db86aabSstevel result = 0; 3527*3db86aabSstevel 3528*3db86aabSstevel mutex_exit(&pcic->pc_lock); 3529*3db86aabSstevel 3530*3db86aabSstevel #if defined(PCIC_DEBUG) 3531*3db86aabSstevel pcic_err(pcic->dip, 8, 3532*3db86aabSstevel "pcic_card_state(%p) if status = %b for %d (rval=0x%x)\n", 3533*3db86aabSstevel (void *) sockp, orig_value, 3534*3db86aabSstevel "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI", 3535*3db86aabSstevel sockp->pcs_socket, result); 3536*3db86aabSstevel #endif 3537*3db86aabSstevel 3538*3db86aabSstevel return (result); 3539*3db86aabSstevel } 3540*3db86aabSstevel 3541*3db86aabSstevel /* 3542*3db86aabSstevel * pcic_set_page() 3543*3db86aabSstevel * SocketServices SetPage function 3544*3db86aabSstevel * set the page of PC Card memory that should be in the mapped 3545*3db86aabSstevel * window 3546*3db86aabSstevel */ 3547*3db86aabSstevel /*ARGSUSED*/ 3548*3db86aabSstevel static int 3549*3db86aabSstevel pcic_set_page(dev_info_t *dip, set_page_t *page) 3550*3db86aabSstevel { 3551*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 3552*3db86aabSstevel pcicdev_t *pcic = anp->an_private; 3553*3db86aabSstevel int select; 3554*3db86aabSstevel int which, socket, window; 3555*3db86aabSstevel uint32_t base; 3556*3db86aabSstevel pcs_memwin_t *memp; 3557*3db86aabSstevel 3558*3db86aabSstevel /* get real socket/window numbers */ 3559*3db86aabSstevel window = page->window % PCIC_NUMWINSOCK; 3560*3db86aabSstevel socket = page->window / PCIC_NUMWINSOCK; 3561*3db86aabSstevel 3562*3db86aabSstevel #if defined(PCIC_DEBUG) 3563*3db86aabSstevel if (pcic_debug) { 3564*3db86aabSstevel cmn_err(CE_CONT, 3565*3db86aabSstevel "pcic_set_page: window=%d, socket=%d, page=%d\n", 3566*3db86aabSstevel window, socket, page->page); 3567*3db86aabSstevel } 3568*3db86aabSstevel #endif 3569*3db86aabSstevel /* only windows 2-6 work on memory */ 3570*3db86aabSstevel if (window < PCIC_IOWINDOWS) 3571*3db86aabSstevel return (BAD_WINDOW); 3572*3db86aabSstevel 3573*3db86aabSstevel /* only one page supported (but any size) */ 3574*3db86aabSstevel if (page->page != 0) 3575*3db86aabSstevel return (BAD_PAGE); 3576*3db86aabSstevel 3577*3db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 3578*3db86aabSstevel 3579*3db86aabSstevel memp = &pcic->pc_sockets[socket].pcs_windows[window].mem; 3580*3db86aabSstevel window -= PCIC_IOWINDOWS; 3581*3db86aabSstevel 3582*3db86aabSstevel #if defined(PCIC_DEBUG) 3583*3db86aabSstevel if (pcic_debug) 3584*3db86aabSstevel cmn_err(CE_CONT, "\tpcw_base=%x, pcw_hostmem=%p, pcw_len=%x\n", 3585*3db86aabSstevel (uint32_t)memp->pcw_base, 3586*3db86aabSstevel (void *)memp->pcw_hostmem, memp->pcw_len); 3587*3db86aabSstevel #endif 3588*3db86aabSstevel 3589*3db86aabSstevel /* window must be enabled */ 3590*3db86aabSstevel if (!(memp->pcw_status & PCW_ENABLED)) 3591*3db86aabSstevel return (BAD_ATTRIBUTE); 3592*3db86aabSstevel 3593*3db86aabSstevel /* find the register set offset */ 3594*3db86aabSstevel select = window * PCIC_MEM_1_OFFSET; 3595*3db86aabSstevel #if defined(PCIC_DEBUG) 3596*3db86aabSstevel if (pcic_debug) 3597*3db86aabSstevel cmn_err(CE_CONT, "\tselect=%x\n", select); 3598*3db86aabSstevel #endif 3599*3db86aabSstevel 3600*3db86aabSstevel /* 3601*3db86aabSstevel * now map the card's memory pages - we start with page 0 3602*3db86aabSstevel */ 3603*3db86aabSstevel 3604*3db86aabSstevel which = 0; /* assume simple case */ 3605*3db86aabSstevel if (page->state & PS_ATTRIBUTE) { 3606*3db86aabSstevel which |= CARDMEM_REG_ACTIVE; 3607*3db86aabSstevel memp->pcw_status |= PCW_ATTRIBUTE; 3608*3db86aabSstevel } else { 3609*3db86aabSstevel memp->pcw_status &= ~PCW_ATTRIBUTE; 3610*3db86aabSstevel } 3611*3db86aabSstevel 3612*3db86aabSstevel /* 3613*3db86aabSstevel * if caller says Write Protect, enforce it. 3614*3db86aabSstevel */ 3615*3db86aabSstevel if (page->state & PS_WP) { 3616*3db86aabSstevel which |= CARDMEM_WRITE_PROTECT; 3617*3db86aabSstevel memp->pcw_status |= PCW_WP; 3618*3db86aabSstevel } else { 3619*3db86aabSstevel memp->pcw_status &= ~PCW_WP; 3620*3db86aabSstevel } 3621*3db86aabSstevel #if defined(PCIC_DEBUG) 3622*3db86aabSstevel if (pcic_debug) { 3623*3db86aabSstevel cmn_err(CE_CONT, "\tmemory type = %s\n", 3624*3db86aabSstevel (which & CARDMEM_REG_ACTIVE) ? "attribute" : "common"); 3625*3db86aabSstevel if (which & CARDMEM_WRITE_PROTECT) 3626*3db86aabSstevel cmn_err(CE_CONT, "\twrite protect\n"); 3627*3db86aabSstevel cmn_err(CE_CONT, "\tpage offset=%x pcw_base=%x (%x)\n", 3628*3db86aabSstevel (unsigned)page->offset, 3629*3db86aabSstevel (unsigned)memp->pcw_base, 3630*3db86aabSstevel (int)page->offset - (int)memp->pcw_base & 0xffffff); 3631*3db86aabSstevel } 3632*3db86aabSstevel #endif 3633*3db86aabSstevel /* address computation based on 64MB range and not larger */ 3634*3db86aabSstevel base = (uint32_t)memp->pcw_base & 0x3ffffff; 3635*3db86aabSstevel pcic_putb(pcic, socket, PCIC_CARDMEM_0_LOW + select, 3636*3db86aabSstevel CARDMEM_LOW((int)page->offset - (int)base)); 3637*3db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_CARDMEM_0_LOW + select); 3638*3db86aabSstevel pcic_putb(pcic, socket, PCIC_CARDMEM_0_HI + select, 3639*3db86aabSstevel CARDMEM_HIGH((int)page->offset - base) | which); 3640*3db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_CARDMEM_0_HI + select); 3641*3db86aabSstevel 3642*3db86aabSstevel /* 3643*3db86aabSstevel * while not really necessary, this just makes sure 3644*3db86aabSstevel * nothing turned the window off behind our backs 3645*3db86aabSstevel */ 3646*3db86aabSstevel which = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE); 3647*3db86aabSstevel which |= SYSMEM_WINDOW(window); 3648*3db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, which); 3649*3db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE); 3650*3db86aabSstevel 3651*3db86aabSstevel memp->pcw_offset = (off_t)page->offset; 3652*3db86aabSstevel 3653*3db86aabSstevel #if defined(PCIC_DEBUG) 3654*3db86aabSstevel if (pcic_debug) { 3655*3db86aabSstevel cmn_err(CE_CONT, "\tbase=%p, *base=%x\n", 3656*3db86aabSstevel (void *)memp->pcw_hostmem, 3657*3db86aabSstevel (uint32_t)*memp->pcw_hostmem); 3658*3db86aabSstevel 3659*3db86aabSstevel xxdmp_all_regs(pcic, socket, -1); 3660*3db86aabSstevel 3661*3db86aabSstevel cmn_err(CE_CONT, "\tbase=%p, *base=%x\n", 3662*3db86aabSstevel (void *)memp->pcw_hostmem, 3663*3db86aabSstevel (uint32_t)*memp->pcw_hostmem); 3664*3db86aabSstevel } 3665*3db86aabSstevel #endif 3666*3db86aabSstevel 3667*3db86aabSstevel if (which & PCW_ATTRIBUTE) 3668*3db86aabSstevel pcic_mswait(pcic, socket, 2); 3669*3db86aabSstevel 3670*3db86aabSstevel mutex_exit(&pcic->pc_lock); 3671*3db86aabSstevel 3672*3db86aabSstevel return (SUCCESS); 3673*3db86aabSstevel } 3674*3db86aabSstevel 3675*3db86aabSstevel /* 3676*3db86aabSstevel * pcic_set_vcc_level() 3677*3db86aabSstevel * 3678*3db86aabSstevel * set voltage based on adapter information 3679*3db86aabSstevel * 3680*3db86aabSstevel * this routine implements a limited solution for support of 3.3v cards. 3681*3db86aabSstevel * the general solution, which would fully support the pcmcia spec 3682*3db86aabSstevel * as far as allowing client drivers to request which voltage levels 3683*3db86aabSstevel * to be set, requires more framework support and driver changes - ess 3684*3db86aabSstevel */ 3685*3db86aabSstevel static int 3686*3db86aabSstevel pcic_set_vcc_level(pcicdev_t *pcic, set_socket_t *socket) 3687*3db86aabSstevel { 3688*3db86aabSstevel uint32_t socket_present_state; 3689*3db86aabSstevel 3690*3db86aabSstevel #if defined(PCIC_DEBUG) 3691*3db86aabSstevel if (pcic_debug) { 3692*3db86aabSstevel cmn_err(CE_CONT, 3693*3db86aabSstevel "pcic_set_vcc_level(pcic=%p, VccLevel=%d)\n", 3694*3db86aabSstevel (void *)pcic, socket->VccLevel); 3695*3db86aabSstevel } 3696*3db86aabSstevel #endif 3697*3db86aabSstevel 3698*3db86aabSstevel /* 3699*3db86aabSstevel * check VccLevel 3700*3db86aabSstevel * if this is zero, power is being turned off 3701*3db86aabSstevel * if it is non-zero, power is being turned on. 3702*3db86aabSstevel */ 3703*3db86aabSstevel if (socket->VccLevel == 0) { 3704*3db86aabSstevel return (0); 3705*3db86aabSstevel } 3706*3db86aabSstevel 3707*3db86aabSstevel /* 3708*3db86aabSstevel * range checking for sanity's sake 3709*3db86aabSstevel */ 3710*3db86aabSstevel if (socket->VccLevel >= pcic->pc_numpower) { 3711*3db86aabSstevel return (BAD_VCC); 3712*3db86aabSstevel } 3713*3db86aabSstevel 3714*3db86aabSstevel switch (pcic->pc_io_type) { 3715*3db86aabSstevel /* 3716*3db86aabSstevel * Yenta-compliant adapters have vcc info in the extended registers 3717*3db86aabSstevel * Other adapters can be added as needed, but the 'default' case 3718*3db86aabSstevel * has been left as it was previously so as not to break existing 3719*3db86aabSstevel * adapters. 3720*3db86aabSstevel */ 3721*3db86aabSstevel case PCIC_IO_TYPE_YENTA: 3722*3db86aabSstevel /* 3723*3db86aabSstevel * Here we ignore the VccLevel passed in and read the 3724*3db86aabSstevel * card type from the adapter socket present state register 3725*3db86aabSstevel */ 3726*3db86aabSstevel socket_present_state = 3727*3db86aabSstevel ddi_get32(pcic->handle, (uint32_t *)(pcic->ioaddr + 3728*3db86aabSstevel PCIC_PRESENT_STATE_REG)); 3729*3db86aabSstevel #if defined(PCIC_DEBUG) 3730*3db86aabSstevel if (pcic_debug) { 3731*3db86aabSstevel cmn_err(CE_CONT, 3732*3db86aabSstevel "socket present state = 0x%x\n", 3733*3db86aabSstevel socket_present_state); 3734*3db86aabSstevel } 3735*3db86aabSstevel #endif 3736*3db86aabSstevel switch (socket_present_state & PCIC_VCC_MASK) { 3737*3db86aabSstevel case PCIC_VCC_3VCARD: 3738*3db86aabSstevel /* fall through */ 3739*3db86aabSstevel case PCIC_VCC_3VCARD|PCIC_VCC_5VCARD: 3740*3db86aabSstevel socket->VccLevel = PCIC_VCC_3VLEVEL; 3741*3db86aabSstevel return 3742*3db86aabSstevel (POWER_3VCARD_ENABLE|POWER_OUTPUT_ENABLE); 3743*3db86aabSstevel case PCIC_VCC_5VCARD: 3744*3db86aabSstevel socket->VccLevel = PCIC_VCC_5VLEVEL; 3745*3db86aabSstevel return 3746*3db86aabSstevel (POWER_CARD_ENABLE|POWER_OUTPUT_ENABLE); 3747*3db86aabSstevel default: 3748*3db86aabSstevel /* 3749*3db86aabSstevel * if no card is present, this can be the 3750*3db86aabSstevel * case of a client making a SetSocket call 3751*3db86aabSstevel * after card removal. In this case we return 3752*3db86aabSstevel * the current power level 3753*3db86aabSstevel */ 3754*3db86aabSstevel return ((unsigned)ddi_get8(pcic->handle, 3755*3db86aabSstevel pcic->ioaddr + CB_R2_OFFSET + 3756*3db86aabSstevel PCIC_POWER_CONTROL)); 3757*3db86aabSstevel } 3758*3db86aabSstevel 3759*3db86aabSstevel default: 3760*3db86aabSstevel 3761*3db86aabSstevel switch (socket->VccLevel) { 3762*3db86aabSstevel case PCIC_VCC_3VLEVEL: 3763*3db86aabSstevel return (BAD_VCC); 3764*3db86aabSstevel case PCIC_VCC_5VLEVEL: 3765*3db86aabSstevel /* enable Vcc */ 3766*3db86aabSstevel return (POWER_CARD_ENABLE|POWER_OUTPUT_ENABLE); 3767*3db86aabSstevel default: 3768*3db86aabSstevel return (BAD_VCC); 3769*3db86aabSstevel } 3770*3db86aabSstevel } 3771*3db86aabSstevel } 3772*3db86aabSstevel 3773*3db86aabSstevel 3774*3db86aabSstevel /* 3775*3db86aabSstevel * pcic_set_socket() 3776*3db86aabSstevel * Socket Services SetSocket call 3777*3db86aabSstevel * sets basic socket configuration 3778*3db86aabSstevel */ 3779*3db86aabSstevel static int 3780*3db86aabSstevel pcic_set_socket(dev_info_t *dip, set_socket_t *socket) 3781*3db86aabSstevel { 3782*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 3783*3db86aabSstevel pcicdev_t *pcic = anp->an_private; 3784*3db86aabSstevel pcic_socket_t *sockp = &pcic->pc_sockets[socket->socket]; 3785*3db86aabSstevel int irq, interrupt, mirq; 3786*3db86aabSstevel int powerlevel = 0; 3787*3db86aabSstevel int ind, value, orig_pwrctl; 3788*3db86aabSstevel 3789*3db86aabSstevel #if defined(PCIC_DEBUG) 3790*3db86aabSstevel if (pcic_debug) { 3791*3db86aabSstevel cmn_err(CE_CONT, 3792*3db86aabSstevel "pcic_set_socket(dip=%p, socket=%d)" 3793*3db86aabSstevel " Vcc=%d Vpp1=%d Vpp2=%d\n", (void *)dip, 3794*3db86aabSstevel socket->socket, socket->VccLevel, socket->Vpp1Level, 3795*3db86aabSstevel socket->Vpp2Level); 3796*3db86aabSstevel } 3797*3db86aabSstevel #endif 3798*3db86aabSstevel /* 3799*3db86aabSstevel * check VccLevel, etc. before setting mutex 3800*3db86aabSstevel * if this is zero, power is being turned off 3801*3db86aabSstevel * if it is non-zero, power is being turned on. 3802*3db86aabSstevel * the default case is to assume Vcc only. 3803*3db86aabSstevel */ 3804*3db86aabSstevel 3805*3db86aabSstevel /* this appears to be very implementation specific */ 3806*3db86aabSstevel 3807*3db86aabSstevel if (socket->Vpp1Level != socket->Vpp2Level) 3808*3db86aabSstevel return (BAD_VPP); 3809*3db86aabSstevel 3810*3db86aabSstevel if (socket->VccLevel == 0 || !(sockp->pcs_flags & PCS_CARD_PRESENT)) { 3811*3db86aabSstevel powerlevel = 0; 3812*3db86aabSstevel sockp->pcs_vcc = 0; 3813*3db86aabSstevel sockp->pcs_vpp1 = 0; 3814*3db86aabSstevel sockp->pcs_vpp2 = 0; 3815*3db86aabSstevel } else { 3816*3db86aabSstevel #if defined(PCIC_DEBUG) 3817*3db86aabSstevel pcic_err(dip, 9, "\tVcc=%d Vpp1Level=%d, Vpp2Level=%d\n", 3818*3db86aabSstevel socket->VccLevel, socket->Vpp1Level, socket->Vpp2Level); 3819*3db86aabSstevel #endif 3820*3db86aabSstevel /* valid Vcc power level? */ 3821*3db86aabSstevel if (socket->VccLevel >= pcic->pc_numpower) 3822*3db86aabSstevel return (BAD_VCC); 3823*3db86aabSstevel 3824*3db86aabSstevel switch (pcic_power[socket->VccLevel].PowerLevel) { 3825*3db86aabSstevel case 33: /* 3.3V */ 3826*3db86aabSstevel case 60: /* for bad CIS in Option GPRS card */ 3827*3db86aabSstevel if (!(pcic->pc_flags & PCF_33VCAP)) { 3828*3db86aabSstevel cmn_err(CE_WARN, 3829*3db86aabSstevel "%s%d: Bad Request for 3.3V " 3830*3db86aabSstevel "(Controller incapable)\n", 3831*3db86aabSstevel ddi_get_name(pcic->dip), 3832*3db86aabSstevel ddi_get_instance(pcic->dip)); 3833*3db86aabSstevel return (BAD_VCC); 3834*3db86aabSstevel } 3835*3db86aabSstevel /* FALLTHROUGH */ 3836*3db86aabSstevel case 50: /* 5V */ 3837*3db86aabSstevel if ((pcic->pc_io_type == PCIC_IO_TYPE_YENTA) && 3838*3db86aabSstevel pcic_getcb(pcic, CB_PRESENT_STATE) & 3839*3db86aabSstevel CB_PS_33VCARD) { 3840*3db86aabSstevel /* 3841*3db86aabSstevel * This is actually a 3.3V card. 3842*3db86aabSstevel * Solaris Card Services 3843*3db86aabSstevel * doesn't understand 3.3V 3844*3db86aabSstevel * so we cheat and change 3845*3db86aabSstevel * the setting to the one appropriate to 3.3V. 3846*3db86aabSstevel * Note that this is the entry number 3847*3db86aabSstevel * in the pcic_power[] array. 3848*3db86aabSstevel */ 3849*3db86aabSstevel sockp->pcs_vcc = PCIC_VCC_3VLEVEL; 3850*3db86aabSstevel } else 3851*3db86aabSstevel sockp->pcs_vcc = socket->VccLevel; 3852*3db86aabSstevel break; 3853*3db86aabSstevel default: 3854*3db86aabSstevel return (BAD_VCC); 3855*3db86aabSstevel } 3856*3db86aabSstevel 3857*3db86aabSstevel /* enable Vcc */ 3858*3db86aabSstevel powerlevel = POWER_CARD_ENABLE; 3859*3db86aabSstevel 3860*3db86aabSstevel #if defined(PCIC_DEBUG) 3861*3db86aabSstevel if (pcic_debug) { 3862*3db86aabSstevel cmn_err(CE_CONT, "\tVcc=%d powerlevel=%x\n", 3863*3db86aabSstevel socket->VccLevel, powerlevel); 3864*3db86aabSstevel } 3865*3db86aabSstevel #endif 3866*3db86aabSstevel ind = 0; /* default index to 0 power */ 3867*3db86aabSstevel if ((int)socket->Vpp1Level >= 0 && 3868*3db86aabSstevel socket->Vpp1Level < pcic->pc_numpower) { 3869*3db86aabSstevel if (!(pcic_power[socket->Vpp1Level].ValidSignals 3870*3db86aabSstevel & VPP1)) { 3871*3db86aabSstevel return (BAD_VPP); 3872*3db86aabSstevel } 3873*3db86aabSstevel ind = pcic_power[socket->Vpp1Level].PowerLevel/10; 3874*3db86aabSstevel powerlevel |= pcic_vpp_levels[ind]; 3875*3db86aabSstevel sockp->pcs_vpp1 = socket->Vpp1Level; 3876*3db86aabSstevel } 3877*3db86aabSstevel if ((int)socket->Vpp2Level >= 0 && 3878*3db86aabSstevel socket->Vpp2Level < pcic->pc_numpower) { 3879*3db86aabSstevel if (!(pcic_power[socket->Vpp2Level].ValidSignals 3880*3db86aabSstevel & VPP2)) { 3881*3db86aabSstevel return (BAD_VPP); 3882*3db86aabSstevel } 3883*3db86aabSstevel ind = pcic_power[socket->Vpp2Level].PowerLevel/10; 3884*3db86aabSstevel powerlevel |= (pcic_vpp_levels[ind] << 2); 3885*3db86aabSstevel sockp->pcs_vpp2 = socket->Vpp2Level; 3886*3db86aabSstevel } 3887*3db86aabSstevel 3888*3db86aabSstevel if (pcic->pc_flags & PCF_VPPX) { 3889*3db86aabSstevel /* 3890*3db86aabSstevel * this adapter doesn't allow separate Vpp1/Vpp2 3891*3db86aabSstevel * if one is turned on, both are turned on and only 3892*3db86aabSstevel * the Vpp1 bits should be set 3893*3db86aabSstevel */ 3894*3db86aabSstevel if (sockp->pcs_vpp2 != sockp->pcs_vpp1) { 3895*3db86aabSstevel /* must be the same if one not zero */ 3896*3db86aabSstevel if (sockp->pcs_vpp1 != 0 && 3897*3db86aabSstevel sockp->pcs_vpp2 != 0) { 3898*3db86aabSstevel cmn_err(CE_WARN, 3899*3db86aabSstevel "%s%d: Bad Power Request " 3900*3db86aabSstevel "(Vpp1/2 not the same)\n", 3901*3db86aabSstevel ddi_get_name(pcic->dip), 3902*3db86aabSstevel ddi_get_instance(pcic->dip)); 3903*3db86aabSstevel return (BAD_VPP); 3904*3db86aabSstevel } 3905*3db86aabSstevel } 3906*3db86aabSstevel powerlevel &= ~(3<<2); 3907*3db86aabSstevel } 3908*3db86aabSstevel 3909*3db86aabSstevel #if defined(PCIC_DEBUG) 3910*3db86aabSstevel if (pcic_debug) { 3911*3db86aabSstevel cmn_err(CE_CONT, "\tpowerlevel=%x, ind=%x\n", 3912*3db86aabSstevel powerlevel, ind); 3913*3db86aabSstevel } 3914*3db86aabSstevel #endif 3915*3db86aabSstevel } 3916*3db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 3917*3db86aabSstevel 3918*3db86aabSstevel /* turn socket->IREQRouting off while programming */ 3919*3db86aabSstevel interrupt = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT); 3920*3db86aabSstevel interrupt &= ~PCIC_INTR_MASK; 3921*3db86aabSstevel if (pcic->pc_flags & PCF_USE_SMI) 3922*3db86aabSstevel interrupt |= PCIC_INTR_ENABLE; 3923*3db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, interrupt); 3924*3db86aabSstevel 3925*3db86aabSstevel switch (pcic->pc_type) { 3926*3db86aabSstevel case PCIC_INTEL_i82092: 3927*3db86aabSstevel pcic_82092_smiirq_ctl(pcic, socket->socket, PCIC_82092_CTL_IRQ, 3928*3db86aabSstevel PCIC_82092_INT_DISABLE); 3929*3db86aabSstevel break; 3930*3db86aabSstevel default: 3931*3db86aabSstevel break; 3932*3db86aabSstevel } /* switch */ 3933*3db86aabSstevel 3934*3db86aabSstevel /* the SCIntMask specifies events to detect */ 3935*3db86aabSstevel mirq = pcic_getb(pcic, socket->socket, PCIC_MANAGEMENT_INT); 3936*3db86aabSstevel 3937*3db86aabSstevel #if defined(PCIC_DEBUG) 3938*3db86aabSstevel if (pcic_debug) 3939*3db86aabSstevel cmn_err(CE_CONT, 3940*3db86aabSstevel "\tSCIntMask=%x, interrupt=%x, mirq=%x\n", 3941*3db86aabSstevel socket->SCIntMask, interrupt, mirq); 3942*3db86aabSstevel #endif 3943*3db86aabSstevel mirq &= ~(PCIC_BD_DETECT|PCIC_BW_DETECT|PCIC_RD_DETECT); 3944*3db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MANAGEMENT_INT, 3945*3db86aabSstevel mirq & ~PCIC_CHANGE_MASK); 3946*3db86aabSstevel 3947*3db86aabSstevel /* save the mask we want to use */ 3948*3db86aabSstevel sockp->pcs_intmask = socket->SCIntMask; 3949*3db86aabSstevel 3950*3db86aabSstevel /* 3951*3db86aabSstevel * Until there is a card present it's not worth enabling 3952*3db86aabSstevel * any interrupts except "Card detect". This is done 3953*3db86aabSstevel * elsewhere in the driver so don't change things if 3954*3db86aabSstevel * there is no card! 3955*3db86aabSstevel */ 3956*3db86aabSstevel if (sockp->pcs_flags & PCS_CARD_PRESENT) { 3957*3db86aabSstevel 3958*3db86aabSstevel /* now update the hardware to reflect events desired */ 3959*3db86aabSstevel if (sockp->pcs_intmask & SBM_BVD1 || socket->IFType == IF_IO) 3960*3db86aabSstevel mirq |= PCIC_BD_DETECT; 3961*3db86aabSstevel 3962*3db86aabSstevel if (sockp->pcs_intmask & SBM_BVD2) 3963*3db86aabSstevel mirq |= PCIC_BW_DETECT; 3964*3db86aabSstevel 3965*3db86aabSstevel if (sockp->pcs_intmask & SBM_RDYBSY) 3966*3db86aabSstevel mirq |= PCIC_RD_DETECT; 3967*3db86aabSstevel 3968*3db86aabSstevel if (sockp->pcs_intmask & SBM_CD) 3969*3db86aabSstevel mirq |= PCIC_CD_DETECT; 3970*3db86aabSstevel } 3971*3db86aabSstevel 3972*3db86aabSstevel if (sockp->pcs_flags & PCS_READY) { 3973*3db86aabSstevel /* 3974*3db86aabSstevel * card just came ready. 3975*3db86aabSstevel * make sure enough time elapses 3976*3db86aabSstevel * before touching it. 3977*3db86aabSstevel */ 3978*3db86aabSstevel sockp->pcs_flags &= ~PCS_READY; 3979*3db86aabSstevel pcic_mswait(pcic, socket->socket, 10); 3980*3db86aabSstevel } 3981*3db86aabSstevel 3982*3db86aabSstevel #if defined(PCIC_DEBUG) 3983*3db86aabSstevel if (pcic_debug) { 3984*3db86aabSstevel cmn_err(CE_CONT, "\tstatus change set to %x\n", mirq); 3985*3db86aabSstevel } 3986*3db86aabSstevel #endif 3987*3db86aabSstevel 3988*3db86aabSstevel switch (pcic->pc_type) { 3989*3db86aabSstevel case PCIC_I82365SL: 3990*3db86aabSstevel case PCIC_VADEM: 3991*3db86aabSstevel case PCIC_VADEM_VG469: 3992*3db86aabSstevel /* 3993*3db86aabSstevel * The Intel version has different options. This is a 3994*3db86aabSstevel * special case of GPI which might be used for eject 3995*3db86aabSstevel */ 3996*3db86aabSstevel 3997*3db86aabSstevel irq = pcic_getb(pcic, socket->socket, PCIC_CARD_DETECT); 3998*3db86aabSstevel if (sockp->pcs_intmask & (SBM_EJECT|SBM_INSERT) && 3999*3db86aabSstevel pcic->pc_flags & PCF_GPI_EJECT) { 4000*3db86aabSstevel irq |= PCIC_GPI_ENABLE; 4001*3db86aabSstevel } else { 4002*3db86aabSstevel irq &= ~PCIC_GPI_ENABLE; 4003*3db86aabSstevel } 4004*3db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_CARD_DETECT, irq); 4005*3db86aabSstevel break; 4006*3db86aabSstevel case PCIC_CL_PD6710: 4007*3db86aabSstevel case PCIC_CL_PD6722: 4008*3db86aabSstevel if (socket->IFType == IF_IO) { 4009*3db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_2, 0x0); 4010*3db86aabSstevel value = pcic_getb(pcic, socket->socket, 4011*3db86aabSstevel PCIC_MISC_CTL_1); 4012*3db86aabSstevel if (pcic->pc_flags & PCF_AUDIO) 4013*3db86aabSstevel value |= PCIC_MC_SPEAKER_ENB; 4014*3db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1, 4015*3db86aabSstevel value); 4016*3db86aabSstevel } else { 4017*3db86aabSstevel value = pcic_getb(pcic, socket->socket, 4018*3db86aabSstevel PCIC_MISC_CTL_1); 4019*3db86aabSstevel value &= ~PCIC_MC_SPEAKER_ENB; 4020*3db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1, 4021*3db86aabSstevel value); 4022*3db86aabSstevel } 4023*3db86aabSstevel break; 4024*3db86aabSstevel case PCIC_CL_PD6729: 4025*3db86aabSstevel case PCIC_CL_PD6730: 4026*3db86aabSstevel case PCIC_CL_PD6832: 4027*3db86aabSstevel value = pcic_getb(pcic, socket->socket, PCIC_MISC_CTL_1); 4028*3db86aabSstevel if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) { 4029*3db86aabSstevel value |= PCIC_MC_SPEAKER_ENB; 4030*3db86aabSstevel } else { 4031*3db86aabSstevel value &= ~PCIC_MC_SPEAKER_ENB; 4032*3db86aabSstevel } 4033*3db86aabSstevel 4034*3db86aabSstevel if (pcic_power[sockp->pcs_vcc].PowerLevel == 33) 4035*3db86aabSstevel value |= PCIC_MC_3VCC; 4036*3db86aabSstevel else 4037*3db86aabSstevel value &= ~PCIC_MC_3VCC; 4038*3db86aabSstevel 4039*3db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1, value); 4040*3db86aabSstevel break; 4041*3db86aabSstevel 4042*3db86aabSstevel case PCIC_O2_OZ6912: 4043*3db86aabSstevel value = pcic_getcb(pcic, CB_MISCCTRL); 4044*3db86aabSstevel if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) 4045*3db86aabSstevel value |= (1<<25); 4046*3db86aabSstevel else 4047*3db86aabSstevel value &= ~(1<<25); 4048*3db86aabSstevel pcic_putcb(pcic, CB_MISCCTRL, value); 4049*3db86aabSstevel if (pcic_power[sockp->pcs_vcc].PowerLevel == 33) 4050*3db86aabSstevel powerlevel |= 0x08; 4051*3db86aabSstevel break; 4052*3db86aabSstevel 4053*3db86aabSstevel case PCIC_TI_PCI1250: 4054*3db86aabSstevel case PCIC_TI_PCI1221: 4055*3db86aabSstevel case PCIC_TI_PCI1225: 4056*3db86aabSstevel case PCIC_TI_PCI1410: 4057*3db86aabSstevel case PCIC_ENE_1410: 4058*3db86aabSstevel case PCIC_TI_PCI1510: 4059*3db86aabSstevel case PCIC_TI_PCI1520: 4060*3db86aabSstevel case PCIC_TI_PCI1420: 4061*3db86aabSstevel case PCIC_ENE_1420: 4062*3db86aabSstevel value = ddi_get8(pcic->cfg_handle, 4063*3db86aabSstevel pcic->cfgaddr + PCIC_CRDCTL_REG); 4064*3db86aabSstevel if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) { 4065*3db86aabSstevel value |= PCIC_CRDCTL_SPKR_ENBL; 4066*3db86aabSstevel } else { 4067*3db86aabSstevel value &= ~PCIC_CRDCTL_SPKR_ENBL; 4068*3db86aabSstevel } 4069*3db86aabSstevel ddi_put8(pcic->cfg_handle, 4070*3db86aabSstevel pcic->cfgaddr + PCIC_CRDCTL_REG, value); 4071*3db86aabSstevel if (pcic_power[sockp->pcs_vcc].PowerLevel == 33) 4072*3db86aabSstevel powerlevel |= 0x08; 4073*3db86aabSstevel break; 4074*3db86aabSstevel } 4075*3db86aabSstevel 4076*3db86aabSstevel /* 4077*3db86aabSstevel * ctlind processing -- we can ignore this 4078*3db86aabSstevel * there aren't any outputs on the chip for this and 4079*3db86aabSstevel * the GUI will display what it thinks is correct 4080*3db86aabSstevel */ 4081*3db86aabSstevel 4082*3db86aabSstevel /* 4083*3db86aabSstevel * If outputs are enabled and the power is going off 4084*3db86aabSstevel * turn off outputs first. 4085*3db86aabSstevel */ 4086*3db86aabSstevel 4087*3db86aabSstevel /* power setup -- if necessary */ 4088*3db86aabSstevel orig_pwrctl = pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL); 4089*3db86aabSstevel if ((orig_pwrctl & POWER_OUTPUT_ENABLE) && sockp->pcs_vcc == 0) { 4090*3db86aabSstevel orig_pwrctl &= ~POWER_OUTPUT_ENABLE; 4091*3db86aabSstevel pcic_putb(pcic, socket->socket, 4092*3db86aabSstevel PCIC_POWER_CONTROL, orig_pwrctl); 4093*3db86aabSstevel (void) pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL); 4094*3db86aabSstevel } 4095*3db86aabSstevel 4096*3db86aabSstevel if (pcic->pc_flags & PCF_CBPWRCTL) { 4097*3db86aabSstevel value = pcic_cbus_powerctl(pcic, socket->socket); 4098*3db86aabSstevel powerlevel = 0; 4099*3db86aabSstevel } else 4100*3db86aabSstevel value = pcic_exca_powerctl(pcic, socket->socket, powerlevel); 4101*3db86aabSstevel 4102*3db86aabSstevel if (value != SUCCESS) { 4103*3db86aabSstevel mutex_exit(&pcic->pc_lock); 4104*3db86aabSstevel return (value); 4105*3db86aabSstevel } 4106*3db86aabSstevel 4107*3db86aabSstevel /* 4108*3db86aabSstevel * If outputs were disabled and the power is going on 4109*3db86aabSstevel * turn on outputs afterwards. 4110*3db86aabSstevel */ 4111*3db86aabSstevel if (!(orig_pwrctl & POWER_OUTPUT_ENABLE) && sockp->pcs_vcc != 0) { 4112*3db86aabSstevel orig_pwrctl = pcic_getb(pcic, socket->socket, 4113*3db86aabSstevel PCIC_POWER_CONTROL); 4114*3db86aabSstevel orig_pwrctl |= POWER_OUTPUT_ENABLE; 4115*3db86aabSstevel pcic_putb(pcic, socket->socket, 4116*3db86aabSstevel PCIC_POWER_CONTROL, orig_pwrctl); 4117*3db86aabSstevel (void) pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL); 4118*3db86aabSstevel } 4119*3db86aabSstevel 4120*3db86aabSstevel /* 4121*3db86aabSstevel * Once we have done the power stuff can re-enable management 4122*3db86aabSstevel * interrupts. 4123*3db86aabSstevel */ 4124*3db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MANAGEMENT_INT, mirq); 4125*3db86aabSstevel 4126*3db86aabSstevel #if defined(PCIC_DEBUG) 4127*3db86aabSstevel pcic_err(dip, 8, "\tmanagement int set to %x pwrctl to 0x%x " 4128*3db86aabSstevel "cbctl 0x%x\n", 4129*3db86aabSstevel mirq, pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL), 4130*3db86aabSstevel pcic_getcb(pcic, CB_CONTROL)); 4131*3db86aabSstevel #endif 4132*3db86aabSstevel 4133*3db86aabSstevel /* irq processing */ 4134*3db86aabSstevel if (socket->IFType == IF_IO) { 4135*3db86aabSstevel /* IRQ only for I/O */ 4136*3db86aabSstevel irq = socket->IREQRouting & PCIC_INTR_MASK; 4137*3db86aabSstevel value = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT); 4138*3db86aabSstevel value &= ~PCIC_INTR_MASK; 4139*3db86aabSstevel 4140*3db86aabSstevel /* to enable I/O operation */ 4141*3db86aabSstevel value |= PCIC_IO_CARD | PCIC_RESET; 4142*3db86aabSstevel sockp->pcs_flags |= PCS_CARD_IO; 4143*3db86aabSstevel if (irq != sockp->pcs_irq) { 4144*3db86aabSstevel if (sockp->pcs_irq != 0) 4145*3db86aabSstevel cmn_err(CE_CONT, 4146*3db86aabSstevel "SetSocket: IRQ mismatch %x != %x!\n", 4147*3db86aabSstevel irq, sockp->pcs_irq); 4148*3db86aabSstevel else 4149*3db86aabSstevel sockp->pcs_irq = irq; 4150*3db86aabSstevel } 4151*3db86aabSstevel irq = sockp->pcs_irq; 4152*3db86aabSstevel 4153*3db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, value); 4154*3db86aabSstevel if (socket->IREQRouting & IRQ_ENABLE) { 4155*3db86aabSstevel pcic_enable_io_intr(pcic, socket->socket, irq); 4156*3db86aabSstevel sockp->pcs_flags |= PCS_IRQ_ENABLED; 4157*3db86aabSstevel } else { 4158*3db86aabSstevel pcic_disable_io_intr(pcic, socket->socket); 4159*3db86aabSstevel sockp->pcs_flags &= ~PCS_IRQ_ENABLED; 4160*3db86aabSstevel } 4161*3db86aabSstevel #if defined(PCIC_DEBUG) 4162*3db86aabSstevel if (pcic_debug) { 4163*3db86aabSstevel cmn_err(CE_CONT, 4164*3db86aabSstevel "\tsocket type is I/O and irq %x is %s\n", irq, 4165*3db86aabSstevel (socket->IREQRouting & IRQ_ENABLE) ? 4166*3db86aabSstevel "enabled" : "not enabled"); 4167*3db86aabSstevel xxdmp_all_regs(pcic, socket->socket, 20); 4168*3db86aabSstevel } 4169*3db86aabSstevel #endif 4170*3db86aabSstevel } else { 4171*3db86aabSstevel /* make sure I/O mode is off */ 4172*3db86aabSstevel 4173*3db86aabSstevel sockp->pcs_irq = 0; 4174*3db86aabSstevel 4175*3db86aabSstevel value = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT); 4176*3db86aabSstevel value &= ~PCIC_IO_CARD; 4177*3db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, value); 4178*3db86aabSstevel pcic_disable_io_intr(pcic, socket->socket); 4179*3db86aabSstevel sockp->pcs_flags &= ~(PCS_CARD_IO|PCS_IRQ_ENABLED); 4180*3db86aabSstevel } 4181*3db86aabSstevel 4182*3db86aabSstevel sockp->pcs_state &= ~socket->State; 4183*3db86aabSstevel 4184*3db86aabSstevel mutex_exit(&pcic->pc_lock); 4185*3db86aabSstevel return (SUCCESS); 4186*3db86aabSstevel } 4187*3db86aabSstevel 4188*3db86aabSstevel /* 4189*3db86aabSstevel * pcic_inquire_socket() 4190*3db86aabSstevel * SocketServices InquireSocket function 4191*3db86aabSstevel * returns basic characteristics of the socket 4192*3db86aabSstevel */ 4193*3db86aabSstevel /*ARGSUSED*/ 4194*3db86aabSstevel static int 4195*3db86aabSstevel pcic_inquire_socket(dev_info_t *dip, inquire_socket_t *socket) 4196*3db86aabSstevel { 4197*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 4198*3db86aabSstevel pcicdev_t *pcic = anp->an_private; 4199*3db86aabSstevel int value; 4200*3db86aabSstevel 4201*3db86aabSstevel socket->SCIntCaps = PCIC_DEFAULT_INT_CAPS; 4202*3db86aabSstevel socket->SCRptCaps = PCIC_DEFAULT_RPT_CAPS; 4203*3db86aabSstevel socket->CtlIndCaps = PCIC_DEFAULT_CTL_CAPS; 4204*3db86aabSstevel value = pcic->pc_sockets[socket->socket].pcs_flags; 4205*3db86aabSstevel socket->SocketCaps = (value & PCS_SOCKET_IO) ? IF_IO : IF_MEMORY; 4206*3db86aabSstevel socket->ActiveHigh = 0; 4207*3db86aabSstevel /* these are the usable IRQs */ 4208*3db86aabSstevel socket->ActiveLow = 0xfff0; 4209*3db86aabSstevel return (SUCCESS); 4210*3db86aabSstevel } 4211*3db86aabSstevel 4212*3db86aabSstevel /* 4213*3db86aabSstevel * pcic_inquire_window() 4214*3db86aabSstevel * SocketServices InquireWindow function 4215*3db86aabSstevel * returns detailed characteristics of the window 4216*3db86aabSstevel * this is where windows get tied to sockets 4217*3db86aabSstevel */ 4218*3db86aabSstevel /*ARGSUSED*/ 4219*3db86aabSstevel static int 4220*3db86aabSstevel pcic_inquire_window(dev_info_t *dip, inquire_window_t *window) 4221*3db86aabSstevel { 4222*3db86aabSstevel int type, socket; 4223*3db86aabSstevel 4224*3db86aabSstevel type = window->window % PCIC_NUMWINSOCK; 4225*3db86aabSstevel socket = window->window / PCIC_NUMWINSOCK; 4226*3db86aabSstevel 4227*3db86aabSstevel #if defined(PCIC_DEBUG) 4228*3db86aabSstevel if (pcic_debug >= 8) 4229*3db86aabSstevel cmn_err(CE_CONT, 4230*3db86aabSstevel "pcic_inquire_window: window = %d/%d socket=%d\n", 4231*3db86aabSstevel window->window, type, socket); 4232*3db86aabSstevel #endif 4233*3db86aabSstevel if (type < PCIC_IOWINDOWS) { 4234*3db86aabSstevel window->WndCaps = WC_IO|WC_WAIT; 4235*3db86aabSstevel type = IF_IO; 4236*3db86aabSstevel } else { 4237*3db86aabSstevel window->WndCaps = WC_COMMON|WC_ATTRIBUTE|WC_WAIT; 4238*3db86aabSstevel type = IF_MEMORY; 4239*3db86aabSstevel } 4240*3db86aabSstevel 4241*3db86aabSstevel /* initialize the socket map - one socket per window */ 4242*3db86aabSstevel PR_ZERO(window->Sockets); 4243*3db86aabSstevel PR_SET(window->Sockets, socket); 4244*3db86aabSstevel 4245*3db86aabSstevel if (type == IF_IO) { 4246*3db86aabSstevel iowin_char_t *io; 4247*3db86aabSstevel io = &window->iowin_char; 4248*3db86aabSstevel io->IOWndCaps = WC_BASE|WC_SIZE|WC_WENABLE|WC_8BIT| 4249*3db86aabSstevel WC_16BIT; 4250*3db86aabSstevel io->FirstByte = (baseaddr_t)IOMEM_FIRST; 4251*3db86aabSstevel io->LastByte = (baseaddr_t)IOMEM_LAST; 4252*3db86aabSstevel io->MinSize = IOMEM_MIN; 4253*3db86aabSstevel io->MaxSize = IOMEM_MAX; 4254*3db86aabSstevel io->ReqGran = IOMEM_GRAN; 4255*3db86aabSstevel io->AddrLines = IOMEM_DECODE; 4256*3db86aabSstevel io->EISASlot = 0; 4257*3db86aabSstevel } else { 4258*3db86aabSstevel mem_win_char_t *mem; 4259*3db86aabSstevel mem = &window->mem_win_char; 4260*3db86aabSstevel mem->MemWndCaps = WC_BASE|WC_SIZE|WC_WENABLE|WC_8BIT| 4261*3db86aabSstevel WC_16BIT|WC_WP; 4262*3db86aabSstevel 4263*3db86aabSstevel mem->FirstByte = (baseaddr_t)MEM_FIRST; 4264*3db86aabSstevel mem->LastByte = (baseaddr_t)MEM_LAST; 4265*3db86aabSstevel 4266*3db86aabSstevel mem->MinSize = MEM_MIN; 4267*3db86aabSstevel mem->MaxSize = MEM_MAX; 4268*3db86aabSstevel mem->ReqGran = PCIC_PAGE; 4269*3db86aabSstevel mem->ReqBase = 0; 4270*3db86aabSstevel mem->ReqOffset = PCIC_PAGE; 4271*3db86aabSstevel mem->Slowest = MEM_SPEED_MAX; 4272*3db86aabSstevel mem->Fastest = MEM_SPEED_MIN; 4273*3db86aabSstevel } 4274*3db86aabSstevel return (SUCCESS); 4275*3db86aabSstevel } 4276*3db86aabSstevel 4277*3db86aabSstevel /* 4278*3db86aabSstevel * pcic_get_adapter() 4279*3db86aabSstevel * SocketServices GetAdapter function 4280*3db86aabSstevel * this is nearly a no-op. 4281*3db86aabSstevel */ 4282*3db86aabSstevel /*ARGSUSED*/ 4283*3db86aabSstevel static int 4284*3db86aabSstevel pcic_get_adapter(dev_info_t *dip, get_adapter_t *adapt) 4285*3db86aabSstevel { 4286*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 4287*3db86aabSstevel pcicdev_t *pcic = anp->an_private; 4288*3db86aabSstevel 4289*3db86aabSstevel if (pcic->pc_flags & PCF_INTRENAB) 4290*3db86aabSstevel adapt->SCRouting = IRQ_ENABLE; 4291*3db86aabSstevel adapt->state = 0; 4292*3db86aabSstevel return (SUCCESS); 4293*3db86aabSstevel } 4294*3db86aabSstevel 4295*3db86aabSstevel /* 4296*3db86aabSstevel * pcic_get_page() 4297*3db86aabSstevel * SocketServices GetPage function 4298*3db86aabSstevel * returns info about the window 4299*3db86aabSstevel */ 4300*3db86aabSstevel /*ARGSUSED*/ 4301*3db86aabSstevel static int 4302*3db86aabSstevel pcic_get_page(dev_info_t *dip, get_page_t *page) 4303*3db86aabSstevel { 4304*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 4305*3db86aabSstevel pcicdev_t *pcic = anp->an_private; 4306*3db86aabSstevel int socket, window; 4307*3db86aabSstevel pcs_memwin_t *winp; 4308*3db86aabSstevel 4309*3db86aabSstevel socket = page->window / PCIC_NUMWINSOCK; 4310*3db86aabSstevel window = page->window % PCIC_NUMWINSOCK; 4311*3db86aabSstevel 4312*3db86aabSstevel /* I/O windows are the first two */ 4313*3db86aabSstevel if (window < PCIC_IOWINDOWS || socket >= pcic->pc_numsockets) { 4314*3db86aabSstevel return (BAD_WINDOW); 4315*3db86aabSstevel } 4316*3db86aabSstevel 4317*3db86aabSstevel winp = &pcic->pc_sockets[socket].pcs_windows[window].mem; 4318*3db86aabSstevel 4319*3db86aabSstevel if (page->page != 0) 4320*3db86aabSstevel return (BAD_PAGE); 4321*3db86aabSstevel 4322*3db86aabSstevel page->state = 0; 4323*3db86aabSstevel if (winp->pcw_status & PCW_ENABLED) 4324*3db86aabSstevel page->state |= PS_ENABLED; 4325*3db86aabSstevel if (winp->pcw_status & PCW_ATTRIBUTE) 4326*3db86aabSstevel page->state |= PS_ATTRIBUTE; 4327*3db86aabSstevel if (winp->pcw_status & PCW_WP) 4328*3db86aabSstevel page->state |= PS_WP; 4329*3db86aabSstevel 4330*3db86aabSstevel page->offset = (off_t)winp->pcw_offset; 4331*3db86aabSstevel 4332*3db86aabSstevel return (SUCCESS); 4333*3db86aabSstevel } 4334*3db86aabSstevel 4335*3db86aabSstevel /* 4336*3db86aabSstevel * pcic_get_socket() 4337*3db86aabSstevel * SocketServices GetSocket 4338*3db86aabSstevel * returns information about the current socket setting 4339*3db86aabSstevel */ 4340*3db86aabSstevel /*ARGSUSED*/ 4341*3db86aabSstevel static int 4342*3db86aabSstevel pcic_get_socket(dev_info_t *dip, get_socket_t *socket) 4343*3db86aabSstevel { 4344*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 4345*3db86aabSstevel pcicdev_t *pcic = anp->an_private; 4346*3db86aabSstevel int socknum, irq_enabled; 4347*3db86aabSstevel pcic_socket_t *sockp; 4348*3db86aabSstevel 4349*3db86aabSstevel socknum = socket->socket; 4350*3db86aabSstevel sockp = &pcic->pc_sockets[socknum]; 4351*3db86aabSstevel 4352*3db86aabSstevel socket->SCIntMask = sockp->pcs_intmask; 4353*3db86aabSstevel sockp->pcs_state = pcic_card_state(pcic, sockp); 4354*3db86aabSstevel 4355*3db86aabSstevel socket->state = sockp->pcs_state; 4356*3db86aabSstevel if (socket->state & SBM_CD) { 4357*3db86aabSstevel socket->VccLevel = sockp->pcs_vcc; 4358*3db86aabSstevel socket->Vpp1Level = sockp->pcs_vpp1; 4359*3db86aabSstevel socket->Vpp2Level = sockp->pcs_vpp2; 4360*3db86aabSstevel irq_enabled = (sockp->pcs_flags & PCS_IRQ_ENABLED) ? 4361*3db86aabSstevel IRQ_ENABLE : 0; 4362*3db86aabSstevel socket->IRQRouting = sockp->pcs_irq | irq_enabled; 4363*3db86aabSstevel socket->IFType = (sockp->pcs_flags & PCS_CARD_IO) ? 4364*3db86aabSstevel IF_IO : IF_MEMORY; 4365*3db86aabSstevel } else { 4366*3db86aabSstevel socket->VccLevel = 0; 4367*3db86aabSstevel socket->Vpp1Level = 0; 4368*3db86aabSstevel socket->Vpp2Level = 0; 4369*3db86aabSstevel socket->IRQRouting = 0; 4370*3db86aabSstevel socket->IFType = IF_MEMORY; 4371*3db86aabSstevel } 4372*3db86aabSstevel socket->CtlInd = 0; /* no indicators */ 4373*3db86aabSstevel 4374*3db86aabSstevel return (SUCCESS); 4375*3db86aabSstevel } 4376*3db86aabSstevel 4377*3db86aabSstevel /* 4378*3db86aabSstevel * pcic_get_status() 4379*3db86aabSstevel * SocketServices GetStatus 4380*3db86aabSstevel * returns status information about the PC Card in 4381*3db86aabSstevel * the selected socket 4382*3db86aabSstevel */ 4383*3db86aabSstevel /*ARGSUSED*/ 4384*3db86aabSstevel static int 4385*3db86aabSstevel pcic_get_status(dev_info_t *dip, get_ss_status_t *status) 4386*3db86aabSstevel { 4387*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 4388*3db86aabSstevel pcicdev_t *pcic = anp->an_private; 4389*3db86aabSstevel int socknum, irq_enabled; 4390*3db86aabSstevel pcic_socket_t *sockp; 4391*3db86aabSstevel 4392*3db86aabSstevel socknum = status->socket; 4393*3db86aabSstevel sockp = &pcic->pc_sockets[socknum]; 4394*3db86aabSstevel 4395*3db86aabSstevel status->CardState = pcic_card_state(pcic, sockp); 4396*3db86aabSstevel status->SocketState = sockp->pcs_state; 4397*3db86aabSstevel status->CtlInd = 0; /* no indicators */ 4398*3db86aabSstevel 4399*3db86aabSstevel if (sockp->pcs_flags & PCS_CARD_PRESENT) 4400*3db86aabSstevel status->SocketState |= SBM_CD; 4401*3db86aabSstevel if (status->CardState & SBM_CD) { 4402*3db86aabSstevel irq_enabled = (sockp->pcs_flags & PCS_CARD_ENABLED) ? 4403*3db86aabSstevel IRQ_ENABLE : 0; 4404*3db86aabSstevel status->IRQRouting = sockp->pcs_irq | irq_enabled; 4405*3db86aabSstevel status->IFType = (sockp->pcs_flags & PCS_CARD_IO) ? 4406*3db86aabSstevel IF_IO : IF_MEMORY; 4407*3db86aabSstevel } else { 4408*3db86aabSstevel status->IRQRouting = 0; 4409*3db86aabSstevel status->IFType = IF_MEMORY; 4410*3db86aabSstevel } 4411*3db86aabSstevel 4412*3db86aabSstevel #if defined(PCIC_DEBUG) 4413*3db86aabSstevel if (pcic_debug >= 8) 4414*3db86aabSstevel cmn_err(CE_CONT, "pcic_get_status: socket=%d, CardState=%x," 4415*3db86aabSstevel "SocketState=%x\n", 4416*3db86aabSstevel socknum, status->CardState, status->SocketState); 4417*3db86aabSstevel #endif 4418*3db86aabSstevel switch (pcic->pc_type) { 4419*3db86aabSstevel uint32_t present_state; 4420*3db86aabSstevel case PCIC_TI_PCI1410: 4421*3db86aabSstevel case PCIC_TI_PCI1520: 4422*3db86aabSstevel case PCIC_TI_PCI1420: 4423*3db86aabSstevel case PCIC_ENE_1420: 4424*3db86aabSstevel case PCIC_TOSHIBA_TOPIC100: 4425*3db86aabSstevel case PCIC_TOSHIBA_TOPIC95: 4426*3db86aabSstevel case PCIC_TOSHIBA_VENDOR: 4427*3db86aabSstevel case PCIC_O2MICRO_VENDOR: 4428*3db86aabSstevel case PCIC_TI_VENDOR: 4429*3db86aabSstevel case PCIC_RICOH_VENDOR: 4430*3db86aabSstevel present_state = pcic_getcb(pcic, CB_PRESENT_STATE); 4431*3db86aabSstevel if (present_state & PCIC_CB_CARD) 4432*3db86aabSstevel status->IFType = IF_CARDBUS; 4433*3db86aabSstevel #if defined(PCIC_DEBUG) 4434*3db86aabSstevel if (pcic_debug >= 8) 4435*3db86aabSstevel cmn_err(CE_CONT, "pcic_get_status: present_state=0x%x\n", 4436*3db86aabSstevel present_state); 4437*3db86aabSstevel #endif 4438*3db86aabSstevel break; 4439*3db86aabSstevel default: 4440*3db86aabSstevel break; 4441*3db86aabSstevel } 4442*3db86aabSstevel 4443*3db86aabSstevel return (SUCCESS); 4444*3db86aabSstevel } 4445*3db86aabSstevel 4446*3db86aabSstevel /* 4447*3db86aabSstevel * pcic_get_window() 4448*3db86aabSstevel * SocketServices GetWindow function 4449*3db86aabSstevel * returns state information about the specified window 4450*3db86aabSstevel */ 4451*3db86aabSstevel /*ARGSUSED*/ 4452*3db86aabSstevel static int 4453*3db86aabSstevel pcic_get_window(dev_info_t *dip, get_window_t *window) 4454*3db86aabSstevel { 4455*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 4456*3db86aabSstevel pcicdev_t *pcic = anp->an_private; 4457*3db86aabSstevel int socket, win; 4458*3db86aabSstevel pcic_socket_t *sockp; 4459*3db86aabSstevel pcs_memwin_t *winp; 4460*3db86aabSstevel 4461*3db86aabSstevel socket = window->window / PCIC_NUMWINSOCK; 4462*3db86aabSstevel win = window->window % PCIC_NUMWINSOCK; 4463*3db86aabSstevel #if defined(PCIC_DEBUG) 4464*3db86aabSstevel if (pcic_debug) { 4465*3db86aabSstevel cmn_err(CE_CONT, "pcic_get_window(socket=%d, window=%d)\n", 4466*3db86aabSstevel socket, win); 4467*3db86aabSstevel } 4468*3db86aabSstevel #endif 4469*3db86aabSstevel 4470*3db86aabSstevel if (socket > pcic->pc_numsockets) 4471*3db86aabSstevel return (BAD_WINDOW); 4472*3db86aabSstevel 4473*3db86aabSstevel sockp = &pcic->pc_sockets[socket]; 4474*3db86aabSstevel winp = &sockp->pcs_windows[win].mem; 4475*3db86aabSstevel 4476*3db86aabSstevel window->socket = socket; 4477*3db86aabSstevel window->size = winp->pcw_len; 4478*3db86aabSstevel window->speed = winp->pcw_speed; 4479*3db86aabSstevel window->handle = (ddi_acc_handle_t)winp->pcw_handle; 4480*3db86aabSstevel window->base = (uint32_t)winp->pcw_base + winp->pcw_offset; 4481*3db86aabSstevel 4482*3db86aabSstevel if (win >= PCIC_IOWINDOWS) { 4483*3db86aabSstevel window->state = 0; 4484*3db86aabSstevel } else { 4485*3db86aabSstevel window->state = WS_IO; 4486*3db86aabSstevel } 4487*3db86aabSstevel if (winp->pcw_status & PCW_ENABLED) 4488*3db86aabSstevel window->state |= WS_ENABLED; 4489*3db86aabSstevel 4490*3db86aabSstevel if (winp->pcw_status & PCS_CARD_16BIT) 4491*3db86aabSstevel window->state |= WS_16BIT; 4492*3db86aabSstevel #if defined(PCIC_DEBUG) 4493*3db86aabSstevel if (pcic_debug) 4494*3db86aabSstevel cmn_err(CE_CONT, "\tsize=%d, speed=%d, base=%p, state=%x\n", 4495*3db86aabSstevel window->size, (unsigned)window->speed, 4496*3db86aabSstevel (void *)window->handle, window->state); 4497*3db86aabSstevel #endif 4498*3db86aabSstevel 4499*3db86aabSstevel return (SUCCESS); 4500*3db86aabSstevel } 4501*3db86aabSstevel 4502*3db86aabSstevel /* 4503*3db86aabSstevel * pcic_ll_reset 4504*3db86aabSstevel * low level reset 4505*3db86aabSstevel * separated out so it can be called when already locked 4506*3db86aabSstevel * 4507*3db86aabSstevel * There are two variables that control the RESET timing: 4508*3db86aabSstevel * pcic_prereset_time - time in mS before asserting RESET 4509*3db86aabSstevel * pcic_reset_time - time in mS to assert RESET 4510*3db86aabSstevel * 4511*3db86aabSstevel */ 4512*3db86aabSstevel int pcic_prereset_time = 1; 4513*3db86aabSstevel int pcic_reset_time = 10; 4514*3db86aabSstevel int pcic_postreset_time = 20; 4515*3db86aabSstevel int pcic_vpp_is_vcc_during_reset = 0; 4516*3db86aabSstevel 4517*3db86aabSstevel static int 4518*3db86aabSstevel pcic_ll_reset(pcicdev_t *pcic, int socket) 4519*3db86aabSstevel { 4520*3db86aabSstevel int windowbits, iobits; 4521*3db86aabSstevel uint32_t pwr; 4522*3db86aabSstevel 4523*3db86aabSstevel /* save windows that were on */ 4524*3db86aabSstevel windowbits = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE); 4525*3db86aabSstevel if (pcic_reset_time == 0) 4526*3db86aabSstevel return (windowbits); 4527*3db86aabSstevel /* turn all windows off */ 4528*3db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, 0); 4529*3db86aabSstevel 4530*3db86aabSstevel #if defined(PCIC_DEBUG) 4531*3db86aabSstevel pcic_err(pcic->dip, 6, 4532*3db86aabSstevel "pcic_ll_reset(socket %d) powerlevel=%x cbctl 0x%x cbps 0x%x\n", 4533*3db86aabSstevel socket, pcic_getb(pcic, socket, PCIC_POWER_CONTROL), 4534*3db86aabSstevel pcic_getcb(pcic, CB_CONTROL), 4535*3db86aabSstevel pcic_getcb(pcic, CB_PRESENT_STATE)); 4536*3db86aabSstevel #endif 4537*3db86aabSstevel 4538*3db86aabSstevel if (pcic_vpp_is_vcc_during_reset) { 4539*3db86aabSstevel 4540*3db86aabSstevel /* 4541*3db86aabSstevel * Set VPP to VCC for the duration of the reset - for aironet 4542*3db86aabSstevel * card. 4543*3db86aabSstevel */ 4544*3db86aabSstevel if (pcic->pc_flags & PCF_CBPWRCTL) { 4545*3db86aabSstevel pwr = pcic_getcb(pcic, CB_CONTROL); 4546*3db86aabSstevel pcic_putcb(pcic, CB_CONTROL, (pwr&~CB_C_VPPMASK)|CB_C_VPPVCC); 4547*3db86aabSstevel (void) pcic_getcb(pcic, CB_CONTROL); 4548*3db86aabSstevel } else { 4549*3db86aabSstevel pwr = pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 4550*3db86aabSstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, 4551*3db86aabSstevel pwr | 1); 4552*3db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 4553*3db86aabSstevel } 4554*3db86aabSstevel } 4555*3db86aabSstevel 4556*3db86aabSstevel if (pcic_prereset_time > 0) { 4557*3db86aabSstevel pcic_err(pcic->dip, 8, "pcic_ll_reset pre_wait %d mS\n", 4558*3db86aabSstevel pcic_prereset_time); 4559*3db86aabSstevel pcic_mswait(pcic, socket, pcic_prereset_time); 4560*3db86aabSstevel } 4561*3db86aabSstevel 4562*3db86aabSstevel /* turn interrupts off and start a reset */ 4563*3db86aabSstevel pcic_err(pcic->dip, 8, 4564*3db86aabSstevel "pcic_ll_reset turn interrupts off and start a reset\n"); 4565*3db86aabSstevel iobits = pcic_getb(pcic, socket, PCIC_INTERRUPT); 4566*3db86aabSstevel iobits &= ~(PCIC_INTR_MASK | PCIC_RESET); 4567*3db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits); 4568*3db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_INTERRUPT); 4569*3db86aabSstevel 4570*3db86aabSstevel switch (pcic->pc_type) { 4571*3db86aabSstevel case PCIC_INTEL_i82092: 4572*3db86aabSstevel pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ, 4573*3db86aabSstevel PCIC_82092_INT_DISABLE); 4574*3db86aabSstevel break; 4575*3db86aabSstevel default: 4576*3db86aabSstevel break; 4577*3db86aabSstevel } /* switch */ 4578*3db86aabSstevel 4579*3db86aabSstevel pcic->pc_sockets[socket].pcs_state = 0; 4580*3db86aabSstevel 4581*3db86aabSstevel if (pcic_reset_time > 0) { 4582*3db86aabSstevel pcic_err(pcic->dip, 8, "pcic_ll_reset reset_wait %d mS\n", 4583*3db86aabSstevel pcic_reset_time); 4584*3db86aabSstevel pcic_mswait(pcic, socket, pcic_reset_time); 4585*3db86aabSstevel } 4586*3db86aabSstevel 4587*3db86aabSstevel pcic_err(pcic->dip, 8, "pcic_ll_reset take it out of reset now\n"); 4588*3db86aabSstevel 4589*3db86aabSstevel /* take it out of RESET now */ 4590*3db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, PCIC_RESET | iobits); 4591*3db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_INTERRUPT); 4592*3db86aabSstevel 4593*3db86aabSstevel /* 4594*3db86aabSstevel * can't access the card for 20ms, but we really don't 4595*3db86aabSstevel * want to sit around that long. The pcic is still usable. 4596*3db86aabSstevel * memory accesses must wait for RDY to come up. 4597*3db86aabSstevel */ 4598*3db86aabSstevel if (pcic_postreset_time > 0) { 4599*3db86aabSstevel pcic_err(pcic->dip, 8, "pcic_ll_reset post_wait %d mS\n", 4600*3db86aabSstevel pcic_postreset_time); 4601*3db86aabSstevel pcic_mswait(pcic, socket, pcic_postreset_time); 4602*3db86aabSstevel } 4603*3db86aabSstevel 4604*3db86aabSstevel if (pcic_vpp_is_vcc_during_reset > 1) { 4605*3db86aabSstevel 4606*3db86aabSstevel /* 4607*3db86aabSstevel * Return VPP power to whatever it was before. 4608*3db86aabSstevel */ 4609*3db86aabSstevel if (pcic->pc_flags & PCF_CBPWRCTL) { 4610*3db86aabSstevel pcic_putcb(pcic, CB_CONTROL, pwr); 4611*3db86aabSstevel (void) pcic_getcb(pcic, CB_CONTROL); 4612*3db86aabSstevel } else { 4613*3db86aabSstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, pwr); 4614*3db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 4615*3db86aabSstevel } 4616*3db86aabSstevel } 4617*3db86aabSstevel 4618*3db86aabSstevel pcic_err(pcic->dip, 7, "pcic_ll_reset returning 0x%x\n", windowbits); 4619*3db86aabSstevel 4620*3db86aabSstevel return (windowbits); 4621*3db86aabSstevel } 4622*3db86aabSstevel 4623*3db86aabSstevel /* 4624*3db86aabSstevel * pcic_reset_socket() 4625*3db86aabSstevel * SocketServices ResetSocket function 4626*3db86aabSstevel * puts the PC Card in the socket into the RESET state 4627*3db86aabSstevel * and then takes it out after the the cycle time 4628*3db86aabSstevel * The socket is back to initial state when done 4629*3db86aabSstevel */ 4630*3db86aabSstevel static int 4631*3db86aabSstevel pcic_reset_socket(dev_info_t *dip, int socket, int mode) 4632*3db86aabSstevel { 4633*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 4634*3db86aabSstevel pcicdev_t *pcic = anp->an_private; 4635*3db86aabSstevel int value; 4636*3db86aabSstevel int i, mint; 4637*3db86aabSstevel pcic_socket_t *sockp; 4638*3db86aabSstevel 4639*3db86aabSstevel #if defined(PCIC_DEBUG) 4640*3db86aabSstevel if (pcic_debug >= 8) 4641*3db86aabSstevel cmn_err(CE_CONT, "pcic_reset_socket(%p, %d, %d/%s)\n", 4642*3db86aabSstevel (void *)dip, socket, mode, 4643*3db86aabSstevel mode == RESET_MODE_FULL ? "full" : "partial"); 4644*3db86aabSstevel #endif 4645*3db86aabSstevel 4646*3db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 4647*3db86aabSstevel 4648*3db86aabSstevel /* Turn off management interupts. */ 4649*3db86aabSstevel mint = pcic_getb(pcic, socket, PCIC_MANAGEMENT_INT); 4650*3db86aabSstevel pcic_putb(pcic, socket, PCIC_MANAGEMENT_INT, mint & ~PCIC_CHANGE_MASK); 4651*3db86aabSstevel 4652*3db86aabSstevel sockp = &pcic->pc_sockets[socket]; 4653*3db86aabSstevel 4654*3db86aabSstevel value = pcic_ll_reset(pcic, socket); 4655*3db86aabSstevel if (mode == RESET_MODE_FULL) { 4656*3db86aabSstevel /* disable and unmap all mapped windows */ 4657*3db86aabSstevel for (i = 0; i < PCIC_NUMWINSOCK; i++) { 4658*3db86aabSstevel if (i < PCIC_IOWINDOWS) { 4659*3db86aabSstevel if (sockp->pcs_windows[i].io.pcw_status & 4660*3db86aabSstevel PCW_MAPPED) { 4661*3db86aabSstevel pcs_iowin_t *io; 4662*3db86aabSstevel io = &sockp->pcs_windows[i].io; 4663*3db86aabSstevel io->pcw_status &= ~PCW_ENABLED; 4664*3db86aabSstevel } 4665*3db86aabSstevel } else { 4666*3db86aabSstevel if (sockp->pcs_windows[i].mem.pcw_status & 4667*3db86aabSstevel PCW_MAPPED) { 4668*3db86aabSstevel pcs_memwin_t *mem; 4669*3db86aabSstevel mem = &sockp->pcs_windows[i].mem; 4670*3db86aabSstevel mem->pcw_status &= ~PCW_ENABLED; 4671*3db86aabSstevel } 4672*3db86aabSstevel } 4673*3db86aabSstevel } 4674*3db86aabSstevel } else { 4675*3db86aabSstevel /* turn windows back on */ 4676*3db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, value); 4677*3db86aabSstevel /* wait the rest of the time here */ 4678*3db86aabSstevel pcic_mswait(pcic, socket, 10); 4679*3db86aabSstevel } 4680*3db86aabSstevel pcic_putb(pcic, socket, PCIC_MANAGEMENT_INT, mint); 4681*3db86aabSstevel mutex_exit(&pcic->pc_lock); 4682*3db86aabSstevel return (SUCCESS); 4683*3db86aabSstevel } 4684*3db86aabSstevel 4685*3db86aabSstevel /* 4686*3db86aabSstevel * pcic_set_interrupt() 4687*3db86aabSstevel * SocketServices SetInterrupt function 4688*3db86aabSstevel */ 4689*3db86aabSstevel static int 4690*3db86aabSstevel pcic_set_interrupt(dev_info_t *dip, set_irq_handler_t *handler) 4691*3db86aabSstevel { 4692*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 4693*3db86aabSstevel pcicdev_t *pcic = anp->an_private; 4694*3db86aabSstevel int value = DDI_SUCCESS; 4695*3db86aabSstevel inthandler_t *intr; 4696*3db86aabSstevel 4697*3db86aabSstevel #if defined(PCIC_DEBUG) 4698*3db86aabSstevel if (pcic_debug) { 4699*3db86aabSstevel cmn_err(CE_CONT, 4700*3db86aabSstevel "pcic_set_interrupt: entered pc_intr_mode=0x%x\n", 4701*3db86aabSstevel pcic->pc_intr_mode); 4702*3db86aabSstevel cmn_err(CE_CONT, 4703*3db86aabSstevel "\t irq_top=%p handler=%p handler_id=%x\n", 4704*3db86aabSstevel (void *)pcic->irq_top, (void *)handler->handler, 4705*3db86aabSstevel handler->handler_id); 4706*3db86aabSstevel } 4707*3db86aabSstevel #endif 4708*3db86aabSstevel 4709*3db86aabSstevel /* 4710*3db86aabSstevel * If we're on a PCI bus, we route all IO IRQs through a single 4711*3db86aabSstevel * PCI interrupt (typically INT A#) so we don't have to do 4712*3db86aabSstevel * much other than add the caller to general interrupt handler 4713*3db86aabSstevel * and set some state. 4714*3db86aabSstevel */ 4715*3db86aabSstevel 4716*3db86aabSstevel intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP); 4717*3db86aabSstevel if (intr == NULL) 4718*3db86aabSstevel return (NO_RESOURCE); 4719*3db86aabSstevel 4720*3db86aabSstevel switch (pcic->pc_intr_mode) { 4721*3db86aabSstevel case PCIC_INTR_MODE_PCI_1: 4722*3db86aabSstevel /* 4723*3db86aabSstevel * We only allow above-lock-level IO IRQ handlers 4724*3db86aabSstevel * in the PCI bus case. 4725*3db86aabSstevel */ 4726*3db86aabSstevel 4727*3db86aabSstevel mutex_enter(&pcic->intr_lock); 4728*3db86aabSstevel 4729*3db86aabSstevel if (pcic->irq_top == NULL) { 4730*3db86aabSstevel pcic->irq_top = intr; 4731*3db86aabSstevel pcic->irq_current = pcic->irq_top; 4732*3db86aabSstevel } else { 4733*3db86aabSstevel while (pcic->irq_current->next != NULL) 4734*3db86aabSstevel pcic->irq_current = pcic->irq_current->next; 4735*3db86aabSstevel pcic->irq_current->next = intr; 4736*3db86aabSstevel pcic->irq_current = pcic->irq_current->next; 4737*3db86aabSstevel } 4738*3db86aabSstevel 4739*3db86aabSstevel pcic->irq_current->intr = 4740*3db86aabSstevel (ddi_intr_handler_t *)handler->handler; 4741*3db86aabSstevel pcic->irq_current->handler_id = handler->handler_id; 4742*3db86aabSstevel pcic->irq_current->arg1 = handler->arg1; 4743*3db86aabSstevel pcic->irq_current->arg2 = handler->arg2; 4744*3db86aabSstevel pcic->irq_current->socket = handler->socket; 4745*3db86aabSstevel 4746*3db86aabSstevel mutex_exit(&pcic->intr_lock); 4747*3db86aabSstevel 4748*3db86aabSstevel handler->iblk_cookie = &pcic->pc_pri; 4749*3db86aabSstevel handler->idev_cookie = &pcic->pc_dcookie; 4750*3db86aabSstevel break; 4751*3db86aabSstevel 4752*3db86aabSstevel default: 4753*3db86aabSstevel intr->intr = (ddi_intr_handler_t *)handler->handler; 4754*3db86aabSstevel intr->handler_id = handler->handler_id; 4755*3db86aabSstevel intr->arg1 = handler->arg1; 4756*3db86aabSstevel intr->arg2 = handler->arg2; 4757*3db86aabSstevel intr->socket = handler->socket; 4758*3db86aabSstevel intr->irq = handler->irq; 4759*3db86aabSstevel 4760*3db86aabSstevel /* 4761*3db86aabSstevel * need to revisit this to see if interrupts can be 4762*3db86aabSstevel * shared someday. Note that IRQ is set in the common 4763*3db86aabSstevel * code. 4764*3db86aabSstevel */ 4765*3db86aabSstevel mutex_enter(&pcic->pc_lock); 4766*3db86aabSstevel if (pcic->pc_handlers == NULL) { 4767*3db86aabSstevel pcic->pc_handlers = intr; 4768*3db86aabSstevel intr->next = intr->prev = intr; 4769*3db86aabSstevel } else { 4770*3db86aabSstevel insque(intr, pcic->pc_handlers); 4771*3db86aabSstevel } 4772*3db86aabSstevel mutex_exit(&pcic->pc_lock); 4773*3db86aabSstevel 4774*3db86aabSstevel break; 4775*3db86aabSstevel } 4776*3db86aabSstevel 4777*3db86aabSstevel /* 4778*3db86aabSstevel * need to fill in cookies in event of multiple high priority 4779*3db86aabSstevel * interrupt handlers on same IRQ 4780*3db86aabSstevel */ 4781*3db86aabSstevel 4782*3db86aabSstevel #if defined(PCIC_DEBUG) 4783*3db86aabSstevel if (pcic_debug) { 4784*3db86aabSstevel cmn_err(CE_CONT, 4785*3db86aabSstevel "pcic_set_interrupt: exit irq_top=%p value=%d\n", 4786*3db86aabSstevel (void *)pcic->irq_top, value); 4787*3db86aabSstevel } 4788*3db86aabSstevel #endif 4789*3db86aabSstevel 4790*3db86aabSstevel if (value == DDI_SUCCESS) { 4791*3db86aabSstevel return (SUCCESS); 4792*3db86aabSstevel } else { 4793*3db86aabSstevel return (BAD_IRQ); 4794*3db86aabSstevel } 4795*3db86aabSstevel } 4796*3db86aabSstevel 4797*3db86aabSstevel /* 4798*3db86aabSstevel * pcic_clear_interrupt() 4799*3db86aabSstevel * SocketServices ClearInterrupt function 4800*3db86aabSstevel * 4801*3db86aabSstevel * Interrupts for PCIC are complicated by the fact that we must 4802*3db86aabSstevel * follow several different models for interrupts. 4803*3db86aabSstevel * ISA: there is an interrupt per adapter and per socket and 4804*3db86aabSstevel * they can't be shared. 4805*3db86aabSstevel * PCI: some adapters have one PCI interrupt available while others 4806*3db86aabSstevel * have up to 4. Solaris may or may not allow us to use more 4807*3db86aabSstevel * than 1 so we essentially share them all at this point. 4808*3db86aabSstevel * Hybrid: PCI bridge but interrupts wired to host interrupt controller. 4809*3db86aabSstevel * This is like ISA but we have to fudge and create an intrspec 4810*3db86aabSstevel * that PCI's parent understands and bypass the PCI nexus. 4811*3db86aabSstevel * multifunction: this requires sharing the interrupts on a per-socket 4812*3db86aabSstevel * basis. 4813*3db86aabSstevel */ 4814*3db86aabSstevel static int 4815*3db86aabSstevel pcic_clear_interrupt(dev_info_t *dip, clear_irq_handler_t *handler) 4816*3db86aabSstevel { 4817*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 4818*3db86aabSstevel pcicdev_t *pcic = anp->an_private; 4819*3db86aabSstevel inthandler_t *intr, *prev, *current; 4820*3db86aabSstevel int i; 4821*3db86aabSstevel 4822*3db86aabSstevel /* 4823*3db86aabSstevel * If we're on a PCI bus, we route all IO IRQs through a single 4824*3db86aabSstevel * PCI interrupt (typically INT A#) so we don't have to do 4825*3db86aabSstevel * much other than remove the caller from the general 4826*3db86aabSstevel * interrupt handler callout list. 4827*3db86aabSstevel */ 4828*3db86aabSstevel 4829*3db86aabSstevel #if defined(PCIC_DEBUG) 4830*3db86aabSstevel if (pcic_debug) { 4831*3db86aabSstevel cmn_err(CE_CONT, 4832*3db86aabSstevel "pcic_clear_interrupt: entered pc_intr_mode=0x%x\n", 4833*3db86aabSstevel pcic->pc_intr_mode); 4834*3db86aabSstevel cmn_err(CE_CONT, 4835*3db86aabSstevel "\t irq_top=%p handler=%p handler_id=%x\n", 4836*3db86aabSstevel (void *)pcic->irq_top, (void *)handler->handler, 4837*3db86aabSstevel handler->handler_id); 4838*3db86aabSstevel } 4839*3db86aabSstevel #endif 4840*3db86aabSstevel 4841*3db86aabSstevel switch (pcic->pc_intr_mode) { 4842*3db86aabSstevel case PCIC_INTR_MODE_PCI_1: 4843*3db86aabSstevel 4844*3db86aabSstevel mutex_enter(&pcic->intr_lock); 4845*3db86aabSstevel if (pcic->irq_top == NULL) { 4846*3db86aabSstevel mutex_exit(&pcic->intr_lock); 4847*3db86aabSstevel return (BAD_IRQ); 4848*3db86aabSstevel } 4849*3db86aabSstevel 4850*3db86aabSstevel intr = NULL; 4851*3db86aabSstevel pcic->irq_current = pcic->irq_top; 4852*3db86aabSstevel 4853*3db86aabSstevel while ((pcic->irq_current != NULL) && 4854*3db86aabSstevel (pcic->irq_current->handler_id != 4855*3db86aabSstevel handler->handler_id)) { 4856*3db86aabSstevel intr = pcic->irq_current; 4857*3db86aabSstevel pcic->irq_current = pcic->irq_current->next; 4858*3db86aabSstevel } 4859*3db86aabSstevel 4860*3db86aabSstevel if (pcic->irq_current == NULL) { 4861*3db86aabSstevel mutex_exit(&pcic->intr_lock); 4862*3db86aabSstevel return (BAD_IRQ); 4863*3db86aabSstevel } 4864*3db86aabSstevel 4865*3db86aabSstevel if (intr != NULL) { 4866*3db86aabSstevel intr->next = pcic->irq_current->next; 4867*3db86aabSstevel } else { 4868*3db86aabSstevel pcic->irq_top = pcic->irq_current->next; 4869*3db86aabSstevel } 4870*3db86aabSstevel 4871*3db86aabSstevel current = pcic->irq_current; 4872*3db86aabSstevel pcic->irq_current = pcic->irq_top; 4873*3db86aabSstevel mutex_exit(&pcic->intr_lock); 4874*3db86aabSstevel kmem_free(current, sizeof (inthandler_t)); 4875*3db86aabSstevel 4876*3db86aabSstevel break; 4877*3db86aabSstevel 4878*3db86aabSstevel default: 4879*3db86aabSstevel 4880*3db86aabSstevel mutex_enter(&pcic->pc_lock); 4881*3db86aabSstevel intr = pcic_handlers; 4882*3db86aabSstevel prev = (inthandler_t *)&pcic_handlers; 4883*3db86aabSstevel 4884*3db86aabSstevel while (intr != NULL) { 4885*3db86aabSstevel if (intr->handler_id == handler->handler_id) { 4886*3db86aabSstevel i = intr->irq & PCIC_INTR_MASK; 4887*3db86aabSstevel if (--pcic_irq_map[i].count == 0) { 4888*3db86aabSstevel /* multi-handler form */ 4889*3db86aabSstevel (void) ddi_intr_disable(pcic->pc_intr_htblp[i]); 4890*3db86aabSstevel (void) ddi_intr_remove_handler( 4891*3db86aabSstevel pcic->pc_intr_htblp[i]); 4892*3db86aabSstevel (void) ddi_intr_free(pcic->pc_intr_htblp[i]); 4893*3db86aabSstevel (void) pcmcia_return_intr(pcic->dip, i); 4894*3db86aabSstevel #if defined(PCIC_DEBUG) 4895*3db86aabSstevel if (pcic_debug) { 4896*3db86aabSstevel cmn_err(CE_CONT, 4897*3db86aabSstevel "removing interrupt %d at %s " 4898*3db86aabSstevel "priority\n", i, "high"); 4899*3db86aabSstevel cmn_err(CE_CONT, 4900*3db86aabSstevel "ddi_remove_intr(%p, %x, %p)\n", 4901*3db86aabSstevel (void *)dip, 4902*3db86aabSstevel 0, 4903*3db86aabSstevel (void *)intr->iblk_cookie); 4904*3db86aabSstevel } 4905*3db86aabSstevel #endif 4906*3db86aabSstevel } 4907*3db86aabSstevel prev->next = intr->next; 4908*3db86aabSstevel kmem_free(intr, sizeof (inthandler_t)); 4909*3db86aabSstevel intr = prev->next; 4910*3db86aabSstevel } else { 4911*3db86aabSstevel prev = intr; 4912*3db86aabSstevel intr = intr->next; 4913*3db86aabSstevel } /* if (handler_id) */ 4914*3db86aabSstevel } /* while */ 4915*3db86aabSstevel 4916*3db86aabSstevel mutex_exit(&pcic->pc_lock); 4917*3db86aabSstevel } 4918*3db86aabSstevel 4919*3db86aabSstevel #if defined(PCIC_DEBUG) 4920*3db86aabSstevel if (pcic_debug) { 4921*3db86aabSstevel cmn_err(CE_CONT, 4922*3db86aabSstevel "pcic_clear_interrupt: exit irq_top=%p\n", 4923*3db86aabSstevel (void *)pcic->irq_top); 4924*3db86aabSstevel } 4925*3db86aabSstevel #endif 4926*3db86aabSstevel 4927*3db86aabSstevel 4928*3db86aabSstevel return (SUCCESS); 4929*3db86aabSstevel } 4930*3db86aabSstevel 4931*3db86aabSstevel struct intel_regs { 4932*3db86aabSstevel char *name; 4933*3db86aabSstevel int off; 4934*3db86aabSstevel char *fmt; 4935*3db86aabSstevel } iregs[] = { 4936*3db86aabSstevel {"ident ", 0}, 4937*3db86aabSstevel {"if-status ", 1, "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI"}, 4938*3db86aabSstevel {"power ", 2, "\020\1Vpp1c0\2Vpp1c1\3Vpp2c0\4Vpp2c1\5PE\6AUTO" 4939*3db86aabSstevel "\7DRD\10OE"}, 4940*3db86aabSstevel {"cardstatus", 4, "\020\1BD\2BW\3RC\4CD\5GPI\6R1\7R2\010R3"}, 4941*3db86aabSstevel {"enable ", 6, "\020\1MW0\2MW1\3MW2\4MW3\5MW4\6MEM16\7IO0\10IO1"}, 4942*3db86aabSstevel {"cd-gcr ", 0x16, "\020\1MDI16\2CRE\3GPIE\4GPIT\5CDR\6S/W"}, 4943*3db86aabSstevel {"GCR ", 0x1e, "\020\1PD\2LEVEL\3WCSC\4PLS14"}, 4944*3db86aabSstevel {"int-gcr ", 3, "\020\5INTR\6IO\7~RST\10RI"}, 4945*3db86aabSstevel {"management", 5, "\020\1BDE\2BWE\3RE\4CDE"}, 4946*3db86aabSstevel {"volt-sense", 0x1f, "\020\1A_VS1\2A_VS2\3B_VS1\4B_VS2"}, 4947*3db86aabSstevel {"volt-sel ", 0x2f, "\020\5EXTCONF\6BUSSELECT\7MIXEDV\10ISAV"}, 4948*3db86aabSstevel {"VG ext A ", 0x3c, "\20\3IVS\4CABLE\5CSTEP\6TEST\7RIO"}, 4949*3db86aabSstevel {"io-ctrl ", 7, "\020\1DS0\2IOCS0\3ZWS0\4WS0\5DS1\6IOS1\7ZWS1\10WS1"}, 4950*3db86aabSstevel {"io0-slow ", 8}, 4951*3db86aabSstevel {"io0-shi ", 9}, 4952*3db86aabSstevel {"io0-elow ", 0xa}, 4953*3db86aabSstevel {"io0-ehi ", 0xb}, 4954*3db86aabSstevel {"io1-slow ", 0xc}, 4955*3db86aabSstevel {"io1-shi ", 0xd}, 4956*3db86aabSstevel {"io1-elow ", 0xe}, 4957*3db86aabSstevel {"io1-ehi ", 0xf}, 4958*3db86aabSstevel {"mem0-slow ", 0x10}, 4959*3db86aabSstevel {"mem0-shi ", 0x11, "\020\7ZW\10DS"}, 4960*3db86aabSstevel {"mem0-elow ", 0x12}, 4961*3db86aabSstevel {"mem0-ehi ", 0x13, "\020\7WS0\10WS1"}, 4962*3db86aabSstevel {"card0-low ", 0x14}, 4963*3db86aabSstevel {"card0-hi ", 0x15, "\020\7AM\10WP"}, 4964*3db86aabSstevel {"mem1-slow ", 0x18}, 4965*3db86aabSstevel {"mem1-shi ", 0x19, "\020\7ZW\10DS"}, 4966*3db86aabSstevel {"mem1-elow ", 0x1a}, 4967*3db86aabSstevel {"mem1-ehi ", 0x1b, "\020\7WS0\10WS1"}, 4968*3db86aabSstevel {"card1-low ", 0x1c}, 4969*3db86aabSstevel {"card1-hi ", 0x1d, "\020\7AM\10WP"}, 4970*3db86aabSstevel {"mem2-slow ", 0x20}, 4971*3db86aabSstevel {"mem2-shi ", 0x21, "\020\7ZW\10DS"}, 4972*3db86aabSstevel {"mem2-elow ", 0x22}, 4973*3db86aabSstevel {"mem2-ehi ", 0x23, "\020\7WS0\10WS1"}, 4974*3db86aabSstevel {"card2-low ", 0x24}, 4975*3db86aabSstevel {"card2-hi ", 0x25, "\020\7AM\10WP"}, 4976*3db86aabSstevel {"mem3-slow ", 0x28}, 4977*3db86aabSstevel {"mem3-shi ", 0x29, "\020\7ZW\10DS"}, 4978*3db86aabSstevel {"mem3-elow ", 0x2a}, 4979*3db86aabSstevel {"mem3-ehi ", 0x2b, "\020\7WS0\10WS1"}, 4980*3db86aabSstevel {"card3-low ", 0x2c}, 4981*3db86aabSstevel {"card3-hi ", 0x2d, "\020\7AM\10WP"}, 4982*3db86aabSstevel 4983*3db86aabSstevel {"mem4-slow ", 0x30}, 4984*3db86aabSstevel {"mem4-shi ", 0x31, "\020\7ZW\10DS"}, 4985*3db86aabSstevel {"mem4-elow ", 0x32}, 4986*3db86aabSstevel {"mem4-ehi ", 0x33, "\020\7WS0\10WS1"}, 4987*3db86aabSstevel {"card4-low ", 0x34}, 4988*3db86aabSstevel {"card4-hi ", 0x35, "\020\7AM\10WP"}, 4989*3db86aabSstevel {"mpage0 ", 0x40}, 4990*3db86aabSstevel {"mpage1 ", 0x41}, 4991*3db86aabSstevel {"mpage2 ", 0x42}, 4992*3db86aabSstevel {"mpage3 ", 0x43}, 4993*3db86aabSstevel {"mpage4 ", 0x44}, 4994*3db86aabSstevel {NULL}, 4995*3db86aabSstevel }; 4996*3db86aabSstevel 4997*3db86aabSstevel static struct intel_regs cregs[] = { 4998*3db86aabSstevel {"misc-ctl1 ", 0x16, "\20\2VCC3\3PMI\4PSI\5SPKR\10INPACK"}, 4999*3db86aabSstevel {"fifo ", 0x17, "\20\6DIOP\7DMEMP\10EMPTY"}, 5000*3db86aabSstevel {"misc-ctl2 ", 0x1e, "\20\1XCLK\2LOW\3SUSP\4CORE5V\5TCD\10RIOUT"}, 5001*3db86aabSstevel {"chip-info ", 0x1f, "\20\6DUAL"}, 5002*3db86aabSstevel {"IO-offlow0", 0x36}, 5003*3db86aabSstevel {"IO-offhi0 ", 0x37}, 5004*3db86aabSstevel {"IO-offlow1", 0x38}, 5005*3db86aabSstevel {"IO-offhi1 ", 0x39}, 5006*3db86aabSstevel NULL, 5007*3db86aabSstevel }; 5008*3db86aabSstevel 5009*3db86aabSstevel static struct intel_regs cxregs[] = { 5010*3db86aabSstevel {"ext-ctl-1 ", 0x03, 5011*3db86aabSstevel "\20\1VCCLCK\2AUTOCLR\3LED\4INVIRQC\5INVIRQM\6PUC"}, 5012*3db86aabSstevel {"misc-ctl3 ", 0x25, "\20\5HWSUSP"}, 5013*3db86aabSstevel {"mem0-up ", 0x05}, 5014*3db86aabSstevel {"mem1-up ", 0x06}, 5015*3db86aabSstevel {"mem2-up ", 0x07}, 5016*3db86aabSstevel {"mem3-up ", 0x08}, 5017*3db86aabSstevel {"mem4-up ", 0x09}, 5018*3db86aabSstevel {NULL} 5019*3db86aabSstevel }; 5020*3db86aabSstevel 5021*3db86aabSstevel void 5022*3db86aabSstevel xxdmp_cl_regs(pcicdev_t *pcic, int socket, uint32_t len) 5023*3db86aabSstevel { 5024*3db86aabSstevel int i, value, j; 5025*3db86aabSstevel char buff[256]; 5026*3db86aabSstevel char *fmt; 5027*3db86aabSstevel 5028*3db86aabSstevel cmn_err(CE_CONT, "--------- Cirrus Logic Registers --------\n"); 5029*3db86aabSstevel for (buff[0] = '\0', i = 0; cregs[i].name != NULL && len-- != 0; i++) { 5030*3db86aabSstevel int sval; 5031*3db86aabSstevel if (cregs[i].off == PCIC_MISC_CTL_2) 5032*3db86aabSstevel sval = 0; 5033*3db86aabSstevel else 5034*3db86aabSstevel sval = socket; 5035*3db86aabSstevel value = pcic_getb(pcic, sval, cregs[i].off); 5036*3db86aabSstevel if (i & 1) { 5037*3db86aabSstevel if (cregs[i].fmt) 5038*3db86aabSstevel fmt = "%s\t%s\t%b\n"; 5039*3db86aabSstevel else 5040*3db86aabSstevel fmt = "%s\t%s\t%x\n"; 5041*3db86aabSstevel cmn_err(CE_CONT, fmt, buff, 5042*3db86aabSstevel cregs[i].name, value, cregs[i].fmt); 5043*3db86aabSstevel buff[0] = '\0'; 5044*3db86aabSstevel } else { 5045*3db86aabSstevel if (cregs[i].fmt) 5046*3db86aabSstevel fmt = "\t%s\t%b"; 5047*3db86aabSstevel else 5048*3db86aabSstevel fmt = "\t%s\t%x"; 5049*3db86aabSstevel (void) sprintf(buff, fmt, 5050*3db86aabSstevel cregs[i].name, value, cregs[i].fmt); 5051*3db86aabSstevel for (j = strlen(buff); j < 40; j++) 5052*3db86aabSstevel buff[j] = ' '; 5053*3db86aabSstevel buff[40] = '\0'; 5054*3db86aabSstevel } 5055*3db86aabSstevel } 5056*3db86aabSstevel cmn_err(CE_CONT, "%s\n", buff); 5057*3db86aabSstevel 5058*3db86aabSstevel i = pcic_getb(pcic, socket, PCIC_TIME_SETUP_0); 5059*3db86aabSstevel j = pcic_getb(pcic, socket, PCIC_TIME_SETUP_1); 5060*3db86aabSstevel cmn_err(CE_CONT, "\tsetup-tim0\t%x\tsetup-tim1\t%x\n", i, j); 5061*3db86aabSstevel 5062*3db86aabSstevel i = pcic_getb(pcic, socket, PCIC_TIME_COMMAND_0); 5063*3db86aabSstevel j = pcic_getb(pcic, socket, PCIC_TIME_COMMAND_1); 5064*3db86aabSstevel cmn_err(CE_CONT, "\tcmd-tim0 \t%x\tcmd-tim1 \t%x\n", i, j); 5065*3db86aabSstevel 5066*3db86aabSstevel i = pcic_getb(pcic, socket, PCIC_TIME_RECOVER_0); 5067*3db86aabSstevel j = pcic_getb(pcic, socket, PCIC_TIME_RECOVER_1); 5068*3db86aabSstevel cmn_err(CE_CONT, "\trcvr-tim0 \t%x\trcvr-tim1 \t%x\n", i, j); 5069*3db86aabSstevel 5070*3db86aabSstevel cmn_err(CE_CONT, "--------- Extended Registers --------\n"); 5071*3db86aabSstevel 5072*3db86aabSstevel for (buff[0] = '\0', i = 0; cxregs[i].name != NULL && len-- != 0; i++) { 5073*3db86aabSstevel value = clext_reg_read(pcic, socket, cxregs[i].off); 5074*3db86aabSstevel if (i & 1) { 5075*3db86aabSstevel if (cxregs[i].fmt) 5076*3db86aabSstevel fmt = "%s\t%s\t%b\n"; 5077*3db86aabSstevel else 5078*3db86aabSstevel fmt = "%s\t%s\t%x\n"; 5079*3db86aabSstevel cmn_err(CE_CONT, fmt, buff, 5080*3db86aabSstevel cxregs[i].name, value, cxregs[i].fmt); 5081*3db86aabSstevel buff[0] = '\0'; 5082*3db86aabSstevel } else { 5083*3db86aabSstevel if (cxregs[i].fmt) 5084*3db86aabSstevel fmt = "\t%s\t%b"; 5085*3db86aabSstevel else 5086*3db86aabSstevel fmt = "\t%s\t%x"; 5087*3db86aabSstevel (void) sprintf(buff, fmt, 5088*3db86aabSstevel cxregs[i].name, value, cxregs[i].fmt); 5089*3db86aabSstevel for (j = strlen(buff); j < 40; j++) 5090*3db86aabSstevel buff[j] = ' '; 5091*3db86aabSstevel buff[40] = '\0'; 5092*3db86aabSstevel } 5093*3db86aabSstevel } 5094*3db86aabSstevel } 5095*3db86aabSstevel 5096*3db86aabSstevel #if defined(PCIC_DEBUG) 5097*3db86aabSstevel static void 5098*3db86aabSstevel xxdmp_all_regs(pcicdev_t *pcic, int socket, uint32_t len) 5099*3db86aabSstevel { 5100*3db86aabSstevel int i, value, j; 5101*3db86aabSstevel char buff[256]; 5102*3db86aabSstevel char *fmt; 5103*3db86aabSstevel 5104*3db86aabSstevel #if defined(PCIC_DEBUG) 5105*3db86aabSstevel if (pcic_debug < 2) 5106*3db86aabSstevel return; 5107*3db86aabSstevel #endif 5108*3db86aabSstevel cmn_err(CE_CONT, 5109*3db86aabSstevel "----------- PCIC Registers for socket %d---------\n", 5110*3db86aabSstevel socket); 5111*3db86aabSstevel cmn_err(CE_CONT, 5112*3db86aabSstevel "\tname value name value\n"); 5113*3db86aabSstevel 5114*3db86aabSstevel for (buff[0] = '\0', i = 0; iregs[i].name != NULL && len-- != 0; i++) { 5115*3db86aabSstevel value = pcic_getb(pcic, socket, iregs[i].off); 5116*3db86aabSstevel if (i & 1) { 5117*3db86aabSstevel if (iregs[i].fmt) 5118*3db86aabSstevel fmt = "%s\t%s\t%b\n"; 5119*3db86aabSstevel else 5120*3db86aabSstevel fmt = "%s\t%s\t%x\n"; 5121*3db86aabSstevel cmn_err(CE_CONT, fmt, buff, 5122*3db86aabSstevel iregs[i].name, value, iregs[i].fmt); 5123*3db86aabSstevel buff[0] = '\0'; 5124*3db86aabSstevel } else { 5125*3db86aabSstevel if (iregs[i].fmt) 5126*3db86aabSstevel fmt = "\t%s\t%b"; 5127*3db86aabSstevel else 5128*3db86aabSstevel fmt = "\t%s\t%x"; 5129*3db86aabSstevel (void) sprintf(buff, fmt, 5130*3db86aabSstevel iregs[i].name, value, iregs[i].fmt); 5131*3db86aabSstevel for (j = strlen(buff); j < 40; j++) 5132*3db86aabSstevel buff[j] = ' '; 5133*3db86aabSstevel buff[40] = '\0'; 5134*3db86aabSstevel } 5135*3db86aabSstevel } 5136*3db86aabSstevel switch (pcic->pc_type) { 5137*3db86aabSstevel case PCIC_CL_PD6710: 5138*3db86aabSstevel case PCIC_CL_PD6722: 5139*3db86aabSstevel case PCIC_CL_PD6729: 5140*3db86aabSstevel case PCIC_CL_PD6832: 5141*3db86aabSstevel (void) xxdmp_cl_regs(pcic, socket, 0xFFFF); 5142*3db86aabSstevel break; 5143*3db86aabSstevel } 5144*3db86aabSstevel cmn_err(CE_CONT, "%s\n", buff); 5145*3db86aabSstevel } 5146*3db86aabSstevel #endif 5147*3db86aabSstevel 5148*3db86aabSstevel /* 5149*3db86aabSstevel * pcic_mswait(ms) 5150*3db86aabSstevel * sleep ms milliseconds 5151*3db86aabSstevel * call drv_usecwait once for each ms 5152*3db86aabSstevel */ 5153*3db86aabSstevel static void 5154*3db86aabSstevel pcic_mswait(pcicdev_t *pcic, int socket, int ms) 5155*3db86aabSstevel { 5156*3db86aabSstevel if (ms) { 5157*3db86aabSstevel pcic->pc_sockets[socket].pcs_flags |= PCS_WAITING; 5158*3db86aabSstevel pcic_mutex_exit(&pcic->pc_lock); 5159*3db86aabSstevel delay(drv_usectohz(ms*1000)); 5160*3db86aabSstevel pcic_mutex_enter(&pcic->pc_lock); 5161*3db86aabSstevel pcic->pc_sockets[socket].pcs_flags &= ~PCS_WAITING; 5162*3db86aabSstevel } 5163*3db86aabSstevel } 5164*3db86aabSstevel 5165*3db86aabSstevel /* 5166*3db86aabSstevel * pcic_check_ready(pcic, index, off) 5167*3db86aabSstevel * Wait for card to come ready 5168*3db86aabSstevel * We only wait if the card is NOT in RESET 5169*3db86aabSstevel * and power is on. 5170*3db86aabSstevel */ 5171*3db86aabSstevel static boolean_t 5172*3db86aabSstevel pcic_check_ready(pcicdev_t *pcic, int socket) 5173*3db86aabSstevel { 5174*3db86aabSstevel int ifstate, intstate; 5175*3db86aabSstevel 5176*3db86aabSstevel intstate = pcic_getb(pcic, socket, PCIC_INTERRUPT); 5177*3db86aabSstevel ifstate = pcic_getb(pcic, socket, PCIC_INTERFACE_STATUS); 5178*3db86aabSstevel 5179*3db86aabSstevel if ((intstate & PCIC_RESET) && 5180*3db86aabSstevel ((ifstate & (PCIC_READY|PCIC_POWER_ON|PCIC_ISTAT_CD_MASK)) == 5181*3db86aabSstevel (PCIC_READY|PCIC_POWER_ON|PCIC_CD_PRESENT_OK))) 5182*3db86aabSstevel return (B_TRUE); 5183*3db86aabSstevel 5184*3db86aabSstevel #ifdef PCIC_DEBUG 5185*3db86aabSstevel pcic_err(NULL, 5, "pcic_check_read: Card not ready, intstate = 0x%x, " 5186*3db86aabSstevel "ifstate = 0x%x\n", intstate, ifstate); 5187*3db86aabSstevel if (pcic_debug) { 5188*3db86aabSstevel pcic_debug += 4; 5189*3db86aabSstevel xxdmp_all_regs(pcic, socket, -1); 5190*3db86aabSstevel pcic_debug -= 4; 5191*3db86aabSstevel } 5192*3db86aabSstevel #endif 5193*3db86aabSstevel return (B_FALSE); 5194*3db86aabSstevel } 5195*3db86aabSstevel 5196*3db86aabSstevel /* 5197*3db86aabSstevel * Cirrus Logic extended register read/write routines 5198*3db86aabSstevel */ 5199*3db86aabSstevel static int 5200*3db86aabSstevel clext_reg_read(pcicdev_t *pcic, int sn, uchar_t ext_reg) 5201*3db86aabSstevel { 5202*3db86aabSstevel int val; 5203*3db86aabSstevel 5204*3db86aabSstevel switch (pcic->pc_io_type) { 5205*3db86aabSstevel case PCIC_IO_TYPE_YENTA: 5206*3db86aabSstevel val = ddi_get8(pcic->handle, 5207*3db86aabSstevel pcic->ioaddr + CB_CLEXT_OFFSET + ext_reg); 5208*3db86aabSstevel break; 5209*3db86aabSstevel default: 5210*3db86aabSstevel pcic_putb(pcic, sn, PCIC_CL_EXINDEX, ext_reg); 5211*3db86aabSstevel val = pcic_getb(pcic, sn, PCIC_CL_EXINDEX + 1); 5212*3db86aabSstevel break; 5213*3db86aabSstevel } 5214*3db86aabSstevel 5215*3db86aabSstevel return (val); 5216*3db86aabSstevel } 5217*3db86aabSstevel 5218*3db86aabSstevel static void 5219*3db86aabSstevel clext_reg_write(pcicdev_t *pcic, int sn, uchar_t ext_reg, uchar_t value) 5220*3db86aabSstevel { 5221*3db86aabSstevel switch (pcic->pc_io_type) { 5222*3db86aabSstevel case PCIC_IO_TYPE_YENTA: 5223*3db86aabSstevel ddi_put8(pcic->handle, 5224*3db86aabSstevel pcic->ioaddr + CB_CLEXT_OFFSET + ext_reg, value); 5225*3db86aabSstevel break; 5226*3db86aabSstevel default: 5227*3db86aabSstevel pcic_putb(pcic, sn, PCIC_CL_EXINDEX, ext_reg); 5228*3db86aabSstevel pcic_putb(pcic, sn, PCIC_CL_EXINDEX + 1, value); 5229*3db86aabSstevel break; 5230*3db86aabSstevel } 5231*3db86aabSstevel } 5232*3db86aabSstevel 5233*3db86aabSstevel /* 5234*3db86aabSstevel * Misc PCI functions 5235*3db86aabSstevel */ 5236*3db86aabSstevel static void 5237*3db86aabSstevel pcic_iomem_pci_ctl(ddi_acc_handle_t handle, uchar_t *cfgaddr, unsigned flags) 5238*3db86aabSstevel { 5239*3db86aabSstevel unsigned cmd; 5240*3db86aabSstevel 5241*3db86aabSstevel if (flags & (PCIC_ENABLE_IO | PCIC_ENABLE_MEM)) { 5242*3db86aabSstevel cmd = ddi_get16(handle, (ushort_t *)(cfgaddr + 4)); 5243*3db86aabSstevel if ((cmd & (PCI_COMM_IO|PCI_COMM_MAE)) == 5244*3db86aabSstevel (PCI_COMM_IO|PCI_COMM_MAE)) 5245*3db86aabSstevel return; 5246*3db86aabSstevel 5247*3db86aabSstevel if (flags & PCIC_ENABLE_IO) 5248*3db86aabSstevel cmd |= PCI_COMM_IO; 5249*3db86aabSstevel 5250*3db86aabSstevel if (flags & PCIC_ENABLE_MEM) 5251*3db86aabSstevel cmd |= PCI_COMM_MAE; 5252*3db86aabSstevel 5253*3db86aabSstevel ddi_put16(handle, (ushort_t *)(cfgaddr + 4), cmd); 5254*3db86aabSstevel } /* if (PCIC_ENABLE_IO | PCIC_ENABLE_MEM) */ 5255*3db86aabSstevel } 5256*3db86aabSstevel 5257*3db86aabSstevel /* 5258*3db86aabSstevel * pcic_find_pci_type - Find and return PCI-PCMCIA adapter type 5259*3db86aabSstevel */ 5260*3db86aabSstevel static int 5261*3db86aabSstevel pcic_find_pci_type(pcicdev_t *pcic) 5262*3db86aabSstevel { 5263*3db86aabSstevel uint32_t vend, device; 5264*3db86aabSstevel 5265*3db86aabSstevel vend = ddi_getprop(DDI_DEV_T_ANY, pcic->dip, 5266*3db86aabSstevel DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS, 5267*3db86aabSstevel "vendor-id", -1); 5268*3db86aabSstevel device = ddi_getprop(DDI_DEV_T_ANY, pcic->dip, 5269*3db86aabSstevel DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS, 5270*3db86aabSstevel "device-id", -1); 5271*3db86aabSstevel 5272*3db86aabSstevel device = PCI_ID(vend, device); 5273*3db86aabSstevel pcic->pc_type = device; 5274*3db86aabSstevel pcic->pc_chipname = "PCI:unknown"; 5275*3db86aabSstevel 5276*3db86aabSstevel switch (device) { 5277*3db86aabSstevel case PCIC_INTEL_i82092: 5278*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_i82092; 5279*3db86aabSstevel break; 5280*3db86aabSstevel case PCIC_CL_PD6729: 5281*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6729; 5282*3db86aabSstevel /* 5283*3db86aabSstevel * Some 6730's incorrectly identify themselves 5284*3db86aabSstevel * as a 6729, so we need to do some more tests 5285*3db86aabSstevel * here to see if the device that's claiming 5286*3db86aabSstevel * to be a 6729 is really a 6730. 5287*3db86aabSstevel */ 5288*3db86aabSstevel if ((clext_reg_read(pcic, 0, PCIC_CLEXT_MISC_CTL_3) & 5289*3db86aabSstevel PCIC_CLEXT_MISC_CTL_3_REV_MASK) == 5290*3db86aabSstevel 0) { 5291*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6730; 5292*3db86aabSstevel pcic->pc_type = PCIC_CL_PD6730; 5293*3db86aabSstevel } 5294*3db86aabSstevel break; 5295*3db86aabSstevel case PCIC_CL_PD6730: 5296*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6730; 5297*3db86aabSstevel break; 5298*3db86aabSstevel case PCIC_CL_PD6832: 5299*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6832; 5300*3db86aabSstevel break; 5301*3db86aabSstevel case PCIC_SMC_34C90: 5302*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_34C90; 5303*3db86aabSstevel break; 5304*3db86aabSstevel case PCIC_TOSHIBA_TOPIC95: 5305*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_TOPIC95; 5306*3db86aabSstevel break; 5307*3db86aabSstevel case PCIC_TOSHIBA_TOPIC100: 5308*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_TOPIC100; 5309*3db86aabSstevel break; 5310*3db86aabSstevel case PCIC_TI_PCI1031: 5311*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1031; 5312*3db86aabSstevel break; 5313*3db86aabSstevel case PCIC_TI_PCI1130: 5314*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1130; 5315*3db86aabSstevel break; 5316*3db86aabSstevel case PCIC_TI_PCI1131: 5317*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1131; 5318*3db86aabSstevel break; 5319*3db86aabSstevel case PCIC_TI_PCI1250: 5320*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1250; 5321*3db86aabSstevel break; 5322*3db86aabSstevel case PCIC_TI_PCI1225: 5323*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1225; 5324*3db86aabSstevel break; 5325*3db86aabSstevel case PCIC_TI_PCI1410: 5326*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1410; 5327*3db86aabSstevel break; 5328*3db86aabSstevel case PCIC_TI_PCI1510: 5329*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1510; 5330*3db86aabSstevel break; 5331*3db86aabSstevel case PCIC_TI_PCI1520: 5332*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1520; 5333*3db86aabSstevel break; 5334*3db86aabSstevel case PCIC_TI_PCI1221: 5335*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1221; 5336*3db86aabSstevel break; 5337*3db86aabSstevel case PCIC_TI_PCI1050: 5338*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1050; 5339*3db86aabSstevel break; 5340*3db86aabSstevel case PCIC_ENE_1410: 5341*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_1410; 5342*3db86aabSstevel break; 5343*3db86aabSstevel case PCIC_O2_OZ6912: 5344*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_OZ6912; 5345*3db86aabSstevel break; 5346*3db86aabSstevel case PCIC_RICOH_RL5C466: 5347*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_RL5C466; 5348*3db86aabSstevel break; 5349*3db86aabSstevel case PCIC_TI_PCI1420: 5350*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1420; 5351*3db86aabSstevel break; 5352*3db86aabSstevel case PCIC_ENE_1420: 5353*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_1420; 5354*3db86aabSstevel break; 5355*3db86aabSstevel default: 5356*3db86aabSstevel switch (PCI_ID(vend, (uint32_t)0)) { 5357*3db86aabSstevel case PCIC_TOSHIBA_VENDOR: 5358*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_TOSHIBA; 5359*3db86aabSstevel pcic->pc_type = PCIC_TOSHIBA_VENDOR; 5360*3db86aabSstevel break; 5361*3db86aabSstevel case PCIC_TI_VENDOR: 5362*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_TI; 5363*3db86aabSstevel pcic->pc_type = PCIC_TI_VENDOR; 5364*3db86aabSstevel break; 5365*3db86aabSstevel case PCIC_O2MICRO_VENDOR: 5366*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_O2MICRO; 5367*3db86aabSstevel pcic->pc_type = PCIC_O2MICRO_VENDOR; 5368*3db86aabSstevel break; 5369*3db86aabSstevel case PCIC_RICOH_VENDOR: 5370*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_RICOH; 5371*3db86aabSstevel pcic->pc_type = PCIC_RICOH_VENDOR; 5372*3db86aabSstevel break; 5373*3db86aabSstevel default: 5374*3db86aabSstevel if (!(pcic->pc_flags & PCF_CARDBUS)) 5375*3db86aabSstevel return (DDI_FAILURE); 5376*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_YENTA; 5377*3db86aabSstevel break; 5378*3db86aabSstevel } 5379*3db86aabSstevel } 5380*3db86aabSstevel return (DDI_SUCCESS); 5381*3db86aabSstevel } 5382*3db86aabSstevel 5383*3db86aabSstevel static void 5384*3db86aabSstevel pcic_82092_smiirq_ctl(pcicdev_t *pcic, int socket, int intr, int state) 5385*3db86aabSstevel { 5386*3db86aabSstevel uchar_t ppirr = ddi_get8(pcic->cfg_handle, 5387*3db86aabSstevel pcic->cfgaddr + PCIC_82092_PPIRR); 5388*3db86aabSstevel uchar_t val; 5389*3db86aabSstevel 5390*3db86aabSstevel if (intr == PCIC_82092_CTL_SMI) { 5391*3db86aabSstevel val = PCIC_82092_SMI_CTL(socket, 5392*3db86aabSstevel PCIC_82092_INT_DISABLE); 5393*3db86aabSstevel ppirr &= ~val; 5394*3db86aabSstevel val = PCIC_82092_SMI_CTL(socket, state); 5395*3db86aabSstevel ppirr |= val; 5396*3db86aabSstevel } else { 5397*3db86aabSstevel val = PCIC_82092_IRQ_CTL(socket, 5398*3db86aabSstevel PCIC_82092_INT_DISABLE); 5399*3db86aabSstevel ppirr &= ~val; 5400*3db86aabSstevel val = PCIC_82092_IRQ_CTL(socket, state); 5401*3db86aabSstevel ppirr |= val; 5402*3db86aabSstevel } 5403*3db86aabSstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_82092_PPIRR, 5404*3db86aabSstevel ppirr); 5405*3db86aabSstevel } 5406*3db86aabSstevel 5407*3db86aabSstevel static uint_t 5408*3db86aabSstevel pcic_cd_softint(caddr_t arg1, caddr_t arg2) 5409*3db86aabSstevel { 5410*3db86aabSstevel pcic_socket_t *sockp = (pcic_socket_t *)arg1; 5411*3db86aabSstevel uint_t rc = DDI_INTR_UNCLAIMED; 5412*3db86aabSstevel 5413*3db86aabSstevel _NOTE(ARGUNUSED(arg2)) 5414*3db86aabSstevel 5415*3db86aabSstevel mutex_enter(&sockp->pcs_pcic->pc_lock); 5416*3db86aabSstevel if (sockp->pcs_cd_softint_flg) { 5417*3db86aabSstevel uint8_t status; 5418*3db86aabSstevel sockp->pcs_cd_softint_flg = 0; 5419*3db86aabSstevel rc = DDI_INTR_CLAIMED; 5420*3db86aabSstevel status = pcic_getb(sockp->pcs_pcic, sockp->pcs_socket, 5421*3db86aabSstevel PCIC_INTERFACE_STATUS); 5422*3db86aabSstevel pcic_handle_cd_change(sockp->pcs_pcic, sockp, status); 5423*3db86aabSstevel } 5424*3db86aabSstevel mutex_exit(&sockp->pcs_pcic->pc_lock); 5425*3db86aabSstevel return (rc); 5426*3db86aabSstevel } 5427*3db86aabSstevel 5428*3db86aabSstevel int pcic_debounce_cnt = PCIC_REM_DEBOUNCE_CNT; 5429*3db86aabSstevel int pcic_debounce_intr_time = PCIC_REM_DEBOUNCE_TIME; 5430*3db86aabSstevel int pcic_debounce_cnt_ok = PCIC_DEBOUNCE_OK_CNT; 5431*3db86aabSstevel 5432*3db86aabSstevel #ifdef CARDBUS 5433*3db86aabSstevel static uint32_t pcic_cbps_on = 0; 5434*3db86aabSstevel static uint32_t pcic_cbps_off = CB_PS_NOTACARD | CB_PS_CCDMASK | 5435*3db86aabSstevel CB_PS_XVCARD | CB_PS_YVCARD; 5436*3db86aabSstevel #else 5437*3db86aabSstevel static uint32_t pcic_cbps_on = CB_PS_16BITCARD; 5438*3db86aabSstevel static uint32_t pcic_cbps_off = CB_PS_NOTACARD | CB_PS_CCDMASK | 5439*3db86aabSstevel CB_PS_CBCARD | 5440*3db86aabSstevel CB_PS_XVCARD | CB_PS_YVCARD; 5441*3db86aabSstevel #endif 5442*3db86aabSstevel static void 5443*3db86aabSstevel pcic_handle_cd_change(pcicdev_t *pcic, pcic_socket_t *sockp, uint8_t status) 5444*3db86aabSstevel { 5445*3db86aabSstevel boolean_t do_debounce = B_FALSE; 5446*3db86aabSstevel int debounce_time = drv_usectohz(pcic_debounce_time); 5447*3db86aabSstevel uint8_t irq; 5448*3db86aabSstevel timeout_id_t debounce; 5449*3db86aabSstevel 5450*3db86aabSstevel /* 5451*3db86aabSstevel * Always reset debounce but may need to check original state later. 5452*3db86aabSstevel */ 5453*3db86aabSstevel debounce = sockp->pcs_debounce_id; 5454*3db86aabSstevel sockp->pcs_debounce_id = 0; 5455*3db86aabSstevel 5456*3db86aabSstevel /* 5457*3db86aabSstevel * Check to see whether a card is present or not. There are 5458*3db86aabSstevel * only two states that we are concerned with - the state 5459*3db86aabSstevel * where both CD pins are asserted, which means that the 5460*3db86aabSstevel * card is fully seated, and the state where neither CD 5461*3db86aabSstevel * pin is asserted, which means that the card is not 5462*3db86aabSstevel * present. 5463*3db86aabSstevel * The CD signals are generally very noisy and cause a lot of 5464*3db86aabSstevel * contact bounce as the card is being inserted and 5465*3db86aabSstevel * removed, so we need to do some software debouncing. 5466*3db86aabSstevel */ 5467*3db86aabSstevel 5468*3db86aabSstevel #ifdef PCIC_DEBUG 5469*3db86aabSstevel pcic_err(pcic->dip, 6, 5470*3db86aabSstevel "pcic%d handle_cd_change: socket %d card status 0x%x" 5471*3db86aabSstevel " deb 0x%p\n", ddi_get_instance(pcic->dip), 5472*3db86aabSstevel sockp->pcs_socket, status, debounce); 5473*3db86aabSstevel #endif 5474*3db86aabSstevel switch (status & PCIC_ISTAT_CD_MASK) { 5475*3db86aabSstevel case PCIC_CD_PRESENT_OK: 5476*3db86aabSstevel sockp->pcs_flags &= ~(PCS_CARD_REMOVED|PCS_CARD_CBREM); 5477*3db86aabSstevel if (!(sockp->pcs_flags & PCS_CARD_PRESENT)) { 5478*3db86aabSstevel uint32_t cbps; 5479*3db86aabSstevel #ifdef PCIC_DEBUG 5480*3db86aabSstevel pcic_err(pcic->dip, 8, "New card (0x%x)\n", sockp->pcs_flags); 5481*3db86aabSstevel #endif 5482*3db86aabSstevel cbps = pcic_getcb(pcic, CB_PRESENT_STATE); 5483*3db86aabSstevel #ifdef PCIC_DEBUG 5484*3db86aabSstevel pcic_err(pcic->dip, 8, "CBus PS (0x%x)\n", cbps); 5485*3db86aabSstevel #endif 5486*3db86aabSstevel /* 5487*3db86aabSstevel * Check the CB bits are sane. 5488*3db86aabSstevel */ 5489*3db86aabSstevel if ((cbps & pcic_cbps_on) != pcic_cbps_on || 5490*3db86aabSstevel cbps & pcic_cbps_off) { 5491*3db86aabSstevel cmn_err(CE_WARN, 5492*3db86aabSstevel "%s%d: Odd Cardbus Present State 0x%x\n", 5493*3db86aabSstevel ddi_get_name(pcic->dip), 5494*3db86aabSstevel ddi_get_instance(pcic->dip), 5495*3db86aabSstevel cbps); 5496*3db86aabSstevel pcic_putcb(pcic, CB_EVENT_FORCE, CB_EF_CVTEST); 5497*3db86aabSstevel debounce = 0; 5498*3db86aabSstevel debounce_time = drv_usectohz(1000000); 5499*3db86aabSstevel } 5500*3db86aabSstevel if (debounce) { 5501*3db86aabSstevel sockp->pcs_flags |= PCS_CARD_PRESENT; 5502*3db86aabSstevel if (pcic_do_insertion) { 5503*3db86aabSstevel 5504*3db86aabSstevel cbps = pcic_getcb(pcic, CB_PRESENT_STATE); 5505*3db86aabSstevel 5506*3db86aabSstevel if (cbps & CB_PS_16BITCARD) { 5507*3db86aabSstevel pcic_err(pcic->dip, 8, "16 bit card inserted\n"); 5508*3db86aabSstevel sockp->pcs_flags |= PCS_CARD_IS16BIT; 5509*3db86aabSstevel /* calls pcm_adapter_callback() */ 5510*3db86aabSstevel if (pcic->pc_callback) { 5511*3db86aabSstevel 5512*3db86aabSstevel (void) ddi_prop_update_string(DDI_DEV_T_NONE, 5513*3db86aabSstevel pcic->dip, PCM_DEVICETYPE, 5514*3db86aabSstevel "pccard"); 5515*3db86aabSstevel PC_CALLBACK(pcic->dip, pcic->pc_cb_arg, 5516*3db86aabSstevel PCE_CARD_INSERT, 5517*3db86aabSstevel sockp->pcs_socket); 5518*3db86aabSstevel } 5519*3db86aabSstevel } else if (cbps & CB_PS_CBCARD) { 5520*3db86aabSstevel pcic_err(pcic->dip, 8, "32 bit card inserted\n"); 5521*3db86aabSstevel 5522*3db86aabSstevel if (pcic->pc_flags & PCF_CARDBUS) { 5523*3db86aabSstevel sockp->pcs_flags |= PCS_CARD_ISCARDBUS; 5524*3db86aabSstevel #ifdef CARDBUS 5525*3db86aabSstevel if (!pcic_load_cardbus(pcic, sockp)) { 5526*3db86aabSstevel pcic_unload_cardbus(pcic, sockp); 5527*3db86aabSstevel } 5528*3db86aabSstevel 5529*3db86aabSstevel #else 5530*3db86aabSstevel cmn_err(CE_NOTE, 5531*3db86aabSstevel "32 bit Cardbus not supported in" 5532*3db86aabSstevel " this device driver\n"); 5533*3db86aabSstevel #endif 5534*3db86aabSstevel } else { 5535*3db86aabSstevel /* 5536*3db86aabSstevel * Ignore the card 5537*3db86aabSstevel */ 5538*3db86aabSstevel cmn_err(CE_NOTE, 5539*3db86aabSstevel "32 bit Cardbus not supported on this" 5540*3db86aabSstevel " device\n"); 5541*3db86aabSstevel } 5542*3db86aabSstevel } else { 5543*3db86aabSstevel cmn_err(CE_NOTE, 5544*3db86aabSstevel "Unsupported PCMCIA card inserted\n"); 5545*3db86aabSstevel } 5546*3db86aabSstevel } 5547*3db86aabSstevel syshw_send_signal(sockp->pcs_syshwsig); 5548*3db86aabSstevel } else { 5549*3db86aabSstevel do_debounce = B_TRUE; 5550*3db86aabSstevel } 5551*3db86aabSstevel } else { 5552*3db86aabSstevel /* 5553*3db86aabSstevel * It is possible to come through here if the system 5554*3db86aabSstevel * starts up with cards already inserted. Do nothing 5555*3db86aabSstevel * and don't worry about it. 5556*3db86aabSstevel */ 5557*3db86aabSstevel #ifdef PCIC_DEBUG 5558*3db86aabSstevel pcic_err(pcic->dip, 5, 5559*3db86aabSstevel "pcic%d: Odd card insertion indication on socket %d\n", 5560*3db86aabSstevel ddi_get_instance(pcic->dip), 5561*3db86aabSstevel sockp->pcs_socket); 5562*3db86aabSstevel #endif 5563*3db86aabSstevel } 5564*3db86aabSstevel break; 5565*3db86aabSstevel 5566*3db86aabSstevel default: 5567*3db86aabSstevel if (!(sockp->pcs_flags & PCS_CARD_PRESENT)) { 5568*3db86aabSstevel /* 5569*3db86aabSstevel * Someone has started to insert a card so delay a while. 5570*3db86aabSstevel */ 5571*3db86aabSstevel do_debounce = B_TRUE; 5572*3db86aabSstevel break; 5573*3db86aabSstevel } 5574*3db86aabSstevel /* 5575*3db86aabSstevel * Otherwise this is basically the same as not present 5576*3db86aabSstevel * so fall through. 5577*3db86aabSstevel */ 5578*3db86aabSstevel 5579*3db86aabSstevel /* FALLTHRU */ 5580*3db86aabSstevel case 0: 5581*3db86aabSstevel if (sockp->pcs_flags & PCS_CARD_PRESENT) { 5582*3db86aabSstevel if (pcic->pc_flags & PCF_CBPWRCTL) { 5583*3db86aabSstevel pcic_putcb(pcic, CB_CONTROL, 0); 5584*3db86aabSstevel } else { 5585*3db86aabSstevel pcic_putb(pcic, sockp->pcs_socket, PCIC_POWER_CONTROL, 0); 5586*3db86aabSstevel (void) pcic_getb(pcic, sockp->pcs_socket, 5587*3db86aabSstevel PCIC_POWER_CONTROL); 5588*3db86aabSstevel } 5589*3db86aabSstevel #ifdef PCIC_DEBUG 5590*3db86aabSstevel pcic_err(pcic->dip, 8, "Card removed\n"); 5591*3db86aabSstevel #endif 5592*3db86aabSstevel sockp->pcs_flags &= ~PCS_CARD_PRESENT; 5593*3db86aabSstevel 5594*3db86aabSstevel if (sockp->pcs_flags & PCS_CARD_IS16BIT) { 5595*3db86aabSstevel sockp->pcs_flags &= ~PCS_CARD_IS16BIT; 5596*3db86aabSstevel if (pcic_do_removal && pcic->pc_callback) { 5597*3db86aabSstevel PC_CALLBACK(pcic->dip, pcic->pc_cb_arg, 5598*3db86aabSstevel PCE_CARD_REMOVAL, sockp->pcs_socket); 5599*3db86aabSstevel } 5600*3db86aabSstevel } 5601*3db86aabSstevel if (sockp->pcs_flags & PCS_CARD_ISCARDBUS) { 5602*3db86aabSstevel sockp->pcs_flags &= ~PCS_CARD_ISCARDBUS; 5603*3db86aabSstevel sockp->pcs_flags |= PCS_CARD_CBREM; 5604*3db86aabSstevel } 5605*3db86aabSstevel sockp->pcs_flags |= PCS_CARD_REMOVED; 5606*3db86aabSstevel 5607*3db86aabSstevel do_debounce = B_TRUE; 5608*3db86aabSstevel } 5609*3db86aabSstevel if (debounce && (sockp->pcs_flags & PCS_CARD_REMOVED)) { 5610*3db86aabSstevel if (sockp->pcs_flags & PCS_CARD_CBREM) { 5611*3db86aabSstevel /* 5612*3db86aabSstevel * Ensure that we do the unloading in the 5613*3db86aabSstevel * debounce handler, that way we're not doing 5614*3db86aabSstevel * nasty things in an interrupt handler. e.g. 5615*3db86aabSstevel * a USB device will wait for data which will 5616*3db86aabSstevel * obviously never come because we've 5617*3db86aabSstevel * unplugged the device, but the wait will 5618*3db86aabSstevel * wait forever because no interrupts can 5619*3db86aabSstevel * come in... 5620*3db86aabSstevel */ 5621*3db86aabSstevel #ifdef CARDBUS 5622*3db86aabSstevel pcic_unload_cardbus(pcic, sockp); 5623*3db86aabSstevel /* pcic_dump_all(pcic); */ 5624*3db86aabSstevel #endif 5625*3db86aabSstevel sockp->pcs_flags &= ~PCS_CARD_CBREM; 5626*3db86aabSstevel } 5627*3db86aabSstevel syshw_send_signal(sockp->pcs_syshwsig); 5628*3db86aabSstevel sockp->pcs_flags &= ~PCS_CARD_REMOVED; 5629*3db86aabSstevel } 5630*3db86aabSstevel break; 5631*3db86aabSstevel } /* switch */ 5632*3db86aabSstevel 5633*3db86aabSstevel if (do_debounce) { 5634*3db86aabSstevel /* 5635*3db86aabSstevel * Delay doing 5636*3db86aabSstevel * anything for a while so that things can settle 5637*3db86aabSstevel * down a little. Interrupts are already disabled. 5638*3db86aabSstevel * Reset the state and we'll reevaluate the 5639*3db86aabSstevel * whole kit 'n kaboodle when the timeout fires 5640*3db86aabSstevel */ 5641*3db86aabSstevel #ifdef PCIC_DEBUG 5642*3db86aabSstevel pcic_err(pcic->dip, 8, "Queueing up debounce timeout for " 5643*3db86aabSstevel "socket %d.%d\n", 5644*3db86aabSstevel ddi_get_instance(pcic->dip), 5645*3db86aabSstevel sockp->pcs_socket); 5646*3db86aabSstevel #endif 5647*3db86aabSstevel sockp->pcs_debounce_id = pcic_add_debqueue(sockp, debounce_time); 5648*3db86aabSstevel 5649*3db86aabSstevel /* 5650*3db86aabSstevel * We bug out here without re-enabling interrupts. They will 5651*3db86aabSstevel * be re-enabled when the debounce timeout swings through 5652*3db86aabSstevel * here. 5653*3db86aabSstevel */ 5654*3db86aabSstevel return; 5655*3db86aabSstevel } 5656*3db86aabSstevel 5657*3db86aabSstevel /* 5658*3db86aabSstevel * Turn on Card detect interrupts. Other interrupts will be 5659*3db86aabSstevel * enabled during set_socket calls. 5660*3db86aabSstevel * 5661*3db86aabSstevel * Note that set_socket only changes interrupt settings when there 5662*3db86aabSstevel * is a card present. 5663*3db86aabSstevel */ 5664*3db86aabSstevel irq = pcic_getb(pcic, sockp->pcs_socket, PCIC_MANAGEMENT_INT); 5665*3db86aabSstevel irq |= PCIC_CD_DETECT; 5666*3db86aabSstevel pcic_putb(pcic, sockp->pcs_socket, PCIC_MANAGEMENT_INT, irq); 5667*3db86aabSstevel 5668*3db86aabSstevel pcic_err(pcic->dip, 7, "Leaving pcic_handle_cd_change\n"); 5669*3db86aabSstevel } 5670*3db86aabSstevel 5671*3db86aabSstevel /* 5672*3db86aabSstevel * pcic_getb() 5673*3db86aabSstevel * get an I/O byte based on the yardware decode method 5674*3db86aabSstevel */ 5675*3db86aabSstevel static uint8_t 5676*3db86aabSstevel pcic_getb(pcicdev_t *pcic, int socket, int reg) 5677*3db86aabSstevel { 5678*3db86aabSstevel int work; 5679*3db86aabSstevel 5680*3db86aabSstevel #if defined(PCIC_DEBUG) 5681*3db86aabSstevel if (pcic_debug == 0x7fff) { 5682*3db86aabSstevel cmn_err(CE_CONT, "pcic_getb0: pcic=%p socket=%d reg=%d\n", 5683*3db86aabSstevel (void *)pcic, socket, reg); 5684*3db86aabSstevel cmn_err(CE_CONT, "pcic_getb1: type=%d handle=%p ioaddr=%p \n", 5685*3db86aabSstevel pcic->pc_io_type, (void *)pcic->handle, 5686*3db86aabSstevel (void *)pcic->ioaddr); 5687*3db86aabSstevel } 5688*3db86aabSstevel #endif 5689*3db86aabSstevel 5690*3db86aabSstevel switch (pcic->pc_io_type) { 5691*3db86aabSstevel case PCIC_IO_TYPE_YENTA: 5692*3db86aabSstevel return (ddi_get8(pcic->handle, 5693*3db86aabSstevel pcic->ioaddr + CB_R2_OFFSET + reg)); 5694*3db86aabSstevel default: 5695*3db86aabSstevel work = (socket * PCIC_SOCKET_1) | reg; 5696*3db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr, work); 5697*3db86aabSstevel return (ddi_get8(pcic->handle, pcic->ioaddr + 1)); 5698*3db86aabSstevel } 5699*3db86aabSstevel } 5700*3db86aabSstevel 5701*3db86aabSstevel static void 5702*3db86aabSstevel pcic_putb(pcicdev_t *pcic, int socket, int reg, int8_t value) 5703*3db86aabSstevel { 5704*3db86aabSstevel int work; 5705*3db86aabSstevel 5706*3db86aabSstevel #if defined(PCIC_DEBUG) 5707*3db86aabSstevel if (pcic_debug == 0x7fff) { 5708*3db86aabSstevel cmn_err(CE_CONT, 5709*3db86aabSstevel "pcic_putb0: pcic=%p socket=%d reg=%d value=%x \n", 5710*3db86aabSstevel (void *)pcic, socket, reg, value); 5711*3db86aabSstevel cmn_err(CE_CONT, 5712*3db86aabSstevel "pcic_putb1: type=%d handle=%p ioaddr=%p \n", 5713*3db86aabSstevel pcic->pc_io_type, (void *)pcic->handle, 5714*3db86aabSstevel (void *)pcic->ioaddr); 5715*3db86aabSstevel } 5716*3db86aabSstevel #endif 5717*3db86aabSstevel 5718*3db86aabSstevel 5719*3db86aabSstevel switch (pcic->pc_io_type) { 5720*3db86aabSstevel case PCIC_IO_TYPE_YENTA: 5721*3db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr + CB_R2_OFFSET + reg, 5722*3db86aabSstevel value); 5723*3db86aabSstevel break; 5724*3db86aabSstevel default: 5725*3db86aabSstevel work = (socket * PCIC_SOCKET_1) | reg; 5726*3db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr, work); 5727*3db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr + 1, value); 5728*3db86aabSstevel break; 5729*3db86aabSstevel } 5730*3db86aabSstevel } 5731*3db86aabSstevel 5732*3db86aabSstevel /* 5733*3db86aabSstevel * chip identification functions 5734*3db86aabSstevel */ 5735*3db86aabSstevel 5736*3db86aabSstevel /* 5737*3db86aabSstevel * chip identification: Cirrus Logic PD6710/6720/6722 5738*3db86aabSstevel */ 5739*3db86aabSstevel static int 5740*3db86aabSstevel pcic_ci_cirrus(pcicdev_t *pcic) 5741*3db86aabSstevel { 5742*3db86aabSstevel int value1, value2; 5743*3db86aabSstevel 5744*3db86aabSstevel /* Init the CL id mode */ 5745*3db86aabSstevel value1 = pcic_getb(pcic, 0, PCIC_CHIP_INFO); 5746*3db86aabSstevel pcic_putb(pcic, 0, PCIC_CHIP_INFO, 0); 5747*3db86aabSstevel value1 = pcic_getb(pcic, 0, PCIC_CHIP_INFO); 5748*3db86aabSstevel value2 = pcic_getb(pcic, 0, PCIC_CHIP_INFO); 5749*3db86aabSstevel 5750*3db86aabSstevel if ((value1 & PCIC_CI_ID) == PCIC_CI_ID && 5751*3db86aabSstevel (value2 & PCIC_CI_ID) == 0) { 5752*3db86aabSstevel /* chip is a Cirrus Logic and not Intel */ 5753*3db86aabSstevel pcic->pc_type = PCIC_CL_PD6710; 5754*3db86aabSstevel if (value1 & PCIC_CI_SLOTS) 5755*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6720; 5756*3db86aabSstevel else 5757*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6710; 5758*3db86aabSstevel /* now fine tune things just in case a 6722 */ 5759*3db86aabSstevel value1 = clext_reg_read(pcic, 0, PCIC_CLEXT_DMASK_0); 5760*3db86aabSstevel if (value1 == 0) { 5761*3db86aabSstevel clext_reg_write(pcic, 0, PCIC_CLEXT_SCRATCH, 0x55); 5762*3db86aabSstevel value1 = clext_reg_read(pcic, 0, PCIC_CLEXT_SCRATCH); 5763*3db86aabSstevel if (value1 == 0x55) { 5764*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6722; 5765*3db86aabSstevel pcic->pc_type = PCIC_CL_PD6722; 5766*3db86aabSstevel clext_reg_write(pcic, 0, PCIC_CLEXT_SCRATCH, 0); 5767*3db86aabSstevel } 5768*3db86aabSstevel } 5769*3db86aabSstevel return (1); 5770*3db86aabSstevel } 5771*3db86aabSstevel return (0); 5772*3db86aabSstevel } 5773*3db86aabSstevel 5774*3db86aabSstevel /* 5775*3db86aabSstevel * chip identification: Vadem (VG365/465/468/469) 5776*3db86aabSstevel */ 5777*3db86aabSstevel 5778*3db86aabSstevel static void 5779*3db86aabSstevel pcic_vadem_enable(pcicdev_t *pcic) 5780*3db86aabSstevel { 5781*3db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr, PCIC_VADEM_P1); 5782*3db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr, PCIC_VADEM_P2); 5783*3db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr, pcic->pc_lastreg); 5784*3db86aabSstevel } 5785*3db86aabSstevel 5786*3db86aabSstevel static int 5787*3db86aabSstevel pcic_ci_vadem(pcicdev_t *pcic) 5788*3db86aabSstevel { 5789*3db86aabSstevel int value; 5790*3db86aabSstevel 5791*3db86aabSstevel pcic_vadem_enable(pcic); 5792*3db86aabSstevel value = pcic_getb(pcic, 0, PCIC_CHIP_REVISION); 5793*3db86aabSstevel pcic_putb(pcic, 0, PCIC_CHIP_REVISION, 0xFF); 5794*3db86aabSstevel if (pcic_getb(pcic, 0, PCIC_CHIP_REVISION) == 5795*3db86aabSstevel (value | PCIC_VADEM_D3) || 5796*3db86aabSstevel (pcic_getb(pcic, 0, PCIC_CHIP_REVISION) & PCIC_REV_MASK) == 5797*3db86aabSstevel PCIC_VADEM_469) { 5798*3db86aabSstevel int vadem, new; 5799*3db86aabSstevel pcic_vadem_enable(pcic); 5800*3db86aabSstevel vadem = pcic_getb(pcic, 0, PCIC_VG_DMA) & 5801*3db86aabSstevel ~(PCIC_V_UNLOCK | PCIC_V_VADEMREV); 5802*3db86aabSstevel new = vadem | (PCIC_V_VADEMREV|PCIC_V_UNLOCK); 5803*3db86aabSstevel pcic_putb(pcic, 0, PCIC_VG_DMA, new); 5804*3db86aabSstevel value = pcic_getb(pcic, 0, PCIC_CHIP_REVISION); 5805*3db86aabSstevel 5806*3db86aabSstevel /* want to lock but leave mouse or other on */ 5807*3db86aabSstevel pcic_putb(pcic, 0, PCIC_VG_DMA, vadem); 5808*3db86aabSstevel switch (value & PCIC_REV_MASK) { 5809*3db86aabSstevel case PCIC_VADEM_365: 5810*3db86aabSstevel pcic->pc_chipname = PCIC_VG_365; 5811*3db86aabSstevel pcic->pc_type = PCIC_VADEM; 5812*3db86aabSstevel break; 5813*3db86aabSstevel case PCIC_VADEM_465: 5814*3db86aabSstevel pcic->pc_chipname = PCIC_VG_465; 5815*3db86aabSstevel pcic->pc_type = PCIC_VADEM; 5816*3db86aabSstevel pcic->pc_flags |= PCF_1SOCKET; 5817*3db86aabSstevel break; 5818*3db86aabSstevel case PCIC_VADEM_468: 5819*3db86aabSstevel pcic->pc_chipname = PCIC_VG_468; 5820*3db86aabSstevel pcic->pc_type = PCIC_VADEM; 5821*3db86aabSstevel break; 5822*3db86aabSstevel case PCIC_VADEM_469: 5823*3db86aabSstevel pcic->pc_chipname = PCIC_VG_469; 5824*3db86aabSstevel pcic->pc_type = PCIC_VADEM_VG469; 5825*3db86aabSstevel break; 5826*3db86aabSstevel } 5827*3db86aabSstevel return (1); 5828*3db86aabSstevel } 5829*3db86aabSstevel return (0); 5830*3db86aabSstevel } 5831*3db86aabSstevel 5832*3db86aabSstevel /* 5833*3db86aabSstevel * chip identification: Ricoh 5834*3db86aabSstevel */ 5835*3db86aabSstevel static int 5836*3db86aabSstevel pcic_ci_ricoh(pcicdev_t *pcic) 5837*3db86aabSstevel { 5838*3db86aabSstevel int value; 5839*3db86aabSstevel 5840*3db86aabSstevel value = pcic_getb(pcic, 0, PCIC_RF_CHIP_IDENT); 5841*3db86aabSstevel switch (value) { 5842*3db86aabSstevel case PCIC_RF_296: 5843*3db86aabSstevel pcic->pc_type = PCIC_RICOH; 5844*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_RF5C296; 5845*3db86aabSstevel return (1); 5846*3db86aabSstevel case PCIC_RF_396: 5847*3db86aabSstevel pcic->pc_type = PCIC_RICOH; 5848*3db86aabSstevel pcic->pc_chipname = PCIC_TYPE_RF5C396; 5849*3db86aabSstevel return (1); 5850*3db86aabSstevel } 5851*3db86aabSstevel return (0); 5852*3db86aabSstevel } 5853*3db86aabSstevel 5854*3db86aabSstevel 5855*3db86aabSstevel /* 5856*3db86aabSstevel * set up available address spaces in busra 5857*3db86aabSstevel */ 5858*3db86aabSstevel static void 5859*3db86aabSstevel pcic_init_assigned(dev_info_t *dip) 5860*3db86aabSstevel { 5861*3db86aabSstevel pcm_regs_t *pcic_avail_p; 5862*3db86aabSstevel pci_regspec_t *pci_avail_p, *regs; 5863*3db86aabSstevel int len, entries, rlen; 5864*3db86aabSstevel dev_info_t *pdip; 5865*3db86aabSstevel 5866*3db86aabSstevel if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 5867*3db86aabSstevel "available", (caddr_t)&pcic_avail_p, &len) == DDI_PROP_SUCCESS) { 5868*3db86aabSstevel /* 5869*3db86aabSstevel * found "available" property at the cardbus/pcmcia node 5870*3db86aabSstevel * need to translate address space entries from pcmcia 5871*3db86aabSstevel * format to pci format 5872*3db86aabSstevel */ 5873*3db86aabSstevel entries = len / sizeof (pcm_regs_t); 5874*3db86aabSstevel pci_avail_p = kmem_alloc(sizeof (pci_regspec_t) * entries, 5875*3db86aabSstevel KM_SLEEP); 5876*3db86aabSstevel if (pcic_apply_avail_ranges(dip, pcic_avail_p, pci_avail_p, 5877*3db86aabSstevel entries) == DDI_SUCCESS) 5878*3db86aabSstevel (void) pci_resource_setup_avail(dip, pci_avail_p, 5879*3db86aabSstevel entries); 5880*3db86aabSstevel kmem_free(pcic_avail_p, len); 5881*3db86aabSstevel kmem_free(pci_avail_p, entries * sizeof (pci_regspec_t)); 5882*3db86aabSstevel return; 5883*3db86aabSstevel } 5884*3db86aabSstevel 5885*3db86aabSstevel /* 5886*3db86aabSstevel * "legacy" platforms will have "available" property in pci node 5887*3db86aabSstevel */ 5888*3db86aabSstevel for (pdip = ddi_get_parent(dip); pdip; pdip = ddi_get_parent(pdip)) { 5889*3db86aabSstevel if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 5890*3db86aabSstevel "available", (caddr_t)&pci_avail_p, &len) == 5891*3db86aabSstevel DDI_PROP_SUCCESS) { 5892*3db86aabSstevel /* (void) pci_resource_setup(pdip); */ 5893*3db86aabSstevel kmem_free(pci_avail_p, len); 5894*3db86aabSstevel break; 5895*3db86aabSstevel } 5896*3db86aabSstevel } 5897*3db86aabSstevel 5898*3db86aabSstevel if (pdip == NULL) { 5899*3db86aabSstevel int len; 5900*3db86aabSstevel char bus_type[16] = "(unknown)"; 5901*3db86aabSstevel dev_info_t *par; 5902*3db86aabSstevel 5903*3db86aabSstevel cmn_err(CE_CONT, 5904*3db86aabSstevel "?pcic_init_assigned: no available property for pcmcia\n"); 5905*3db86aabSstevel 5906*3db86aabSstevel /* 5907*3db86aabSstevel * This code is taken from pci_resource_setup() but does 5908*3db86aabSstevel * not attempt to use the "available" property to populate 5909*3db86aabSstevel * the ndi maps that are created. 5910*3db86aabSstevel * The fact that we will actually 5911*3db86aabSstevel * free some resource below (that was allocated by OBP) 5912*3db86aabSstevel * should be enough to be going on with. 5913*3db86aabSstevel */ 5914*3db86aabSstevel for (par = dip; par != NULL; par = ddi_get_parent(par)) { 5915*3db86aabSstevel len = sizeof (bus_type); 5916*3db86aabSstevel 5917*3db86aabSstevel if ((ddi_prop_op(DDI_DEV_T_ANY, par, 5918*3db86aabSstevel PROP_LEN_AND_VAL_BUF, 5919*3db86aabSstevel DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, 5920*3db86aabSstevel "device_type", 5921*3db86aabSstevel (caddr_t)&bus_type, &len) == DDI_SUCCESS) && 5922*3db86aabSstevel (strcmp(bus_type, "pci") == 0)) 5923*3db86aabSstevel break; 5924*3db86aabSstevel } 5925*3db86aabSstevel if (par != NULL && 5926*3db86aabSstevel (ndi_ra_map_setup(par, NDI_RA_TYPE_MEM) != NDI_SUCCESS || 5927*3db86aabSstevel ndi_ra_map_setup(par, NDI_RA_TYPE_IO) != NDI_SUCCESS)) 5928*3db86aabSstevel par = NULL; 5929*3db86aabSstevel } else { 5930*3db86aabSstevel #ifdef CARDBUS 5931*3db86aabSstevel cardbus_bus_range_t *bus_range; 5932*3db86aabSstevel int k; 5933*3db86aabSstevel 5934*3db86aabSstevel if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "bus-range", 5935*3db86aabSstevel (caddr_t)&bus_range, &k) == DDI_PROP_SUCCESS) { 5936*3db86aabSstevel if (bus_range->lo != bus_range->hi) 5937*3db86aabSstevel pcic_err(pdip, 9, "allowable bus range is " 5938*3db86aabSstevel "%u->%u\n", bus_range->lo, bus_range->hi); 5939*3db86aabSstevel else { 5940*3db86aabSstevel pcic_err(pdip, 0, 5941*3db86aabSstevel "!No spare PCI bus numbers, range is " 5942*3db86aabSstevel "%u->%u, cardbus isn't usable\n", 5943*3db86aabSstevel bus_range->lo, bus_range->hi); 5944*3db86aabSstevel } 5945*3db86aabSstevel kmem_free(bus_range, k); 5946*3db86aabSstevel } else 5947*3db86aabSstevel pcic_err(pdip, 0, "!No bus-range property seems to " 5948*3db86aabSstevel "have been set up\n"); 5949*3db86aabSstevel #endif 5950*3db86aabSstevel /* 5951*3db86aabSstevel * Have a valid parent with the "available" property 5952*3db86aabSstevel */ 5953*3db86aabSstevel (void) pci_resource_setup(pdip); 5954*3db86aabSstevel } 5955*3db86aabSstevel 5956*3db86aabSstevel if ((strcmp(ddi_get_name(dip), "pcma") == 0) && 5957*3db86aabSstevel ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 5958*3db86aabSstevel "assigned-addresses", 5959*3db86aabSstevel (caddr_t)®s, &rlen) == DDI_SUCCESS) { 5960*3db86aabSstevel ra_return_t ra; 5961*3db86aabSstevel 5962*3db86aabSstevel /* 5963*3db86aabSstevel * On the UltraBook IIi the ranges are assigned under 5964*3db86aabSstevel * openboot. If we don't free them here the first I/O 5965*3db86aabSstevel * space that can be used is up above 0x10000 which 5966*3db86aabSstevel * doesn't work for this driver due to restrictions 5967*3db86aabSstevel * on the PCI I/O addresses the controllers can cope with. 5968*3db86aabSstevel * They are never going to be used by anything else 5969*3db86aabSstevel * so free them up to the general pool. AG. 5970*3db86aabSstevel */ 5971*3db86aabSstevel pcic_err(dip, 1, "Free assigned addresses\n"); 5972*3db86aabSstevel 5973*3db86aabSstevel if ((PCI_REG_ADDR_G(regs[0].pci_phys_hi) == 5974*3db86aabSstevel PCI_REG_ADDR_G(PCI_ADDR_MEM32)) && 5975*3db86aabSstevel regs[0].pci_size_low == 0x1000000) { 5976*3db86aabSstevel ra.ra_addr_lo = regs[0].pci_phys_low; 5977*3db86aabSstevel ra.ra_len = regs[0].pci_size_low; 5978*3db86aabSstevel (void) pcmcia_free_mem(dip, &ra); 5979*3db86aabSstevel } 5980*3db86aabSstevel if ((PCI_REG_ADDR_G(regs[1].pci_phys_hi) == 5981*3db86aabSstevel PCI_REG_ADDR_G(PCI_ADDR_IO)) && 5982*3db86aabSstevel (regs[1].pci_size_low == 0x8000 || 5983*3db86aabSstevel regs[1].pci_size_low == 0x4000)) /* UB-IIi || UB-I */ 5984*3db86aabSstevel { 5985*3db86aabSstevel ra.ra_addr_lo = regs[1].pci_phys_low; 5986*3db86aabSstevel ra.ra_len = regs[1].pci_size_low; 5987*3db86aabSstevel (void) pcmcia_free_io(dip, &ra); 5988*3db86aabSstevel } 5989*3db86aabSstevel kmem_free((caddr_t)regs, rlen); 5990*3db86aabSstevel } 5991*3db86aabSstevel } 5992*3db86aabSstevel 5993*3db86aabSstevel /* 5994*3db86aabSstevel * translate "available" from pcmcia format to pci format 5995*3db86aabSstevel */ 5996*3db86aabSstevel static int 5997*3db86aabSstevel pcic_apply_avail_ranges(dev_info_t *dip, pcm_regs_t *pcic_p, 5998*3db86aabSstevel pci_regspec_t *pci_p, int entries) 5999*3db86aabSstevel { 6000*3db86aabSstevel int i, range_len, range_entries; 6001*3db86aabSstevel pcic_ranges_t *pcic_range_p; 6002*3db86aabSstevel 6003*3db86aabSstevel if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", 6004*3db86aabSstevel (caddr_t)&pcic_range_p, &range_len) != DDI_PROP_SUCCESS) { 6005*3db86aabSstevel cmn_err(CE_CONT, "?pcic_apply_avail_ranges: " 6006*3db86aabSstevel "no ranges property for pcmcia\n"); 6007*3db86aabSstevel return (DDI_FAILURE); 6008*3db86aabSstevel } 6009*3db86aabSstevel 6010*3db86aabSstevel range_entries = range_len / sizeof (pcic_ranges_t); 6011*3db86aabSstevel 6012*3db86aabSstevel /* for each "available" entry to be translated */ 6013*3db86aabSstevel for (i = 0; i < entries; i++, pcic_p++, pci_p++) { 6014*3db86aabSstevel int j; 6015*3db86aabSstevel pcic_ranges_t *range_p = pcic_range_p; 6016*3db86aabSstevel pci_p->pci_phys_hi = -1u; /* default invalid value */ 6017*3db86aabSstevel 6018*3db86aabSstevel /* for each "ranges" entry to be searched */ 6019*3db86aabSstevel for (j = 0; j < range_entries; j++, range_p++) { 6020*3db86aabSstevel uint64_t range_end = range_p->pcic_range_caddrlo + 6021*3db86aabSstevel range_p->pcic_range_size; 6022*3db86aabSstevel uint64_t avail_end = pcic_p->phys_lo + pcic_p->phys_len; 6023*3db86aabSstevel 6024*3db86aabSstevel if ((range_p->pcic_range_caddrhi != pcic_p->phys_hi) || 6025*3db86aabSstevel (range_p->pcic_range_caddrlo > pcic_p->phys_lo) || 6026*3db86aabSstevel (range_end < avail_end)) 6027*3db86aabSstevel continue; 6028*3db86aabSstevel 6029*3db86aabSstevel pci_p->pci_phys_hi = range_p->pcic_range_paddrhi; 6030*3db86aabSstevel pci_p->pci_phys_mid = range_p->pcic_range_paddrmid; 6031*3db86aabSstevel pci_p->pci_phys_low = range_p->pcic_range_paddrlo 6032*3db86aabSstevel + (pcic_p->phys_lo - range_p->pcic_range_caddrlo); 6033*3db86aabSstevel pci_p->pci_size_hi = 0; 6034*3db86aabSstevel pci_p->pci_size_low = pcic_p->phys_len; 6035*3db86aabSstevel } 6036*3db86aabSstevel } 6037*3db86aabSstevel kmem_free(pcic_range_p, range_len); 6038*3db86aabSstevel return (DDI_SUCCESS); 6039*3db86aabSstevel } 6040*3db86aabSstevel 6041*3db86aabSstevel static int 6042*3db86aabSstevel pcic_open(dev_t *dev, int flag, int otyp, cred_t *cred) 6043*3db86aabSstevel { 6044*3db86aabSstevel if (getminor(*dev) == SYSHW_MINOR) 6045*3db86aabSstevel return (syshw_open(dev, flag, otyp, cred)); 6046*3db86aabSstevel #ifdef CARDBUS 6047*3db86aabSstevel if (cardbus_is_cb_minor(*dev)) 6048*3db86aabSstevel return (cardbus_open(dev, flag, otyp, cred)); 6049*3db86aabSstevel #endif 6050*3db86aabSstevel return (EINVAL); 6051*3db86aabSstevel } 6052*3db86aabSstevel 6053*3db86aabSstevel static int 6054*3db86aabSstevel pcic_close(dev_t dev, int flag, int otyp, cred_t *cred) 6055*3db86aabSstevel { 6056*3db86aabSstevel if (getminor(dev) == SYSHW_MINOR) 6057*3db86aabSstevel return (syshw_close(dev, flag, otyp, cred)); 6058*3db86aabSstevel #ifdef CARDBUS 6059*3db86aabSstevel if (cardbus_is_cb_minor(dev)) 6060*3db86aabSstevel return (cardbus_close(dev, flag, otyp, cred)); 6061*3db86aabSstevel #endif 6062*3db86aabSstevel return (EINVAL); 6063*3db86aabSstevel } 6064*3db86aabSstevel 6065*3db86aabSstevel static int 6066*3db86aabSstevel pcic_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, 6067*3db86aabSstevel int *rval) 6068*3db86aabSstevel { 6069*3db86aabSstevel if (getminor(dev) == SYSHW_MINOR) 6070*3db86aabSstevel return (syshw_ioctl(dev, cmd, arg, mode, cred, rval)); 6071*3db86aabSstevel #ifdef CARDBUS 6072*3db86aabSstevel if (cardbus_is_cb_minor(dev)) 6073*3db86aabSstevel return (cardbus_ioctl(dev, cmd, arg, mode, cred, rval)); 6074*3db86aabSstevel #endif 6075*3db86aabSstevel return (EINVAL); 6076*3db86aabSstevel } 6077*3db86aabSstevel 6078*3db86aabSstevel 6079*3db86aabSstevel static boolean_t 6080*3db86aabSstevel pcic_load_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp) 6081*3db86aabSstevel { 6082*3db86aabSstevel uint32_t present_state; 6083*3db86aabSstevel dev_info_t *dip = pcic->dip; 6084*3db86aabSstevel set_socket_t s; 6085*3db86aabSstevel get_socket_t g; 6086*3db86aabSstevel boolean_t retval; 6087*3db86aabSstevel unsigned vccLevel; 6088*3db86aabSstevel 6089*3db86aabSstevel pcic_err(dip, 8, "entering pcic_load_cardbus\n"); 6090*3db86aabSstevel 6091*3db86aabSstevel pcic_mutex_exit(&pcic->pc_lock); 6092*3db86aabSstevel 6093*3db86aabSstevel bzero(&s, sizeof (set_socket_t)); 6094*3db86aabSstevel s.socket = sockp->pcs_socket; 6095*3db86aabSstevel s.SCIntMask = SBM_CD|SBM_RDYBSY; 6096*3db86aabSstevel s.IFType = IF_CARDBUS; 6097*3db86aabSstevel s.State = (unsigned)~0; 6098*3db86aabSstevel 6099*3db86aabSstevel present_state = pcic_getcb(pcic, CB_PRESENT_STATE); 6100*3db86aabSstevel if (present_state & PCIC_VCC_3VCARD) 6101*3db86aabSstevel s.VccLevel = PCIC_VCC_3VLEVEL; 6102*3db86aabSstevel else if (present_state & PCIC_VCC_5VCARD) 6103*3db86aabSstevel s.VccLevel = PCIC_VCC_5VLEVEL; 6104*3db86aabSstevel else { 6105*3db86aabSstevel cmn_err(CE_CONT, 6106*3db86aabSstevel "pcic_load_cardbus: unsupported card voltage\n"); 6107*3db86aabSstevel goto failure; 6108*3db86aabSstevel } 6109*3db86aabSstevel vccLevel = s.VccLevel; 6110*3db86aabSstevel s.Vpp1Level = s.Vpp2Level = 0; 6111*3db86aabSstevel 6112*3db86aabSstevel if (pcic_set_socket(dip, &s) != SUCCESS) 6113*3db86aabSstevel goto failure; 6114*3db86aabSstevel 6115*3db86aabSstevel if (pcic_reset_socket(dip, sockp->pcs_socket, 6116*3db86aabSstevel RESET_MODE_CARD_ONLY) != SUCCESS) 6117*3db86aabSstevel goto failure; 6118*3db86aabSstevel 6119*3db86aabSstevel bzero(&g, sizeof (get_socket_t)); 6120*3db86aabSstevel g.socket = sockp->pcs_socket; 6121*3db86aabSstevel if (pcic_get_socket(dip, &g) != SUCCESS) 6122*3db86aabSstevel goto failure; 6123*3db86aabSstevel 6124*3db86aabSstevel bzero(&s, sizeof (set_socket_t)); 6125*3db86aabSstevel s.socket = sockp->pcs_socket; 6126*3db86aabSstevel s.SCIntMask = SBM_CD; 6127*3db86aabSstevel s.IREQRouting = g.IRQRouting; 6128*3db86aabSstevel s.IFType = g.IFType; 6129*3db86aabSstevel s.CtlInd = g.CtlInd; 6130*3db86aabSstevel s.State = (unsigned)~0; 6131*3db86aabSstevel s.VccLevel = vccLevel; 6132*3db86aabSstevel s.Vpp1Level = s.Vpp2Level = 0; 6133*3db86aabSstevel 6134*3db86aabSstevel if (pcic_set_socket(dip, &s) != SUCCESS) 6135*3db86aabSstevel goto failure; 6136*3db86aabSstevel 6137*3db86aabSstevel retval = cardbus_load_cardbus(dip, sockp->pcs_socket, pcic->pc_base); 6138*3db86aabSstevel goto exit; 6139*3db86aabSstevel 6140*3db86aabSstevel failure: 6141*3db86aabSstevel retval = B_FALSE; 6142*3db86aabSstevel 6143*3db86aabSstevel exit: 6144*3db86aabSstevel pcic_mutex_enter(&pcic->pc_lock); 6145*3db86aabSstevel pcic_err(dip, 8, "exit pcic_load_cardbus (%s)\n", 6146*3db86aabSstevel retval ? "success" : "failure"); 6147*3db86aabSstevel return (retval); 6148*3db86aabSstevel } 6149*3db86aabSstevel 6150*3db86aabSstevel static void 6151*3db86aabSstevel pcic_unload_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp) 6152*3db86aabSstevel { 6153*3db86aabSstevel dev_info_t *dip = pcic->dip; 6154*3db86aabSstevel set_socket_t s; 6155*3db86aabSstevel 6156*3db86aabSstevel pcic_mutex_exit(&pcic->pc_lock); 6157*3db86aabSstevel 6158*3db86aabSstevel cardbus_unload_cardbus(dip); 6159*3db86aabSstevel 6160*3db86aabSstevel bzero(&s, sizeof (set_socket_t)); 6161*3db86aabSstevel s.socket = sockp->pcs_socket; 6162*3db86aabSstevel s.SCIntMask = SBM_CD|SBM_RDYBSY; 6163*3db86aabSstevel s.IREQRouting = 0; 6164*3db86aabSstevel s.IFType = IF_MEMORY; 6165*3db86aabSstevel s.CtlInd = 0; 6166*3db86aabSstevel s.State = 0; 6167*3db86aabSstevel s.VccLevel = s.Vpp1Level = s.Vpp2Level = 0; 6168*3db86aabSstevel 6169*3db86aabSstevel (void) pcic_set_socket(dip, &s); 6170*3db86aabSstevel 6171*3db86aabSstevel pcic_mutex_enter(&pcic->pc_lock); 6172*3db86aabSstevel } 6173*3db86aabSstevel 6174*3db86aabSstevel static uint32_t 6175*3db86aabSstevel pcic_getcb(pcicdev_t *pcic, int reg) 6176*3db86aabSstevel { 6177*3db86aabSstevel ASSERT(pcic->pc_io_type == PCIC_IO_TYPE_YENTA); 6178*3db86aabSstevel 6179*3db86aabSstevel return (ddi_get32(pcic->handle, 6180*3db86aabSstevel (uint32_t *)(pcic->ioaddr + CB_CB_OFFSET + reg))); 6181*3db86aabSstevel } 6182*3db86aabSstevel 6183*3db86aabSstevel static void 6184*3db86aabSstevel pcic_putcb(pcicdev_t *pcic, int reg, uint32_t value) 6185*3db86aabSstevel { 6186*3db86aabSstevel ASSERT(pcic->pc_io_type == PCIC_IO_TYPE_YENTA); 6187*3db86aabSstevel 6188*3db86aabSstevel ddi_put32(pcic->handle, 6189*3db86aabSstevel (uint32_t *)(pcic->ioaddr + CB_CB_OFFSET + reg), value); 6190*3db86aabSstevel } 6191*3db86aabSstevel 6192*3db86aabSstevel static void 6193*3db86aabSstevel pcic_enable_io_intr(pcicdev_t *pcic, int socket, int irq) 6194*3db86aabSstevel { 6195*3db86aabSstevel uint8_t value; 6196*3db86aabSstevel uint16_t brdgctl; 6197*3db86aabSstevel 6198*3db86aabSstevel value = pcic_getb(pcic, socket, PCIC_INTERRUPT) & ~PCIC_INTR_MASK; 6199*3db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, value | irq); 6200*3db86aabSstevel 6201*3db86aabSstevel switch (pcic->pc_type) { 6202*3db86aabSstevel case PCIC_INTEL_i82092: 6203*3db86aabSstevel pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ, 6204*3db86aabSstevel PCIC_82092_INT_ENABLE); 6205*3db86aabSstevel break; 6206*3db86aabSstevel case PCIC_O2_OZ6912: 6207*3db86aabSstevel value = pcic_getb(pcic, 0, PCIC_CENTDMA); 6208*3db86aabSstevel value |= 0x8; 6209*3db86aabSstevel pcic_putb(pcic, 0, PCIC_CENTDMA, value); 6210*3db86aabSstevel break; 6211*3db86aabSstevel case PCIC_CL_PD6832: 6212*3db86aabSstevel case PCIC_TI_PCI1250: 6213*3db86aabSstevel case PCIC_TI_PCI1221: 6214*3db86aabSstevel case PCIC_TI_PCI1225: 6215*3db86aabSstevel case PCIC_TI_PCI1410: 6216*3db86aabSstevel case PCIC_ENE_1410: 6217*3db86aabSstevel case PCIC_TI_PCI1510: 6218*3db86aabSstevel case PCIC_TI_PCI1520: 6219*3db86aabSstevel case PCIC_TI_PCI1420: 6220*3db86aabSstevel case PCIC_ENE_1420: 6221*3db86aabSstevel /* route card functional interrupts to PCI interrupts */ 6222*3db86aabSstevel brdgctl = ddi_get16(pcic->cfg_handle, 6223*3db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL)); 6224*3db86aabSstevel pcic_err(NULL, 1, 6225*3db86aabSstevel "pcic_enable_io_intr brdgctl(0x%x) was: 0x%x\n", 6226*3db86aabSstevel PCI_CBUS_BRIDGE_CTRL, brdgctl); 6227*3db86aabSstevel brdgctl &= ~PCIC_BRDGCTL_INTR_MASK; 6228*3db86aabSstevel ddi_put16(pcic->cfg_handle, 6229*3db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL), 6230*3db86aabSstevel brdgctl); 6231*3db86aabSstevel /* Flush the write */ 6232*3db86aabSstevel (void) ddi_get16(pcic->cfg_handle, 6233*3db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL)); 6234*3db86aabSstevel break; 6235*3db86aabSstevel default: 6236*3db86aabSstevel break; 6237*3db86aabSstevel } 6238*3db86aabSstevel } 6239*3db86aabSstevel 6240*3db86aabSstevel static void 6241*3db86aabSstevel pcic_disable_io_intr(pcicdev_t *pcic, int socket) 6242*3db86aabSstevel { 6243*3db86aabSstevel uint8_t value; 6244*3db86aabSstevel uint16_t brdgctl; 6245*3db86aabSstevel 6246*3db86aabSstevel value = pcic_getb(pcic, socket, PCIC_INTERRUPT) & ~PCIC_INTR_MASK; 6247*3db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, value); 6248*3db86aabSstevel 6249*3db86aabSstevel switch (pcic->pc_type) { 6250*3db86aabSstevel case PCIC_INTEL_i82092: 6251*3db86aabSstevel pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ, 6252*3db86aabSstevel PCIC_82092_INT_DISABLE); 6253*3db86aabSstevel break; 6254*3db86aabSstevel case PCIC_O2_OZ6912: 6255*3db86aabSstevel value = pcic_getb(pcic, 0, PCIC_CENTDMA); 6256*3db86aabSstevel value &= ~0x8; 6257*3db86aabSstevel pcic_putb(pcic, 0, PCIC_CENTDMA, value); 6258*3db86aabSstevel /* Flush the write */ 6259*3db86aabSstevel (void) pcic_getb(pcic, 0, PCIC_CENTDMA); 6260*3db86aabSstevel break; 6261*3db86aabSstevel case PCIC_CL_PD6832: 6262*3db86aabSstevel case PCIC_TI_PCI1250: 6263*3db86aabSstevel case PCIC_TI_PCI1221: 6264*3db86aabSstevel case PCIC_TI_PCI1225: 6265*3db86aabSstevel case PCIC_TI_PCI1410: 6266*3db86aabSstevel case PCIC_ENE_1410: 6267*3db86aabSstevel case PCIC_TI_PCI1510: 6268*3db86aabSstevel case PCIC_TI_PCI1520: 6269*3db86aabSstevel case PCIC_TI_PCI1420: 6270*3db86aabSstevel case PCIC_ENE_1420: 6271*3db86aabSstevel /* 6272*3db86aabSstevel * This maps I/O interrupts to ExCA which 6273*3db86aabSstevel * have been turned off by the write to 6274*3db86aabSstevel * PCIC_INTERRUPT above. It would appear to 6275*3db86aabSstevel * be the only way to actually turn I/O Ints off 6276*3db86aabSstevel * while retaining CS Ints. 6277*3db86aabSstevel */ 6278*3db86aabSstevel brdgctl = ddi_get16(pcic->cfg_handle, 6279*3db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL)); 6280*3db86aabSstevel pcic_err(NULL, 1, 6281*3db86aabSstevel "pcic_disable_io_intr brdgctl(0x%x) was: 0x%x\n", 6282*3db86aabSstevel PCI_CBUS_BRIDGE_CTRL, brdgctl); 6283*3db86aabSstevel brdgctl |= PCIC_BRDGCTL_INTR_MASK; 6284*3db86aabSstevel ddi_put16(pcic->cfg_handle, 6285*3db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL), 6286*3db86aabSstevel brdgctl); 6287*3db86aabSstevel /* Flush the write */ 6288*3db86aabSstevel (void) ddi_get16(pcic->cfg_handle, 6289*3db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL)); 6290*3db86aabSstevel break; 6291*3db86aabSstevel default: 6292*3db86aabSstevel break; 6293*3db86aabSstevel } 6294*3db86aabSstevel } 6295*3db86aabSstevel 6296*3db86aabSstevel static void 6297*3db86aabSstevel pcic_cb_enable_intr(dev_info_t *dip) 6298*3db86aabSstevel { 6299*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 6300*3db86aabSstevel pcicdev_t *pcic = anp->an_private; 6301*3db86aabSstevel 6302*3db86aabSstevel mutex_enter(&pcic->pc_lock); 6303*3db86aabSstevel pcic_enable_io_intr(pcic, 0, pcic->pc_sockets[0].pcs_irq); 6304*3db86aabSstevel mutex_exit(&pcic->pc_lock); 6305*3db86aabSstevel } 6306*3db86aabSstevel 6307*3db86aabSstevel static void 6308*3db86aabSstevel pcic_cb_disable_intr(dev_info_t *dip) 6309*3db86aabSstevel { 6310*3db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 6311*3db86aabSstevel pcicdev_t *pcic = anp->an_private; 6312*3db86aabSstevel 6313*3db86aabSstevel mutex_enter(&pcic->pc_lock); 6314*3db86aabSstevel pcic_disable_io_intr(pcic, 0); 6315*3db86aabSstevel mutex_exit(&pcic->pc_lock); 6316*3db86aabSstevel } 6317*3db86aabSstevel 6318*3db86aabSstevel static int 6319*3db86aabSstevel log_pci_cfg_err(ushort_t e, int bridge_secondary) 6320*3db86aabSstevel { 6321*3db86aabSstevel int nerr = 0; 6322*3db86aabSstevel if (e & PCI_STAT_PERROR) { 6323*3db86aabSstevel nerr++; 6324*3db86aabSstevel cmn_err(CE_CONT, "detected parity error.\n"); 6325*3db86aabSstevel } 6326*3db86aabSstevel if (e & PCI_STAT_S_SYSERR) { 6327*3db86aabSstevel nerr++; 6328*3db86aabSstevel if (bridge_secondary) 6329*3db86aabSstevel cmn_err(CE_CONT, "received system error.\n"); 6330*3db86aabSstevel else 6331*3db86aabSstevel cmn_err(CE_CONT, "signalled system error.\n"); 6332*3db86aabSstevel } 6333*3db86aabSstevel if (e & PCI_STAT_R_MAST_AB) { 6334*3db86aabSstevel nerr++; 6335*3db86aabSstevel cmn_err(CE_CONT, "received master abort.\n"); 6336*3db86aabSstevel } 6337*3db86aabSstevel if (e & PCI_STAT_R_TARG_AB) 6338*3db86aabSstevel cmn_err(CE_CONT, "received target abort.\n"); 6339*3db86aabSstevel if (e & PCI_STAT_S_TARG_AB) 6340*3db86aabSstevel cmn_err(CE_CONT, "signalled target abort\n"); 6341*3db86aabSstevel if (e & PCI_STAT_S_PERROR) { 6342*3db86aabSstevel nerr++; 6343*3db86aabSstevel cmn_err(CE_CONT, "signalled parity error\n"); 6344*3db86aabSstevel } 6345*3db86aabSstevel return (nerr); 6346*3db86aabSstevel } 6347*3db86aabSstevel 6348*3db86aabSstevel #if defined(__sparc) 6349*3db86aabSstevel static int 6350*3db86aabSstevel pcic_fault(enum pci_fault_ops op, void *arg) 6351*3db86aabSstevel { 6352*3db86aabSstevel pcicdev_t *pcic = (pcicdev_t *)arg; 6353*3db86aabSstevel ushort_t pci_cfg_stat = 6354*3db86aabSstevel pci_config_get16(pcic->cfg_handle, PCI_CONF_STAT); 6355*3db86aabSstevel ushort_t pci_cfg_sec_stat = 6356*3db86aabSstevel pci_config_get16(pcic->cfg_handle, 0x16); 6357*3db86aabSstevel char nm[24]; 6358*3db86aabSstevel int nerr = 0; 6359*3db86aabSstevel 6360*3db86aabSstevel cardbus_dump_pci_config(pcic->dip); 6361*3db86aabSstevel 6362*3db86aabSstevel switch (op) { 6363*3db86aabSstevel case FAULT_LOG: 6364*3db86aabSstevel (void) sprintf(nm, "%s-%d", ddi_driver_name(pcic->dip), 6365*3db86aabSstevel ddi_get_instance(pcic->dip)); 6366*3db86aabSstevel 6367*3db86aabSstevel cmn_err(CE_WARN, "%s: PCIC fault log start:\n", nm); 6368*3db86aabSstevel cmn_err(CE_WARN, "%s: primary err (%x):\n", nm, pci_cfg_stat); 6369*3db86aabSstevel nerr += log_pci_cfg_err(pci_cfg_stat, 0); 6370*3db86aabSstevel cmn_err(CE_WARN, "%s: sec err (%x):\n", nm, pci_cfg_sec_stat); 6371*3db86aabSstevel nerr += log_pci_cfg_err(pci_cfg_sec_stat, 1); 6372*3db86aabSstevel cmn_err(CE_CONT, "%s: PCI fault log end.\n", nm); 6373*3db86aabSstevel return (nerr); 6374*3db86aabSstevel case FAULT_POKEFINI: 6375*3db86aabSstevel case FAULT_RESET: 6376*3db86aabSstevel pci_config_put16(pcic->cfg_handle, 6377*3db86aabSstevel PCI_CONF_STAT, pci_cfg_stat); 6378*3db86aabSstevel pci_config_put16(pcic->cfg_handle, 0x16, pci_cfg_sec_stat); 6379*3db86aabSstevel break; 6380*3db86aabSstevel case FAULT_POKEFLT: 6381*3db86aabSstevel if (!(pci_cfg_stat & PCI_STAT_S_SYSERR)) 6382*3db86aabSstevel return (1); 6383*3db86aabSstevel if (!(pci_cfg_sec_stat & PCI_STAT_R_MAST_AB)) 6384*3db86aabSstevel return (1); 6385*3db86aabSstevel break; 6386*3db86aabSstevel default: 6387*3db86aabSstevel break; 6388*3db86aabSstevel } 6389*3db86aabSstevel return (DDI_SUCCESS); 6390*3db86aabSstevel } 6391*3db86aabSstevel #endif 6392*3db86aabSstevel 6393*3db86aabSstevel static void 6394*3db86aabSstevel pcic_delayed_resume(void *arg) 6395*3db86aabSstevel { 6396*3db86aabSstevel int i, j, interrupt; 6397*3db86aabSstevel anp_t *pcic_nexus; 6398*3db86aabSstevel pcicdev_t *pcic; 6399*3db86aabSstevel 6400*3db86aabSstevel _NOTE(ARGUNUSED(arg)) 6401*3db86aabSstevel 6402*3db86aabSstevel #if defined(PCIC_DEBUG) 6403*3db86aabSstevel pcic_err(NULL, 6, "pcic_delayed_resume(): entered\n"); 6404*3db86aabSstevel #endif 6405*3db86aabSstevel for (j = 0; j <= pcic_maxinst; j++) { 6406*3db86aabSstevel 6407*3db86aabSstevel pcic_nexus = ddi_get_soft_state(pcic_soft_state_p, j); 6408*3db86aabSstevel if (!pcic_nexus) 6409*3db86aabSstevel continue; 6410*3db86aabSstevel pcic = (pcicdev_t *)pcic_nexus->an_private; 6411*3db86aabSstevel if (!pcic) 6412*3db86aabSstevel continue; 6413*3db86aabSstevel 6414*3db86aabSstevel pcic_mutex_enter(&pcic->pc_lock); /* protect the registers */ 6415*3db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) { 6416*3db86aabSstevel /* Enable interrupts on PCI if needs be */ 6417*3db86aabSstevel interrupt = pcic_getb(pcic, i, PCIC_INTERRUPT); 6418*3db86aabSstevel if (pcic->pc_flags & PCF_USE_SMI) 6419*3db86aabSstevel interrupt |= PCIC_INTR_ENABLE; 6420*3db86aabSstevel pcic_putb(pcic, i, PCIC_INTERRUPT, 6421*3db86aabSstevel PCIC_RESET | interrupt); 6422*3db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id = 6423*3db86aabSstevel pcic_add_debqueue(&pcic->pc_sockets[i], 6424*3db86aabSstevel drv_usectohz(pcic_debounce_time)); 6425*3db86aabSstevel } 6426*3db86aabSstevel pcic_mutex_exit(&pcic->pc_lock); /* protect the registers */ 6427*3db86aabSstevel if (pcic_do_pcmcia_sr) 6428*3db86aabSstevel (void) pcmcia_wait_insert(pcic->dip); 6429*3db86aabSstevel } 6430*3db86aabSstevel } 6431*3db86aabSstevel 6432*3db86aabSstevel static void 6433*3db86aabSstevel pcic_debounce(pcic_socket_t *pcs) 6434*3db86aabSstevel { 6435*3db86aabSstevel uint8_t status, stschng; 6436*3db86aabSstevel 6437*3db86aabSstevel pcic_mutex_enter(&pcs->pcs_pcic->pc_lock); 6438*3db86aabSstevel pcs->pcs_flags &= ~PCS_STARTING; 6439*3db86aabSstevel stschng = pcic_getb(pcs->pcs_pcic, pcs->pcs_socket, 6440*3db86aabSstevel PCIC_CARD_STATUS_CHANGE); 6441*3db86aabSstevel status = pcic_getb(pcs->pcs_pcic, pcs->pcs_socket, 6442*3db86aabSstevel PCIC_INTERFACE_STATUS); 6443*3db86aabSstevel #ifdef PCIC_DEBUG 6444*3db86aabSstevel pcic_err(pcs->pcs_pcic->dip, 8, 6445*3db86aabSstevel "pcic_debounce(0x%p, dip=0x%p) socket %d st 0x%x " 6446*3db86aabSstevel "chg 0x%x flg 0x%x\n", 6447*3db86aabSstevel (void *)pcs, (void *) pcs->pcs_pcic->dip, pcs->pcs_socket, 6448*3db86aabSstevel status, stschng, pcs->pcs_flags); 6449*3db86aabSstevel #endif 6450*3db86aabSstevel 6451*3db86aabSstevel pcic_putb(pcs->pcs_pcic, pcs->pcs_socket, PCIC_CARD_STATUS_CHANGE, 6452*3db86aabSstevel PCIC_CD_DETECT); 6453*3db86aabSstevel pcic_handle_cd_change(pcs->pcs_pcic, pcs, status); 6454*3db86aabSstevel pcic_mutex_exit(&pcs->pcs_pcic->pc_lock); 6455*3db86aabSstevel } 6456*3db86aabSstevel 6457*3db86aabSstevel static void 6458*3db86aabSstevel pcic_deb_thread() 6459*3db86aabSstevel { 6460*3db86aabSstevel callb_cpr_t cprinfo; 6461*3db86aabSstevel struct debounce *debp; 6462*3db86aabSstevel clock_t lastt; 6463*3db86aabSstevel 6464*3db86aabSstevel CALLB_CPR_INIT(&cprinfo, &pcic_deb_mtx, 6465*3db86aabSstevel callb_generic_cpr, "pcic debounce thread"); 6466*3db86aabSstevel mutex_enter(&pcic_deb_mtx); 6467*3db86aabSstevel while (pcic_deb_threadid) { 6468*3db86aabSstevel while (pcic_deb_queue) { 6469*3db86aabSstevel #ifdef PCIC_DEBUG 6470*3db86aabSstevel pcic_dump_debqueue("Thread"); 6471*3db86aabSstevel #endif 6472*3db86aabSstevel debp = pcic_deb_queue; 6473*3db86aabSstevel (void) drv_getparm(LBOLT, &lastt); 6474*3db86aabSstevel if (lastt >= debp->expire) { 6475*3db86aabSstevel pcic_deb_queue = debp->next; 6476*3db86aabSstevel mutex_exit(&pcic_deb_mtx); 6477*3db86aabSstevel pcic_debounce(debp->pcs); 6478*3db86aabSstevel mutex_enter(&pcic_deb_mtx); 6479*3db86aabSstevel kmem_free(debp, sizeof (*debp)); 6480*3db86aabSstevel } else { 6481*3db86aabSstevel (void) cv_timedwait(&pcic_deb_cv, 6482*3db86aabSstevel &pcic_deb_mtx, debp->expire); 6483*3db86aabSstevel } 6484*3db86aabSstevel } 6485*3db86aabSstevel CALLB_CPR_SAFE_BEGIN(&cprinfo); 6486*3db86aabSstevel cv_wait(&pcic_deb_cv, &pcic_deb_mtx); 6487*3db86aabSstevel CALLB_CPR_SAFE_END(&cprinfo, &pcic_deb_mtx); 6488*3db86aabSstevel } 6489*3db86aabSstevel pcic_deb_threadid = (kthread_t *)1; 6490*3db86aabSstevel cv_signal(&pcic_deb_cv); 6491*3db86aabSstevel CALLB_CPR_EXIT(&cprinfo); /* Also exits the mutex */ 6492*3db86aabSstevel thread_exit(); 6493*3db86aabSstevel } 6494*3db86aabSstevel 6495*3db86aabSstevel static void * 6496*3db86aabSstevel pcic_add_debqueue(pcic_socket_t *pcs, int clocks) 6497*3db86aabSstevel { 6498*3db86aabSstevel clock_t lbolt; 6499*3db86aabSstevel struct debounce *dbp, **dbpp = &pcic_deb_queue; 6500*3db86aabSstevel 6501*3db86aabSstevel (void) drv_getparm(LBOLT, &lbolt); 6502*3db86aabSstevel dbp = kmem_alloc(sizeof (struct debounce), KM_NOSLEEP); 6503*3db86aabSstevel 6504*3db86aabSstevel dbp->expire = lbolt + clocks; 6505*3db86aabSstevel dbp->pcs = pcs; 6506*3db86aabSstevel mutex_enter(&pcic_deb_mtx); 6507*3db86aabSstevel while (*dbpp) { 6508*3db86aabSstevel if (dbp->expire > (*dbpp)->expire) 6509*3db86aabSstevel dbpp = &((*dbpp)->next); 6510*3db86aabSstevel else 6511*3db86aabSstevel break; 6512*3db86aabSstevel } 6513*3db86aabSstevel dbp->next = *dbpp; 6514*3db86aabSstevel *dbpp = dbp; 6515*3db86aabSstevel #ifdef PCIC_DEBUG 6516*3db86aabSstevel pcic_dump_debqueue("Add"); 6517*3db86aabSstevel #endif 6518*3db86aabSstevel cv_signal(&pcic_deb_cv); 6519*3db86aabSstevel mutex_exit(&pcic_deb_mtx); 6520*3db86aabSstevel return (dbp); 6521*3db86aabSstevel } 6522*3db86aabSstevel 6523*3db86aabSstevel static void 6524*3db86aabSstevel pcic_rm_debqueue(void *id) 6525*3db86aabSstevel { 6526*3db86aabSstevel struct debounce *dbp, **dbpp = &pcic_deb_queue; 6527*3db86aabSstevel 6528*3db86aabSstevel dbp = (struct debounce *)id; 6529*3db86aabSstevel mutex_enter(&pcic_deb_mtx); 6530*3db86aabSstevel while (*dbpp) { 6531*3db86aabSstevel if (*dbpp == dbp) { 6532*3db86aabSstevel *dbpp = dbp->next; 6533*3db86aabSstevel kmem_free(dbp, sizeof (*dbp)); 6534*3db86aabSstevel #ifdef PCIC_DEBUG 6535*3db86aabSstevel pcic_dump_debqueue("Remove"); 6536*3db86aabSstevel #endif 6537*3db86aabSstevel cv_signal(&pcic_deb_cv); 6538*3db86aabSstevel mutex_exit(&pcic_deb_mtx); 6539*3db86aabSstevel return; 6540*3db86aabSstevel } 6541*3db86aabSstevel dbpp = &((*dbpp)->next); 6542*3db86aabSstevel } 6543*3db86aabSstevel pcic_err(NULL, 6, "pcic: Failed to find debounce id 0x%p\n", id); 6544*3db86aabSstevel mutex_exit(&pcic_deb_mtx); 6545*3db86aabSstevel } 6546*3db86aabSstevel 6547*3db86aabSstevel 6548*3db86aabSstevel static int pcic_powerdelay = 0; 6549*3db86aabSstevel 6550*3db86aabSstevel static int 6551*3db86aabSstevel pcic_exca_powerctl(pcicdev_t *pcic, int socket, int powerlevel) 6552*3db86aabSstevel { 6553*3db86aabSstevel int ind, value, orig_pwrctl; 6554*3db86aabSstevel 6555*3db86aabSstevel /* power setup -- if necessary */ 6556*3db86aabSstevel orig_pwrctl = pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 6557*3db86aabSstevel 6558*3db86aabSstevel #if defined(PCIC_DEBUG) 6559*3db86aabSstevel pcic_err(pcic->dip, 6, 6560*3db86aabSstevel "pcic_exca_powerctl(socket %d) powerlevel=%x orig 0x%x\n", 6561*3db86aabSstevel socket, powerlevel, orig_pwrctl); 6562*3db86aabSstevel #endif 6563*3db86aabSstevel /* Preserve the PCIC_OUTPUT_ENABLE (control lines output enable) bit. */ 6564*3db86aabSstevel powerlevel = (powerlevel & ~POWER_OUTPUT_ENABLE) | 6565*3db86aabSstevel (orig_pwrctl & POWER_OUTPUT_ENABLE); 6566*3db86aabSstevel if (powerlevel != orig_pwrctl) { 6567*3db86aabSstevel if (powerlevel & ~POWER_OUTPUT_ENABLE) { 6568*3db86aabSstevel int ifs; 6569*3db86aabSstevel /* 6570*3db86aabSstevel * set power to socket 6571*3db86aabSstevel * note that the powerlevel was calculated earlier 6572*3db86aabSstevel */ 6573*3db86aabSstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel); 6574*3db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 6575*3db86aabSstevel 6576*3db86aabSstevel /* 6577*3db86aabSstevel * this second write to the power control register 6578*3db86aabSstevel * is needed to resolve a problem on 6579*3db86aabSstevel * the IBM ThinkPad 750 6580*3db86aabSstevel * where the first write doesn't latch. 6581*3db86aabSstevel * The second write appears to always work and 6582*3db86aabSstevel * doesn't hurt the operation of other chips 6583*3db86aabSstevel * so we can just use it -- this is good since we can't 6584*3db86aabSstevel * determine what chip the 750 actually uses 6585*3db86aabSstevel * (I suspect an early Ricoh). 6586*3db86aabSstevel */ 6587*3db86aabSstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel); 6588*3db86aabSstevel 6589*3db86aabSstevel value = pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 6590*3db86aabSstevel pcic_mswait(pcic, socket, pcic_powerdelay); 6591*3db86aabSstevel #if defined(PCIC_DEBUG) 6592*3db86aabSstevel pcic_err(pcic->dip, 8, 6593*3db86aabSstevel "\tpowerlevel reg = %x (ifs %x)\n", 6594*3db86aabSstevel value, pcic_getb(pcic, socket, 6595*3db86aabSstevel PCIC_INTERFACE_STATUS)); 6596*3db86aabSstevel pcic_err(pcic->dip, 8, 6597*3db86aabSstevel "CBus regs: PS 0x%x, Control 0x%x\n", 6598*3db86aabSstevel pcic_getcb(pcic, CB_PRESENT_STATE), 6599*3db86aabSstevel pcic_getcb(pcic, CB_CONTROL)); 6600*3db86aabSstevel #endif 6601*3db86aabSstevel /* 6602*3db86aabSstevel * since power was touched, make sure it says it 6603*3db86aabSstevel * is on. This lets it become stable. 6604*3db86aabSstevel */ 6605*3db86aabSstevel for (ind = 0; ind < 20; ind++) { 6606*3db86aabSstevel ifs = pcic_getb(pcic, socket, 6607*3db86aabSstevel PCIC_INTERFACE_STATUS); 6608*3db86aabSstevel if (ifs & PCIC_POWER_ON) 6609*3db86aabSstevel break; 6610*3db86aabSstevel else { 6611*3db86aabSstevel pcic_putb(pcic, socket, 6612*3db86aabSstevel PCIC_POWER_CONTROL, 0); 6613*3db86aabSstevel (void) pcic_getb(pcic, socket, 6614*3db86aabSstevel PCIC_POWER_CONTROL); 6615*3db86aabSstevel pcic_mswait(pcic, socket, 40); 6616*3db86aabSstevel if (ind == 10) { 6617*3db86aabSstevel pcic_putcb(pcic, CB_EVENT_FORCE, 6618*3db86aabSstevel CB_EF_CVTEST); 6619*3db86aabSstevel pcic_mswait(pcic, socket, 100); 6620*3db86aabSstevel } 6621*3db86aabSstevel pcic_putb(pcic, socket, 6622*3db86aabSstevel PCIC_POWER_CONTROL, 6623*3db86aabSstevel powerlevel & ~POWER_OUTPUT_ENABLE); 6624*3db86aabSstevel (void) pcic_getb(pcic, socket, 6625*3db86aabSstevel PCIC_POWER_CONTROL); 6626*3db86aabSstevel pcic_mswait(pcic, socket, 6627*3db86aabSstevel pcic_powerdelay); 6628*3db86aabSstevel pcic_putb(pcic, socket, 6629*3db86aabSstevel PCIC_POWER_CONTROL, powerlevel); 6630*3db86aabSstevel (void) pcic_getb(pcic, socket, 6631*3db86aabSstevel PCIC_POWER_CONTROL); 6632*3db86aabSstevel pcic_mswait(pcic, socket, 6633*3db86aabSstevel pcic_powerdelay); 6634*3db86aabSstevel } 6635*3db86aabSstevel } 6636*3db86aabSstevel 6637*3db86aabSstevel if (!(ifs & PCIC_POWER_ON)) { 6638*3db86aabSstevel cmn_err(CE_WARN, 6639*3db86aabSstevel "pcic socket %d: Power didn't get turned" 6640*3db86aabSstevel "on!\nif status 0x%x pwrc 0x%x(x%x) " 6641*3db86aabSstevel "misc1 0x%x igc 0x%x ind %d\n", 6642*3db86aabSstevel socket, ifs, 6643*3db86aabSstevel pcic_getb(pcic, socket, PCIC_POWER_CONTROL), 6644*3db86aabSstevel orig_pwrctl, 6645*3db86aabSstevel pcic_getb(pcic, socket, PCIC_MISC_CTL_1), 6646*3db86aabSstevel pcic_getb(pcic, socket, PCIC_INTERRUPT), 6647*3db86aabSstevel ind); 6648*3db86aabSstevel return (BAD_VCC); 6649*3db86aabSstevel } 6650*3db86aabSstevel #if defined(PCIC_DEBUG) 6651*3db86aabSstevel pcic_err(pcic->dip, 8, 6652*3db86aabSstevel "\tind = %d, if status %x pwrc 0x%x " 6653*3db86aabSstevel "misc1 0x%x igc 0x%x\n", 6654*3db86aabSstevel ind, ifs, 6655*3db86aabSstevel pcic_getb(pcic, socket, PCIC_POWER_CONTROL), 6656*3db86aabSstevel pcic_getb(pcic, socket, PCIC_MISC_CTL_1), 6657*3db86aabSstevel pcic_getb(pcic, socket, PCIC_INTERRUPT)); 6658*3db86aabSstevel #endif 6659*3db86aabSstevel } else { 6660*3db86aabSstevel /* explicitly turned off the power */ 6661*3db86aabSstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel); 6662*3db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 6663*3db86aabSstevel } 6664*3db86aabSstevel } 6665*3db86aabSstevel return (SUCCESS); 6666*3db86aabSstevel } 6667*3db86aabSstevel 6668*3db86aabSstevel static int pcic_cbdoreset_during_poweron = 1; 6669*3db86aabSstevel static int 6670*3db86aabSstevel pcic_cbus_powerctl(pcicdev_t *pcic, int socket) 6671*3db86aabSstevel { 6672*3db86aabSstevel uint32_t cbctl = 0, orig_cbctl, cbstev, cbps; 6673*3db86aabSstevel int ind, iobits; 6674*3db86aabSstevel pcic_socket_t *sockp = &pcic->pc_sockets[socket]; 6675*3db86aabSstevel 6676*3db86aabSstevel pcic_putcb(pcic, CB_STATUS_EVENT, CB_SE_POWER_CYCLE); 6677*3db86aabSstevel 6678*3db86aabSstevel ind = pcic_power[sockp->pcs_vpp1].PowerLevel/10; 6679*3db86aabSstevel cbctl |= pcic_cbv_levels[ind]; 6680*3db86aabSstevel 6681*3db86aabSstevel ind = pcic_power[sockp->pcs_vcc].PowerLevel/10; 6682*3db86aabSstevel cbctl |= (pcic_cbv_levels[ind]<<4); 6683*3db86aabSstevel 6684*3db86aabSstevel orig_cbctl = pcic_getcb(pcic, CB_CONTROL); 6685*3db86aabSstevel 6686*3db86aabSstevel #if defined(PCIC_DEBUG) 6687*3db86aabSstevel pcic_err(pcic->dip, 6, 6688*3db86aabSstevel "pcic_cbus_powerctl(socket %d) vcc %d vpp1 %d " 6689*3db86aabSstevel "cbctl 0x%x->0x%x\n", 6690*3db86aabSstevel socket, sockp->pcs_vcc, sockp->pcs_vpp1, orig_cbctl, cbctl); 6691*3db86aabSstevel #endif 6692*3db86aabSstevel if (cbctl != orig_cbctl) { 6693*3db86aabSstevel if (pcic_cbdoreset_during_poweron && 6694*3db86aabSstevel (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) { 6695*3db86aabSstevel iobits = pcic_getb(pcic, socket, PCIC_INTERRUPT); 6696*3db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits & ~PCIC_RESET); 6697*3db86aabSstevel } 6698*3db86aabSstevel pcic_putcb(pcic, CB_CONTROL, cbctl); 6699*3db86aabSstevel 6700*3db86aabSstevel if ((cbctl & CB_C_VCCMASK) == (orig_cbctl & CB_C_VCCMASK)) { 6701*3db86aabSstevel pcic_mswait(pcic, socket, pcic_powerdelay); 6702*3db86aabSstevel return (SUCCESS); 6703*3db86aabSstevel } 6704*3db86aabSstevel for (ind = 0; ind < 20; ind++) { 6705*3db86aabSstevel cbstev = pcic_getcb(pcic, CB_STATUS_EVENT); 6706*3db86aabSstevel 6707*3db86aabSstevel if (cbstev & CB_SE_POWER_CYCLE) { 6708*3db86aabSstevel 6709*3db86aabSstevel /* 6710*3db86aabSstevel * delay 400 ms: though the standard defines that the Vcc 6711*3db86aabSstevel * set-up time is 20 ms, some PC-Card bridge requires longer 6712*3db86aabSstevel * duration. 6713*3db86aabSstevel * Note: We should check the status AFTER the delay to give time 6714*3db86aabSstevel * for things to stabilize. 6715*3db86aabSstevel */ 6716*3db86aabSstevel pcic_mswait(pcic, socket, 400); 6717*3db86aabSstevel 6718*3db86aabSstevel cbps = pcic_getcb(pcic, CB_PRESENT_STATE); 6719*3db86aabSstevel if (cbctl && !(cbps & CB_PS_POWER_CYCLE)) { 6720*3db86aabSstevel /* break; */ 6721*3db86aabSstevel cmn_err(CE_WARN, "cbus_powerctl: power off??\n"); 6722*3db86aabSstevel } 6723*3db86aabSstevel if (cbctl & CB_PS_BADVCC) { 6724*3db86aabSstevel cmn_err(CE_WARN, "cbus_powerctl: bad power request\n"); 6725*3db86aabSstevel break; 6726*3db86aabSstevel } 6727*3db86aabSstevel 6728*3db86aabSstevel #if defined(PCIC_DEBUG) 6729*3db86aabSstevel pcic_err(pcic->dip, 8, 6730*3db86aabSstevel "cbstev = 0x%x cbps = 0x%x cbctl 0x%x(0x%x)", 6731*3db86aabSstevel cbstev, pcic_getcb(pcic, CB_PRESENT_STATE), 6732*3db86aabSstevel cbctl, orig_cbctl); 6733*3db86aabSstevel #endif 6734*3db86aabSstevel if (pcic_cbdoreset_during_poweron && 6735*3db86aabSstevel (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) { 6736*3db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits); 6737*3db86aabSstevel } 6738*3db86aabSstevel return (SUCCESS); 6739*3db86aabSstevel } 6740*3db86aabSstevel pcic_mswait(pcic, socket, 40); 6741*3db86aabSstevel } 6742*3db86aabSstevel if (pcic_cbdoreset_during_poweron && 6743*3db86aabSstevel (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) { 6744*3db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits); 6745*3db86aabSstevel } 6746*3db86aabSstevel cmn_err(CE_WARN, 6747*3db86aabSstevel "pcic socket %d: Power didn't get turned on/off!\n" 6748*3db86aabSstevel "cbstev = 0x%x cbps = 0x%x cbctl 0x%x(0x%x) " 6749*3db86aabSstevel "vcc %d vpp1 %d", socket, cbstev, 6750*3db86aabSstevel pcic_getcb(pcic, CB_PRESENT_STATE), 6751*3db86aabSstevel cbctl, orig_cbctl, sockp->pcs_vcc, sockp->pcs_vpp1); 6752*3db86aabSstevel return (BAD_VCC); 6753*3db86aabSstevel } 6754*3db86aabSstevel return (SUCCESS); 6755*3db86aabSstevel } 6756*3db86aabSstevel 6757*3db86aabSstevel static int pcic_do_pprintf = 0; 6758*3db86aabSstevel 6759*3db86aabSstevel static void 6760*3db86aabSstevel pcic_dump_debqueue(char *msg) 6761*3db86aabSstevel { 6762*3db86aabSstevel struct debounce *debp = pcic_deb_queue; 6763*3db86aabSstevel clock_t lbolt; 6764*3db86aabSstevel 6765*3db86aabSstevel (void) drv_getparm(LBOLT, &lbolt); 6766*3db86aabSstevel pcic_err(NULL, 6, debp ? "pcic debounce list (%s) lbolt 0x%x:\n" : 6767*3db86aabSstevel "pcic debounce_list (%s) EMPTY lbolt 0x%x\n", msg, lbolt); 6768*3db86aabSstevel while (debp) { 6769*3db86aabSstevel pcic_err(NULL, 6, "%p: exp 0x%x next 0x%p id 0x%p\n", 6770*3db86aabSstevel (void *) debp, (int)debp->expire, (void *) debp->next, 6771*3db86aabSstevel debp->pcs->pcs_debounce_id); 6772*3db86aabSstevel debp = debp->next; 6773*3db86aabSstevel } 6774*3db86aabSstevel } 6775*3db86aabSstevel 6776*3db86aabSstevel 6777*3db86aabSstevel /* PRINTFLIKE3 */ 6778*3db86aabSstevel static void 6779*3db86aabSstevel pcic_err(dev_info_t *dip, int level, const char *fmt, ...) 6780*3db86aabSstevel { 6781*3db86aabSstevel if (pcic_debug && (level <= pcic_debug)) { 6782*3db86aabSstevel va_list adx; 6783*3db86aabSstevel int instance; 6784*3db86aabSstevel char buf[256]; 6785*3db86aabSstevel const char *name; 6786*3db86aabSstevel #if !defined(PCIC_DEBUG) 6787*3db86aabSstevel int ce; 6788*3db86aabSstevel char qmark = 0; 6789*3db86aabSstevel 6790*3db86aabSstevel if (level <= 3) 6791*3db86aabSstevel ce = CE_WARN; 6792*3db86aabSstevel else 6793*3db86aabSstevel ce = CE_CONT; 6794*3db86aabSstevel if (level == 4) 6795*3db86aabSstevel qmark = 1; 6796*3db86aabSstevel #endif 6797*3db86aabSstevel 6798*3db86aabSstevel if (dip) { 6799*3db86aabSstevel instance = ddi_get_instance(dip); 6800*3db86aabSstevel /* name = ddi_binding_name(dip); */ 6801*3db86aabSstevel name = ddi_driver_name(dip); 6802*3db86aabSstevel } else { 6803*3db86aabSstevel instance = 0; 6804*3db86aabSstevel name = ""; 6805*3db86aabSstevel } 6806*3db86aabSstevel 6807*3db86aabSstevel va_start(adx, fmt); 6808*3db86aabSstevel (void) vsprintf(buf, fmt, adx); 6809*3db86aabSstevel va_end(adx); 6810*3db86aabSstevel 6811*3db86aabSstevel #if defined(PCIC_DEBUG) 6812*3db86aabSstevel if (pcic_do_pprintf) { 6813*3db86aabSstevel if (dip) { 6814*3db86aabSstevel if (instance >= 0) 6815*3db86aabSstevel prom_printf("%s(%d),0x%p: %s", name, 6816*3db86aabSstevel instance, dip, buf); 6817*3db86aabSstevel else 6818*3db86aabSstevel prom_printf("%s,0x%p: %s", 6819*3db86aabSstevel name, dip, buf); 6820*3db86aabSstevel } else 6821*3db86aabSstevel prom_printf(buf); 6822*3db86aabSstevel } else { 6823*3db86aabSstevel if (dip) { 6824*3db86aabSstevel if (instance >= 0) 6825*3db86aabSstevel cmn_err(CE_CONT, "%s(%d),0x%p: %s", 6826*3db86aabSstevel name, instance, (void *) dip, buf); 6827*3db86aabSstevel else 6828*3db86aabSstevel cmn_err(CE_CONT, "%s,0x%p: %s", 6829*3db86aabSstevel name, (void *) dip, buf); 6830*3db86aabSstevel } else 6831*3db86aabSstevel cmn_err(CE_CONT, buf); 6832*3db86aabSstevel } 6833*3db86aabSstevel #else 6834*3db86aabSstevel if (dip) 6835*3db86aabSstevel cmn_err(ce, qmark ? "?%s%d: %s" : "%s%d: %s", name, 6836*3db86aabSstevel instance, buf); 6837*3db86aabSstevel else 6838*3db86aabSstevel cmn_err(ce, qmark ? "?%s" : buf, buf); 6839*3db86aabSstevel #endif 6840*3db86aabSstevel } 6841*3db86aabSstevel } 6842*3db86aabSstevel 6843*3db86aabSstevel 6844*3db86aabSstevel static void 6845*3db86aabSstevel pcic_syshw_cardstate(syshw_t *item, void *arg) 6846*3db86aabSstevel { 6847*3db86aabSstevel pcic_socket_t *pcs = (pcic_socket_t *)arg; 6848*3db86aabSstevel 6849*3db86aabSstevel if (pcs->pcs_flags & PCS_CARD_PRESENT) { 6850*3db86aabSstevel item->state = B_TRUE; 6851*3db86aabSstevel if (pcs->pcs_flags & PCS_CARD_IS16BIT) 6852*3db86aabSstevel item->values[0] = 1; 6853*3db86aabSstevel else if (pcs->pcs_flags & PCS_CARD_ISCARDBUS) 6854*3db86aabSstevel item->values[0] = 2; 6855*3db86aabSstevel else 6856*3db86aabSstevel item->values[0] = 0; 6857*3db86aabSstevel } else { 6858*3db86aabSstevel item->state = B_FALSE; 6859*3db86aabSstevel item->values[0] = 0; 6860*3db86aabSstevel } 6861*3db86aabSstevel } 6862*3db86aabSstevel 6863*3db86aabSstevel /* 6864*3db86aabSstevel * Tadpole additional for the syshw interface used to control the 6865*3db86aabSstevel * start/stop switch which is physically linked to the GPIO1 pin 6866*3db86aabSstevel * on the 1250a. 6867*3db86aabSstevel */ 6868*3db86aabSstevel 6869*3db86aabSstevel #define CLIENT_CALLED 0x8000000 6870*3db86aabSstevel #define NCE_EVENT_MASK 0xffff 6871*3db86aabSstevel 6872*3db86aabSstevel typedef struct _client { 6873*3db86aabSstevel pid_t pid; /* set by kernel */ 6874*3db86aabSstevel int flags; /* NCE_REGISTER... */ 6875*3db86aabSstevel int priority; /* >100 unless root */ 6876*3db86aabSstevel int events; /* pending event flags */ 6877*3db86aabSstevel int event_sig; /* SIG... etc */ 6878*3db86aabSstevel struct _client *next; /* set by kernel */ 6879*3db86aabSstevel struct _client *prev; /* set by kernel */ 6880*3db86aabSstevel } client_data; 6881*3db86aabSstevel 6882*3db86aabSstevel static client_data *cl_data; 6883*3db86aabSstevel static int n_clients; 6884*3db86aabSstevel static kmutex_t client_mtx, intr_mtx; 6885*3db86aabSstevel 6886*3db86aabSstevel static void delete_client(int); 6887*3db86aabSstevel 6888*3db86aabSstevel #ifdef VOYAGER 6889*3db86aabSstevel static uint32_t runstop_sig; 6890*3db86aabSstevel static ddi_softintr_t softint_id; 6891*3db86aabSstevel static uchar_t softint_flag; 6892*3db86aabSstevel static int switch_debounce_time = 100; /* in milliseconds */ 6893*3db86aabSstevel static timeout_id_t switch_to_id; 6894*3db86aabSstevel 6895*3db86aabSstevel static syshw_t syshw_run_stop = { 6896*3db86aabSstevel 0, "Run/Stop", SH_SWITCH, 6897*3db86aabSstevel SYSHW_CAN_SIGNAL_CHANGE|SYSHW_STATE_VALID, 6898*3db86aabSstevel B_FALSE, { 0 } }; 6899*3db86aabSstevel 6900*3db86aabSstevel static void 6901*3db86aabSstevel syshw_get_run_stop(syshw_t *item, void *arg) 6902*3db86aabSstevel { 6903*3db86aabSstevel pcicdev_t *pcic = (pcicdev_t *)arg; 6904*3db86aabSstevel 6905*3db86aabSstevel if (ddi_get8(pcic->cfg_handle, 6906*3db86aabSstevel pcic->cfgaddr + PCIC_GPIO1_REG) & PCIC_GPIO_DIN) 6907*3db86aabSstevel item->state = B_TRUE; 6908*3db86aabSstevel else 6909*3db86aabSstevel item->state = B_FALSE; 6910*3db86aabSstevel } 6911*3db86aabSstevel 6912*3db86aabSstevel 6913*3db86aabSstevel #endif 6914*3db86aabSstevel 6915*3db86aabSstevel static void 6916*3db86aabSstevel syshw_attach(pcicdev_t *pcic) 6917*3db86aabSstevel { 6918*3db86aabSstevel if (ddi_get_instance(pcic->dip) != 0) 6919*3db86aabSstevel return; 6920*3db86aabSstevel 6921*3db86aabSstevel #ifdef VOYAGER 6922*3db86aabSstevel if (pcic->pc_type == PCIC_TI_PCI1250) { 6923*3db86aabSstevel 6924*3db86aabSstevel /* 6925*3db86aabSstevel * Only setup run/stop on a Voyager. 6926*3db86aabSstevel * This is currently defined as 6927*3db86aabSstevel * a TI1250 on a SPARC architecture. May have to make this a 6928*3db86aabSstevel * property definition in the future. 6929*3db86aabSstevel */ 6930*3db86aabSstevel if (ddi_add_softintr(pcic->dip, 6931*3db86aabSstevel DDI_SOFTINT_LOW, &softint_id, 6932*3db86aabSstevel NULL, NULL, syshw_intr, 6933*3db86aabSstevel (caddr_t)pcic) == DDI_SUCCESS) { 6934*3db86aabSstevel runstop_sig = syshw_add2map(&syshw_run_stop, 6935*3db86aabSstevel syshw_get_run_stop, pcic); 6936*3db86aabSstevel mutex_init(&intr_mtx, NULL, MUTEX_DRIVER, 6937*3db86aabSstevel pcic->pc_pri); 6938*3db86aabSstevel ddi_put8(pcic->cfg_handle, 6939*3db86aabSstevel pcic->cfgaddr + PCIC_GPIO1_REG, 6940*3db86aabSstevel PCIC_GPIO_FINPUT | PCIC_GPIO_INTENBL | 6941*3db86aabSstevel PCIC_GPIO_DELTA); 6942*3db86aabSstevel } 6943*3db86aabSstevel } 6944*3db86aabSstevel #endif 6945*3db86aabSstevel mutex_init(&client_mtx, "syshw client", MUTEX_DRIVER, NULL); 6946*3db86aabSstevel (void) ddi_create_minor_node(pcic->dip, "syshw", S_IFCHR, 6947*3db86aabSstevel SYSHW_MINOR, NULL, NULL); 6948*3db86aabSstevel } 6949*3db86aabSstevel 6950*3db86aabSstevel static void 6951*3db86aabSstevel syshw_detach(pcicdev_t *pcic) 6952*3db86aabSstevel { 6953*3db86aabSstevel #ifdef VOYAGER 6954*3db86aabSstevel if (pcic->pc_type == PCIC_TI_PCI1250) { 6955*3db86aabSstevel pcic_mutex_enter(&intr_mtx); 6956*3db86aabSstevel 6957*3db86aabSstevel /* 6958*3db86aabSstevel * Turn off this interrupt. 6959*3db86aabSstevel */ 6960*3db86aabSstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_GPIO1_REG, 6961*3db86aabSstevel PCIC_GPIO_FINPUT); 6962*3db86aabSstevel 6963*3db86aabSstevel if (switch_to_id) 6964*3db86aabSstevel (void) untimeout(switch_to_id); 6965*3db86aabSstevel switch_to_id = 0; 6966*3db86aabSstevel softint_flag = 0; 6967*3db86aabSstevel 6968*3db86aabSstevel pcic_mutex_exit(&intr_mtx); 6969*3db86aabSstevel ddi_remove_softintr(softint_id); 6970*3db86aabSstevel mutex_destroy(&intr_mtx); 6971*3db86aabSstevel } 6972*3db86aabSstevel #endif 6973*3db86aabSstevel 6974*3db86aabSstevel ddi_remove_minor_node(pcic->dip, NULL); 6975*3db86aabSstevel mutex_destroy(&client_mtx); 6976*3db86aabSstevel } 6977*3db86aabSstevel 6978*3db86aabSstevel static void 6979*3db86aabSstevel syshw_resume(pcicdev_t *pcic) 6980*3db86aabSstevel { 6981*3db86aabSstevel #ifdef VOYAGER 6982*3db86aabSstevel if (pcic->pc_type == PCIC_TI_PCI1250) { 6983*3db86aabSstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_GPIO1_REG, 6984*3db86aabSstevel PCIC_GPIO_FINPUT | PCIC_GPIO_INTENBL | PCIC_GPIO_DELTA); 6985*3db86aabSstevel } 6986*3db86aabSstevel #else 6987*3db86aabSstevel _NOTE(ARGUNUSED(pcic)) 6988*3db86aabSstevel #endif 6989*3db86aabSstevel } 6990*3db86aabSstevel 6991*3db86aabSstevel #ifdef VOYAGER 6992*3db86aabSstevel static uint_t 6993*3db86aabSstevel syshw_intr_hi(pcicdev_t *pcic) 6994*3db86aabSstevel { 6995*3db86aabSstevel uchar_t regval; 6996*3db86aabSstevel 6997*3db86aabSstevel if (pcic->pc_type != PCIC_TI_PCI1250) 6998*3db86aabSstevel return (DDI_INTR_UNCLAIMED); 6999*3db86aabSstevel 7000*3db86aabSstevel regval = ddi_get8(pcic->cfg_handle, pcic->cfgaddr + PCIC_GPIO1_REG); 7001*3db86aabSstevel if (regval & PCIC_GPIO_DELTA) { 7002*3db86aabSstevel pcic_mutex_enter(&intr_mtx); 7003*3db86aabSstevel if (softint_flag == 0 && switch_to_id == 0) { 7004*3db86aabSstevel softint_flag = 1; 7005*3db86aabSstevel ddi_trigger_softintr(softint_id); 7006*3db86aabSstevel } 7007*3db86aabSstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_GPIO1_REG, 7008*3db86aabSstevel regval); 7009*3db86aabSstevel pcic_mutex_exit(&intr_mtx); 7010*3db86aabSstevel return (DDI_INTR_CLAIMED); 7011*3db86aabSstevel } 7012*3db86aabSstevel 7013*3db86aabSstevel return (DDI_INTR_UNCLAIMED); 7014*3db86aabSstevel } 7015*3db86aabSstevel 7016*3db86aabSstevel /* 7017*3db86aabSstevel * Don't deliver the signal until the debounce period has expired. 7018*3db86aabSstevel * Unfortuately this means it end up as a three tier interrupt just 7019*3db86aabSstevel * to indicate a bit change. 7020*3db86aabSstevel */ 7021*3db86aabSstevel static void 7022*3db86aabSstevel syshw_debounce_to(void *arg) 7023*3db86aabSstevel { 7024*3db86aabSstevel _NOTE(ARGUNUSED(arg)) 7025*3db86aabSstevel 7026*3db86aabSstevel if (switch_to_id) { 7027*3db86aabSstevel pcic_mutex_enter(&intr_mtx); 7028*3db86aabSstevel switch_to_id = 0; 7029*3db86aabSstevel pcic_mutex_exit(&intr_mtx); 7030*3db86aabSstevel syshw_send_signal(runstop_sig); 7031*3db86aabSstevel return; 7032*3db86aabSstevel } 7033*3db86aabSstevel } 7034*3db86aabSstevel 7035*3db86aabSstevel static uint_t 7036*3db86aabSstevel syshw_intr(caddr_t arg) 7037*3db86aabSstevel { 7038*3db86aabSstevel _NOTE(ARGUNUSED(arg)) 7039*3db86aabSstevel 7040*3db86aabSstevel if (softint_flag) { 7041*3db86aabSstevel pcic_mutex_enter(&intr_mtx); 7042*3db86aabSstevel softint_flag = 0; 7043*3db86aabSstevel if (!switch_to_id) 7044*3db86aabSstevel switch_to_id = timeout(syshw_debounce_to, arg, 7045*3db86aabSstevel drv_usectohz(switch_debounce_time * 1000)); 7046*3db86aabSstevel pcic_mutex_exit(&intr_mtx); 7047*3db86aabSstevel return (DDI_INTR_CLAIMED); 7048*3db86aabSstevel } 7049*3db86aabSstevel return (DDI_INTR_UNCLAIMED); 7050*3db86aabSstevel } 7051*3db86aabSstevel #endif 7052*3db86aabSstevel 7053*3db86aabSstevel /* 7054*3db86aabSstevel * Send signals to the registered clients 7055*3db86aabSstevel */ 7056*3db86aabSstevel static void 7057*3db86aabSstevel syshw_send_signal(int events) 7058*3db86aabSstevel { 7059*3db86aabSstevel client_data *ptr; 7060*3db86aabSstevel proc_t *pr; 7061*3db86aabSstevel int done_flag; 7062*3db86aabSstevel 7063*3db86aabSstevel ptr = cl_data; 7064*3db86aabSstevel while (ptr != NULL) { 7065*3db86aabSstevel done_flag = CLIENT_CALLED; 7066*3db86aabSstevel 7067*3db86aabSstevel if ((ptr->flags & events) && 7068*3db86aabSstevel (ptr->event_sig != 0) && 7069*3db86aabSstevel ((ptr->flags & done_flag) == 0)) { 7070*3db86aabSstevel 7071*3db86aabSstevel /* 7072*3db86aabSstevel * only call the process if: 7073*3db86aabSstevel * it has not already received the nce signal 7074*3db86aabSstevel * its signal was not zero (just in case) 7075*3db86aabSstevel * and it is registered to receive this signal 7076*3db86aabSstevel */ 7077*3db86aabSstevel pcic_mutex_enter(&pidlock); 7078*3db86aabSstevel pr = prfind(ptr->pid); 7079*3db86aabSstevel pcic_mutex_exit(&pidlock); 7080*3db86aabSstevel if (pr == NULL) { 7081*3db86aabSstevel /* 7082*3db86aabSstevel * This process has died, 7083*3db86aabSstevel * so we free its memory and move on 7084*3db86aabSstevel * start at the begining again: 7085*3db86aabSstevel * a waste of cycles but it makes things easy.. 7086*3db86aabSstevel */ 7087*3db86aabSstevel delete_client(ptr->pid); 7088*3db86aabSstevel ptr = cl_data; 7089*3db86aabSstevel } else { 7090*3db86aabSstevel ptr->events |= (events & ptr->flags & 7091*3db86aabSstevel NCE_EVENT_MASK); 7092*3db86aabSstevel psignal(pr, ptr->event_sig); 7093*3db86aabSstevel ptr->flags |= done_flag; 7094*3db86aabSstevel ptr = ptr->next; 7095*3db86aabSstevel } 7096*3db86aabSstevel } else { 7097*3db86aabSstevel ptr = ptr->next; 7098*3db86aabSstevel } 7099*3db86aabSstevel } 7100*3db86aabSstevel 7101*3db86aabSstevel ptr = cl_data; 7102*3db86aabSstevel while (ptr != NULL) { 7103*3db86aabSstevel ptr->flags &= ~done_flag; 7104*3db86aabSstevel ptr = ptr->next; 7105*3db86aabSstevel } 7106*3db86aabSstevel } 7107*3db86aabSstevel 7108*3db86aabSstevel static int 7109*3db86aabSstevel syshw_open(dev_t *dev, int flag, int otyp, cred_t *cred) 7110*3db86aabSstevel { 7111*3db86aabSstevel _NOTE(ARGUNUSED(dev, flag, cred)) 7112*3db86aabSstevel 7113*3db86aabSstevel if (otyp != OTYP_CHR) 7114*3db86aabSstevel return (EINVAL); 7115*3db86aabSstevel 7116*3db86aabSstevel return (0); 7117*3db86aabSstevel } 7118*3db86aabSstevel 7119*3db86aabSstevel static int 7120*3db86aabSstevel syshw_close(dev_t dev, int flag, int otyp, cred_t *cred) 7121*3db86aabSstevel { 7122*3db86aabSstevel _NOTE(ARGUNUSED(dev, flag, otyp, cred)) 7123*3db86aabSstevel 7124*3db86aabSstevel return (0); 7125*3db86aabSstevel } 7126*3db86aabSstevel 7127*3db86aabSstevel /* 7128*3db86aabSstevel * Add a client to the list of interested processes 7129*3db86aabSstevel */ 7130*3db86aabSstevel static void 7131*3db86aabSstevel add_client(client_data *new) 7132*3db86aabSstevel { 7133*3db86aabSstevel client_data * ptr; 7134*3db86aabSstevel 7135*3db86aabSstevel n_clients++; 7136*3db86aabSstevel if (cl_data == NULL) { 7137*3db86aabSstevel cl_data = new; 7138*3db86aabSstevel return; 7139*3db86aabSstevel } 7140*3db86aabSstevel 7141*3db86aabSstevel ptr = cl_data; 7142*3db86aabSstevel while ((ptr->next != NULL) && (ptr->priority <= new->priority)) 7143*3db86aabSstevel ptr = ptr->next; 7144*3db86aabSstevel 7145*3db86aabSstevel if (ptr == cl_data) { 7146*3db86aabSstevel /* at head of the list */ 7147*3db86aabSstevel cl_data = new; 7148*3db86aabSstevel new->next = ptr; 7149*3db86aabSstevel new->prev = NULL; 7150*3db86aabSstevel if (ptr != NULL) 7151*3db86aabSstevel ptr->prev = new; 7152*3db86aabSstevel } else { 7153*3db86aabSstevel /* somewhere else in the list - insert after */ 7154*3db86aabSstevel new->next = ptr->next; 7155*3db86aabSstevel ptr->next = new; 7156*3db86aabSstevel new->prev = ptr; 7157*3db86aabSstevel if (new->next != NULL) 7158*3db86aabSstevel (new->next)->prev = new; 7159*3db86aabSstevel } 7160*3db86aabSstevel } 7161*3db86aabSstevel 7162*3db86aabSstevel /* 7163*3db86aabSstevel * Locate a client data structure in the client list by looking for a PID match. 7164*3db86aabSstevel */ 7165*3db86aabSstevel static client_data * 7166*3db86aabSstevel locate_client(pid_t pid) 7167*3db86aabSstevel { 7168*3db86aabSstevel client_data * ptr = cl_data; 7169*3db86aabSstevel 7170*3db86aabSstevel while ((ptr != NULL) && (ptr->pid != pid)) 7171*3db86aabSstevel ptr = ptr->next; 7172*3db86aabSstevel 7173*3db86aabSstevel return (ptr); 7174*3db86aabSstevel } 7175*3db86aabSstevel 7176*3db86aabSstevel /* 7177*3db86aabSstevel * Remove a client record from the client list 7178*3db86aabSstevel */ 7179*3db86aabSstevel static void 7180*3db86aabSstevel delete_client(pid_t pid) 7181*3db86aabSstevel { 7182*3db86aabSstevel client_data * ptr; 7183*3db86aabSstevel 7184*3db86aabSstevel ptr = locate_client(pid); 7185*3db86aabSstevel if (ptr == NULL) 7186*3db86aabSstevel return; /* hmmm!! */ 7187*3db86aabSstevel 7188*3db86aabSstevel n_clients--; 7189*3db86aabSstevel 7190*3db86aabSstevel if (ptr == cl_data) { 7191*3db86aabSstevel /* remove the head of the list */ 7192*3db86aabSstevel cl_data = ptr->next; 7193*3db86aabSstevel } 7194*3db86aabSstevel if (ptr->prev != NULL) 7195*3db86aabSstevel (ptr->prev)->next = ptr->next; 7196*3db86aabSstevel if (ptr->next != NULL) 7197*3db86aabSstevel (ptr->next)->prev = ptr->prev; 7198*3db86aabSstevel 7199*3db86aabSstevel kmem_free(ptr, sizeof (client_data)); 7200*3db86aabSstevel } 7201*3db86aabSstevel 7202*3db86aabSstevel static void 7203*3db86aabSstevel unregister_event_client() 7204*3db86aabSstevel { 7205*3db86aabSstevel pcic_mutex_enter(&client_mtx); 7206*3db86aabSstevel delete_client(ddi_get_pid()); 7207*3db86aabSstevel pcic_mutex_exit(&client_mtx); 7208*3db86aabSstevel } 7209*3db86aabSstevel 7210*3db86aabSstevel static int 7211*3db86aabSstevel register_event_client(client_data *u_client) 7212*3db86aabSstevel { 7213*3db86aabSstevel int error; 7214*3db86aabSstevel client_data * client; 7215*3db86aabSstevel 7216*3db86aabSstevel pcic_mutex_enter(&client_mtx); 7217*3db86aabSstevel client = locate_client(ddi_get_pid()); 7218*3db86aabSstevel if (client) { 7219*3db86aabSstevel /* 7220*3db86aabSstevel * we are re-registering ourself 7221*3db86aabSstevel * so we delete the previous entry 7222*3db86aabSstevel */ 7223*3db86aabSstevel delete_client(ddi_get_pid()); 7224*3db86aabSstevel } 7225*3db86aabSstevel 7226*3db86aabSstevel client = (client_data *)kmem_alloc(sizeof (client_data), KM_SLEEP); 7227*3db86aabSstevel 7228*3db86aabSstevel if (client) { 7229*3db86aabSstevel client->pid = ddi_get_pid(); 7230*3db86aabSstevel client->priority = u_client->priority; 7231*3db86aabSstevel client->flags = u_client->flags & NCE_EVENT_MASK; 7232*3db86aabSstevel client->events = 0; 7233*3db86aabSstevel client->event_sig = u_client->event_sig; 7234*3db86aabSstevel client->next = NULL; 7235*3db86aabSstevel client->prev = NULL; 7236*3db86aabSstevel add_client(client); 7237*3db86aabSstevel error = 0; 7238*3db86aabSstevel } else 7239*3db86aabSstevel error = EIO; 7240*3db86aabSstevel 7241*3db86aabSstevel pcic_mutex_exit(&client_mtx); 7242*3db86aabSstevel return (error); 7243*3db86aabSstevel } 7244*3db86aabSstevel 7245*3db86aabSstevel /* 7246*3db86aabSstevel * Read the currently pending event flags for the process in question 7247*3db86aabSstevel */ 7248*3db86aabSstevel static int 7249*3db86aabSstevel check_events_pending(caddr_t data) 7250*3db86aabSstevel { 7251*3db86aabSstevel client_data * client; 7252*3db86aabSstevel int error = 0; 7253*3db86aabSstevel 7254*3db86aabSstevel pcic_mutex_enter(&client_mtx); 7255*3db86aabSstevel client = locate_client(ddi_get_pid()); 7256*3db86aabSstevel if (client) { 7257*3db86aabSstevel if (copyout((caddr_t)&client->events, data, sizeof (int))) 7258*3db86aabSstevel error = EFAULT; 7259*3db86aabSstevel else 7260*3db86aabSstevel client->events = 0; 7261*3db86aabSstevel } else 7262*3db86aabSstevel error = EINVAL; 7263*3db86aabSstevel 7264*3db86aabSstevel pcic_mutex_exit(&client_mtx); 7265*3db86aabSstevel return (error); 7266*3db86aabSstevel } 7267*3db86aabSstevel 7268*3db86aabSstevel 7269*3db86aabSstevel #define MAXITEMS 8 7270*3db86aabSstevel static syshw_t *syshw_map[MAXITEMS]; 7271*3db86aabSstevel static void (*syshw_getfuncs[MAXITEMS])(syshw_t *, void *); 7272*3db86aabSstevel static void *syshw_getfunc_args[MAXITEMS]; 7273*3db86aabSstevel static int nsyshw_items = 0; 7274*3db86aabSstevel #define NSYSHW_ITEMS nsyshw_items 7275*3db86aabSstevel 7276*3db86aabSstevel static uint32_t 7277*3db86aabSstevel syshw_add2map(syshw_t *item, void (*getfunc)(syshw_t *, void *), void *getarg) 7278*3db86aabSstevel { 7279*3db86aabSstevel uint32_t rval = (1 << nsyshw_items); 7280*3db86aabSstevel if (nsyshw_items == MAXITEMS) 7281*3db86aabSstevel return (0); 7282*3db86aabSstevel item->hw_id = nsyshw_items; 7283*3db86aabSstevel syshw_map[nsyshw_items] = item; 7284*3db86aabSstevel syshw_getfuncs[nsyshw_items] = getfunc; 7285*3db86aabSstevel syshw_getfunc_args[nsyshw_items] = getarg; 7286*3db86aabSstevel nsyshw_items++; 7287*3db86aabSstevel return (rval); 7288*3db86aabSstevel } 7289*3db86aabSstevel 7290*3db86aabSstevel static int 7291*3db86aabSstevel syshw_ioctl(dev_t dev, int cmd, intptr_t ioctldata, int mode, 7292*3db86aabSstevel cred_t *cred, int *rval) 7293*3db86aabSstevel { 7294*3db86aabSstevel caddr_t data = (caddr_t)ioctldata; 7295*3db86aabSstevel syshw_t sh; 7296*3db86aabSstevel hwev_t hwev; 7297*3db86aabSstevel client_data dummy_client; 7298*3db86aabSstevel int rc = 0, i; 7299*3db86aabSstevel 7300*3db86aabSstevel _NOTE(ARGUNUSED(dev, mode, cred, rval)) 7301*3db86aabSstevel 7302*3db86aabSstevel switch (cmd) { 7303*3db86aabSstevel default: 7304*3db86aabSstevel rc = EINVAL; 7305*3db86aabSstevel break; 7306*3db86aabSstevel 7307*3db86aabSstevel case SYSHW_GET_ITEM: 7308*3db86aabSstevel case SYSHW_GET_ITEM_MAXVALUES: 7309*3db86aabSstevel if (copyin(data, (caddr_t)&sh, sizeof (sh))) { 7310*3db86aabSstevel rc = EFAULT; 7311*3db86aabSstevel break; 7312*3db86aabSstevel } 7313*3db86aabSstevel 7314*3db86aabSstevel if (sh.hw_id >= NSYSHW_ITEMS) { 7315*3db86aabSstevel rc = EINVAL; 7316*3db86aabSstevel break; 7317*3db86aabSstevel } 7318*3db86aabSstevel 7319*3db86aabSstevel sh = *syshw_map[sh.hw_id]; 7320*3db86aabSstevel if (!sh.id_string[0]) { 7321*3db86aabSstevel rc = ENOTTY; 7322*3db86aabSstevel break; 7323*3db86aabSstevel } 7324*3db86aabSstevel if (cmd == SYSHW_GET_ITEM) { 7325*3db86aabSstevel if (syshw_getfuncs[sh.hw_id]) 7326*3db86aabSstevel syshw_getfuncs[sh.hw_id](&sh, 7327*3db86aabSstevel syshw_getfunc_args[sh.hw_id]); 7328*3db86aabSstevel else 7329*3db86aabSstevel rc = ENOTTY; 7330*3db86aabSstevel } 7331*3db86aabSstevel 7332*3db86aabSstevel if (copyout((caddr_t)&sh, data, sizeof (sh))) { 7333*3db86aabSstevel rc = EFAULT; 7334*3db86aabSstevel break; 7335*3db86aabSstevel } 7336*3db86aabSstevel break; 7337*3db86aabSstevel 7338*3db86aabSstevel case SYSHW_SET_ITEM: 7339*3db86aabSstevel if (copyin(data, (caddr_t)&sh, sizeof (sh))) { 7340*3db86aabSstevel rc = EFAULT; 7341*3db86aabSstevel break; 7342*3db86aabSstevel } 7343*3db86aabSstevel 7344*3db86aabSstevel if (sh.hw_id >= NSYSHW_ITEMS || 7345*3db86aabSstevel !syshw_map[sh.hw_id]->id_string[0] || 7346*3db86aabSstevel !(syshw_map[sh.hw_id]->capabilities & 7347*3db86aabSstevel (SYSHW_STATE_MODIFY | SYSHW_VAL0_MODIFY | 7348*3db86aabSstevel SYSHW_VAL1_MODIFY | SYSHW_VAL2_MODIFY | 7349*3db86aabSstevel SYSHW_VAL3_MODIFY))) { 7350*3db86aabSstevel rc = EINVAL; 7351*3db86aabSstevel break; 7352*3db86aabSstevel } 7353*3db86aabSstevel 7354*3db86aabSstevel switch (sh.hw_id) { 7355*3db86aabSstevel default: 7356*3db86aabSstevel rc = EINVAL; 7357*3db86aabSstevel break; 7358*3db86aabSstevel } 7359*3db86aabSstevel break; 7360*3db86aabSstevel 7361*3db86aabSstevel case SYSHW_EVREG: 7362*3db86aabSstevel if (copyin(data, (caddr_t)&hwev, sizeof (hwev))) { 7363*3db86aabSstevel rc = EFAULT; 7364*3db86aabSstevel break; 7365*3db86aabSstevel } 7366*3db86aabSstevel 7367*3db86aabSstevel for (i = 0; i < NSYSHW_ITEMS; i++) { 7368*3db86aabSstevel if (hwev.events & (1 << i) && 7369*3db86aabSstevel !(syshw_map[i]->capabilities & 7370*3db86aabSstevel SYSHW_CAN_SIGNAL_CHANGE)) { 7371*3db86aabSstevel rc = EINVAL; 7372*3db86aabSstevel break; 7373*3db86aabSstevel } 7374*3db86aabSstevel } 7375*3db86aabSstevel if (hwev.event_sig != SIGUSR1 && hwev.event_sig != SIGUSR2) 7376*3db86aabSstevel rc = EINVAL; 7377*3db86aabSstevel 7378*3db86aabSstevel if (!rc) { 7379*3db86aabSstevel dummy_client.priority = 100; 7380*3db86aabSstevel dummy_client.flags = hwev.events; 7381*3db86aabSstevel dummy_client.event_sig = hwev.event_sig; 7382*3db86aabSstevel rc = register_event_client(&dummy_client); 7383*3db86aabSstevel } 7384*3db86aabSstevel break; 7385*3db86aabSstevel 7386*3db86aabSstevel case SYSHW_EVUNREG: 7387*3db86aabSstevel unregister_event_client(); 7388*3db86aabSstevel break; 7389*3db86aabSstevel 7390*3db86aabSstevel case SYSHW_CHKEV: 7391*3db86aabSstevel rc = check_events_pending(data); 7392*3db86aabSstevel break; 7393*3db86aabSstevel } 7394*3db86aabSstevel return (rc); 7395*3db86aabSstevel } 7396