12305Sstevel /* 22305Sstevel * CDDL HEADER START 32305Sstevel * 42305Sstevel * The contents of this file are subject to the terms of the 52305Sstevel * Common Development and Distribution License (the "License"). 62305Sstevel * You may not use this file except in compliance with the License. 72305Sstevel * 82305Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92305Sstevel * or http://www.opensolaris.org/os/licensing. 102305Sstevel * See the License for the specific language governing permissions 112305Sstevel * and limitations under the License. 122305Sstevel * 132305Sstevel * When distributing Covered Code, include this CDDL HEADER in each 142305Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152305Sstevel * If applicable, add the following below this CDDL HEADER, with the 162305Sstevel * fields enclosed by brackets "[]" replaced with your own identifying 172305Sstevel * information: Portions Copyright [yyyy] [name of copyright owner] 182305Sstevel * 192305Sstevel * CDDL HEADER END 202305Sstevel */ 212305Sstevel 222305Sstevel /* 237151Srw148561 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 242305Sstevel * Use is subject to license terms. 252305Sstevel */ 262305Sstevel 272305Sstevel /* 282305Sstevel * PCIC device/interrupt handler 292305Sstevel * The "pcic" driver handles the Intel 82365SL, Cirrus Logic 302305Sstevel * and Toshiba (and possibly other clones) PCMCIA adapter chip 312305Sstevel * sets. It implements a subset of Socket Services as defined 322305Sstevel * in the Solaris PCMCIA design documents 332305Sstevel */ 342305Sstevel 352305Sstevel /* 362305Sstevel * currently defined "properties" 372305Sstevel * 382305Sstevel * clock-frequency bus clock frequency 392305Sstevel * smi system management interrupt override 402305Sstevel * need-mult-irq need status IRQ for each pair of sockets 412305Sstevel * disable-audio don't route audio signal to speaker 422305Sstevel */ 432305Sstevel 442305Sstevel 452305Sstevel #include <sys/types.h> 462305Sstevel #include <sys/inttypes.h> 472305Sstevel #include <sys/param.h> 482305Sstevel #include <sys/systm.h> 492305Sstevel #include <sys/user.h> 502305Sstevel #include <sys/buf.h> 512305Sstevel #include <sys/file.h> 522305Sstevel #include <sys/uio.h> 532305Sstevel #include <sys/conf.h> 542305Sstevel #include <sys/stat.h> 552305Sstevel #include <sys/autoconf.h> 562305Sstevel #include <sys/vtoc.h> 572305Sstevel #include <sys/dkio.h> 582305Sstevel #include <sys/ddi.h> 592305Sstevel #include <sys/sunddi.h> 602305Sstevel #include <sys/sunndi.h> 612305Sstevel #include <sys/var.h> 622305Sstevel #include <sys/callb.h> 632305Sstevel #include <sys/open.h> 642305Sstevel #include <sys/ddidmareq.h> 652305Sstevel #include <sys/dma_engine.h> 662305Sstevel #include <sys/kstat.h> 672305Sstevel #include <sys/kmem.h> 682305Sstevel #include <sys/modctl.h> 692305Sstevel #include <sys/pci.h> 702305Sstevel #include <sys/pci_impl.h> 712305Sstevel 722305Sstevel #include <sys/pctypes.h> 732305Sstevel #include <sys/pcmcia.h> 742305Sstevel #include <sys/sservice.h> 752305Sstevel 762305Sstevel #include <sys/note.h> 772305Sstevel 782305Sstevel #include <sys/pcic_reg.h> 792305Sstevel #include <sys/pcic_var.h> 802305Sstevel 817493SVincent.Wang@Sun.COM #if defined(__i386) || defined(__amd64) 827493SVincent.Wang@Sun.COM #include <sys/pci_cfgspace.h> 837493SVincent.Wang@Sun.COM #endif 847493SVincent.Wang@Sun.COM 852305Sstevel #if defined(__sparc) 862305Sstevel #include <sys/pci/pci_nexus.h> 872305Sstevel #endif 882305Sstevel 892451Srw148561 #include <sys/hotplug/hpcsvc.h> 902305Sstevel #include "cardbus/cardbus.h" 912305Sstevel 922305Sstevel #define SOFTC_SIZE (sizeof (anp_t)) 932305Sstevel 942305Sstevel static int pcic_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 952305Sstevel static int pcic_attach(dev_info_t *, ddi_attach_cmd_t); 962305Sstevel static int pcic_detach(dev_info_t *, ddi_detach_cmd_t); 972305Sstevel static uint_t pcic_intr(caddr_t, caddr_t); 982305Sstevel static int pcic_do_io_intr(pcicdev_t *, uint32_t); 992305Sstevel static int pcic_probe(dev_info_t *); 1002305Sstevel 1012305Sstevel static int pcic_open(dev_t *, int, int, cred_t *); 1022305Sstevel static int pcic_close(dev_t, int, int, cred_t *); 1032305Sstevel static int pcic_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 1042305Sstevel 1052305Sstevel typedef struct pcm_regs pcm_regs_t; 1062305Sstevel 1072305Sstevel static void pcic_init_assigned(dev_info_t *); 1082305Sstevel static int pcic_apply_avail_ranges(dev_info_t *, pcm_regs_t *, 1092305Sstevel pci_regspec_t *, int); 1102305Sstevel int pci_resource_setup_avail(dev_info_t *, pci_regspec_t *, int); 1112305Sstevel 1122305Sstevel /* 1132305Sstevel * On x86 platforms the ddi_iobp_alloc(9F) and ddi_mem_alloc(9F) calls 1142305Sstevel * are xlated into DMA ctlops. To make this nexus work on x86, we 1152305Sstevel * need to have the default ddi_dma_mctl ctlops in the bus_ops 1162305Sstevel * structure, just to pass the request to the parent. The correct 1172305Sstevel * ctlops should be ddi_no_dma_mctl because so far we don't do DMA. 1182305Sstevel */ 1192305Sstevel static 1202305Sstevel struct bus_ops pcmciabus_ops = { 1212305Sstevel BUSO_REV, 1222305Sstevel pcmcia_bus_map, 1232305Sstevel NULL, 1242305Sstevel NULL, 1252305Sstevel NULL, 1262305Sstevel i_ddi_map_fault, 1272305Sstevel ddi_no_dma_map, 1282305Sstevel ddi_no_dma_allochdl, 1292305Sstevel ddi_no_dma_freehdl, 1302305Sstevel ddi_no_dma_bindhdl, 1312305Sstevel ddi_no_dma_unbindhdl, 1322305Sstevel ddi_no_dma_flush, 1332305Sstevel ddi_no_dma_win, 1342305Sstevel ddi_dma_mctl, 1352305Sstevel pcmcia_ctlops, 1362305Sstevel pcmcia_prop_op, 1372305Sstevel NULL, /* (*bus_get_eventcookie)(); */ 1382305Sstevel NULL, /* (*bus_add_eventcall)(); */ 1392305Sstevel NULL, /* (*bus_remove_eventcall)(); */ 1402305Sstevel NULL, /* (*bus_post_event)(); */ 1412305Sstevel NULL, /* (*bus_intr_ctl)(); */ 1422305Sstevel NULL, /* (*bus_config)(); */ 1432305Sstevel NULL, /* (*bus_unconfig)(); */ 1442305Sstevel NULL, /* (*bus_fm_init)(); */ 1452305Sstevel NULL, /* (*bus_fm_fini)(); */ 1462305Sstevel NULL, /* (*bus_enter)() */ 1472305Sstevel NULL, /* (*bus_exit)() */ 1482305Sstevel NULL, /* (*bus_power)() */ 1492305Sstevel pcmcia_intr_ops /* (*bus_intr_op)(); */ 1502305Sstevel }; 1512305Sstevel 1522305Sstevel static struct cb_ops pcic_cbops = { 1532305Sstevel pcic_open, 1542305Sstevel pcic_close, 1552305Sstevel nodev, 1562305Sstevel nodev, 1572305Sstevel nodev, 1582305Sstevel nodev, 1592305Sstevel nodev, 1602305Sstevel pcic_ioctl, 1612305Sstevel nodev, 1622305Sstevel nodev, 1632305Sstevel nodev, 1642305Sstevel nochpoll, 1652305Sstevel ddi_prop_op, 1662305Sstevel NULL, 1672305Sstevel #ifdef CARDBUS 1682305Sstevel D_NEW | D_MP | D_HOTPLUG 1692305Sstevel #else 1702305Sstevel D_NEW | D_MP 1712305Sstevel #endif 1722305Sstevel }; 1732305Sstevel 1742305Sstevel static struct dev_ops pcic_devops = { 1752305Sstevel DEVO_REV, 1762305Sstevel 0, 1772305Sstevel pcic_getinfo, 1782305Sstevel nulldev, 1792305Sstevel pcic_probe, 1802305Sstevel pcic_attach, 1812305Sstevel pcic_detach, 1822305Sstevel nulldev, 1832305Sstevel &pcic_cbops, 1842305Sstevel &pcmciabus_ops, 185*7656SSherry.Moore@Sun.COM NULL, 186*7656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */ 1872305Sstevel }; 1882305Sstevel 1892305Sstevel void *pcic_soft_state_p = NULL; 1902305Sstevel static int pcic_maxinst = -1; 1912305Sstevel 1922305Sstevel int pcic_do_insertion = 1; 1932305Sstevel int pcic_do_removal = 1; 1942305Sstevel 1952305Sstevel struct irqmap { 1962305Sstevel int irq; 1972305Sstevel int count; 1982305Sstevel } pcic_irq_map[16]; 1992305Sstevel 2002305Sstevel 2012305Sstevel int pcic_debug = 0x0; 2022305Sstevel static void pcic_err(dev_info_t *dip, int level, const char *fmt, ...); 2032305Sstevel extern void cardbus_dump_pci_config(dev_info_t *dip); 2042305Sstevel extern void cardbus_dump_socket(dev_info_t *dip); 2052305Sstevel extern int cardbus_validate_iline(dev_info_t *dip, ddi_acc_handle_t handle); 2062305Sstevel static void pcic_dump_debqueue(char *msg); 2072305Sstevel 2082305Sstevel #if defined(PCIC_DEBUG) 2092305Sstevel static void xxdmp_all_regs(pcicdev_t *, int, uint32_t); 2102305Sstevel 2112305Sstevel #define pcic_mutex_enter(a) \ 2122305Sstevel { \ 2132305Sstevel pcic_err(NULL, 10, "Set lock at %d\n", __LINE__); \ 2142305Sstevel mutex_enter(a); \ 2152305Sstevel }; 2162305Sstevel 2172305Sstevel #define pcic_mutex_exit(a) \ 2182305Sstevel { \ 2192305Sstevel pcic_err(NULL, 10, "Clear lock at %d\n", __LINE__); \ 2202305Sstevel mutex_exit(a); \ 2212305Sstevel }; 2222305Sstevel 2232305Sstevel #else 2242305Sstevel #define pcic_mutex_enter(a) mutex_enter(a) 2252305Sstevel #define pcic_mutex_exit(a) mutex_exit(a) 2262305Sstevel #endif 2272305Sstevel 2282305Sstevel #define PCIC_VCC_3VLEVEL 1 2292305Sstevel #define PCIC_VCC_5VLEVEL 2 2302305Sstevel #define PCIC_VCC_12LEVEL 3 2312305Sstevel 2322305Sstevel /* bit patterns to select voltage levels */ 2332305Sstevel int pcic_vpp_levels[13] = { 2342305Sstevel 0, 0, 0, 2352305Sstevel 1, /* 3.3V */ 2362305Sstevel 0, 2372305Sstevel 1, /* 5V */ 2382305Sstevel 0, 0, 0, 0, 0, 0, 2392305Sstevel 2 /* 12V */ 2402305Sstevel }; 2412305Sstevel 2422305Sstevel uint8_t pcic_cbv_levels[13] = { 2432305Sstevel 0, 0, 0, 2442305Sstevel 3, /* 3.3V */ 2452305Sstevel 0, 2462305Sstevel 2, /* 5V */ 2472305Sstevel 0, 0, 0, 0, 0, 0, 2482305Sstevel 1 /* 12V */ 2492305Sstevel }; 2502305Sstevel 2512305Sstevel struct power_entry pcic_power[4] = { 2522305Sstevel { 2532305Sstevel 0, VCC|VPP1|VPP2 2542305Sstevel }, 2552305Sstevel { 2562305Sstevel 33, /* 3.3Volt */ 2572305Sstevel VCC|VPP1|VPP2 2582305Sstevel }, 2592305Sstevel { 2602305Sstevel 5*10, /* 5Volt */ 2612305Sstevel VCC|VPP1|VPP2 /* currently only know about this */ 2622305Sstevel }, 2632305Sstevel { 2642305Sstevel 12*10, /* 12Volt */ 2652305Sstevel VPP1|VPP2 2662305Sstevel } 2672305Sstevel }; 2682305Sstevel 2692305Sstevel /* 2702305Sstevel * Base used to allocate ranges of PCI memory on x86 systems 2712305Sstevel * Each instance gets a chunk above the base that is used to map 2722305Sstevel * in the memory and I/O windows for that device. 2732305Sstevel * Pages below the base are also allocated for the EXCA registers, 2742305Sstevel * one per instance. 2752305Sstevel */ 2762305Sstevel #define PCIC_PCI_MEMCHUNK 0x1000000 2772305Sstevel 2782305Sstevel static int pcic_wait_insert_time = 5000000; /* In micro-seconds */ 2792305Sstevel static int pcic_debounce_time = 200000; /* In micro-seconds */ 2802305Sstevel 2812305Sstevel struct debounce { 2822305Sstevel pcic_socket_t *pcs; 2832305Sstevel clock_t expire; 2842305Sstevel struct debounce *next; 2852305Sstevel }; 2862305Sstevel 2872305Sstevel static struct debounce *pcic_deb_queue = NULL; 2882305Sstevel static kmutex_t pcic_deb_mtx; 2892305Sstevel static kcondvar_t pcic_deb_cv; 2902305Sstevel static kthread_t *pcic_deb_threadid; 2912305Sstevel 2922305Sstevel static inthandler_t *pcic_handlers; 2932305Sstevel 2942305Sstevel static void pcic_setup_adapter(pcicdev_t *); 2952305Sstevel static int pcic_change(pcicdev_t *, int); 2962305Sstevel static int pcic_ll_reset(pcicdev_t *, int); 2972305Sstevel static void pcic_mswait(pcicdev_t *, int, int); 2982305Sstevel static boolean_t pcic_check_ready(pcicdev_t *, int); 2992305Sstevel static void pcic_set_cdtimers(pcicdev_t *, int, uint32_t, int); 3002305Sstevel static void pcic_ready_wait(pcicdev_t *, int); 3012305Sstevel extern int pcmcia_get_intr(dev_info_t *, int); 3022305Sstevel extern int pcmcia_return_intr(dev_info_t *, int); 3037151Srw148561 extern void pcmcia_cb_suspended(int); 3047151Srw148561 extern void pcmcia_cb_resumed(int); 3052305Sstevel 3062305Sstevel static int pcic_callback(dev_info_t *, int (*)(), int); 3072305Sstevel static int pcic_inquire_adapter(dev_info_t *, inquire_adapter_t *); 3082305Sstevel static int pcic_get_adapter(dev_info_t *, get_adapter_t *); 3092305Sstevel static int pcic_get_page(dev_info_t *, get_page_t *); 3102305Sstevel static int pcic_get_socket(dev_info_t *, get_socket_t *); 3112305Sstevel static int pcic_get_status(dev_info_t *, get_ss_status_t *); 3122305Sstevel static int pcic_get_window(dev_info_t *, get_window_t *); 3132305Sstevel static int pcic_inquire_socket(dev_info_t *, inquire_socket_t *); 3142305Sstevel static int pcic_inquire_window(dev_info_t *, inquire_window_t *); 3152305Sstevel static int pcic_reset_socket(dev_info_t *, int, int); 3162305Sstevel static int pcic_set_page(dev_info_t *, set_page_t *); 3172305Sstevel static int pcic_set_window(dev_info_t *, set_window_t *); 3182305Sstevel static int pcic_set_socket(dev_info_t *, set_socket_t *); 3192305Sstevel static int pcic_set_interrupt(dev_info_t *, set_irq_handler_t *); 3202305Sstevel static int pcic_clear_interrupt(dev_info_t *, clear_irq_handler_t *); 3212305Sstevel static void pcic_pm_detection(void *); 3222305Sstevel static void pcic_iomem_pci_ctl(ddi_acc_handle_t, uchar_t *, unsigned); 3232305Sstevel static int clext_reg_read(pcicdev_t *, int, uchar_t); 3242305Sstevel static void clext_reg_write(pcicdev_t *, int, uchar_t, uchar_t); 3252305Sstevel static int pcic_calc_speed(pcicdev_t *, uint32_t); 3262305Sstevel static int pcic_card_state(pcicdev_t *, pcic_socket_t *); 3272305Sstevel static int pcic_find_pci_type(pcicdev_t *); 3282305Sstevel static void pcic_82092_smiirq_ctl(pcicdev_t *, int, int, int); 3292305Sstevel static void pcic_handle_cd_change(pcicdev_t *, pcic_socket_t *, uint8_t); 3302305Sstevel static uint_t pcic_cd_softint(caddr_t, caddr_t); 3312305Sstevel static uint8_t pcic_getb(pcicdev_t *, int, int); 3322305Sstevel static void pcic_putb(pcicdev_t *, int, int, int8_t); 3332305Sstevel static int pcic_set_vcc_level(pcicdev_t *, set_socket_t *); 3342305Sstevel static uint_t pcic_softintr(caddr_t, caddr_t); 3352305Sstevel 3362305Sstevel static void pcic_debounce(pcic_socket_t *); 3377151Srw148561 static void pcic_do_resume(pcicdev_t *); 3382305Sstevel static void *pcic_add_debqueue(pcic_socket_t *, int); 3392305Sstevel static void pcic_rm_debqueue(void *); 3402305Sstevel static void pcic_deb_thread(); 3412305Sstevel 3422305Sstevel static boolean_t pcic_load_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp); 3432305Sstevel static void pcic_unload_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp); 3442305Sstevel static uint32_t pcic_getcb(pcicdev_t *pcic, int reg); 3452305Sstevel static void pcic_putcb(pcicdev_t *pcic, int reg, uint32_t value); 3462305Sstevel static void pcic_cb_enable_intr(dev_info_t *); 3472305Sstevel static void pcic_cb_disable_intr(dev_info_t *); 3482305Sstevel static void pcic_enable_io_intr(pcicdev_t *pcic, int socket, int irq); 3492305Sstevel static void pcic_disable_io_intr(pcicdev_t *pcic, int socket); 3502305Sstevel 3512305Sstevel static cb_nexus_cb_t pcic_cbnexus_ops = { 3522305Sstevel pcic_cb_enable_intr, 3532305Sstevel pcic_cb_disable_intr 3542305Sstevel }; 3552305Sstevel 3562305Sstevel static int pcic_exca_powerctl(pcicdev_t *pcic, int socket, int powerlevel); 3572305Sstevel static int pcic_cbus_powerctl(pcicdev_t *pcic, int socket); 3582305Sstevel 3592305Sstevel #if defined(__sparc) 3602305Sstevel static int pcic_fault(enum pci_fault_ops op, void *arg); 3612305Sstevel #endif 3622305Sstevel 3632305Sstevel 3642305Sstevel /* 3652305Sstevel * pcmcia interface operations structure 3662305Sstevel * this is the private interface that is exported to the nexus 3672305Sstevel */ 3682305Sstevel pcmcia_if_t pcic_if_ops = { 3692305Sstevel PCIF_MAGIC, 3702305Sstevel PCIF_VERSION, 3712305Sstevel pcic_callback, 3722305Sstevel pcic_get_adapter, 3732305Sstevel pcic_get_page, 3742305Sstevel pcic_get_socket, 3752305Sstevel pcic_get_status, 3762305Sstevel pcic_get_window, 3772305Sstevel pcic_inquire_adapter, 3782305Sstevel pcic_inquire_socket, 3792305Sstevel pcic_inquire_window, 3802305Sstevel pcic_reset_socket, 3812305Sstevel pcic_set_page, 3822305Sstevel pcic_set_window, 3832305Sstevel pcic_set_socket, 3842305Sstevel pcic_set_interrupt, 3852305Sstevel pcic_clear_interrupt, 3862305Sstevel NULL, 3872305Sstevel }; 3882305Sstevel 3892305Sstevel /* 3902305Sstevel * chip type identification routines 3912305Sstevel * this list of functions is searched until one of them succeeds 3922305Sstevel * or all fail. i82365SL is assumed if failed. 3932305Sstevel */ 3942305Sstevel static int pcic_ci_cirrus(pcicdev_t *); 3952305Sstevel static int pcic_ci_vadem(pcicdev_t *); 3962305Sstevel static int pcic_ci_ricoh(pcicdev_t *); 3972305Sstevel 3982305Sstevel int (*pcic_ci_funcs[])(pcicdev_t *) = { 3992305Sstevel pcic_ci_cirrus, 4002305Sstevel pcic_ci_vadem, 4012305Sstevel pcic_ci_ricoh, 4022305Sstevel NULL 4032305Sstevel }; 4042305Sstevel 4052305Sstevel static struct modldrv modldrv = { 4062305Sstevel &mod_driverops, /* Type of module. This one is a driver */ 4077240Srh87107 "PCIC PCMCIA adapter driver", /* Name of the module. */ 4082305Sstevel &pcic_devops, /* driver ops */ 4092305Sstevel }; 4102305Sstevel 4112305Sstevel static struct modlinkage modlinkage = { 4122305Sstevel MODREV_1, (void *)&modldrv, NULL 4132305Sstevel }; 4142305Sstevel 4152305Sstevel int 4162305Sstevel _init() 4172305Sstevel { 4182305Sstevel int stat; 4192305Sstevel 4202305Sstevel /* Allocate soft state */ 4212305Sstevel if ((stat = ddi_soft_state_init(&pcic_soft_state_p, 4222305Sstevel SOFTC_SIZE, 2)) != DDI_SUCCESS) 4232305Sstevel return (stat); 4242305Sstevel 4252305Sstevel if ((stat = mod_install(&modlinkage)) != 0) 4262305Sstevel ddi_soft_state_fini(&pcic_soft_state_p); 4272305Sstevel 4282305Sstevel return (stat); 4292305Sstevel } 4302305Sstevel 4312305Sstevel int 4322305Sstevel _fini() 4332305Sstevel { 4342305Sstevel int stat = 0; 4352305Sstevel 4362305Sstevel if ((stat = mod_remove(&modlinkage)) != 0) 4372305Sstevel return (stat); 4382305Sstevel 4392305Sstevel if (pcic_deb_threadid) { 4402305Sstevel mutex_enter(&pcic_deb_mtx); 4412305Sstevel pcic_deb_threadid = 0; 4422305Sstevel while (!pcic_deb_threadid) 4432305Sstevel cv_wait(&pcic_deb_cv, &pcic_deb_mtx); 4442305Sstevel pcic_deb_threadid = 0; 4452305Sstevel mutex_exit(&pcic_deb_mtx); 4462305Sstevel 4472305Sstevel mutex_destroy(&pcic_deb_mtx); 4482305Sstevel cv_destroy(&pcic_deb_cv); 4492305Sstevel } 4502305Sstevel 4512305Sstevel ddi_soft_state_fini(&pcic_soft_state_p); 4522305Sstevel 4532305Sstevel return (stat); 4542305Sstevel } 4552305Sstevel 4562305Sstevel int 4572305Sstevel _info(struct modinfo *modinfop) 4582305Sstevel { 4592305Sstevel return (mod_info(&modlinkage, modinfop)); 4602305Sstevel } 4612305Sstevel 4622305Sstevel /* 4632305Sstevel * pcic_getinfo() 4642305Sstevel * provide instance/device information about driver 4652305Sstevel */ 4662305Sstevel /*ARGSUSED*/ 4672305Sstevel static int 4682305Sstevel pcic_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 4692305Sstevel { 4702305Sstevel anp_t *anp; 4712305Sstevel int error = DDI_SUCCESS; 4722305Sstevel minor_t minor; 4732305Sstevel 4742305Sstevel switch (cmd) { 475*7656SSherry.Moore@Sun.COM case DDI_INFO_DEVT2DEVINFO: 4762305Sstevel minor = getminor((dev_t)arg); 4773981Sgd78059 minor &= 0x7f; 4782305Sstevel if (!(anp = ddi_get_soft_state(pcic_soft_state_p, minor))) 4792305Sstevel *result = NULL; 4802305Sstevel else 4812305Sstevel *result = anp->an_dip; 4822305Sstevel break; 483*7656SSherry.Moore@Sun.COM case DDI_INFO_DEVT2INSTANCE: 4842305Sstevel minor = getminor((dev_t)arg); 4853981Sgd78059 minor &= 0x7f; 4862305Sstevel *result = (void *)((long)minor); 4872305Sstevel break; 488*7656SSherry.Moore@Sun.COM default: 4892305Sstevel error = DDI_FAILURE; 4902305Sstevel break; 4912305Sstevel } 4922305Sstevel return (error); 4932305Sstevel } 4942305Sstevel 4952305Sstevel static int 4962305Sstevel pcic_probe(dev_info_t *dip) 4972305Sstevel { 4982305Sstevel int value; 4992305Sstevel ddi_device_acc_attr_t attr; 5002305Sstevel ddi_acc_handle_t handle; 5012305Sstevel uchar_t *index, *data; 5022305Sstevel 5032305Sstevel if (ddi_dev_is_sid(dip) == DDI_SUCCESS) 504*7656SSherry.Moore@Sun.COM return (DDI_PROBE_DONTCARE); 5052305Sstevel 5062305Sstevel /* 5072305Sstevel * find a PCIC device (any vendor) 5082305Sstevel * while there can be up to 4 such devices in 5092305Sstevel * a system, we currently only look for 1 5102305Sstevel * per probe. There will be up to 2 chips per 5112305Sstevel * instance since they share I/O space 5122305Sstevel */ 5132305Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 5142305Sstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 5152305Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 5162305Sstevel 5172305Sstevel if (ddi_regs_map_setup(dip, PCIC_ISA_CONTROL_REG_NUM, 518*7656SSherry.Moore@Sun.COM (caddr_t *)&index, 519*7656SSherry.Moore@Sun.COM PCIC_ISA_CONTROL_REG_OFFSET, 520*7656SSherry.Moore@Sun.COM PCIC_ISA_CONTROL_REG_LENGTH, 521*7656SSherry.Moore@Sun.COM &attr, &handle) != DDI_SUCCESS) 522*7656SSherry.Moore@Sun.COM return (DDI_PROBE_FAILURE); 5232305Sstevel 5242305Sstevel data = index + 1; 5252305Sstevel 5262305Sstevel #if defined(PCIC_DEBUG) 5272305Sstevel if (pcic_debug) 5282305Sstevel cmn_err(CE_CONT, "pcic_probe: entered\n"); 5292305Sstevel if (pcic_debug) 5302305Sstevel cmn_err(CE_CONT, "\tindex=%p\n", (void *)index); 5312305Sstevel #endif 5322305Sstevel ddi_put8(handle, index, PCIC_CHIP_REVISION); 5332305Sstevel ddi_put8(handle, data, 0); 5342305Sstevel value = ddi_get8(handle, data); 5352305Sstevel #if defined(PCIC_DEBUG) 5362305Sstevel if (pcic_debug) 5372305Sstevel cmn_err(CE_CONT, "\tchip revision register = %x\n", value); 5382305Sstevel #endif 5392305Sstevel if ((value & PCIC_REV_MASK) >= PCIC_REV_LEVEL_LOW && 5402305Sstevel (value & 0x30) == 0) { 5412305Sstevel /* 5422305Sstevel * we probably have a PCIC chip in the system 5432305Sstevel * do a little more checking. If we find one, 5442305Sstevel * reset everything in case of softboot 5452305Sstevel */ 5462305Sstevel ddi_put8(handle, index, PCIC_MAPPING_ENABLE); 5472305Sstevel ddi_put8(handle, data, 0); 5482305Sstevel value = ddi_get8(handle, data); 5492305Sstevel #if defined(PCIC_DEBUG) 5502305Sstevel if (pcic_debug) 5512305Sstevel cmn_err(CE_CONT, "\tzero test = %x\n", value); 5522305Sstevel #endif 5532305Sstevel /* should read back as zero */ 5542305Sstevel if (value == 0) { 5552305Sstevel /* 5562305Sstevel * we do have one and it is off the bus 5572305Sstevel */ 5582305Sstevel #if defined(PCIC_DEBUG) 5592305Sstevel if (pcic_debug) 5602305Sstevel cmn_err(CE_CONT, "pcic_probe: success\n"); 5612305Sstevel #endif 5622305Sstevel ddi_regs_map_free(&handle); 5632305Sstevel return (DDI_PROBE_SUCCESS); 5642305Sstevel } 5652305Sstevel } 5662305Sstevel #if defined(PCIC_DEBUG) 5672305Sstevel if (pcic_debug) 5682305Sstevel cmn_err(CE_CONT, "pcic_probe: failed\n"); 5692305Sstevel #endif 5702305Sstevel ddi_regs_map_free(&handle); 5712305Sstevel return (DDI_PROBE_FAILURE); 5722305Sstevel } 5732305Sstevel 5742305Sstevel /* 5752305Sstevel * These are just defaults they can also be changed via a property in the 5762305Sstevel * conf file. 5772305Sstevel */ 5782305Sstevel static int pci_config_reg_num = PCIC_PCI_CONFIG_REG_NUM; 5792305Sstevel static int pci_control_reg_num = PCIC_PCI_CONTROL_REG_NUM; 5807151Srw148561 static int pcic_do_pcmcia_sr = 1; 5812305Sstevel static int pcic_use_cbpwrctl = PCF_CBPWRCTL; 5822305Sstevel 5832305Sstevel /* 5842305Sstevel * enable insertion/removal interrupt for 32bit cards 5852305Sstevel */ 5862305Sstevel static int 5872305Sstevel cardbus_enable_cd_intr(dev_info_t *dip) 5882305Sstevel { 5892305Sstevel ddi_acc_handle_t iohandle; 5902305Sstevel caddr_t ioaddr; 5912305Sstevel ddi_device_acc_attr_t attr; 5922305Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 5932305Sstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 5942305Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 5952305Sstevel (void) ddi_regs_map_setup(dip, 1, 596*7656SSherry.Moore@Sun.COM (caddr_t *)&ioaddr, 597*7656SSherry.Moore@Sun.COM 0, 598*7656SSherry.Moore@Sun.COM 4096, 599*7656SSherry.Moore@Sun.COM &attr, &iohandle); 6002305Sstevel 6012305Sstevel /* CSC Interrupt: Card detect interrupt on */ 6022305Sstevel ddi_put32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_MASK), 603*7656SSherry.Moore@Sun.COM ddi_get32(iohandle, 604*7656SSherry.Moore@Sun.COM (uint32_t *)(ioaddr+CB_STATUS_MASK)) | CB_SE_CCDMASK); 6052305Sstevel 6062305Sstevel ddi_put32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT), 607*7656SSherry.Moore@Sun.COM ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT))); 6082305Sstevel 6092305Sstevel ddi_regs_map_free(&iohandle); 6102305Sstevel return (1); 6112305Sstevel } 6122305Sstevel 6132305Sstevel /* 6142305Sstevel * pcic_attach() 6152305Sstevel * attach the PCIC (Intel 82365SL/CirrusLogic/Toshiba) driver 6162305Sstevel * to the system. This is a child of "sysbus" since that is where 6172305Sstevel * the hardware lives, but it provides services to the "pcmcia" 6182305Sstevel * nexus driver. It gives a pointer back via its private data 6192305Sstevel * structure which contains both the dip and socket services entry 6202305Sstevel * points 6212305Sstevel */ 6222305Sstevel static int 6232305Sstevel pcic_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 6242305Sstevel { 6252305Sstevel anp_t *pcic_nexus; 6262305Sstevel pcicdev_t *pcic; 6272305Sstevel int irqlevel, value; 6282305Sstevel int pci_cfrn, pci_ctrn; 6292305Sstevel int i, j, smi, actual; 6302305Sstevel char *typename; 6312305Sstevel char bus_type[16] = "(unknown)"; 6322305Sstevel int len = sizeof (bus_type); 6332305Sstevel ddi_device_acc_attr_t attr; 6342305Sstevel anp_t *anp = ddi_get_driver_private(dip); 6352305Sstevel uint_t pri; 6362305Sstevel 6372305Sstevel #if defined(PCIC_DEBUG) 6382305Sstevel if (pcic_debug) { 6392305Sstevel cmn_err(CE_CONT, "pcic_attach: entered\n"); 6402305Sstevel } 6412305Sstevel #endif 6422305Sstevel switch (cmd) { 6432305Sstevel case DDI_ATTACH: 6442305Sstevel break; 6452305Sstevel case DDI_RESUME: 6462305Sstevel pcic = anp->an_private; 6472305Sstevel /* 6482305Sstevel * for now, this is a simulated resume. 6492305Sstevel * a real one may need different things. 6502305Sstevel */ 6512305Sstevel if (pcic != NULL && pcic->pc_flags & PCF_SUSPENDED) { 6522305Sstevel mutex_enter(&pcic->pc_lock); 6532305Sstevel /* should probe for new sockets showing up */ 6542305Sstevel pcic_setup_adapter(pcic); 6552305Sstevel pcic->pc_flags &= ~PCF_SUSPENDED; 6562305Sstevel mutex_exit(&pcic->pc_lock); 6572305Sstevel (void) pcmcia_begin_resume(dip); 6587151Srw148561 6597151Srw148561 pcic_do_resume(pcic); 6607151Srw148561 #ifdef CARDBUS 6617151Srw148561 cardbus_restore_children(ddi_get_child(dip)); 6627151Srw148561 #endif 6632305Sstevel 6642305Sstevel /* 6652305Sstevel * for complete implementation need END_RESUME (later) 6662305Sstevel */ 6672305Sstevel return (DDI_SUCCESS); 6682305Sstevel 6692305Sstevel } 6702305Sstevel return (DDI_SUCCESS); 6712305Sstevel default: 6722305Sstevel return (DDI_FAILURE); 6732305Sstevel } 6742305Sstevel 6752305Sstevel /* 6762305Sstevel * Allocate soft state associated with this instance. 6772305Sstevel */ 6782305Sstevel if (ddi_soft_state_zalloc(pcic_soft_state_p, 679*7656SSherry.Moore@Sun.COM ddi_get_instance(dip)) != DDI_SUCCESS) { 6802305Sstevel cmn_err(CE_CONT, "pcic%d: Unable to alloc state\n", 681*7656SSherry.Moore@Sun.COM ddi_get_instance(dip)); 6822305Sstevel return (DDI_FAILURE); 6832305Sstevel } 6842305Sstevel 6852305Sstevel pcic_nexus = ddi_get_soft_state(pcic_soft_state_p, 6862305Sstevel ddi_get_instance(dip)); 6872305Sstevel 6882305Sstevel pcic = kmem_zalloc(sizeof (pcicdev_t), KM_SLEEP); 6892305Sstevel 6902305Sstevel pcic->dip = dip; 6912305Sstevel pcic_nexus->an_dip = dip; 6922305Sstevel pcic_nexus->an_if = &pcic_if_ops; 6932305Sstevel pcic_nexus->an_private = pcic; 6942305Sstevel pcic->pc_numpower = sizeof (pcic_power)/sizeof (pcic_power[0]); 6952305Sstevel pcic->pc_power = pcic_power; 6962305Sstevel 6972305Sstevel pci_ctrn = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP, 6982305Sstevel "pci-control-reg-number", pci_control_reg_num); 6992305Sstevel pci_cfrn = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP, 7002305Sstevel "pci-config-reg-number", pci_config_reg_num); 7012305Sstevel 7022305Sstevel ddi_set_driver_private(dip, pcic_nexus); 7032305Sstevel 7042305Sstevel /* 7052305Sstevel * pcic->pc_irq is really the IPL level we want to run at 7062305Sstevel * set the default values here and override from intr spec 7072305Sstevel */ 7082305Sstevel pcic->pc_irq = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP, 709*7656SSherry.Moore@Sun.COM "interrupt-priorities", -1); 7102305Sstevel 7112305Sstevel if (pcic->pc_irq == -1) { 7122305Sstevel int actual; 7132305Sstevel uint_t pri; 7142305Sstevel ddi_intr_handle_t hdl; 7152305Sstevel 7162305Sstevel /* see if intrspec tells us different */ 7172305Sstevel if (ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED, 7182305Sstevel 0, 1, &actual, DDI_INTR_ALLOC_NORMAL) == DDI_SUCCESS) { 7192305Sstevel if (ddi_intr_get_pri(hdl, &pri) == DDI_SUCCESS) 7202305Sstevel pcic->pc_irq = pri; 7212305Sstevel else 7222305Sstevel pcic->pc_irq = LOCK_LEVEL + 1; 7232305Sstevel (void) ddi_intr_free(hdl); 7242305Sstevel } 7252305Sstevel } 7262305Sstevel pcic_nexus->an_ipl = pcic->pc_irq; 7272305Sstevel 7282305Sstevel /* 7292305Sstevel * Check our parent bus type. We do different things based on which 7302305Sstevel * bus we're on. 7312305Sstevel */ 7322305Sstevel if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip), 733*7656SSherry.Moore@Sun.COM PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP, 734*7656SSherry.Moore@Sun.COM "device_type", (caddr_t)&bus_type[0], &len) != 735*7656SSherry.Moore@Sun.COM DDI_PROP_SUCCESS) { 7362305Sstevel if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip), 737*7656SSherry.Moore@Sun.COM PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP, 738*7656SSherry.Moore@Sun.COM "bus-type", (caddr_t)&bus_type[0], &len) != 739*7656SSherry.Moore@Sun.COM DDI_PROP_SUCCESS) { 7402305Sstevel 7412305Sstevel cmn_err(CE_CONT, 742*7656SSherry.Moore@Sun.COM "pcic%d: can't find parent bus type\n", 743*7656SSherry.Moore@Sun.COM ddi_get_instance(dip)); 7442305Sstevel 7452305Sstevel kmem_free(pcic, sizeof (pcicdev_t)); 7463867Srw148561 ddi_soft_state_free(pcic_soft_state_p, 747*7656SSherry.Moore@Sun.COM ddi_get_instance(dip)); 7482305Sstevel return (DDI_FAILURE); 7492305Sstevel } 7502305Sstevel } /* ddi_prop_op("device_type") */ 7512305Sstevel 7523664Srw148561 if (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0 || 753*7656SSherry.Moore@Sun.COM strcmp(bus_type, DEVI_PCIEX_NEXNAME) == 0) { 7542305Sstevel pcic->pc_flags = PCF_PCIBUS; 7552305Sstevel } else { 7563867Srw148561 cmn_err(CE_WARN, "!pcic%d: non-pci mode (%s) not supported, " 757*7656SSherry.Moore@Sun.COM "set BIOS to yenta mode if applicable\n", 758*7656SSherry.Moore@Sun.COM ddi_get_instance(dip), bus_type); 7592305Sstevel kmem_free(pcic, sizeof (pcicdev_t)); 7603867Srw148561 ddi_soft_state_free(pcic_soft_state_p, 761*7656SSherry.Moore@Sun.COM ddi_get_instance(dip)); 7622305Sstevel return (DDI_FAILURE); 7632305Sstevel } 7642305Sstevel 7652305Sstevel if ((pcic->bus_speed = ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip), 766*7656SSherry.Moore@Sun.COM DDI_PROP_CANSLEEP, 767*7656SSherry.Moore@Sun.COM "clock-frequency", 0)) == 0) { 7682305Sstevel if (pcic->pc_flags & PCF_PCIBUS) 7692305Sstevel pcic->bus_speed = PCIC_PCI_DEF_SYSCLK; 7702305Sstevel else 7712305Sstevel pcic->bus_speed = PCIC_ISA_DEF_SYSCLK; 7722305Sstevel } else { 7732305Sstevel /* 7742305Sstevel * OBP can declare the speed in Hz... 7752305Sstevel */ 7762305Sstevel if (pcic->bus_speed > 1000000) 7772305Sstevel pcic->bus_speed /= 1000000; 7782305Sstevel } /* ddi_prop_op("clock-frequency") */ 7792305Sstevel 7802305Sstevel pcic->pc_io_type = PCIC_IO_TYPE_82365SL; /* default mode */ 7812305Sstevel 7822305Sstevel #ifdef PCIC_DEBUG 7832305Sstevel if (pcic_debug) { 7842305Sstevel cmn_err(CE_CONT, 785*7656SSherry.Moore@Sun.COM "pcic%d: parent bus type = [%s], speed = %d MHz\n", 786*7656SSherry.Moore@Sun.COM ddi_get_instance(dip), 787*7656SSherry.Moore@Sun.COM bus_type, pcic->bus_speed); 7882305Sstevel } 7892305Sstevel #endif 7902305Sstevel 7912305Sstevel /* 7922305Sstevel * The reg properties on a PCI node are different than those 7932305Sstevel * on a non-PCI node. Handle that difference here. 7942305Sstevel * If it turns out to be a CardBus chip, we have even more 7952305Sstevel * differences. 7962305Sstevel */ 7972305Sstevel if (pcic->pc_flags & PCF_PCIBUS) { 7982305Sstevel int class_code; 7992305Sstevel #if defined(__i386) || defined(__amd64) 8002305Sstevel pcic->pc_base = 0x1000000; 8012305Sstevel pcic->pc_bound = (uint32_t)~0; 8022305Sstevel pcic->pc_iobase = 0x1000; 8032305Sstevel pcic->pc_iobound = 0xefff; 8042305Sstevel #elif defined(__sparc) 8052305Sstevel pcic->pc_base = 0x0; 8062305Sstevel pcic->pc_bound = (uint32_t)~0; 8072305Sstevel pcic->pc_iobase = 0x00000; 8082305Sstevel pcic->pc_iobound = 0xffff; 8092305Sstevel #endif 8102305Sstevel 8112305Sstevel /* usually need to get at config space so map first */ 8122305Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 8132305Sstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 8142305Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 8152305Sstevel 8162305Sstevel if (ddi_regs_map_setup(dip, pci_cfrn, 817*7656SSherry.Moore@Sun.COM (caddr_t *)&pcic->cfgaddr, 818*7656SSherry.Moore@Sun.COM PCIC_PCI_CONFIG_REG_OFFSET, 819*7656SSherry.Moore@Sun.COM PCIC_PCI_CONFIG_REG_LENGTH, 820*7656SSherry.Moore@Sun.COM &attr, 821*7656SSherry.Moore@Sun.COM &pcic->cfg_handle) != 8222305Sstevel DDI_SUCCESS) { 8232305Sstevel cmn_err(CE_CONT, 824*7656SSherry.Moore@Sun.COM "pcic%d: unable to map config space" 825*7656SSherry.Moore@Sun.COM "regs\n", 826*7656SSherry.Moore@Sun.COM ddi_get_instance(dip)); 8272305Sstevel 8282305Sstevel kmem_free(pcic, sizeof (pcicdev_t)); 8292305Sstevel return (DDI_FAILURE); 8302305Sstevel } /* ddi_regs_map_setup */ 8312305Sstevel 8322305Sstevel class_code = ddi_getprop(DDI_DEV_T_ANY, dip, 833*7656SSherry.Moore@Sun.COM DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS, 834*7656SSherry.Moore@Sun.COM "class-code", -1); 8352305Sstevel #ifdef PCIC_DEBUG 8362305Sstevel if (pcic_debug) { 8372305Sstevel cmn_err(CE_CONT, "pcic_attach class_code=%x\n", 8382305Sstevel class_code); 8392305Sstevel } 8402305Sstevel #endif 8412305Sstevel 8422305Sstevel switch (class_code) { 8432305Sstevel case PCIC_PCI_CARDBUS: 8442305Sstevel pcic->pc_flags |= PCF_CARDBUS; 8452305Sstevel pcic->pc_io_type = PCIC_IO_TYPE_YENTA; 8462305Sstevel /* 8472305Sstevel * Get access to the adapter registers on the 8482305Sstevel * PCI bus. A 4K memory page 8492305Sstevel */ 8502305Sstevel #if defined(PCIC_DEBUG) 8512305Sstevel pcic_err(dip, 8, "Is Cardbus device\n"); 8522305Sstevel if (pcic_debug) { 8532305Sstevel int nr; 8542305Sstevel long rs; 8552305Sstevel (void) ddi_dev_nregs(dip, &nr); 8562305Sstevel pcic_err(dip, 9, "\tdev, cfgaddr 0x%p," 8572305Sstevel "cfghndl 0x%p nregs %d", 8582305Sstevel (void *)pcic->cfgaddr, 8592305Sstevel (void *)pcic->cfg_handle, nr); 8602305Sstevel 8612305Sstevel (void) ddi_dev_regsize(dip, 8622305Sstevel PCIC_PCI_CONTROL_REG_NUM, &rs); 8632305Sstevel 8642305Sstevel pcic_err(dip, 9, "\tsize of reg %d is 0x%x\n", 8652305Sstevel PCIC_PCI_CONTROL_REG_NUM, (int)rs); 8662305Sstevel } 8672305Sstevel #endif 8682305Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 8692305Sstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 8702305Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 8712305Sstevel 8722305Sstevel if (ddi_regs_map_setup(dip, pci_ctrn, 873*7656SSherry.Moore@Sun.COM (caddr_t *)&pcic->ioaddr, 874*7656SSherry.Moore@Sun.COM PCIC_PCI_CONTROL_REG_OFFSET, 875*7656SSherry.Moore@Sun.COM PCIC_CB_CONTROL_REG_LENGTH, 876*7656SSherry.Moore@Sun.COM &attr, &pcic->handle) != 8772305Sstevel DDI_SUCCESS) { 8782305Sstevel cmn_err(CE_CONT, 879*7656SSherry.Moore@Sun.COM "pcic%d: unable to map PCI regs\n", 880*7656SSherry.Moore@Sun.COM ddi_get_instance(dip)); 8812305Sstevel ddi_regs_map_free(&pcic->cfg_handle); 8822305Sstevel kmem_free(pcic, sizeof (pcicdev_t)); 8832305Sstevel return (DDI_FAILURE); 8842305Sstevel } /* ddi_regs_map_setup */ 8852305Sstevel 8862305Sstevel /* 8872305Sstevel * Find out the chip type - If we're on a PCI bus, 8882305Sstevel * the adapter has that information in the PCI 8892305Sstevel * config space. 8902305Sstevel * Note that we call pcic_find_pci_type here since 8912305Sstevel * it needs a valid mapped pcic->handle to 8922305Sstevel * access some of the adapter registers in 8932305Sstevel * some cases. 8942305Sstevel */ 8952305Sstevel if (pcic_find_pci_type(pcic) != DDI_SUCCESS) { 8962305Sstevel ddi_regs_map_free(&pcic->handle); 8972305Sstevel ddi_regs_map_free(&pcic->cfg_handle); 8982305Sstevel kmem_free(pcic, sizeof (pcicdev_t)); 8992305Sstevel cmn_err(CE_WARN, "pcic: %s: unsupported " 900*7656SSherry.Moore@Sun.COM "bridge\n", ddi_get_name_addr(dip)); 9012305Sstevel return (DDI_FAILURE); 9022305Sstevel } 9032305Sstevel break; 9042305Sstevel 9052305Sstevel default: 9062305Sstevel case PCIC_PCI_PCMCIA: 9072305Sstevel /* 9082305Sstevel * Get access to the adapter IO registers on the 9092305Sstevel * PCI bus config space. 9102305Sstevel */ 9112305Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 9122305Sstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 9132305Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 9142305Sstevel 9152305Sstevel /* 9162305Sstevel * We need a default mapping to the adapter's IO 9172305Sstevel * control register space. For most adapters 9182305Sstevel * that are of class PCIC_PCI_PCMCIA (or of 9192305Sstevel * a default class) the control registers 9202305Sstevel * will be using the 82365-type control/data 9212305Sstevel * format. 9222305Sstevel */ 9232305Sstevel if (ddi_regs_map_setup(dip, pci_ctrn, 924*7656SSherry.Moore@Sun.COM (caddr_t *)&pcic->ioaddr, 925*7656SSherry.Moore@Sun.COM PCIC_PCI_CONTROL_REG_OFFSET, 926*7656SSherry.Moore@Sun.COM PCIC_PCI_CONTROL_REG_LENGTH, 927*7656SSherry.Moore@Sun.COM &attr, 928*7656SSherry.Moore@Sun.COM &pcic->handle) != DDI_SUCCESS) { 9292305Sstevel cmn_err(CE_CONT, 930*7656SSherry.Moore@Sun.COM "pcic%d: unable to map PCI regs\n", 931*7656SSherry.Moore@Sun.COM ddi_get_instance(dip)); 9322305Sstevel ddi_regs_map_free(&pcic->cfg_handle); 9332305Sstevel kmem_free(pcic, sizeof (pcicdev_t)); 9342305Sstevel return (DDI_FAILURE); 9352305Sstevel } /* ddi_regs_map_setup */ 9362305Sstevel 9372305Sstevel /* 9382305Sstevel * Find out the chip type - If we're on a PCI bus, 9392305Sstevel * the adapter has that information in the PCI 9402305Sstevel * config space. 9412305Sstevel * Note that we call pcic_find_pci_type here since 9422305Sstevel * it needs a valid mapped pcic->handle to 9432305Sstevel * access some of the adapter registers in 9442305Sstevel * some cases. 9452305Sstevel */ 9462305Sstevel if (pcic_find_pci_type(pcic) != DDI_SUCCESS) { 9472305Sstevel ddi_regs_map_free(&pcic->handle); 9482305Sstevel ddi_regs_map_free(&pcic->cfg_handle); 9492305Sstevel kmem_free(pcic, sizeof (pcicdev_t)); 9502305Sstevel cmn_err(CE_WARN, "pcic: %s: unsupported " 951*7656SSherry.Moore@Sun.COM "bridge\n", 952*7656SSherry.Moore@Sun.COM ddi_get_name_addr(dip)); 9532305Sstevel return (DDI_FAILURE); 9542305Sstevel } 9552305Sstevel 9562305Sstevel /* 9572305Sstevel * Some PCI-PCMCIA(R2) adapters are Yenta-compliant 9582305Sstevel * for extended registers even though they are 9592305Sstevel * not CardBus adapters. For those adapters, 9602305Sstevel * re-map pcic->handle to be large enough to 9612305Sstevel * encompass the Yenta registers. 9622305Sstevel */ 9632305Sstevel switch (pcic->pc_type) { 964*7656SSherry.Moore@Sun.COM case PCIC_TI_PCI1031: 9652305Sstevel ddi_regs_map_free(&pcic->handle); 9662305Sstevel 9672305Sstevel if (ddi_regs_map_setup(dip, 968*7656SSherry.Moore@Sun.COM PCIC_PCI_CONTROL_REG_NUM, 969*7656SSherry.Moore@Sun.COM (caddr_t *)&pcic->ioaddr, 970*7656SSherry.Moore@Sun.COM PCIC_PCI_CONTROL_REG_OFFSET, 971*7656SSherry.Moore@Sun.COM PCIC_CB_CONTROL_REG_LENGTH, 972*7656SSherry.Moore@Sun.COM &attr, 973*7656SSherry.Moore@Sun.COM &pcic->handle) != DDI_SUCCESS) { 9742305Sstevel cmn_err(CE_CONT, 975*7656SSherry.Moore@Sun.COM "pcic%d: unable to map " 976*7656SSherry.Moore@Sun.COM "PCI regs\n", 977*7656SSherry.Moore@Sun.COM ddi_get_instance(dip)); 9782305Sstevel ddi_regs_map_free(&pcic->cfg_handle); 9792305Sstevel kmem_free(pcic, sizeof (pcicdev_t)); 9802305Sstevel return (DDI_FAILURE); 9812305Sstevel } /* ddi_regs_map_setup */ 9822305Sstevel break; 983*7656SSherry.Moore@Sun.COM default: 9842305Sstevel break; 9852305Sstevel } /* switch (pcic->pc_type) */ 9862305Sstevel break; 9872305Sstevel } /* switch (class_code) */ 9882305Sstevel } else { 9892305Sstevel /* 9902305Sstevel * We're not on a PCI bus, so assume an ISA bus type 9912305Sstevel * register property. Get access to the adapter IO 9922305Sstevel * registers on a non-PCI bus. 9932305Sstevel */ 9942305Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 9952305Sstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 9962305Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 9972305Sstevel pcic->mem_reg_num = PCIC_ISA_MEM_REG_NUM; 9982305Sstevel pcic->io_reg_num = PCIC_ISA_IO_REG_NUM; 9992305Sstevel 10002305Sstevel if (ddi_regs_map_setup(dip, PCIC_ISA_CONTROL_REG_NUM, 1001*7656SSherry.Moore@Sun.COM (caddr_t *)&pcic->ioaddr, 1002*7656SSherry.Moore@Sun.COM PCIC_ISA_CONTROL_REG_OFFSET, 1003*7656SSherry.Moore@Sun.COM PCIC_ISA_CONTROL_REG_LENGTH, 1004*7656SSherry.Moore@Sun.COM &attr, 1005*7656SSherry.Moore@Sun.COM &pcic->handle) != DDI_SUCCESS) { 10062305Sstevel cmn_err(CE_CONT, 1007*7656SSherry.Moore@Sun.COM "pcic%d: unable to map ISA registers\n", 1008*7656SSherry.Moore@Sun.COM ddi_get_instance(dip)); 10092305Sstevel 10102305Sstevel kmem_free(pcic, sizeof (pcicdev_t)); 10112305Sstevel return (DDI_FAILURE); 10122305Sstevel } /* ddi_regs_map_setup */ 10132305Sstevel 10142305Sstevel /* ISA bus is limited to 24-bits, but not first 640K */ 10152305Sstevel pcic->pc_base = 0xd0000; 10162305Sstevel pcic->pc_bound = (uint32_t)~0; 10172305Sstevel pcic->pc_iobase = 0x1000; 10182305Sstevel pcic->pc_iobound = 0xefff; 10192305Sstevel } /* !PCF_PCIBUS */ 10202305Sstevel 10212305Sstevel #ifdef PCIC_DEBUG 10222305Sstevel if (pcic_debug) { 10232305Sstevel cmn_err(CE_CONT, "pcic_attach pc_flags=%x pc_type=%x\n", 10242305Sstevel pcic->pc_flags, pcic->pc_type); 10252305Sstevel } 10262305Sstevel #endif 10272305Sstevel 10282305Sstevel /* 10292305Sstevel * Setup various adapter registers for the PCI case. For the 10302305Sstevel * non-PCI case, find out the chip type. 10312305Sstevel */ 10322305Sstevel if (pcic->pc_flags & PCF_PCIBUS) { 10332305Sstevel int iline; 10342305Sstevel #if defined(__sparc) 10352305Sstevel iline = 0; 10362305Sstevel #else 10372305Sstevel iline = cardbus_validate_iline(dip, pcic->cfg_handle); 10382305Sstevel #endif 10392305Sstevel 10402305Sstevel /* set flags and socket counts based on chip type */ 10412305Sstevel switch (pcic->pc_type) { 10422305Sstevel uint32_t cfg; 10432305Sstevel case PCIC_INTEL_i82092: 10442305Sstevel cfg = ddi_get8(pcic->cfg_handle, 1045*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_82092_PCICON); 10462305Sstevel /* we can only support 4 Socket version */ 10472305Sstevel if (cfg & PCIC_82092_4_SOCKETS) { 1048*7656SSherry.Moore@Sun.COM pcic->pc_numsockets = 4; 1049*7656SSherry.Moore@Sun.COM pcic->pc_type = PCIC_INTEL_i82092; 1050*7656SSherry.Moore@Sun.COM if (iline != 0xFF) 1051*7656SSherry.Moore@Sun.COM pcic->pc_intr_mode = 1052*7656SSherry.Moore@Sun.COM PCIC_INTR_MODE_PCI_1; 1053*7656SSherry.Moore@Sun.COM else 1054*7656SSherry.Moore@Sun.COM pcic->pc_intr_mode = PCIC_INTR_MODE_ISA; 10552305Sstevel } else { 1056*7656SSherry.Moore@Sun.COM cmn_err(CE_CONT, 10572305Sstevel "pcic%d: Intel 82092 adapter " 10582305Sstevel "in unsupported configuration: 0x%x", 10592305Sstevel ddi_get_instance(pcic->dip), cfg); 1060*7656SSherry.Moore@Sun.COM pcic->pc_numsockets = 0; 10612305Sstevel } /* PCIC_82092_4_SOCKETS */ 10622305Sstevel break; 10632305Sstevel case PCIC_CL_PD6730: 10642305Sstevel case PCIC_CL_PD6729: 10652305Sstevel pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1; 10662305Sstevel cfg = ddi_getprop(DDI_DEV_T_ANY, dip, 1067*7656SSherry.Moore@Sun.COM DDI_PROP_CANSLEEP, 1068*7656SSherry.Moore@Sun.COM "interrupts", 0); 10692305Sstevel /* if not interrupt pin then must use ISA style IRQs */ 10702305Sstevel if (cfg == 0 || iline == 0xFF) 10712305Sstevel pcic->pc_intr_mode = PCIC_INTR_MODE_ISA; 10722305Sstevel else { 10732305Sstevel /* 10742305Sstevel * we have the option to use PCI interrupts. 10752305Sstevel * this might not be optimal but in some cases 10762305Sstevel * is the only thing possible (sparc case). 10772305Sstevel * we now deterine what is possible. 10782305Sstevel */ 10792305Sstevel pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1; 10802305Sstevel } 10812305Sstevel pcic->pc_numsockets = 2; 10822305Sstevel pcic->pc_flags |= PCF_IO_REMAP; 10832305Sstevel break; 10842305Sstevel case PCIC_TI_PCI1031: 10852305Sstevel /* this chip doesn't do CardBus but looks like one */ 10862305Sstevel pcic->pc_flags &= ~PCF_CARDBUS; 10872305Sstevel /* FALLTHROUGH */ 10882305Sstevel default: 10892305Sstevel pcic->pc_flags |= PCF_IO_REMAP; 10902305Sstevel /* FALLTHROUGH */ 10912305Sstevel /* indicate feature even if not supported */ 10922305Sstevel pcic->pc_flags |= PCF_DMA | PCF_ZV; 10932305Sstevel /* Not sure if these apply to all these chips */ 10942305Sstevel pcic->pc_flags |= (PCF_VPPX|PCF_33VCAP); 10952305Sstevel pcic->pc_flags |= pcic_use_cbpwrctl; 10962305Sstevel 10972305Sstevel pcic->pc_numsockets = 1; /* one per function */ 10982305Sstevel if (iline != 0xFF) { 10992305Sstevel uint8_t cfg; 11002305Sstevel pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1; 11012305Sstevel 11022305Sstevel cfg = ddi_get8(pcic->cfg_handle, 1103*7656SSherry.Moore@Sun.COM (pcic->cfgaddr + PCIC_BRIDGE_CTL_REG)); 11042305Sstevel cfg &= (~PCIC_FUN_INT_MOD_ISA); 11052305Sstevel ddi_put8(pcic->cfg_handle, (pcic->cfgaddr + 1106*7656SSherry.Moore@Sun.COM PCIC_BRIDGE_CTL_REG), cfg); 11072305Sstevel } 11082305Sstevel else 11092305Sstevel pcic->pc_intr_mode = PCIC_INTR_MODE_ISA; 11102305Sstevel pcic->pc_io_type = PCIC_IOTYPE_YENTA; 11112305Sstevel break; 11122305Sstevel } 11132305Sstevel } else { 11142305Sstevel /* 11152305Sstevel * We're not on a PCI bus so do some more 11162305Sstevel * checking for adapter type here. 11172305Sstevel * For the non-PCI bus case: 11182305Sstevel * It could be any one of a number of different chips 11192305Sstevel * If we can't determine anything else, it is assumed 11202305Sstevel * to be an Intel 82365SL. The Cirrus Logic PD6710 11212305Sstevel * has an extension register that provides unique 11222305Sstevel * identification. Toshiba chip isn't detailed as yet. 11232305Sstevel */ 11242305Sstevel 11252305Sstevel /* Init the CL id mode */ 11262305Sstevel pcic_putb(pcic, 0, PCIC_CHIP_INFO, 0); 11272305Sstevel value = pcic_getb(pcic, 0, PCIC_CHIP_INFO); 11282305Sstevel 11292305Sstevel /* default to Intel i82365SL and then refine */ 11302305Sstevel pcic->pc_type = PCIC_I82365SL; 11312305Sstevel pcic->pc_chipname = PCIC_TYPE_I82365SL; 11322305Sstevel for (value = 0; pcic_ci_funcs[value] != NULL; value++) { 11332305Sstevel /* go until one succeeds or none left */ 11342305Sstevel if (pcic_ci_funcs[value](pcic)) 11352305Sstevel break; 11362305Sstevel } 11372305Sstevel 11382305Sstevel /* any chip specific flags get set here */ 11392305Sstevel switch (pcic->pc_type) { 11402305Sstevel case PCIC_CL_PD6722: 11412305Sstevel pcic->pc_flags |= PCF_DMA; 11422305Sstevel } 11432305Sstevel 11442305Sstevel for (i = 0; i < PCIC_MAX_SOCKETS; i++) { 11452305Sstevel /* 11462305Sstevel * look for total number of sockets. 11472305Sstevel * basically check each possible socket for 11482305Sstevel * presence like in probe 11492305Sstevel */ 11502305Sstevel 11512305Sstevel /* turn all windows off */ 11522305Sstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0); 11532305Sstevel value = pcic_getb(pcic, i, PCIC_MAPPING_ENABLE); 11542305Sstevel 11552305Sstevel /* 11562305Sstevel * if a zero is read back, then this socket 11572305Sstevel * might be present. It would be except for 11582305Sstevel * some systems that map the secondary PCIC 11592305Sstevel * chip space back to the first. 11602305Sstevel */ 11612305Sstevel if (value != 0) { 11622305Sstevel /* definitely not so skip */ 11632305Sstevel /* note: this is for Compaq support */ 11642305Sstevel continue; 11652305Sstevel } 11662305Sstevel 11672305Sstevel /* further tests */ 11682305Sstevel value = pcic_getb(pcic, i, PCIC_CHIP_REVISION) & 1169*7656SSherry.Moore@Sun.COM PCIC_REV_MASK; 11702305Sstevel if (!(value >= PCIC_REV_LEVEL_LOW && 1171*7656SSherry.Moore@Sun.COM value <= PCIC_REV_LEVEL_HI)) 11722305Sstevel break; 11732305Sstevel 11742305Sstevel pcic_putb(pcic, i, PCIC_SYSMEM_0_STARTLOW, 0xaa); 11752305Sstevel pcic_putb(pcic, i, PCIC_SYSMEM_1_STARTLOW, 0x55); 11762305Sstevel value = pcic_getb(pcic, i, PCIC_SYSMEM_0_STARTLOW); 11772305Sstevel 11782305Sstevel j = pcic_getb(pcic, i, PCIC_SYSMEM_1_STARTLOW); 11792305Sstevel if (value != 0xaa || j != 0x55) 11802305Sstevel break; 11812305Sstevel 11822305Sstevel /* 11832305Sstevel * at this point we know if we have hardware 11842305Sstevel * of some type and not just the bus holding 11852305Sstevel * a pattern for us. We still have to determine 11862305Sstevel * the case where more than 2 sockets are 11872305Sstevel * really the same due to peculiar mappings of 11882305Sstevel * hardware. 11892305Sstevel */ 11902305Sstevel j = pcic->pc_numsockets++; 11912305Sstevel pcic->pc_sockets[j].pcs_flags = 0; 11922305Sstevel pcic->pc_sockets[j].pcs_io = pcic->ioaddr; 11932305Sstevel pcic->pc_sockets[j].pcs_socket = i; 11942305Sstevel 11952305Sstevel /* put PC Card into RESET, just in case */ 11962305Sstevel value = pcic_getb(pcic, i, PCIC_INTERRUPT); 11972305Sstevel pcic_putb(pcic, i, PCIC_INTERRUPT, 1198*7656SSherry.Moore@Sun.COM value & ~PCIC_RESET); 11992305Sstevel } 12002305Sstevel 12012305Sstevel #if defined(PCIC_DEBUG) 12022305Sstevel if (pcic_debug) 12032305Sstevel cmn_err(CE_CONT, "num sockets = %d\n", 1204*7656SSherry.Moore@Sun.COM pcic->pc_numsockets); 12052305Sstevel #endif 12062305Sstevel if (pcic->pc_numsockets == 0) { 12072305Sstevel ddi_regs_map_free(&pcic->handle); 12082305Sstevel kmem_free(pcic, sizeof (pcicdev_t)); 12092305Sstevel return (DDI_FAILURE); 12102305Sstevel } 12112305Sstevel 12122305Sstevel /* 12132305Sstevel * need to think this through again in light of 12142305Sstevel * Compaq not following the model that all the 12152305Sstevel * chip vendors recommend. IBM 755 seems to be 12162305Sstevel * afflicted as well. Basically, if the vendor 12172305Sstevel * wired things wrong, socket 0 responds for socket 2 12182305Sstevel * accesses, etc. 12192305Sstevel */ 12202305Sstevel if (pcic->pc_numsockets > 2) { 12212305Sstevel int count = pcic->pc_numsockets / 4; 12222305Sstevel for (i = 0; i < count; i++) { 12232305Sstevel /* put pattern into socket 0 */ 12242305Sstevel pcic_putb(pcic, i, 1225*7656SSherry.Moore@Sun.COM PCIC_SYSMEM_0_STARTLOW, 0x11); 12262305Sstevel 12272305Sstevel /* put pattern into socket 2 */ 12282305Sstevel pcic_putb(pcic, i + 2, 1229*7656SSherry.Moore@Sun.COM PCIC_SYSMEM_0_STARTLOW, 0x33); 12302305Sstevel 12312305Sstevel /* read back socket 0 */ 12322305Sstevel value = pcic_getb(pcic, i, 1233*7656SSherry.Moore@Sun.COM PCIC_SYSMEM_0_STARTLOW); 12342305Sstevel 12352305Sstevel /* read back chip 1 socket 0 */ 12362305Sstevel j = pcic_getb(pcic, i + 2, 1237*7656SSherry.Moore@Sun.COM PCIC_SYSMEM_0_STARTLOW); 12382305Sstevel if (j == value) { 12392305Sstevel pcic->pc_numsockets -= 2; 12402305Sstevel } 12412305Sstevel } 12422305Sstevel } 12432305Sstevel 12442305Sstevel smi = 0xff; /* no more override */ 12452305Sstevel 12462305Sstevel if (ddi_getprop(DDI_DEV_T_NONE, dip, 1247*7656SSherry.Moore@Sun.COM DDI_PROP_DONTPASS, "need-mult-irq", 1248*7656SSherry.Moore@Sun.COM 0xffff) != 0xffff) 12492305Sstevel pcic->pc_flags |= PCF_MULT_IRQ; 12502305Sstevel 12512305Sstevel } /* !PCF_PCIBUS */ 12522305Sstevel 12532305Sstevel /* 12542305Sstevel * some platforms/busses need to have resources setup 12552305Sstevel * this is temporary until a real resource allocator is 12562305Sstevel * implemented. 12572305Sstevel */ 12582305Sstevel 12592305Sstevel pcic_init_assigned(dip); 12602305Sstevel 12612305Sstevel typename = pcic->pc_chipname; 12622305Sstevel 12632305Sstevel #ifdef PCIC_DEBUG 12642305Sstevel if (pcic_debug) { 12652305Sstevel int nregs, nintrs; 12662305Sstevel 12672305Sstevel if (ddi_dev_nregs(dip, &nregs) != DDI_SUCCESS) 12682305Sstevel nregs = 0; 12692305Sstevel 12702305Sstevel if (ddi_dev_nintrs(dip, &nintrs) != DDI_SUCCESS) 12712305Sstevel nintrs = 0; 12722305Sstevel 12732305Sstevel cmn_err(CE_CONT, 1274*7656SSherry.Moore@Sun.COM "pcic%d: %d register sets, %d interrupts\n", 1275*7656SSherry.Moore@Sun.COM ddi_get_instance(dip), nregs, nintrs); 12762305Sstevel 12772305Sstevel nintrs = 0; 12782305Sstevel while (nregs--) { 12792305Sstevel off_t size; 12802305Sstevel 12812305Sstevel if (ddi_dev_regsize(dip, nintrs, &size) == 12822305Sstevel DDI_SUCCESS) { 12832305Sstevel cmn_err(CE_CONT, 1284*7656SSherry.Moore@Sun.COM "\tregnum %d size %ld (0x%lx)" 1285*7656SSherry.Moore@Sun.COM "bytes", 1286*7656SSherry.Moore@Sun.COM nintrs, size, size); 12872305Sstevel if (nintrs == 12882305Sstevel (pcic->pc_io_type == PCIC_IO_TYPE_82365SL ? 12892305Sstevel PCIC_ISA_CONTROL_REG_NUM : 12902305Sstevel PCIC_PCI_CONTROL_REG_NUM)) 12912305Sstevel cmn_err(CE_CONT, 1292*7656SSherry.Moore@Sun.COM " mapped at: 0x%p\n", 1293*7656SSherry.Moore@Sun.COM (void *)pcic->ioaddr); 12942305Sstevel else 12952305Sstevel cmn_err(CE_CONT, "\n"); 12962305Sstevel } else { 12972305Sstevel cmn_err(CE_CONT, 1298*7656SSherry.Moore@Sun.COM "\tddi_dev_regsize(rnumber" 1299*7656SSherry.Moore@Sun.COM "= %d) returns DDI_FAILURE\n", 1300*7656SSherry.Moore@Sun.COM nintrs); 13012305Sstevel } 13022305Sstevel nintrs++; 13032305Sstevel } /* while */ 13042305Sstevel } /* if (pcic_debug) */ 13052305Sstevel #endif 13062305Sstevel 13072305Sstevel cv_init(&pcic->pm_cv, NULL, CV_DRIVER, NULL); 13082305Sstevel 13092305Sstevel if (!ddi_getprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 1310*7656SSherry.Moore@Sun.COM "disable-audio", 0)) 13112305Sstevel pcic->pc_flags |= PCF_AUDIO; 13122305Sstevel 13132305Sstevel if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP, 13142305Sstevel "disable-cardbus", 0)) 13152305Sstevel pcic->pc_flags &= ~PCF_CARDBUS; 13162305Sstevel 13172305Sstevel (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, PCICPROP_CTL, 13182305Sstevel typename); 13192305Sstevel 13202305Sstevel /* 13212305Sstevel * Init all socket SMI levels to 0 (no SMI) 13222305Sstevel */ 13232305Sstevel for (i = 0; i < PCIC_MAX_SOCKETS; i++) { 1324*7656SSherry.Moore@Sun.COM pcic->pc_sockets[i].pcs_smi = 0; 1325*7656SSherry.Moore@Sun.COM pcic->pc_sockets[i].pcs_debounce_id = 0; 1326*7656SSherry.Moore@Sun.COM pcic->pc_sockets[i].pcs_pcic = pcic; 13272305Sstevel } 13282305Sstevel pcic->pc_lastreg = -1; /* just to make sure we are in sync */ 13292305Sstevel 13302305Sstevel /* 13312305Sstevel * Setup the IRQ handler(s) 13322305Sstevel */ 13332305Sstevel switch (pcic->pc_intr_mode) { 13342305Sstevel int xx; 13352305Sstevel case PCIC_INTR_MODE_ISA: 13362305Sstevel /* 13372305Sstevel * On a non-PCI bus, we just use whatever SMI IRQ level was 13382305Sstevel * specified above, and the IO IRQ levels are allocated 13392305Sstevel * dynamically. 13402305Sstevel */ 13412305Sstevel for (xx = 15, smi = 0; xx >= 0; xx--) { 13422305Sstevel if (PCIC_IRQ(xx) & 13432305Sstevel PCIC_AVAIL_IRQS) { 13442305Sstevel smi = pcmcia_get_intr(dip, xx); 13452305Sstevel if (smi >= 0) 13462305Sstevel break; 13472305Sstevel } 13482305Sstevel } 13492305Sstevel #if defined(PCIC_DEBUG) 13502305Sstevel if (pcic_debug) 13512305Sstevel cmn_err(CE_NOTE, "\tselected IRQ %d as SMI\n", smi); 13522305Sstevel #endif 13532305Sstevel /* init to same so share is easy */ 13542305Sstevel for (i = 0; i < pcic->pc_numsockets; i++) 13552305Sstevel pcic->pc_sockets[i].pcs_smi = smi; 13562305Sstevel /* any special handling of IRQ levels */ 13572305Sstevel if (pcic->pc_flags & PCF_MULT_IRQ) { 13582305Sstevel for (i = 2; i < pcic->pc_numsockets; i++) { 13592305Sstevel if ((i & 1) == 0) { 13602305Sstevel int xx; 13612305Sstevel for (xx = 15, smi = 0; xx >= 0; xx--) { 13622305Sstevel if (PCIC_IRQ(xx) & 13632305Sstevel PCIC_AVAIL_IRQS) { 13642305Sstevel smi = 13652305Sstevel pcmcia_get_intr(dip, 1366*7656SSherry.Moore@Sun.COM xx); 13672305Sstevel if (smi >= 0) 13682305Sstevel break; 13692305Sstevel } 13702305Sstevel } 13712305Sstevel } 13722305Sstevel if (smi >= 0) 13732305Sstevel pcic->pc_sockets[i].pcs_smi = smi; 13742305Sstevel } 13752305Sstevel } 13762305Sstevel pcic->pc_intr_htblp = kmem_alloc(pcic->pc_numsockets * 13772305Sstevel sizeof (ddi_intr_handle_t), KM_SLEEP); 13782305Sstevel for (i = 0, irqlevel = -1; i < pcic->pc_numsockets; i++) { 13792305Sstevel struct intrspec *ispecp; 13802305Sstevel struct ddi_parent_private_data *pdp; 13812305Sstevel 13822305Sstevel if (irqlevel == pcic->pc_sockets[i].pcs_smi) 13832305Sstevel continue; 13842305Sstevel else { 13852305Sstevel irqlevel = pcic->pc_sockets[i].pcs_smi; 13862305Sstevel } 13872305Sstevel /* 13882305Sstevel * now convert the allocated IRQ into an intrspec 13892305Sstevel * and ask our parent to add it. Don't use 13902305Sstevel * the ddi_add_intr since we don't have a 13912305Sstevel * default intrspec in all cases. 13922305Sstevel * 13932305Sstevel * note: this sort of violates DDI but we don't 13942305Sstevel * get hardware intrspecs for many of the devices. 13952305Sstevel * at the same time, we know how to allocate them 13962305Sstevel * so we do the right thing. 13972305Sstevel */ 13982305Sstevel if (ddi_intr_alloc(dip, &pcic->pc_intr_htblp[i], 13992305Sstevel DDI_INTR_TYPE_FIXED, 0, 1, &actual, 14002305Sstevel DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) { 14012305Sstevel cmn_err(CE_WARN, "%s: ddi_intr_alloc failed", 14022305Sstevel ddi_get_name(dip)); 14032305Sstevel goto isa_exit1; 14042305Sstevel } 14052305Sstevel 14062305Sstevel /* 14072305Sstevel * See earlier note: 14082305Sstevel * Since some devices don't have 'intrspec' 14092305Sstevel * we make one up in rootnex. 14102305Sstevel * 14112305Sstevel * However, it is not properly initialized as 14122305Sstevel * the data it needs is present in this driver 14132305Sstevel * and there is no interface to pass that up. 14142305Sstevel * Specially 'irqlevel' is very important and 14152305Sstevel * it is part of pcic struct. 14162305Sstevel * 14172305Sstevel * Set 'intrspec' up here; otherwise adding the 14182305Sstevel * interrupt will fail. 14192305Sstevel */ 14202305Sstevel pdp = ddi_get_parent_data(dip); 14212305Sstevel ispecp = (struct intrspec *)&pdp->par_intr[0]; 14222305Sstevel ispecp->intrspec_vec = irqlevel; 14232305Sstevel ispecp->intrspec_pri = pcic->pc_irq; 14242305Sstevel 14252305Sstevel /* Stay compatible w/ PCMCIA */ 14262305Sstevel pcic->pc_pri = (ddi_iblock_cookie_t) 14272305Sstevel (uintptr_t)pcic->pc_irq; 14282305Sstevel pcic->pc_dcookie.idev_priority = 14292305Sstevel (uintptr_t)pcic->pc_pri; 14302305Sstevel pcic->pc_dcookie.idev_vector = (ushort_t)irqlevel; 14312305Sstevel 14322305Sstevel (void) ddi_intr_set_pri(pcic->pc_intr_htblp[i], 14332305Sstevel pcic->pc_irq); 14342305Sstevel 14352305Sstevel if (i == 0) { 14362305Sstevel mutex_init(&pcic->intr_lock, NULL, MUTEX_DRIVER, 14372305Sstevel DDI_INTR_PRI(pcic->pc_irq)); 14382305Sstevel mutex_init(&pcic->pc_lock, NULL, MUTEX_DRIVER, 14392305Sstevel NULL); 14402305Sstevel } 14412305Sstevel 14422305Sstevel if (ddi_intr_add_handler(pcic->pc_intr_htblp[i], 14432305Sstevel pcic_intr, (caddr_t)pcic, NULL)) { 14442305Sstevel cmn_err(CE_WARN, 14452305Sstevel "%s: ddi_intr_add_handler failed", 14462305Sstevel ddi_get_name(dip)); 14472305Sstevel goto isa_exit2; 14482305Sstevel } 14492305Sstevel 14502305Sstevel if (ddi_intr_enable(pcic->pc_intr_htblp[i])) { 14512305Sstevel cmn_err(CE_WARN, "%s: ddi_intr_enable failed", 14522305Sstevel ddi_get_name(dip)); 14532305Sstevel for (j = i; j < 0; j--) 14542305Sstevel (void) ddi_intr_remove_handler( 14552305Sstevel pcic->pc_intr_htblp[j]); 14562305Sstevel goto isa_exit2; 14572305Sstevel } 14582305Sstevel } 14592305Sstevel break; 14602305Sstevel case PCIC_INTR_MODE_PCI_1: 14612305Sstevel case PCIC_INTR_MODE_PCI: 14622305Sstevel /* 14632305Sstevel * If we're on a PCI bus, we route all interrupts, both SMI 14642305Sstevel * and IO interrupts, through a single interrupt line. 14652305Sstevel * Assign the SMI IRQ level to the IO IRQ level here. 14662305Sstevel */ 14672305Sstevel pcic->pc_pci_intr_hdlp = kmem_alloc(sizeof (ddi_intr_handle_t), 14682305Sstevel KM_SLEEP); 14692305Sstevel if (ddi_intr_alloc(dip, pcic->pc_pci_intr_hdlp, 14702305Sstevel DDI_INTR_TYPE_FIXED, 0, 1, &actual, 14712305Sstevel DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) 14722305Sstevel goto pci_exit1; 14732305Sstevel 14742305Sstevel if (ddi_intr_get_pri(pcic->pc_pci_intr_hdlp[0], 14752305Sstevel &pri) != DDI_SUCCESS) { 14762305Sstevel (void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]); 14772305Sstevel goto pci_exit1; 14782305Sstevel } 14792305Sstevel 14802305Sstevel pcic->pc_pri = (void *)(uintptr_t)pri; 14812305Sstevel mutex_init(&pcic->intr_lock, NULL, MUTEX_DRIVER, pcic->pc_pri); 14822305Sstevel mutex_init(&pcic->pc_lock, NULL, MUTEX_DRIVER, NULL); 14832305Sstevel 14842305Sstevel if (ddi_intr_add_handler(pcic->pc_pci_intr_hdlp[0], 14852305Sstevel pcic_intr, (caddr_t)pcic, NULL)) 14862305Sstevel goto pci_exit2; 14872305Sstevel 14882305Sstevel if (ddi_intr_enable(pcic->pc_pci_intr_hdlp[0])) { 14892305Sstevel (void) ddi_intr_remove_handler( 14902305Sstevel pcic->pc_pci_intr_hdlp[0]); 14912305Sstevel goto pci_exit2; 14922305Sstevel } 14932305Sstevel 14942305Sstevel /* Stay compatible w/ PCMCIA */ 14952305Sstevel pcic->pc_dcookie.idev_priority = (ushort_t)pri; 14962305Sstevel 14972305Sstevel /* init to same (PCI) so share is easy */ 14982305Sstevel for (i = 0; i < pcic->pc_numsockets; i++) 14992305Sstevel pcic->pc_sockets[i].pcs_smi = 0xF; /* any valid */ 15002305Sstevel break; 15012305Sstevel } 15022305Sstevel 15032305Sstevel /* 15042305Sstevel * Setup the adapter hardware to some reasonable defaults. 15052305Sstevel */ 15062305Sstevel mutex_enter(&pcic->pc_lock); 15072305Sstevel /* mark the driver state as attached */ 15082305Sstevel pcic->pc_flags |= PCF_ATTACHED; 15092305Sstevel pcic_setup_adapter(pcic); 15102305Sstevel 15112305Sstevel for (j = 0; j < pcic->pc_numsockets; j++) 15122305Sstevel if (ddi_intr_add_softint(dip, 15132305Sstevel &pcic->pc_sockets[j].pcs_cd_softint_hdl, 15142305Sstevel PCIC_SOFTINT_PRI_VAL, pcic_cd_softint, 15152305Sstevel (caddr_t)&pcic->pc_sockets[j]) != DDI_SUCCESS) 15162305Sstevel goto pci_exit2; 15172305Sstevel 15182305Sstevel #if defined(PCIC_DEBUG) 15192305Sstevel if (pcic_debug) 15202305Sstevel cmn_err(CE_CONT, "type = %s sockets = %d\n", typename, 1521*7656SSherry.Moore@Sun.COM pcic->pc_numsockets); 15222305Sstevel #endif 15232305Sstevel 15242305Sstevel pcic_nexus->an_iblock = &pcic->pc_pri; 15252305Sstevel pcic_nexus->an_idev = &pcic->pc_dcookie; 15262305Sstevel 15272305Sstevel mutex_exit(&pcic->pc_lock); 15282305Sstevel 15292305Sstevel #ifdef CARDBUS 15302305Sstevel (void) cardbus_enable_cd_intr(dip); 15312305Sstevel if (pcic_debug) { 15322305Sstevel 15332305Sstevel cardbus_dump_pci_config(dip); 15342305Sstevel cardbus_dump_socket(dip); 15352305Sstevel } 15362305Sstevel 15372305Sstevel /* 15382305Sstevel * Give the Cardbus misc module a chance to do it's per-adapter 15392305Sstevel * instance setup. Note that there is no corresponding detach() 15402305Sstevel * call. 15412305Sstevel */ 15422305Sstevel if (pcic->pc_flags & PCF_CARDBUS) 15432305Sstevel if (cardbus_attach(dip, &pcic_cbnexus_ops) != DDI_SUCCESS) { 15442305Sstevel cmn_err(CE_CONT, 15452305Sstevel "pcic_attach: cardbus_attach failed\n"); 15462305Sstevel goto pci_exit2; 15472305Sstevel } 15482305Sstevel #endif 15492305Sstevel 15502305Sstevel /* 15512305Sstevel * Give the PCMCIA misc module a chance to do it's per-adapter 15522305Sstevel * instance setup. 15532305Sstevel */ 15542305Sstevel if ((i = pcmcia_attach(dip, pcic_nexus)) != DDI_SUCCESS) 15552305Sstevel goto pci_exit2; 15562305Sstevel 15572305Sstevel if (pcic_maxinst == -1) { 15582305Sstevel /* This assumes that all instances run at the same IPL. */ 15592305Sstevel mutex_init(&pcic_deb_mtx, NULL, MUTEX_DRIVER, NULL); 15602305Sstevel cv_init(&pcic_deb_cv, NULL, CV_DRIVER, NULL); 15612305Sstevel pcic_deb_threadid = thread_create((caddr_t)NULL, 0, 15622305Sstevel pcic_deb_thread, (caddr_t)NULL, 0, &p0, TS_RUN, 15632305Sstevel v.v_maxsyspri - 2); 15642305Sstevel } 15652305Sstevel pcic_maxinst = max(pcic_maxinst, ddi_get_instance(dip)); 15662305Sstevel /* 15672305Sstevel * Setup a debounce timeout to do an initial card detect 15682305Sstevel * and enable interrupts. 15692305Sstevel */ 15702305Sstevel for (j = 0; j < pcic->pc_numsockets; j++) { 15712305Sstevel pcic->pc_sockets[j].pcs_debounce_id = 15722305Sstevel pcic_add_debqueue(&pcic->pc_sockets[j], 1573*7656SSherry.Moore@Sun.COM drv_usectohz(pcic_debounce_time)); 15742305Sstevel } 15752305Sstevel 15762305Sstevel return (i); 15772305Sstevel 15782305Sstevel isa_exit2: 15792305Sstevel mutex_destroy(&pcic->intr_lock); 15802305Sstevel mutex_destroy(&pcic->pc_lock); 15812305Sstevel for (j = i; j < 0; j--) 15822305Sstevel (void) ddi_intr_free(pcic->pc_intr_htblp[j]); 15832305Sstevel isa_exit1: 15842305Sstevel (void) pcmcia_return_intr(dip, pcic->pc_sockets[i].pcs_smi); 15852305Sstevel ddi_regs_map_free(&pcic->handle); 15862305Sstevel if (pcic->pc_flags & PCF_PCIBUS) 15872305Sstevel ddi_regs_map_free(&pcic->cfg_handle); 15882305Sstevel kmem_free(pcic->pc_intr_htblp, pcic->pc_numsockets * 15892305Sstevel sizeof (ddi_intr_handle_t)); 15902305Sstevel kmem_free(pcic, sizeof (pcicdev_t)); 15912305Sstevel return (DDI_FAILURE); 15922305Sstevel 15932305Sstevel pci_exit2: 15942305Sstevel mutex_destroy(&pcic->intr_lock); 15952305Sstevel mutex_destroy(&pcic->pc_lock); 15962305Sstevel (void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]); 15972305Sstevel pci_exit1: 15982305Sstevel ddi_regs_map_free(&pcic->handle); 15992305Sstevel if (pcic->pc_flags & PCF_PCIBUS) 16002305Sstevel ddi_regs_map_free(&pcic->cfg_handle); 16012305Sstevel kmem_free(pcic->pc_pci_intr_hdlp, sizeof (ddi_intr_handle_t)); 16022305Sstevel kmem_free(pcic, sizeof (pcicdev_t)); 16032305Sstevel return (DDI_FAILURE); 16042305Sstevel } 16052305Sstevel 16062305Sstevel /* 16072305Sstevel * pcic_detach() 16082305Sstevel * request to detach from the system 16092305Sstevel */ 16102305Sstevel static int 16112305Sstevel pcic_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 16122305Sstevel { 16132305Sstevel anp_t *anp = ddi_get_driver_private(dip); 16142305Sstevel pcicdev_t *pcic = anp->an_private; 16152305Sstevel int i; 16162305Sstevel 16172305Sstevel switch (cmd) { 16182305Sstevel case DDI_DETACH: 16192305Sstevel /* don't detach if the nexus still talks to us */ 16202305Sstevel if (pcic->pc_callback != NULL) 16212305Sstevel return (DDI_FAILURE); 16222305Sstevel 16232305Sstevel /* kill off the pm simulation */ 16242305Sstevel if (pcic->pc_pmtimer) 16252305Sstevel (void) untimeout(pcic->pc_pmtimer); 16262305Sstevel 16272305Sstevel /* turn everything off for all sockets and chips */ 16282305Sstevel for (i = 0; i < pcic->pc_numsockets; i++) { 16292305Sstevel if (pcic->pc_sockets[i].pcs_debounce_id) 16302305Sstevel pcic_rm_debqueue( 16312305Sstevel pcic->pc_sockets[i].pcs_debounce_id); 16322305Sstevel pcic->pc_sockets[i].pcs_debounce_id = 0; 16332305Sstevel 16342305Sstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0); 16352305Sstevel pcic_putb(pcic, i, PCIC_CARD_DETECT, 0); 16362305Sstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0); 16372305Sstevel /* disable interrupts and put card into RESET */ 16382305Sstevel pcic_putb(pcic, i, PCIC_INTERRUPT, 0); 16392305Sstevel } 16402305Sstevel (void) ddi_intr_disable(pcic->pc_pci_intr_hdlp[0]); 16412305Sstevel (void) ddi_intr_remove_handler(pcic->pc_pci_intr_hdlp[0]); 16422305Sstevel (void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]); 16432305Sstevel kmem_free(pcic->pc_pci_intr_hdlp, sizeof (ddi_intr_handle_t)); 16442305Sstevel pcic->pc_flags = 0; 16452305Sstevel mutex_destroy(&pcic->pc_lock); 16462305Sstevel mutex_destroy(&pcic->intr_lock); 16472305Sstevel cv_destroy(&pcic->pm_cv); 16482305Sstevel if (pcic->pc_flags & PCF_PCIBUS) 1649*7656SSherry.Moore@Sun.COM ddi_regs_map_free(&pcic->cfg_handle); 16502305Sstevel if (pcic->handle) 1651*7656SSherry.Moore@Sun.COM ddi_regs_map_free(&pcic->handle); 16522305Sstevel kmem_free(pcic, sizeof (pcicdev_t)); 16532305Sstevel ddi_soft_state_free(pcic_soft_state_p, ddi_get_instance(dip)); 16542305Sstevel return (DDI_SUCCESS); 16552305Sstevel 16562305Sstevel case DDI_SUSPEND: 16572305Sstevel case DDI_PM_SUSPEND: 16582305Sstevel /* 16592305Sstevel * we got a suspend event (either real or imagined) 16602305Sstevel * so notify the nexus proper that all existing cards 16612305Sstevel * should go away. 16622305Sstevel */ 16632305Sstevel mutex_enter(&pcic->pc_lock); 16642305Sstevel #ifdef CARDBUS 16657151Srw148561 if (pcic->pc_flags & PCF_CARDBUS) { 16667151Srw148561 for (i = 0; i < pcic->pc_numsockets; i++) { 16672305Sstevel if ((pcic->pc_sockets[i].pcs_flags & 16682305Sstevel (PCS_CARD_PRESENT|PCS_CARD_ISCARDBUS)) == 16697151Srw148561 (PCS_CARD_PRESENT|PCS_CARD_ISCARDBUS)) { 16707151Srw148561 16717151Srw148561 pcmcia_cb_suspended( 1672*7656SSherry.Moore@Sun.COM pcic->pc_sockets[i].pcs_socket); 16737151Srw148561 } 16747151Srw148561 } 16757151Srw148561 16767151Srw148561 cardbus_save_children(ddi_get_child(dip)); 16777151Srw148561 } 16782305Sstevel #endif 16792305Sstevel /* turn everything off for all sockets and chips */ 16802305Sstevel for (i = 0; i < pcic->pc_numsockets; i++) { 16812305Sstevel if (pcic->pc_sockets[i].pcs_debounce_id) 16822305Sstevel pcic_rm_debqueue( 16832305Sstevel pcic->pc_sockets[i].pcs_debounce_id); 16842305Sstevel pcic->pc_sockets[i].pcs_debounce_id = 0; 16852305Sstevel 16862305Sstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0); 16872305Sstevel pcic_putb(pcic, i, PCIC_CARD_DETECT, 0); 16882305Sstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0); 16892305Sstevel /* disable interrupts and put card into RESET */ 16902305Sstevel pcic_putb(pcic, i, PCIC_INTERRUPT, 0); 16912305Sstevel pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0); 16922305Sstevel if (pcic->pc_flags & PCF_CBPWRCTL) 16932305Sstevel pcic_putcb(pcic, CB_CONTROL, 0); 16942305Sstevel 16952305Sstevel if (pcic->pc_sockets[i].pcs_flags & PCS_CARD_PRESENT) { 16962305Sstevel pcic->pc_sockets[i].pcs_flags = PCS_STARTING; 16972305Sstevel /* 16982305Sstevel * Because we are half way through a save 16992305Sstevel * all this does is schedule a removal event 17002305Sstevel * to cs for when the system comes back. 17012305Sstevel * This doesn't actually matter. 17022305Sstevel */ 17032305Sstevel if (!pcic_do_pcmcia_sr && pcic_do_removal && 17042305Sstevel pcic->pc_callback) { 17052305Sstevel PC_CALLBACK(pcic->dip, pcic->pc_cb_arg, 17062305Sstevel PCE_CARD_REMOVAL, 17072305Sstevel pcic->pc_sockets[i].pcs_socket); 17082305Sstevel } 17092305Sstevel } 17102305Sstevel } 17112305Sstevel 17122305Sstevel pcic->pc_flags |= PCF_SUSPENDED; 17132305Sstevel mutex_exit(&pcic->pc_lock); 17142305Sstevel 17152305Sstevel /* 17162305Sstevel * when true power management exists, save the adapter 17172305Sstevel * state here to enable a recovery. For the emulation 17182305Sstevel * condition, the state is gone 17192305Sstevel */ 17202305Sstevel return (DDI_SUCCESS); 17212305Sstevel 17222305Sstevel default: 17232305Sstevel return (EINVAL); 17242305Sstevel } 17252305Sstevel } 17262305Sstevel 17272305Sstevel static uint32_t pcic_tisysctl_onbits = ((1<<27) | (1<<15) | (1<<14)); 17282305Sstevel static uint32_t pcic_tisysctl_offbits = 0; 17292305Sstevel static uint32_t pcic_default_latency = 0x40; 17302305Sstevel 17312305Sstevel static void 17322305Sstevel pcic_setup_adapter(pcicdev_t *pcic) 17332305Sstevel { 17342305Sstevel int i; 17352305Sstevel int value, flags; 17362305Sstevel 17377493SVincent.Wang@Sun.COM #if defined(__i386) || defined(__amd64) 17387493SVincent.Wang@Sun.COM pci_regspec_t *reg; 17397493SVincent.Wang@Sun.COM uchar_t bus, dev, func; 17407493SVincent.Wang@Sun.COM uint_t classcode; 17417493SVincent.Wang@Sun.COM int length; 17427493SVincent.Wang@Sun.COM #endif 17437493SVincent.Wang@Sun.COM 17442305Sstevel if (pcic->pc_flags & PCF_PCIBUS) { 17452305Sstevel /* 17462305Sstevel * all PCI-to-PCMCIA bus bridges need memory and I/O enabled 17472305Sstevel */ 17482305Sstevel flags = (PCIC_ENABLE_IO | PCIC_ENABLE_MEM); 17492305Sstevel pcic_iomem_pci_ctl(pcic->cfg_handle, pcic->cfgaddr, flags); 17502305Sstevel } 17512305Sstevel /* enable each socket */ 17522305Sstevel for (i = 0; i < pcic->pc_numsockets; i++) { 17532305Sstevel pcic->pc_sockets[i].pcs_flags = 0; 17542305Sstevel /* find out the socket capabilities (I/O vs memory) */ 17552305Sstevel value = pcic_getb(pcic, i, 1756*7656SSherry.Moore@Sun.COM PCIC_CHIP_REVISION) & PCIC_REV_ID_MASK; 17572305Sstevel if (value == PCIC_REV_ID_IO || value == PCIC_REV_ID_BOTH) 17582305Sstevel pcic->pc_sockets[i].pcs_flags |= PCS_SOCKET_IO; 17592305Sstevel 17602305Sstevel /* disable all windows just in case */ 17612305Sstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0); 17622305Sstevel 17632305Sstevel switch (pcic->pc_type) { 17642305Sstevel uint32_t cfg32; 17652305Sstevel uint16_t cfg16; 17662305Sstevel uint8_t cfg; 17672305Sstevel 17682305Sstevel /* enable extended registers for Vadem */ 1769*7656SSherry.Moore@Sun.COM case PCIC_VADEM_VG469: 1770*7656SSherry.Moore@Sun.COM case PCIC_VADEM: 17712305Sstevel 17722305Sstevel /* enable card status change interrupt for socket */ 17732305Sstevel break; 17742305Sstevel 1775*7656SSherry.Moore@Sun.COM case PCIC_I82365SL: 17762305Sstevel break; 17772305Sstevel 1778*7656SSherry.Moore@Sun.COM case PCIC_CL_PD6710: 17792305Sstevel pcic_putb(pcic, 0, PCIC_MISC_CTL_2, PCIC_LED_ENABLE); 17802305Sstevel break; 17812305Sstevel 17822305Sstevel /* 17832305Sstevel * On the CL_6730, we need to set up the interrupt 17842305Sstevel * signalling mode (PCI mode) and set the SMI and 17852305Sstevel * IRQ interrupt lines to PCI/level-mode. 17862305Sstevel */ 1787*7656SSherry.Moore@Sun.COM case PCIC_CL_PD6730: 17882305Sstevel switch (pcic->pc_intr_mode) { 17892305Sstevel case PCIC_INTR_MODE_PCI_1: 17902305Sstevel clext_reg_write(pcic, i, PCIC_CLEXT_MISC_CTL_3, 1791*7656SSherry.Moore@Sun.COM ((clext_reg_read(pcic, i, 1792*7656SSherry.Moore@Sun.COM PCIC_CLEXT_MISC_CTL_3) & 1793*7656SSherry.Moore@Sun.COM ~PCIC_CLEXT_INT_PCI) | 1794*7656SSherry.Moore@Sun.COM PCIC_CLEXT_INT_PCI)); 17952305Sstevel clext_reg_write(pcic, i, PCIC_CLEXT_EXT_CTL_1, 1796*7656SSherry.Moore@Sun.COM (PCIC_CLEXT_IRQ_LVL_MODE | 1797*7656SSherry.Moore@Sun.COM PCIC_CLEXT_SMI_LVL_MODE)); 17982305Sstevel cfg = PCIC_CL_LP_DYN_MODE; 17992305Sstevel pcic_putb(pcic, i, PCIC_MISC_CTL_2, cfg); 18002305Sstevel break; 18012305Sstevel case PCIC_INTR_MODE_ISA: 18022305Sstevel break; 18032305Sstevel } 18042305Sstevel break; 18052305Sstevel /* 18062305Sstevel * On the CL_6729, we set the SMI and IRQ interrupt 18072305Sstevel * lines to PCI/level-mode. as well as program the 18082305Sstevel * correct clock speed divider bit. 18092305Sstevel */ 1810*7656SSherry.Moore@Sun.COM case PCIC_CL_PD6729: 18112305Sstevel switch (pcic->pc_intr_mode) { 18122305Sstevel case PCIC_INTR_MODE_PCI_1: 18132305Sstevel clext_reg_write(pcic, i, PCIC_CLEXT_EXT_CTL_1, 1814*7656SSherry.Moore@Sun.COM (PCIC_CLEXT_IRQ_LVL_MODE | 1815*7656SSherry.Moore@Sun.COM PCIC_CLEXT_SMI_LVL_MODE)); 18162305Sstevel 18172305Sstevel break; 18182305Sstevel case PCIC_INTR_MODE_ISA: 18192305Sstevel break; 18202305Sstevel } 18212305Sstevel if (pcic->bus_speed > PCIC_PCI_25MHZ && i == 0) { 18222305Sstevel cfg = 0; 18232305Sstevel cfg |= PCIC_CL_TIMER_CLK_DIV; 18242305Sstevel pcic_putb(pcic, i, PCIC_MISC_CTL_2, cfg); 18252305Sstevel } 18262305Sstevel break; 1827*7656SSherry.Moore@Sun.COM case PCIC_INTEL_i82092: 18282305Sstevel cfg = PCIC_82092_EN_TIMING; 18292305Sstevel if (pcic->bus_speed < PCIC_SYSCLK_33MHZ) 1830*7656SSherry.Moore@Sun.COM cfg |= PCIC_82092_PCICLK_25MHZ; 18312305Sstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr + 1832*7656SSherry.Moore@Sun.COM PCIC_82092_PCICON, cfg); 18332305Sstevel break; 1834*7656SSherry.Moore@Sun.COM case PCIC_TI_PCI1130: 1835*7656SSherry.Moore@Sun.COM case PCIC_TI_PCI1131: 1836*7656SSherry.Moore@Sun.COM case PCIC_TI_PCI1250: 1837*7656SSherry.Moore@Sun.COM case PCIC_TI_PCI1031: 18382305Sstevel cfg = ddi_get8(pcic->cfg_handle, 1839*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_DEVCTL_REG); 18402305Sstevel cfg &= ~PCIC_DEVCTL_INTR_MASK; 18412305Sstevel switch (pcic->pc_intr_mode) { 18422305Sstevel case PCIC_INTR_MODE_ISA: 18432305Sstevel cfg |= PCIC_DEVCTL_INTR_ISA; 18442305Sstevel break; 18452305Sstevel } 18462305Sstevel #ifdef PCIC_DEBUG 18472305Sstevel if (pcic_debug) { 18482305Sstevel cmn_err(CE_CONT, "pcic_setup_adapter: " 18492305Sstevel "write reg 0x%x=%x \n", 18502305Sstevel PCIC_DEVCTL_REG, cfg); 18512305Sstevel } 18522305Sstevel #endif 18532305Sstevel ddi_put8(pcic->cfg_handle, 1854*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_DEVCTL_REG, 1855*7656SSherry.Moore@Sun.COM cfg); 18562305Sstevel 18572305Sstevel cfg = ddi_get8(pcic->cfg_handle, 1858*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_CRDCTL_REG); 18592305Sstevel cfg &= ~(PCIC_CRDCTL_PCIINTR|PCIC_CRDCTL_PCICSC| 1860*7656SSherry.Moore@Sun.COM PCIC_CRDCTL_PCIFUNC); 18612305Sstevel switch (pcic->pc_intr_mode) { 18622305Sstevel case PCIC_INTR_MODE_PCI_1: 18632305Sstevel cfg |= PCIC_CRDCTL_PCIINTR | 1864*7656SSherry.Moore@Sun.COM PCIC_CRDCTL_PCICSC | 1865*7656SSherry.Moore@Sun.COM PCIC_CRDCTL_PCIFUNC; 18662305Sstevel pcic->pc_flags |= PCF_USE_SMI; 18672305Sstevel break; 18682305Sstevel } 18692305Sstevel #ifdef PCIC_DEBUG 18702305Sstevel if (pcic_debug) { 18712305Sstevel cmn_err(CE_CONT, "pcic_setup_adapter: " 18722305Sstevel " write reg 0x%x=%x \n", 18732305Sstevel PCIC_CRDCTL_REG, cfg); 18742305Sstevel } 18752305Sstevel #endif 18762305Sstevel ddi_put8(pcic->cfg_handle, 1877*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_CRDCTL_REG, 1878*7656SSherry.Moore@Sun.COM cfg); 18792305Sstevel break; 1880*7656SSherry.Moore@Sun.COM case PCIC_TI_PCI1221: 1881*7656SSherry.Moore@Sun.COM case PCIC_TI_PCI1225: 18822305Sstevel cfg = ddi_get8(pcic->cfg_handle, 18832305Sstevel pcic->cfgaddr + PCIC_DEVCTL_REG); 18842305Sstevel cfg |= (PCIC_DEVCTL_INTR_DFLT | PCIC_DEVCTL_3VCAPABLE); 18852305Sstevel #ifdef PCIC_DEBUG 18862305Sstevel if (pcic_debug) { 18872305Sstevel cmn_err(CE_CONT, "pcic_setup_adapter: " 18882305Sstevel " write reg 0x%x=%x \n", 18892305Sstevel PCIC_DEVCTL_REG, cfg); 18902305Sstevel } 18912305Sstevel #endif 18922305Sstevel ddi_put8(pcic->cfg_handle, 18932305Sstevel pcic->cfgaddr + PCIC_DEVCTL_REG, cfg); 18942305Sstevel 18952305Sstevel cfg = ddi_get8(pcic->cfg_handle, 18962305Sstevel pcic->cfgaddr + PCIC_DIAG_REG); 18972305Sstevel if (pcic->pc_type == PCIC_TI_PCI1225) { 18982305Sstevel cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC); 18992305Sstevel } else { 19002305Sstevel cfg |= PCIC_DIAG_ASYNC; 19012305Sstevel } 19022305Sstevel pcic->pc_flags |= PCF_USE_SMI; 19032305Sstevel #ifdef PCIC_DEBUG 19042305Sstevel if (pcic_debug) { 19052305Sstevel cmn_err(CE_CONT, "pcic_setup_adapter: " 19062305Sstevel " write reg 0x%x=%x \n", 19072305Sstevel PCIC_DIAG_REG, cfg); 19082305Sstevel } 19092305Sstevel #endif 19102305Sstevel ddi_put8(pcic->cfg_handle, 19112305Sstevel pcic->cfgaddr + PCIC_DIAG_REG, cfg); 19122305Sstevel break; 1913*7656SSherry.Moore@Sun.COM case PCIC_TI_PCI1520: 1914*7656SSherry.Moore@Sun.COM case PCIC_TI_PCI1510: 1915*7656SSherry.Moore@Sun.COM case PCIC_TI_VENDOR: 19162305Sstevel if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) { 19177493SVincent.Wang@Sun.COM /* functional intr routed by ExCA register */ 19182305Sstevel cfg = ddi_get8(pcic->cfg_handle, 1919*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG); 19202305Sstevel cfg |= PCIC_FUN_INT_MOD_ISA; 19212305Sstevel ddi_put8(pcic->cfg_handle, 1922*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG, 1923*7656SSherry.Moore@Sun.COM cfg); 19247493SVincent.Wang@Sun.COM 19257493SVincent.Wang@Sun.COM /* IRQ serialized interrupts */ 19267493SVincent.Wang@Sun.COM cfg = ddi_get8(pcic->cfg_handle, 1927*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_DEVCTL_REG); 19287493SVincent.Wang@Sun.COM cfg &= ~PCIC_DEVCTL_INTR_MASK; 19297493SVincent.Wang@Sun.COM cfg |= PCIC_DEVCTL_INTR_ISA; 19307493SVincent.Wang@Sun.COM ddi_put8(pcic->cfg_handle, 1931*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_DEVCTL_REG, 1932*7656SSherry.Moore@Sun.COM cfg); 19337493SVincent.Wang@Sun.COM break; 19342305Sstevel } 19357493SVincent.Wang@Sun.COM 19367493SVincent.Wang@Sun.COM /* CSC interrupt routed to PCI */ 19377493SVincent.Wang@Sun.COM cfg = ddi_get8(pcic->cfg_handle, 19387493SVincent.Wang@Sun.COM pcic->cfgaddr + PCIC_DIAG_REG); 19397493SVincent.Wang@Sun.COM cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC); 19407493SVincent.Wang@Sun.COM ddi_put8(pcic->cfg_handle, 19417493SVincent.Wang@Sun.COM pcic->cfgaddr + PCIC_DIAG_REG, cfg); 19427493SVincent.Wang@Sun.COM 19437493SVincent.Wang@Sun.COM #if defined(__i386) || defined(__amd64) 19447493SVincent.Wang@Sun.COM /* 19457493SVincent.Wang@Sun.COM * Some TI chips have 2 cardbus slots(function0 and 19467493SVincent.Wang@Sun.COM * function1), and others may have just 1 cardbus slot. 19477493SVincent.Wang@Sun.COM * The interrupt routing register is shared between the 19487493SVincent.Wang@Sun.COM * 2 functions and can only be accessed through 19497493SVincent.Wang@Sun.COM * function0. Here we check the presence of the second 19507493SVincent.Wang@Sun.COM * cardbus slot and do the right thing. 19517493SVincent.Wang@Sun.COM */ 19527493SVincent.Wang@Sun.COM 19537493SVincent.Wang@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, pcic->dip, 19547493SVincent.Wang@Sun.COM DDI_PROP_DONTPASS, "reg", (caddr_t)®, 19557493SVincent.Wang@Sun.COM &length) != DDI_PROP_SUCCESS) { 1956*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, 1957*7656SSherry.Moore@Sun.COM "pcic_setup_adapter(), failed to" 1958*7656SSherry.Moore@Sun.COM " read reg property\n"); 19597493SVincent.Wang@Sun.COM break; 19607493SVincent.Wang@Sun.COM } 19617493SVincent.Wang@Sun.COM 19627493SVincent.Wang@Sun.COM bus = PCI_REG_BUS_G(reg->pci_phys_hi); 19637493SVincent.Wang@Sun.COM dev = PCI_REG_DEV_G(reg->pci_phys_hi); 19647493SVincent.Wang@Sun.COM func = PCI_REG_FUNC_G(reg->pci_phys_hi); 19657493SVincent.Wang@Sun.COM kmem_free((caddr_t)reg, length); 19667493SVincent.Wang@Sun.COM 19677493SVincent.Wang@Sun.COM if (func != 0) { 19687493SVincent.Wang@Sun.COM break; 19697493SVincent.Wang@Sun.COM } 19707493SVincent.Wang@Sun.COM 19717493SVincent.Wang@Sun.COM classcode = (*pci_getl_func)(bus, dev, 1, 1972*7656SSherry.Moore@Sun.COM PCI_CONF_REVID); 19737493SVincent.Wang@Sun.COM classcode >>= 8; 19747493SVincent.Wang@Sun.COM if (classcode != 0x060700 && 19757493SVincent.Wang@Sun.COM classcode != 0x060500) { 19767493SVincent.Wang@Sun.COM break; 19777493SVincent.Wang@Sun.COM } 19787493SVincent.Wang@Sun.COM 19797493SVincent.Wang@Sun.COM /* Parallel PCI interrupts only */ 19802305Sstevel cfg = ddi_get8(pcic->cfg_handle, 1981*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_DEVCTL_REG); 19822305Sstevel cfg &= ~PCIC_DEVCTL_INTR_MASK; 19832305Sstevel ddi_put8(pcic->cfg_handle, 1984*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_DEVCTL_REG, 1985*7656SSherry.Moore@Sun.COM cfg); 19862305Sstevel 19872305Sstevel /* tie INTA and INTB together */ 19882305Sstevel cfg = ddi_get8(pcic->cfg_handle, 1989*7656SSherry.Moore@Sun.COM (pcic->cfgaddr + PCIC_SYSCTL_REG + 3)); 19902305Sstevel cfg |= PCIC_SYSCTL_INTRTIE; 19912305Sstevel ddi_put8(pcic->cfg_handle, (pcic->cfgaddr + 1992*7656SSherry.Moore@Sun.COM PCIC_SYSCTL_REG + 3), cfg); 19937493SVincent.Wang@Sun.COM #endif 19947493SVincent.Wang@Sun.COM 19952305Sstevel break; 1996*7656SSherry.Moore@Sun.COM case PCIC_TI_PCI1410: 19972305Sstevel cfg = ddi_get8(pcic->cfg_handle, 19982305Sstevel pcic->cfgaddr + PCIC_DIAG_REG); 19992305Sstevel cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC); 20002305Sstevel ddi_put8(pcic->cfg_handle, 20012305Sstevel pcic->cfgaddr + PCIC_DIAG_REG, cfg); 20022305Sstevel break; 2003*7656SSherry.Moore@Sun.COM case PCIC_TOSHIBA_TOPIC100: 2004*7656SSherry.Moore@Sun.COM case PCIC_TOSHIBA_TOPIC95: 2005*7656SSherry.Moore@Sun.COM case PCIC_TOSHIBA_VENDOR: 20062305Sstevel cfg = ddi_get8(pcic->cfg_handle, pcic->cfgaddr + 2007*7656SSherry.Moore@Sun.COM PCIC_TOSHIBA_SLOT_CTL_REG); 20082305Sstevel cfg |= (PCIC_TOSHIBA_SCR_SLOTON | 2009*7656SSherry.Moore@Sun.COM PCIC_TOSHIBA_SCR_SLOTEN); 20102305Sstevel cfg &= (~PCIC_TOSHIBA_SCR_PRT_MASK); 20112305Sstevel cfg |= PCIC_TOSHIBA_SCR_PRT_3E2; 20122305Sstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr + 2013*7656SSherry.Moore@Sun.COM PCIC_TOSHIBA_SLOT_CTL_REG, cfg); 20142305Sstevel cfg = ddi_get8(pcic->cfg_handle, pcic->cfgaddr + 2015*7656SSherry.Moore@Sun.COM PCIC_TOSHIBA_INTR_CTL_REG); 20162305Sstevel switch (pcic->pc_intr_mode) { 20172305Sstevel case PCIC_INTR_MODE_ISA: 20182305Sstevel cfg &= ~PCIC_TOSHIBA_ICR_SRC; 20192305Sstevel ddi_put8(pcic->cfg_handle, 2020*7656SSherry.Moore@Sun.COM pcic->cfgaddr + 2021*7656SSherry.Moore@Sun.COM PCIC_TOSHIBA_INTR_CTL_REG, cfg); 20222305Sstevel 20232305Sstevel cfg = ddi_get8(pcic->cfg_handle, 2024*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG); 20252305Sstevel cfg |= PCIC_FUN_INT_MOD_ISA; 20262305Sstevel ddi_put8(pcic->cfg_handle, 2027*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG, 2028*7656SSherry.Moore@Sun.COM cfg); 20292305Sstevel break; 20302305Sstevel case PCIC_INTR_MODE_PCI_1: 20312305Sstevel cfg |= PCIC_TOSHIBA_ICR_SRC; 20322305Sstevel cfg &= (~PCIC_TOSHIBA_ICR_PIN_MASK); 20332305Sstevel cfg |= PCIC_TOSHIBA_ICR_PIN_INTA; 20342305Sstevel ddi_put8(pcic->cfg_handle, 2035*7656SSherry.Moore@Sun.COM pcic->cfgaddr + 2036*7656SSherry.Moore@Sun.COM PCIC_TOSHIBA_INTR_CTL_REG, cfg); 20372305Sstevel break; 20382305Sstevel } 20392305Sstevel break; 2040*7656SSherry.Moore@Sun.COM case PCIC_O2MICRO_VENDOR: 20412305Sstevel cfg32 = ddi_get32(pcic->cfg_handle, 2042*7656SSherry.Moore@Sun.COM (uint32_t *)(pcic->cfgaddr + 2043*7656SSherry.Moore@Sun.COM PCIC_O2MICRO_MISC_CTL)); 20442305Sstevel switch (pcic->pc_intr_mode) { 20452305Sstevel case PCIC_INTR_MODE_ISA: 20462305Sstevel cfg32 |= (PCIC_O2MICRO_ISA_LEGACY | 2047*7656SSherry.Moore@Sun.COM PCIC_O2MICRO_INT_MOD_PCI); 20482305Sstevel ddi_put32(pcic->cfg_handle, 2049*7656SSherry.Moore@Sun.COM (uint32_t *)(pcic->cfgaddr + 2050*7656SSherry.Moore@Sun.COM PCIC_O2MICRO_MISC_CTL), 2051*7656SSherry.Moore@Sun.COM cfg32); 20522305Sstevel cfg = ddi_get8(pcic->cfg_handle, 2053*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG); 20542305Sstevel cfg |= PCIC_FUN_INT_MOD_ISA; 20552305Sstevel ddi_put8(pcic->cfg_handle, 2056*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG, 2057*7656SSherry.Moore@Sun.COM cfg); 20582305Sstevel break; 20592305Sstevel case PCIC_INTR_MODE_PCI_1: 20602305Sstevel cfg32 &= ~PCIC_O2MICRO_ISA_LEGACY; 20612305Sstevel cfg32 |= PCIC_O2MICRO_INT_MOD_PCI; 20622305Sstevel ddi_put32(pcic->cfg_handle, 2063*7656SSherry.Moore@Sun.COM (uint32_t *)(pcic->cfgaddr + 2064*7656SSherry.Moore@Sun.COM PCIC_O2MICRO_MISC_CTL), 2065*7656SSherry.Moore@Sun.COM cfg32); 20662305Sstevel break; 20672305Sstevel } 20682305Sstevel break; 2069*7656SSherry.Moore@Sun.COM case PCIC_RICOH_VENDOR: 20702305Sstevel if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) { 20712305Sstevel cfg16 = ddi_get16(pcic->cfg_handle, 2072*7656SSherry.Moore@Sun.COM (uint16_t *)(pcic->cfgaddr + 2073*7656SSherry.Moore@Sun.COM PCIC_RICOH_MISC_CTL_2)); 20742305Sstevel cfg16 |= (PCIC_RICOH_CSC_INT_MOD | 2075*7656SSherry.Moore@Sun.COM PCIC_RICOH_FUN_INT_MOD); 20762305Sstevel ddi_put16(pcic->cfg_handle, 2077*7656SSherry.Moore@Sun.COM (uint16_t *)(pcic->cfgaddr + 2078*7656SSherry.Moore@Sun.COM PCIC_RICOH_MISC_CTL_2), 2079*7656SSherry.Moore@Sun.COM cfg16); 20802305Sstevel 20812305Sstevel cfg16 = ddi_get16(pcic->cfg_handle, 2082*7656SSherry.Moore@Sun.COM (uint16_t *)(pcic->cfgaddr + 2083*7656SSherry.Moore@Sun.COM PCIC_RICOH_MISC_CTL)); 20842305Sstevel cfg16 |= PCIC_RICOH_SIRQ_EN; 20852305Sstevel ddi_put16(pcic->cfg_handle, 2086*7656SSherry.Moore@Sun.COM (uint16_t *)(pcic->cfgaddr + 2087*7656SSherry.Moore@Sun.COM PCIC_RICOH_MISC_CTL), 2088*7656SSherry.Moore@Sun.COM cfg16); 20892305Sstevel 20902305Sstevel cfg = ddi_get8(pcic->cfg_handle, 2091*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG); 20922305Sstevel cfg |= PCIC_FUN_INT_MOD_ISA; 20932305Sstevel ddi_put8(pcic->cfg_handle, 2094*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG, 2095*7656SSherry.Moore@Sun.COM cfg); 20962305Sstevel } 20972305Sstevel break; 2098*7656SSherry.Moore@Sun.COM default: 20992305Sstevel break; 21002305Sstevel } /* switch */ 21012305Sstevel 21023097Srw148561 /* 21033097Srw148561 * The default value in the EEPROM (loaded on reset) for 21043097Srw148561 * MFUNC0/MFUNC1 may be incorrect. Here we make sure that 21053097Srw148561 * MFUNC0 is connected to INTA, and MFUNC1 is connected to 21063097Srw148561 * INTB. This applies to all TI CardBus controllers. 21073097Srw148561 */ 21083097Srw148561 if ((pcic->pc_type >> 16) == PCIC_TI_VENDORID && 2109*7656SSherry.Moore@Sun.COM pcic->pc_intr_mode == PCIC_INTR_MODE_PCI_1) { 21103097Srw148561 value = ddi_get32(pcic->cfg_handle, 21113097Srw148561 (uint32_t *)(pcic->cfgaddr + PCIC_MFROUTE_REG)); 21123097Srw148561 value &= ~0xff; 21133097Srw148561 ddi_put32(pcic->cfg_handle, (uint32_t *)(pcic->cfgaddr + 21143664Srw148561 PCIC_MFROUTE_REG), value|PCIC_TI_MFUNC_SEL); 21153097Srw148561 } 21163097Srw148561 21172305Sstevel /* setup general card status change interrupt */ 21182305Sstevel switch (pcic->pc_type) { 21192305Sstevel case PCIC_TI_PCI1225: 21202305Sstevel case PCIC_TI_PCI1221: 21212305Sstevel case PCIC_TI_PCI1031: 21222305Sstevel case PCIC_TI_PCI1520: 21232305Sstevel case PCIC_TI_PCI1410: 21242305Sstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 21252305Sstevel PCIC_CHANGE_DEFAULT); 21262305Sstevel break; 21272305Sstevel default: 21282305Sstevel if (pcic->pc_intr_mode == 2129*7656SSherry.Moore@Sun.COM PCIC_INTR_MODE_PCI_1) { 21302305Sstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 2131*7656SSherry.Moore@Sun.COM PCIC_CHANGE_DEFAULT); 21322305Sstevel break; 21332305Sstevel } else { 21342305Sstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 2135*7656SSherry.Moore@Sun.COM PCIC_CHANGE_DEFAULT | 2136*7656SSherry.Moore@Sun.COM (pcic->pc_sockets[i].pcs_smi << 4)); 21372305Sstevel break; 21382305Sstevel } 21392305Sstevel } 21402305Sstevel 21412305Sstevel pcic->pc_flags |= PCF_INTRENAB; 21422305Sstevel 21432305Sstevel /* take card out of RESET */ 21442305Sstevel pcic_putb(pcic, i, PCIC_INTERRUPT, PCIC_RESET); 21452305Sstevel /* turn power off and let CS do this */ 21462305Sstevel pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0); 21472305Sstevel 21482305Sstevel /* final chip specific initialization */ 21492305Sstevel switch (pcic->pc_type) { 2150*7656SSherry.Moore@Sun.COM case PCIC_VADEM: 21512305Sstevel pcic_putb(pcic, i, PCIC_VG_CONTROL, 2152*7656SSherry.Moore@Sun.COM PCIC_VC_DELAYENABLE); 21532305Sstevel pcic->pc_flags |= PCF_DEBOUNCE; 21542305Sstevel /* FALLTHROUGH */ 2155*7656SSherry.Moore@Sun.COM case PCIC_I82365SL: 21562305Sstevel pcic_putb(pcic, i, PCIC_GLOBAL_CONTROL, 2157*7656SSherry.Moore@Sun.COM PCIC_GC_CSC_WRITE); 21582305Sstevel /* clear any pending interrupts */ 21592305Sstevel value = pcic_getb(pcic, i, PCIC_CARD_STATUS_CHANGE); 21602305Sstevel pcic_putb(pcic, i, PCIC_CARD_STATUS_CHANGE, value); 21612305Sstevel break; 21622305Sstevel /* The 82092 uses PCI config space to enable interrupts */ 2163*7656SSherry.Moore@Sun.COM case PCIC_INTEL_i82092: 21642305Sstevel pcic_82092_smiirq_ctl(pcic, i, PCIC_82092_CTL_SMI, 2165*7656SSherry.Moore@Sun.COM PCIC_82092_INT_ENABLE); 21662305Sstevel break; 2167*7656SSherry.Moore@Sun.COM case PCIC_CL_PD6729: 21682305Sstevel if (pcic->bus_speed >= PCIC_PCI_DEF_SYSCLK && i == 0) { 21692305Sstevel value = pcic_getb(pcic, i, PCIC_MISC_CTL_2); 21702305Sstevel pcic_putb(pcic, i, PCIC_MISC_CTL_2, 2171*7656SSherry.Moore@Sun.COM value | PCIC_CL_TIMER_CLK_DIV); 21722305Sstevel } 21732305Sstevel break; 21742305Sstevel } /* switch */ 21752305Sstevel 21762305Sstevel #if defined(PCIC_DEBUG) 21772305Sstevel if (pcic_debug) 21782305Sstevel cmn_err(CE_CONT, 2179*7656SSherry.Moore@Sun.COM "socket %d value=%x, flags = %x (%s)\n", 2180*7656SSherry.Moore@Sun.COM i, value, pcic->pc_sockets[i].pcs_flags, 2181*7656SSherry.Moore@Sun.COM (pcic->pc_sockets[i].pcs_flags & 2182*7656SSherry.Moore@Sun.COM PCS_CARD_PRESENT) ? 2183*7656SSherry.Moore@Sun.COM "card present" : "no card"); 21842305Sstevel #endif 21852305Sstevel } 21862305Sstevel } 21872305Sstevel 21882305Sstevel /* 21892305Sstevel * pcic_intr(caddr_t, caddr_t) 21902305Sstevel * interrupt handler for the PCIC style adapter 21912305Sstevel * handles all basic interrupts and also checks 21922305Sstevel * for status changes and notifies the nexus if 21932305Sstevel * necessary 21942305Sstevel * 21952305Sstevel * On PCI bus adapters, also handles all card 21962305Sstevel * IO interrupts. 21972305Sstevel */ 21982305Sstevel /*ARGSUSED*/ 21992305Sstevel uint32_t 22002305Sstevel pcic_intr(caddr_t arg1, caddr_t arg2) 22012305Sstevel { 22022305Sstevel pcicdev_t *pcic = (pcicdev_t *)arg1; 22032305Sstevel int value = 0, i, ret = DDI_INTR_UNCLAIMED; 22042305Sstevel uint8_t status; 22052305Sstevel uint_t io_ints; 22062305Sstevel 22072305Sstevel #if defined(PCIC_DEBUG) 22082305Sstevel pcic_err(pcic->dip, 0xf, 2209*7656SSherry.Moore@Sun.COM "pcic_intr: enter pc_flags=0x%x PCF_ATTACHED=0x%x" 2210*7656SSherry.Moore@Sun.COM " pc_numsockets=%d \n", 2211*7656SSherry.Moore@Sun.COM pcic->pc_flags, PCF_ATTACHED, pcic->pc_numsockets); 22122305Sstevel #endif 22132305Sstevel 22142305Sstevel if (!(pcic->pc_flags & PCF_ATTACHED)) 2215*7656SSherry.Moore@Sun.COM return (DDI_INTR_UNCLAIMED); 22162305Sstevel 22172305Sstevel mutex_enter(&pcic->intr_lock); 22182305Sstevel 22192305Sstevel if (pcic->pc_flags & PCF_SUSPENDED) { 22202305Sstevel mutex_exit(&pcic->intr_lock); 22212305Sstevel return (ret); 22222305Sstevel } 22232305Sstevel 22242305Sstevel /* 22252305Sstevel * need to change to only ACK and touch the slot that 22262305Sstevel * actually caused the interrupt. Currently everything 22272305Sstevel * is acked 22282305Sstevel * 22292305Sstevel * we need to look at all known sockets to determine 22302305Sstevel * what might have happened, so step through the list 22312305Sstevel * of them 22322305Sstevel */ 22332305Sstevel 22342305Sstevel /* 22352305Sstevel * Set the bitmask for IO interrupts to initially include all sockets 22362305Sstevel */ 22372305Sstevel io_ints = (1 << pcic->pc_numsockets) - 1; 22382305Sstevel 22392305Sstevel for (i = 0; i < pcic->pc_numsockets; i++) { 22402305Sstevel int card_type; 22412305Sstevel pcic_socket_t *sockp; 22422305Sstevel int value_cb = 0; 22432305Sstevel 22442305Sstevel sockp = &pcic->pc_sockets[i]; 22452305Sstevel /* get the socket's I/O addresses */ 22462305Sstevel 22472305Sstevel if (sockp->pcs_flags & PCS_WAITING) { 22482305Sstevel io_ints &= ~(1 << i); 22492305Sstevel continue; 22502305Sstevel } 22512305Sstevel 22522305Sstevel if (sockp->pcs_flags & PCS_CARD_IO) 22532305Sstevel card_type = IF_IO; 22542305Sstevel else 22552305Sstevel card_type = IF_MEMORY; 22562305Sstevel 22572305Sstevel if (pcic->pc_io_type == PCIC_IO_TYPE_YENTA) 22582305Sstevel value_cb = pcic_getcb(pcic, CB_STATUS_EVENT); 22592305Sstevel 22602305Sstevel value = pcic_change(pcic, i); 22612305Sstevel 22622305Sstevel if ((value != 0) || (value_cb != 0)) { 22632305Sstevel int x = pcic->pc_cb_arg; 22642305Sstevel 22652305Sstevel ret = DDI_INTR_CLAIMED; 22662305Sstevel 22672305Sstevel #if defined(PCIC_DEBUG) 22682305Sstevel pcic_err(pcic->dip, 0x9, 22692305Sstevel "card_type = %d, value_cb = 0x%x\n", 22702305Sstevel card_type, 22712305Sstevel value_cb ? value_cb : 2272*7656SSherry.Moore@Sun.COM pcic_getcb(pcic, CB_STATUS_EVENT)); 22732305Sstevel if (pcic_debug) 22742305Sstevel cmn_err(CE_CONT, 2275*7656SSherry.Moore@Sun.COM "\tchange on socket %d (%x)\n", i, 2276*7656SSherry.Moore@Sun.COM value); 22772305Sstevel #endif 22782305Sstevel /* find out what happened */ 22792305Sstevel status = pcic_getb(pcic, i, PCIC_INTERFACE_STATUS); 22802305Sstevel 22812305Sstevel /* acknowledge the interrupt */ 22822305Sstevel if (value_cb) 22832305Sstevel pcic_putcb(pcic, CB_STATUS_EVENT, value_cb); 22842305Sstevel 22852305Sstevel if (value) 22862305Sstevel pcic_putb(pcic, i, PCIC_CARD_STATUS_CHANGE, 22872305Sstevel value); 22882305Sstevel 22892305Sstevel if (pcic->pc_callback == NULL) { 22902305Sstevel /* if not callback handler, nothing to do */ 22912305Sstevel continue; 22922305Sstevel } 22932305Sstevel 22942305Sstevel /* Card Detect */ 22952305Sstevel if (value & PCIC_CD_DETECT || 22962305Sstevel value_cb & CB_PS_CCDMASK) { 22972305Sstevel uint8_t irq; 22982305Sstevel #if defined(PCIC_DEBUG) 22992305Sstevel if (pcic_debug) 23002305Sstevel cmn_err(CE_CONT, 2301*7656SSherry.Moore@Sun.COM "\tcd_detect: status=%x," 2302*7656SSherry.Moore@Sun.COM " flags=%x\n", 2303*7656SSherry.Moore@Sun.COM status, sockp->pcs_flags); 23042305Sstevel #else 23052305Sstevel #ifdef lint 23062305Sstevel if (status == 0) 2307*7656SSherry.Moore@Sun.COM status++; 23082305Sstevel #endif 23092305Sstevel #endif 23102305Sstevel /* 23112305Sstevel * Turn off all interrupts for this socket here. 23122305Sstevel */ 23132305Sstevel irq = pcic_getb(pcic, sockp->pcs_socket, 23142305Sstevel PCIC_MANAGEMENT_INT); 23152305Sstevel irq &= ~PCIC_CHANGE_MASK; 23162305Sstevel pcic_putb(pcic, sockp->pcs_socket, 23172305Sstevel PCIC_MANAGEMENT_INT, irq); 23182305Sstevel 23192305Sstevel pcic_putcb(pcic, CB_STATUS_MASK, 0x0); 23202305Sstevel 23212451Srw148561 /* 23222451Srw148561 * Put the socket in debouncing state so that 23232451Srw148561 * the leaf driver won't receive interrupts. 23242451Srw148561 * Crucial for handling surprise-removal. 23252451Srw148561 */ 23262451Srw148561 sockp->pcs_flags |= PCS_DEBOUNCING; 23272451Srw148561 23282305Sstevel if (!sockp->pcs_cd_softint_flg) { 23292305Sstevel sockp->pcs_cd_softint_flg = 1; 23302305Sstevel (void) ddi_intr_trigger_softint( 23312305Sstevel sockp->pcs_cd_softint_hdl, NULL); 23322305Sstevel } 23332305Sstevel 23342305Sstevel io_ints &= ~(1 << i); 23352305Sstevel } /* PCIC_CD_DETECT */ 23362305Sstevel 23372305Sstevel /* Ready/Change Detect */ 23382305Sstevel sockp->pcs_state ^= SBM_RDYBSY; 23392305Sstevel if (card_type == IF_MEMORY && value & PCIC_RD_DETECT) { 23402305Sstevel sockp->pcs_flags |= PCS_READY; 23412305Sstevel PC_CALLBACK(pcic->dip, x, PCE_CARD_READY, i); 23422305Sstevel } 23432305Sstevel 23442305Sstevel /* Battery Warn Detect */ 23452305Sstevel if (card_type == IF_MEMORY && 23462305Sstevel value & PCIC_BW_DETECT && 23472305Sstevel !(sockp->pcs_state & SBM_BVD2)) { 23482305Sstevel sockp->pcs_state |= SBM_BVD2; 23492305Sstevel PC_CALLBACK(pcic->dip, x, 2350*7656SSherry.Moore@Sun.COM PCE_CARD_BATTERY_WARN, i); 23512305Sstevel } 23522305Sstevel 23532305Sstevel /* Battery Dead Detect */ 23542305Sstevel if (value & PCIC_BD_DETECT) { 23552305Sstevel /* 23562305Sstevel * need to work out event if RI not enabled 23572305Sstevel * and card_type == IF_IO 23582305Sstevel */ 23592305Sstevel if (card_type == IF_MEMORY && 2360*7656SSherry.Moore@Sun.COM !(sockp->pcs_state & SBM_BVD1)) { 23612305Sstevel sockp->pcs_state |= SBM_BVD1; 23622305Sstevel PC_CALLBACK(pcic->dip, x, 2363*7656SSherry.Moore@Sun.COM PCE_CARD_BATTERY_DEAD, 2364*7656SSherry.Moore@Sun.COM i); 23652305Sstevel } else { 23662305Sstevel /* 23672305Sstevel * information in pin replacement 23682305Sstevel * register if one is available 23692305Sstevel */ 23702305Sstevel PC_CALLBACK(pcic->dip, x, 2371*7656SSherry.Moore@Sun.COM PCE_CARD_STATUS_CHANGE, 2372*7656SSherry.Moore@Sun.COM i); 23732305Sstevel } /* IF_MEMORY */ 23742305Sstevel } /* PCIC_BD_DETECT */ 23752305Sstevel } /* if pcic_change */ 23762305Sstevel /* 23772305Sstevel * for any controllers that we can detect whether a socket 23782305Sstevel * had an interrupt for the PC Card, we should sort that out 23792305Sstevel * here. 23802305Sstevel */ 23812305Sstevel } /* for pc_numsockets */ 23822305Sstevel 23832305Sstevel /* 23842305Sstevel * If we're on a PCI bus, we may need to cycle through each IO 23852305Sstevel * interrupt handler that is registered since they all 23862305Sstevel * share the same interrupt line. 23872305Sstevel */ 23882305Sstevel 23892305Sstevel 23902305Sstevel #if defined(PCIC_DEBUG) 23912305Sstevel pcic_err(pcic->dip, 0xf, 23922305Sstevel "pcic_intr: pc_intr_mode=%d pc_type=%x io_ints=0x%x\n", 23932305Sstevel pcic->pc_intr_mode, pcic->pc_type, io_ints); 23942305Sstevel #endif 23952305Sstevel 23962451Srw148561 if (io_ints) { 23972451Srw148561 if (pcic_do_io_intr(pcic, io_ints) == DDI_INTR_CLAIMED) 23982305Sstevel ret = DDI_INTR_CLAIMED; 23992305Sstevel } 24002305Sstevel 24012305Sstevel mutex_exit(&pcic->intr_lock); 24022305Sstevel 24032305Sstevel #if defined(PCIC_DEBUG) 24042305Sstevel pcic_err(pcic->dip, 0xf, 24052305Sstevel "pcic_intr: ret=%d value=%d DDI_INTR_CLAIMED=%d\n", 24062305Sstevel ret, value, DDI_INTR_CLAIMED); 24072305Sstevel #endif 24082305Sstevel 24092305Sstevel return (ret); 24102305Sstevel } 24112305Sstevel 24122305Sstevel /* 24132305Sstevel * pcic_change() 24142305Sstevel * check to see if this socket had a change in state 24152305Sstevel * by checking the status change register 24162305Sstevel */ 24172305Sstevel static int 24182305Sstevel pcic_change(pcicdev_t *pcic, int socket) 24192305Sstevel { 24202305Sstevel return (pcic_getb(pcic, socket, PCIC_CARD_STATUS_CHANGE)); 24212305Sstevel } 24222305Sstevel 24232305Sstevel /* 24242305Sstevel * pcic_do_io_intr - calls client interrupt handlers 24252305Sstevel */ 24262305Sstevel static int 24272305Sstevel pcic_do_io_intr(pcicdev_t *pcic, uint32_t sockets) 24282305Sstevel { 24292305Sstevel inthandler_t *tmp; 24302305Sstevel int ret = DDI_INTR_UNCLAIMED; 24312305Sstevel 24322305Sstevel #if defined(PCIC_DEBUG) 24332305Sstevel pcic_err(pcic->dip, 0xf, 2434*7656SSherry.Moore@Sun.COM "pcic_do_io_intr: pcic=%p sockets=%d irq_top=%p\n", 2435*7656SSherry.Moore@Sun.COM (void *)pcic, (int)sockets, (void *)pcic->irq_top); 24362305Sstevel #endif 24372305Sstevel 24382305Sstevel if (pcic->irq_top != NULL) { 2439*7656SSherry.Moore@Sun.COM tmp = pcic->irq_current; 2440*7656SSherry.Moore@Sun.COM 2441*7656SSherry.Moore@Sun.COM do { 24422305Sstevel int cur = pcic->irq_current->socket; 24432305Sstevel pcic_socket_t *sockp = 2444*7656SSherry.Moore@Sun.COM &pcic->pc_sockets[cur]; 24452305Sstevel 24462305Sstevel #if defined(PCIC_DEBUG) 24472305Sstevel pcic_err(pcic->dip, 0xf, 24482305Sstevel "\t pcs_flags=0x%x PCS_CARD_PRESENT=0x%x\n", 24492305Sstevel sockp->pcs_flags, PCS_CARD_PRESENT); 24502305Sstevel pcic_err(pcic->dip, 0xf, 24512305Sstevel "\t sockets=%d cur=%d intr=%p arg1=%p " 24522305Sstevel "arg2=%p\n", 24532305Sstevel sockets, cur, (void *)pcic->irq_current->intr, 24542305Sstevel pcic->irq_current->arg1, 24552305Sstevel pcic->irq_current->arg2); 24562305Sstevel #endif 24572451Srw148561 if ((sockp->pcs_flags & PCS_CARD_PRESENT) && 24582451Srw148561 !(sockp->pcs_flags & PCS_DEBOUNCING) && 24592451Srw148561 (sockets & (1 << cur))) { 24602305Sstevel 24612305Sstevel if ((*pcic->irq_current->intr)(pcic->irq_current->arg1, 24622305Sstevel pcic->irq_current->arg2) == DDI_INTR_CLAIMED) 24632305Sstevel ret = DDI_INTR_CLAIMED; 24642305Sstevel 24652305Sstevel #if defined(PCIC_DEBUG) 24662305Sstevel pcic_err(pcic->dip, 0xf, 24672305Sstevel "\t ret=%d DDI_INTR_CLAIMED=%d\n", 24682305Sstevel ret, DDI_INTR_CLAIMED); 24692305Sstevel #endif 24702305Sstevel } 24712305Sstevel 24722305Sstevel 24732305Sstevel if ((pcic->irq_current = pcic->irq_current->next) == NULL) 24742305Sstevel pcic->irq_current = pcic->irq_top; 24752305Sstevel 2476*7656SSherry.Moore@Sun.COM } while (pcic->irq_current != tmp); 2477*7656SSherry.Moore@Sun.COM 2478*7656SSherry.Moore@Sun.COM if ((pcic->irq_current = pcic->irq_current->next) == NULL) 24792305Sstevel pcic->irq_current = pcic->irq_top; 24802305Sstevel 24812305Sstevel } else { 24822305Sstevel ret = DDI_INTR_UNCLAIMED; 24832305Sstevel } 24842305Sstevel 24852305Sstevel #if defined(PCIC_DEBUG) 24862305Sstevel pcic_err(pcic->dip, 0xf, 2487*7656SSherry.Moore@Sun.COM "pcic_do_io_intr: exit ret=%d DDI_INTR_CLAIMED=%d\n", 2488*7656SSherry.Moore@Sun.COM ret, DDI_INTR_CLAIMED); 24892305Sstevel #endif 24902305Sstevel 24912305Sstevel return (ret); 24922305Sstevel 24932305Sstevel } 24942305Sstevel 24952305Sstevel /* 24962305Sstevel * pcic_inquire_adapter() 24972305Sstevel * SocketServices InquireAdapter function 24982305Sstevel * get characteristics of the physical adapter 24992305Sstevel */ 25002305Sstevel /*ARGSUSED*/ 25012305Sstevel static int 25022305Sstevel pcic_inquire_adapter(dev_info_t *dip, inquire_adapter_t *config) 25032305Sstevel { 25042305Sstevel anp_t *anp = ddi_get_driver_private(dip); 25052305Sstevel pcicdev_t *pcic = anp->an_private; 25062305Sstevel 25072305Sstevel config->NumSockets = pcic->pc_numsockets; 25082305Sstevel config->NumWindows = pcic->pc_numsockets * PCIC_NUMWINSOCK; 25092305Sstevel config->NumEDCs = 0; 25102305Sstevel config->AdpCaps = 0; 25112305Sstevel config->ActiveHigh = 0; 25122305Sstevel config->ActiveLow = PCIC_AVAIL_IRQS; 25132305Sstevel config->NumPower = pcic->pc_numpower; 25142305Sstevel config->power_entry = pcic->pc_power; /* until we resolve this */ 25152305Sstevel #if defined(PCIC_DEBUG) 25162305Sstevel if (pcic_debug) { 25172305Sstevel cmn_err(CE_CONT, "pcic_inquire_adapter:\n"); 25182305Sstevel cmn_err(CE_CONT, "\tNumSockets=%d\n", config->NumSockets); 25192305Sstevel cmn_err(CE_CONT, "\tNumWindows=%d\n", config->NumWindows); 25202305Sstevel } 25212305Sstevel #endif 25222305Sstevel config->ResourceFlags = 0; 25232305Sstevel switch (pcic->pc_intr_mode) { 25242305Sstevel case PCIC_INTR_MODE_PCI_1: 25252305Sstevel config->ResourceFlags |= RES_OWN_IRQ | RES_IRQ_NEXUS | 2526*7656SSherry.Moore@Sun.COM RES_IRQ_SHAREABLE; 25272305Sstevel break; 25282305Sstevel } 25292305Sstevel return (SUCCESS); 25302305Sstevel } 25312305Sstevel 25322305Sstevel /* 25332305Sstevel * pcic_callback() 25342305Sstevel * The PCMCIA nexus calls us via this function 25352305Sstevel * in order to set the callback function we are 25362305Sstevel * to call the nexus with 25372305Sstevel */ 25382305Sstevel /*ARGSUSED*/ 25392305Sstevel static int 25402305Sstevel pcic_callback(dev_info_t *dip, int (*handler)(), int arg) 25412305Sstevel { 25422305Sstevel anp_t *anp = ddi_get_driver_private(dip); 25432305Sstevel pcicdev_t *pcic = anp->an_private; 25442305Sstevel 25452305Sstevel if (handler != NULL) { 25462305Sstevel pcic->pc_callback = handler; 25472305Sstevel pcic->pc_cb_arg = arg; 25482305Sstevel pcic->pc_flags |= PCF_CALLBACK; 25492305Sstevel } else { 25502305Sstevel pcic->pc_callback = NULL; 25512305Sstevel pcic->pc_cb_arg = 0; 25522305Sstevel pcic->pc_flags &= ~PCF_CALLBACK; 25532305Sstevel } 25542305Sstevel /* 25552305Sstevel * we're now registered with the nexus 25562305Sstevel * it is acceptable to do callbacks at this point. 25572305Sstevel * don't call back from here though since it could block 25582305Sstevel */ 25592305Sstevel return (PC_SUCCESS); 25602305Sstevel } 25612305Sstevel 25622305Sstevel /* 25632305Sstevel * pcic_calc_speed (pcicdev_t *pcic, uint32_t speed) 25642305Sstevel * calculate the speed bits from the specified memory speed 25652305Sstevel * there may be more to do here 25662305Sstevel */ 25672305Sstevel 25682305Sstevel static int 25692305Sstevel pcic_calc_speed(pcicdev_t *pcic, uint32_t speed) 25702305Sstevel { 25712305Sstevel uint32_t wspeed = 1; /* assume 1 wait state when unknown */ 25722305Sstevel uint32_t bspeed = PCIC_ISA_DEF_SYSCLK; 25732305Sstevel 25742305Sstevel switch (pcic->pc_type) { 2575*7656SSherry.Moore@Sun.COM case PCIC_I82365SL: 2576*7656SSherry.Moore@Sun.COM case PCIC_VADEM: 2577*7656SSherry.Moore@Sun.COM case PCIC_VADEM_VG469: 2578*7656SSherry.Moore@Sun.COM default: 25792305Sstevel /* Intel chip wants it in waitstates */ 25802305Sstevel wspeed = mhztons(PCIC_ISA_DEF_SYSCLK) * 3; 25812305Sstevel if (speed <= wspeed) 25822305Sstevel wspeed = 0; 25832305Sstevel else if (speed <= (wspeed += mhztons(bspeed))) 25842305Sstevel wspeed = 1; 25852305Sstevel else if (speed <= (wspeed += mhztons(bspeed))) 25862305Sstevel wspeed = 2; 25872305Sstevel else 25882305Sstevel wspeed = 3; 25892305Sstevel wspeed <<= 6; /* put in right bit positions */ 25902305Sstevel break; 25912305Sstevel 2592*7656SSherry.Moore@Sun.COM case PCIC_INTEL_i82092: 25932305Sstevel wspeed = SYSMEM_82092_80NS; 25942305Sstevel if (speed > 80) 2595*7656SSherry.Moore@Sun.COM wspeed = SYSMEM_82092_100NS; 25962305Sstevel if (speed > 100) 2597*7656SSherry.Moore@Sun.COM wspeed = SYSMEM_82092_150NS; 25982305Sstevel if (speed > 150) 2599*7656SSherry.Moore@Sun.COM wspeed = SYSMEM_82092_200NS; 26002305Sstevel if (speed > 200) 2601*7656SSherry.Moore@Sun.COM wspeed = SYSMEM_82092_250NS; 26022305Sstevel if (speed > 250) 2603*7656SSherry.Moore@Sun.COM wspeed = SYSMEM_82092_600NS; 26042305Sstevel wspeed <<= 5; /* put in right bit positions */ 26052305Sstevel break; 26062305Sstevel 26072305Sstevel } /* switch */ 26082305Sstevel 26092305Sstevel return (wspeed); 26102305Sstevel } 26112305Sstevel 26122305Sstevel /* 26132305Sstevel * These values are taken from the PC Card Standard Electrical Specification. 26142305Sstevel * Generally the larger value is taken if 2 are possible. 26152305Sstevel */ 26162305Sstevel static struct pcic_card_times { 26172305Sstevel uint16_t cycle; /* Speed as found in the atribute space of he card. */ 26182305Sstevel uint16_t setup; /* Corresponding address setup time. */ 26192305Sstevel uint16_t width; /* Corresponding width, OE or WE. */ 26202305Sstevel uint16_t hold; /* Corresponding data or address hold time. */ 26212305Sstevel } pcic_card_times[] = { 26222305Sstevel 26232305Sstevel /* 26242305Sstevel * Note: The rounded up times for 250, 200 & 150 have been increased 26252305Sstevel * due to problems with the 3-Com ethernet cards (pcelx) on UBIIi. 26262305Sstevel * See BugID 00663. 26272305Sstevel */ 26282305Sstevel 26292305Sstevel /* 26302305Sstevel * Rounded up times Original times from 26312305Sstevel * that add up to the the PCMCIA Spec. 26322305Sstevel * cycle time. 26332305Sstevel */ 26342305Sstevel {600, 180, 370, 140}, /* 100, 300, 70 */ 26352305Sstevel {400, 120, 300, 90}, /* Made this one up */ 26362305Sstevel {250, 100, 190, 70}, /* 30, 150, 30 */ 26372305Sstevel {200, 80, 170, 70}, /* 20, 120, 30 */ 26382305Sstevel {150, 50, 110, 40}, /* 20, 80, 20 */ 26392305Sstevel {100, 40, 80, 40}, /* 10, 60, 15 */ 26402305Sstevel {0, 10, 60, 15} /* 10, 60, 15 */ 26412305Sstevel }; 26422305Sstevel 26432305Sstevel /* 26442305Sstevel * pcic_set_cdtimers 26452305Sstevel * This is specific to several Cirrus Logic chips 26462305Sstevel */ 26472305Sstevel static void 26482305Sstevel pcic_set_cdtimers(pcicdev_t *pcic, int socket, uint32_t speed, int tset) 26492305Sstevel { 26502305Sstevel int cmd, set, rec, offset, clk_pulse; 26512305Sstevel struct pcic_card_times *ctp; 26522305Sstevel 26532305Sstevel if ((tset == IOMEM_CLTIMER_SET_1) || (tset == SYSMEM_CLTIMER_SET_1)) 26542305Sstevel offset = 3; 26552305Sstevel else 26562305Sstevel offset = 0; 26572305Sstevel 26582305Sstevel clk_pulse = mhztons(pcic->bus_speed); 2659*7656SSherry.Moore@Sun.COM for (ctp = pcic_card_times; speed < ctp->cycle; ctp++) 2660*7656SSherry.Moore@Sun.COM ; 26612305Sstevel 26622305Sstevel /* 26632305Sstevel * Add (clk_pulse/2) and an extra 1 to account for rounding errors. 26642305Sstevel */ 26652305Sstevel set = ((ctp->setup + 10 + 1 + (clk_pulse/2))/clk_pulse) - 1; 26662305Sstevel if (set < 0) 26672305Sstevel set = 0; 26682305Sstevel 26692305Sstevel cmd = ((ctp->width + 10 + 1 + (clk_pulse/2))/clk_pulse) - 1; 26702305Sstevel if (cmd < 0) 26712305Sstevel cmd = 0; 26722305Sstevel 26732305Sstevel rec = ((ctp->hold + 10 + 1 + (clk_pulse/2))/clk_pulse) - 2; 26742305Sstevel if (rec < 0) 26752305Sstevel rec = 0; 26762305Sstevel 26772305Sstevel #if defined(PCIC_DEBUG) 26782305Sstevel pcic_err(pcic->dip, 8, "pcic_set_cdtimers(%d, Timer Set %d)\n" 26792305Sstevel "ct=%d, cp=%d, cmd=0x%x, setup=0x%x, rec=0x%x\n", 26802305Sstevel (unsigned)speed, offset == 3 ? 1 : 0, 26812305Sstevel ctp->cycle, clk_pulse, cmd, set, rec); 26822305Sstevel #endif 26832305Sstevel 26842305Sstevel pcic_putb(pcic, socket, PCIC_TIME_COMMAND_0 + offset, cmd); 26852305Sstevel pcic_putb(pcic, socket, PCIC_TIME_SETUP_0 + offset, set); 26862305Sstevel pcic_putb(pcic, socket, PCIC_TIME_RECOVER_0 + offset, rec); 26872305Sstevel } 26882305Sstevel 26892305Sstevel /* 26902305Sstevel * pcic_set_window 26912305Sstevel * essentially the same as the Socket Services specification 26922305Sstevel * We use socket and not adapter since they are identifiable 26932305Sstevel * but the rest is the same 26942305Sstevel * 26952305Sstevel * dip pcic driver's device information 26962305Sstevel * window parameters for the request 26972305Sstevel */ 26982305Sstevel static int 26992305Sstevel pcic_set_window(dev_info_t *dip, set_window_t *window) 27002305Sstevel { 27012305Sstevel anp_t *anp = ddi_get_driver_private(dip); 27022305Sstevel pcicdev_t *pcic = anp->an_private; 27032305Sstevel int select; 27042305Sstevel int socket, pages, which, ret; 27052305Sstevel pcic_socket_t *sockp = &pcic->pc_sockets[window->socket]; 27062305Sstevel ra_return_t res; 27072305Sstevel ndi_ra_request_t req; 27082305Sstevel uint32_t base = window->base; 27092305Sstevel 27102305Sstevel #if defined(PCIC_DEBUG) 27112305Sstevel if (pcic_debug) { 27122305Sstevel cmn_err(CE_CONT, "pcic_set_window: entered\n"); 27132305Sstevel cmn_err(CE_CONT, 2714*7656SSherry.Moore@Sun.COM "\twindow=%d, socket=%d, WindowSize=%d, speed=%d\n", 2715*7656SSherry.Moore@Sun.COM window->window, window->socket, window->WindowSize, 2716*7656SSherry.Moore@Sun.COM window->speed); 27172305Sstevel cmn_err(CE_CONT, 2718*7656SSherry.Moore@Sun.COM "\tbase=%x, state=%x\n", (unsigned)window->base, 2719*7656SSherry.Moore@Sun.COM (unsigned)window->state); 27202305Sstevel } 27212305Sstevel #endif 27222305Sstevel 27232305Sstevel /* 27242305Sstevel * do some basic sanity checking on what we support 27252305Sstevel * we don't do paged mode 27262305Sstevel */ 27272305Sstevel if (window->state & WS_PAGED) { 27282305Sstevel cmn_err(CE_WARN, "pcic_set_window: BAD_ATTRIBUTE\n"); 27292305Sstevel return (BAD_ATTRIBUTE); 27302305Sstevel } 27312305Sstevel 27322305Sstevel /* 27332305Sstevel * we don't care about previous mappings. 27342305Sstevel * Card Services will deal with that so don't 27352305Sstevel * even check 27362305Sstevel */ 27372305Sstevel 27382305Sstevel socket = window->socket; 27392305Sstevel 27402305Sstevel if (!(window->state & WS_IO)) { 27412305Sstevel int win, tmp; 27422305Sstevel pcs_memwin_t *memp; 27432305Sstevel #if defined(PCIC_DEBUG) 27442305Sstevel if (pcic_debug) 27452305Sstevel cmn_err(CE_CONT, "\twindow type is memory\n"); 27462305Sstevel #endif 27472305Sstevel /* this is memory window mapping */ 27482305Sstevel win = window->window % PCIC_NUMWINSOCK; 27492305Sstevel tmp = window->window / PCIC_NUMWINSOCK; 27502305Sstevel 27512305Sstevel /* only windows 2-6 can do memory mapping */ 27522305Sstevel if (tmp != window->socket || win < PCIC_IOWINDOWS) { 27532305Sstevel cmn_err(CE_CONT, 2754*7656SSherry.Moore@Sun.COM "\tattempt to map to non-mem window\n"); 27552305Sstevel return (BAD_WINDOW); 27562305Sstevel } 27572305Sstevel 27582305Sstevel if (window->WindowSize == 0) 27592305Sstevel window->WindowSize = MEM_MIN; 27602305Sstevel else if ((window->WindowSize & (PCIC_PAGE-1)) != 0) { 27612305Sstevel cmn_err(CE_WARN, "pcic_set_window: BAD_SIZE\n"); 27622305Sstevel return (BAD_SIZE); 27632305Sstevel } 27642305Sstevel 27652305Sstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 27662305Sstevel 27672305Sstevel memp = &sockp->pcs_windows[win].mem; 27682305Sstevel memp->pcw_speed = window->speed; 27692305Sstevel 27702305Sstevel win -= PCIC_IOWINDOWS; /* put in right range */ 27712305Sstevel 27722305Sstevel if (window->WindowSize != memp->pcw_len) 27732305Sstevel which = memp->pcw_len; 27742305Sstevel else 27752305Sstevel which = 0; 27762305Sstevel 27772305Sstevel if (window->state & WS_ENABLED) { 27782305Sstevel uint32_t wspeed; 27792305Sstevel #if defined(PCIC_DEBUG) 27802305Sstevel if (pcic_debug) { 27812305Sstevel cmn_err(CE_CONT, 2782*7656SSherry.Moore@Sun.COM "\tbase=%x, win=%d\n", (unsigned)base, 2783*7656SSherry.Moore@Sun.COM win); 27842305Sstevel if (which) 27852305Sstevel cmn_err(CE_CONT, 2786*7656SSherry.Moore@Sun.COM "\tneed to remap window\n"); 27872305Sstevel } 27882305Sstevel #endif 27892305Sstevel 27902305Sstevel if (which && (memp->pcw_status & PCW_MAPPED)) { 27912305Sstevel ddi_regs_map_free(&memp->pcw_handle); 27922305Sstevel res.ra_addr_lo = memp->pcw_base; 27932305Sstevel res.ra_len = memp->pcw_len; 27943664Srw148561 (void) pcmcia_free_mem(memp->res_dip, &res); 27952305Sstevel memp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED); 27962305Sstevel memp->pcw_hostmem = NULL; 27972305Sstevel memp->pcw_base = NULL; 27982305Sstevel memp->pcw_len = 0; 27992305Sstevel } 28002305Sstevel 28012305Sstevel which = window->WindowSize >> PAGE_SHIFT; 28022305Sstevel 28032305Sstevel if (!(memp->pcw_status & PCW_MAPPED)) { 28042305Sstevel ret = 0; 28052305Sstevel 28062305Sstevel memp->pcw_base = base; 28072305Sstevel bzero(&req, sizeof (req)); 28082305Sstevel req.ra_len = which << PAGE_SHIFT; 28092305Sstevel req.ra_addr = (uint64_t)memp->pcw_base; 28102305Sstevel req.ra_boundbase = pcic->pc_base; 28112305Sstevel req.ra_boundlen = pcic->pc_bound; 28122305Sstevel req.ra_flags = (memp->pcw_base ? 2813*7656SSherry.Moore@Sun.COM NDI_RA_ALLOC_SPECIFIED : 0) | 2814*7656SSherry.Moore@Sun.COM NDI_RA_ALLOC_BOUNDED; 28152305Sstevel req.ra_align_mask = 2816*7656SSherry.Moore@Sun.COM (PAGESIZE - 1) | (PCIC_PAGE - 1); 28172305Sstevel #if defined(PCIC_DEBUG) 2818*7656SSherry.Moore@Sun.COM pcic_err(dip, 8, 28192305Sstevel "\tlen 0x%"PRIx64 28202305Sstevel "addr 0x%"PRIx64"bbase 0x%"PRIx64 28212305Sstevel " blen 0x%"PRIx64" flags 0x%x" 28222305Sstevel " algn 0x%"PRIx64"\n", 28232305Sstevel req.ra_len, req.ra_addr, 28242305Sstevel req.ra_boundbase, 28252305Sstevel req.ra_boundlen, req.ra_flags, 28262305Sstevel req.ra_align_mask); 28272305Sstevel #endif 28282305Sstevel 28293664Srw148561 ret = pcmcia_alloc_mem(dip, &req, &res, 2830*7656SSherry.Moore@Sun.COM &memp->res_dip); 28312305Sstevel if (ret == DDI_FAILURE) { 28322305Sstevel mutex_exit(&pcic->pc_lock); 28332305Sstevel cmn_err(CE_WARN, 28342305Sstevel "\tpcmcia_alloc_mem() failed\n"); 28352305Sstevel return (BAD_SIZE); 28362305Sstevel } 28372305Sstevel memp->pcw_base = res.ra_addr_lo; 28382305Sstevel base = memp->pcw_base; 28392305Sstevel 28402305Sstevel #if defined(PCIC_DEBUG) 28412305Sstevel if (pcic_debug) 28422305Sstevel cmn_err(CE_CONT, 2843*7656SSherry.Moore@Sun.COM "\tsetwindow: new base=%x\n", 2844*7656SSherry.Moore@Sun.COM (unsigned)memp->pcw_base); 28452305Sstevel #endif 28462305Sstevel memp->pcw_len = window->WindowSize; 28472305Sstevel 28482305Sstevel which = pcmcia_map_reg(pcic->dip, 2849*7656SSherry.Moore@Sun.COM window->child, 2850*7656SSherry.Moore@Sun.COM &res, 2851*7656SSherry.Moore@Sun.COM (uint32_t)(window->state & 2852*7656SSherry.Moore@Sun.COM 0xffff) | 2853*7656SSherry.Moore@Sun.COM (window->socket << 16), 2854*7656SSherry.Moore@Sun.COM (caddr_t *)&memp->pcw_hostmem, 2855*7656SSherry.Moore@Sun.COM &memp->pcw_handle, 2856*7656SSherry.Moore@Sun.COM &window->attr, NULL); 28572305Sstevel 28582305Sstevel if (which != DDI_SUCCESS) { 28592305Sstevel 28602305Sstevel cmn_err(CE_WARN, "\tpcmcia_map_reg() " 2861*7656SSherry.Moore@Sun.COM "failed\n"); 2862*7656SSherry.Moore@Sun.COM 2863*7656SSherry.Moore@Sun.COM res.ra_addr_lo = memp->pcw_base; 2864*7656SSherry.Moore@Sun.COM res.ra_len = memp->pcw_len; 2865*7656SSherry.Moore@Sun.COM (void) pcmcia_free_mem(memp->res_dip, 2866*7656SSherry.Moore@Sun.COM &res); 2867*7656SSherry.Moore@Sun.COM 2868*7656SSherry.Moore@Sun.COM mutex_exit(&pcic->pc_lock); 2869*7656SSherry.Moore@Sun.COM 2870*7656SSherry.Moore@Sun.COM return (BAD_WINDOW); 28712305Sstevel } 28722305Sstevel memp->pcw_status |= PCW_MAPPED; 28732305Sstevel #if defined(PCIC_DEBUG) 28742305Sstevel if (pcic_debug) 28752305Sstevel cmn_err(CE_CONT, 2876*7656SSherry.Moore@Sun.COM "\tmap=%x, hostmem=%p\n", 2877*7656SSherry.Moore@Sun.COM which, 2878*7656SSherry.Moore@Sun.COM (void *)memp->pcw_hostmem); 28792305Sstevel #endif 28802305Sstevel } else { 28812305Sstevel base = memp->pcw_base; 28822305Sstevel } 28832305Sstevel 28842305Sstevel /* report the handle back to caller */ 28852305Sstevel window->handle = memp->pcw_handle; 28862305Sstevel 28872305Sstevel #if defined(PCIC_DEBUG) 28882305Sstevel if (pcic_debug) { 28892305Sstevel cmn_err(CE_CONT, 2890*7656SSherry.Moore@Sun.COM "\twindow mapped to %x@%x len=%d\n", 2891*7656SSherry.Moore@Sun.COM (unsigned)window->base, 2892*7656SSherry.Moore@Sun.COM (unsigned)memp->pcw_base, 2893*7656SSherry.Moore@Sun.COM memp->pcw_len); 28942305Sstevel } 28952305Sstevel #endif 28962305Sstevel 28972305Sstevel /* find the register set offset */ 28982305Sstevel select = win * PCIC_MEM_1_OFFSET; 28992305Sstevel #if defined(PCIC_DEBUG) 29002305Sstevel if (pcic_debug) 29012305Sstevel cmn_err(CE_CONT, "\tselect=%x\n", select); 29022305Sstevel #endif 29032305Sstevel 29042305Sstevel /* 29052305Sstevel * at this point, the register window indicator has 29062305Sstevel * been converted to be an offset from the first 29072305Sstevel * set of registers that are used for programming 29082305Sstevel * the window mapping and the offset used to select 29092305Sstevel * the correct set of registers to access the 29102305Sstevel * specified socket. This allows basing everything 29112305Sstevel * off the _0 window 29122305Sstevel */ 29132305Sstevel 29142305Sstevel /* map the physical page base address */ 29152305Sstevel which = (window->state & WS_16BIT) ? SYSMEM_DATA_16 : 0; 29162305Sstevel which |= (window->speed <= MEM_SPEED_MIN) ? 2917*7656SSherry.Moore@Sun.COM SYSMEM_ZERO_WAIT : 0; 29182305Sstevel 29192305Sstevel /* need to select register set */ 29202305Sstevel select = PCIC_MEM_1_OFFSET * win; 29212305Sstevel 29222305Sstevel pcic_putb(pcic, socket, 2923*7656SSherry.Moore@Sun.COM PCIC_SYSMEM_0_STARTLOW + select, 2924*7656SSherry.Moore@Sun.COM SYSMEM_LOW(base)); 29252305Sstevel pcic_putb(pcic, socket, 2926*7656SSherry.Moore@Sun.COM PCIC_SYSMEM_0_STARTHI + select, 2927*7656SSherry.Moore@Sun.COM SYSMEM_HIGH(base) | which); 29282305Sstevel 29292305Sstevel /* 29302305Sstevel * Some adapters can decode window addresses greater 29312305Sstevel * than 16-bits worth, so handle them here. 29322305Sstevel */ 29332305Sstevel switch (pcic->pc_type) { 29342305Sstevel case PCIC_INTEL_i82092: 29352305Sstevel pcic_putb(pcic, socket, 2936*7656SSherry.Moore@Sun.COM PCIC_82092_CPAGE, 2937*7656SSherry.Moore@Sun.COM SYSMEM_EXT(base)); 29382305Sstevel break; 29392305Sstevel case PCIC_CL_PD6729: 29402305Sstevel case PCIC_CL_PD6730: 29412305Sstevel clext_reg_write(pcic, socket, 2942*7656SSherry.Moore@Sun.COM PCIC_CLEXT_MMAP0_UA + win, 2943*7656SSherry.Moore@Sun.COM SYSMEM_EXT(base)); 29442305Sstevel break; 29452305Sstevel case PCIC_TI_PCI1130: 29462305Sstevel /* 29472305Sstevel * Note that the TI chip has one upper byte 29482305Sstevel * per socket so all windows get bound to a 29492305Sstevel * 16MB segment. This must be detected and 29502305Sstevel * handled appropriately. We can detect that 29512305Sstevel * it is done by seeing if the pc_base has 29522305Sstevel * changed and changing when the register 29532305Sstevel * is first set. This will force the bounds 29542305Sstevel * to be correct. 29552305Sstevel */ 29562305Sstevel if (pcic->pc_bound == 0xffffffff) { 29572305Sstevel pcic_putb(pcic, socket, 2958*7656SSherry.Moore@Sun.COM PCIC_TI_WINDOW_PAGE_PCI, 2959*7656SSherry.Moore@Sun.COM SYSMEM_EXT(base)); 29602305Sstevel pcic->pc_base = SYSMEM_EXT(base) << 24; 29612305Sstevel pcic->pc_bound = 0x1000000; 29622305Sstevel } 29632305Sstevel break; 29642305Sstevel case PCIC_TI_PCI1031: 29652305Sstevel case PCIC_TI_PCI1131: 29662305Sstevel case PCIC_TI_PCI1250: 29672305Sstevel case PCIC_TI_PCI1225: 29682305Sstevel case PCIC_TI_PCI1221: 29692305Sstevel case PCIC_SMC_34C90: 29702305Sstevel case PCIC_CL_PD6832: 29712305Sstevel case PCIC_RICOH_RL5C466: 29722305Sstevel case PCIC_TI_PCI1410: 29732305Sstevel case PCIC_ENE_1410: 29742305Sstevel case PCIC_TI_PCI1510: 29752305Sstevel case PCIC_TI_PCI1520: 29762305Sstevel case PCIC_O2_OZ6912: 29772305Sstevel case PCIC_TI_PCI1420: 29782305Sstevel case PCIC_ENE_1420: 29792305Sstevel case PCIC_TI_VENDOR: 29802305Sstevel case PCIC_TOSHIBA_TOPIC100: 29812305Sstevel case PCIC_TOSHIBA_TOPIC95: 29822305Sstevel case PCIC_TOSHIBA_VENDOR: 29832305Sstevel case PCIC_RICOH_VENDOR: 29842305Sstevel case PCIC_O2MICRO_VENDOR: 29852305Sstevel pcic_putb(pcic, socket, 2986*7656SSherry.Moore@Sun.COM PCIC_YENTA_MEM_PAGE + win, 2987*7656SSherry.Moore@Sun.COM SYSMEM_EXT(base)); 29882305Sstevel break; 29892305Sstevel default: 29902305Sstevel cmn_err(CE_NOTE, "pcic_set_window: unknown " 2991*7656SSherry.Moore@Sun.COM "cardbus vendor:0x%X\n", 2992*7656SSherry.Moore@Sun.COM pcic->pc_type); 29932305Sstevel pcic_putb(pcic, socket, 2994*7656SSherry.Moore@Sun.COM PCIC_YENTA_MEM_PAGE + win, 2995*7656SSherry.Moore@Sun.COM SYSMEM_EXT(base)); 29962305Sstevel 29972305Sstevel break; 29982305Sstevel } /* switch */ 29992305Sstevel 30002305Sstevel /* 30012305Sstevel * specify the length of the mapped range 30022305Sstevel * we convert to pages (rounding up) so that 30032305Sstevel * the hardware gets the right thing 30042305Sstevel */ 30052305Sstevel pages = (window->WindowSize+PCIC_PAGE-1)/PCIC_PAGE; 30062305Sstevel 30072305Sstevel /* 30082305Sstevel * Setup this window's timing. 30092305Sstevel */ 30102305Sstevel switch (pcic->pc_type) { 30112305Sstevel case PCIC_CL_PD6729: 30122305Sstevel case PCIC_CL_PD6730: 30132305Sstevel case PCIC_CL_PD6710: 30142305Sstevel case PCIC_CL_PD6722: 30152305Sstevel wspeed = SYSMEM_CLTIMER_SET_0; 30162305Sstevel pcic_set_cdtimers(pcic, socket, 3017*7656SSherry.Moore@Sun.COM window->speed, 3018*7656SSherry.Moore@Sun.COM wspeed); 30192305Sstevel break; 30202305Sstevel 30212305Sstevel case PCIC_INTEL_i82092: 30222305Sstevel default: 30232305Sstevel wspeed = pcic_calc_speed(pcic, window->speed); 30242305Sstevel break; 30252305Sstevel } /* switch */ 30262305Sstevel 30272305Sstevel #if defined(PCIC_DEBUG) 30282305Sstevel if (pcic_debug) 30292305Sstevel cmn_err(CE_CONT, 3030*7656SSherry.Moore@Sun.COM "\twindow %d speed bits = %x for " 3031*7656SSherry.Moore@Sun.COM "%dns\n", 3032*7656SSherry.Moore@Sun.COM win, (unsigned)wspeed, window->speed); 30332305Sstevel #endif 30342305Sstevel 30352305Sstevel pcic_putb(pcic, socket, PCIC_SYSMEM_0_STOPLOW + select, 3036*7656SSherry.Moore@Sun.COM SYSMEM_LOW(base + 3037*7656SSherry.Moore@Sun.COM (pages * PCIC_PAGE)-1)); 30382305Sstevel 30392305Sstevel wspeed |= SYSMEM_HIGH(base + (pages * PCIC_PAGE)-1); 30402305Sstevel pcic_putb(pcic, socket, PCIC_SYSMEM_0_STOPHI + select, 3041*7656SSherry.Moore@Sun.COM wspeed); 30422305Sstevel 30432305Sstevel /* 30442305Sstevel * now map the card's memory pages - we start with page 30452305Sstevel * 0 30462305Sstevel * we also default to AM -- set page might change it 30472305Sstevel */ 30482305Sstevel base = memp->pcw_base; 30492305Sstevel pcic_putb(pcic, socket, 3050*7656SSherry.Moore@Sun.COM PCIC_CARDMEM_0_LOW + select, 3051*7656SSherry.Moore@Sun.COM CARDMEM_LOW(0 - (uint32_t)base)); 30522305Sstevel 30532305Sstevel pcic_putb(pcic, socket, 3054*7656SSherry.Moore@Sun.COM PCIC_CARDMEM_0_HI + select, 3055*7656SSherry.Moore@Sun.COM CARDMEM_HIGH(0 - (uint32_t)base) | 3056*7656SSherry.Moore@Sun.COM CARDMEM_REG_ACTIVE); 30572305Sstevel 30582305Sstevel /* 30592305Sstevel * enable the window even though redundant 30602305Sstevel * and SetPage may do it again. 30612305Sstevel */ 30622305Sstevel select = pcic_getb(pcic, socket, 3063*7656SSherry.Moore@Sun.COM PCIC_MAPPING_ENABLE); 30642305Sstevel select |= SYSMEM_WINDOW(win); 30652305Sstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, select); 30662305Sstevel memp->pcw_offset = 0; 30672305Sstevel memp->pcw_status |= PCW_ENABLED; 30682305Sstevel } else { 30692305Sstevel /* 30702305Sstevel * not only do we unmap the memory, the 30712305Sstevel * window has been turned off. 30722305Sstevel */ 30732305Sstevel if (which && memp->pcw_status & PCW_MAPPED) { 30742305Sstevel ddi_regs_map_free(&memp->pcw_handle); 30752305Sstevel res.ra_addr_lo = memp->pcw_base; 30762305Sstevel res.ra_len = memp->pcw_len; 30773664Srw148561 (void) pcmcia_free_mem(memp->res_dip, &res); 30782305Sstevel memp->pcw_hostmem = NULL; 30792305Sstevel memp->pcw_status &= ~PCW_MAPPED; 30802305Sstevel } 30812305Sstevel 30822305Sstevel /* disable current mapping */ 30832305Sstevel select = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE); 30842305Sstevel select &= ~SYSMEM_WINDOW(win); 30852305Sstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, select); 30862305Sstevel memp->pcw_status &= ~PCW_ENABLED; 30872305Sstevel } 30882305Sstevel memp->pcw_len = window->WindowSize; 30892305Sstevel window->handle = memp->pcw_handle; 30902305Sstevel #if defined(PCIC_DEBUG) 30912305Sstevel if (pcic_debug) 30922305Sstevel xxdmp_all_regs(pcic, window->socket, -1); 30932305Sstevel #endif 30942305Sstevel } else { 30952305Sstevel /* 30962305Sstevel * This is a request for an IO window 30972305Sstevel */ 30982305Sstevel int win, tmp; 30992305Sstevel pcs_iowin_t *winp; 31002305Sstevel /* I/O windows */ 31012305Sstevel #if defined(PCIC_DEBUG) 31022305Sstevel if (pcic_debug) 31032305Sstevel cmn_err(CE_CONT, "\twindow type is I/O\n"); 31042305Sstevel #endif 31052305Sstevel 31062305Sstevel /* only windows 0 and 1 can do I/O */ 31072305Sstevel win = window->window % PCIC_NUMWINSOCK; 31082305Sstevel tmp = window->window / PCIC_NUMWINSOCK; 31092305Sstevel 31102305Sstevel if (win >= PCIC_IOWINDOWS || tmp != window->socket) { 31112305Sstevel cmn_err(CE_WARN, 3112*7656SSherry.Moore@Sun.COM "\twindow is out of range (%d)\n", 3113*7656SSherry.Moore@Sun.COM window->window); 31142305Sstevel return (BAD_WINDOW); 31152305Sstevel } 31162305Sstevel 31172305Sstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 31182305Sstevel 31192305Sstevel winp = &sockp->pcs_windows[win].io; 31202305Sstevel winp->pcw_speed = window->speed; 31212305Sstevel if (window->WindowSize != 1 && window->WindowSize & 1) { 31222305Sstevel /* we don't want an odd-size window */ 31232305Sstevel window->WindowSize++; 31242305Sstevel } 31252305Sstevel winp->pcw_len = window->WindowSize; 31262305Sstevel 31272305Sstevel if (window->state & WS_ENABLED) { 31282305Sstevel if (winp->pcw_status & PCW_MAPPED) { 31292305Sstevel ddi_regs_map_free(&winp->pcw_handle); 31302305Sstevel res.ra_addr_lo = winp->pcw_base; 31312305Sstevel res.ra_len = winp->pcw_len; 31323664Srw148561 (void) pcmcia_free_io(winp->res_dip, &res); 31332305Sstevel winp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED); 31342305Sstevel } 31352305Sstevel 31362305Sstevel /* 31372305Sstevel * if the I/O address wasn't allocated, allocate 31382305Sstevel * it now. If it was allocated, it better 31392305Sstevel * be free to use. 31402305Sstevel * The winp->pcw_offset value is set and used 31412305Sstevel * later on if the particular adapter 31422305Sstevel * that we're running on has the ability 31432305Sstevel * to translate IO accesses to the card 31442305Sstevel * (such as some adapters in the Cirrus 31452305Sstevel * Logic family). 31462305Sstevel */ 31472305Sstevel winp->pcw_offset = 0; 31482305Sstevel 31492305Sstevel /* 31502305Sstevel * Setup the request parameters for the 31512305Sstevel * requested base and length. If 31522305Sstevel * we're on an adapter that has 31532305Sstevel * IO window offset registers, then 31542305Sstevel * we don't need a specific base 31552305Sstevel * address, just a length, and then 31562305Sstevel * we'll cause the correct IO address 31572305Sstevel * to be generated on the socket by 31582305Sstevel * setting up the IO window offset 31592305Sstevel * registers. 31602305Sstevel * For adapters that support this capability, we 31612305Sstevel * always use the IO window offset registers, 31622305Sstevel * even if the passed base/length would be in 31632305Sstevel * range. 31642305Sstevel */ 31652305Sstevel base = window->base; 31662305Sstevel bzero(&req, sizeof (req)); 31672305Sstevel req.ra_len = window->WindowSize; 31682305Sstevel 31692305Sstevel req.ra_addr = (uint64_t) 3170*7656SSherry.Moore@Sun.COM ((pcic->pc_flags & PCF_IO_REMAP) ? 0 : base); 31712305Sstevel req.ra_flags = (req.ra_addr) ? 3172*7656SSherry.Moore@Sun.COM NDI_RA_ALLOC_SPECIFIED : 0; 31732305Sstevel 31742305Sstevel req.ra_flags |= NDI_RA_ALIGN_SIZE; 31752305Sstevel /* need to rethink this */ 31762305Sstevel req.ra_boundbase = pcic->pc_iobase; 31772305Sstevel req.ra_boundlen = pcic->pc_iobound; 31782305Sstevel req.ra_flags |= NDI_RA_ALLOC_BOUNDED; 31792305Sstevel 31802305Sstevel #if defined(PCIC_DEBUG) 3181*7656SSherry.Moore@Sun.COM pcic_err(dip, 8, 3182*7656SSherry.Moore@Sun.COM "\tlen 0x%"PRIx64" addr 0x%"PRIx64 3183*7656SSherry.Moore@Sun.COM "bbase 0x%"PRIx64 3184*7656SSherry.Moore@Sun.COM "blen 0x%"PRIx64" flags 0x%x algn 0x%" 3185*7656SSherry.Moore@Sun.COM PRIx64"\n", 3186*7656SSherry.Moore@Sun.COM req.ra_len, (uint64_t)req.ra_addr, 3187*7656SSherry.Moore@Sun.COM req.ra_boundbase, 3188*7656SSherry.Moore@Sun.COM req.ra_boundlen, req.ra_flags, 3189*7656SSherry.Moore@Sun.COM req.ra_align_mask); 31902305Sstevel #endif 31912305Sstevel 31922305Sstevel /* 31932305Sstevel * Try to allocate the space. If we fail this, 31942305Sstevel * return the appropriate error depending 31952305Sstevel * on whether the caller specified a 31962305Sstevel * specific base address or not. 31972305Sstevel */ 31983664Srw148561 if (pcmcia_alloc_io(dip, &req, &res, 3199*7656SSherry.Moore@Sun.COM &winp->res_dip) == DDI_FAILURE) { 32002305Sstevel winp->pcw_status &= ~PCW_ENABLED; 32012305Sstevel mutex_exit(&pcic->pc_lock); 32022305Sstevel cmn_err(CE_WARN, "Failed to alloc I/O:\n" 3203*7656SSherry.Moore@Sun.COM "\tlen 0x%" PRIx64 " addr 0x%" PRIx64 3204*7656SSherry.Moore@Sun.COM "bbase 0x%" PRIx64 3205*7656SSherry.Moore@Sun.COM "blen 0x%" PRIx64 "flags 0x%x" 3206*7656SSherry.Moore@Sun.COM "algn 0x%" PRIx64 "\n", 3207*7656SSherry.Moore@Sun.COM req.ra_len, req.ra_addr, 3208*7656SSherry.Moore@Sun.COM req.ra_boundbase, 3209*7656SSherry.Moore@Sun.COM req.ra_boundlen, req.ra_flags, 3210*7656SSherry.Moore@Sun.COM req.ra_align_mask); 32112305Sstevel 32122305Sstevel return (base?BAD_BASE:BAD_SIZE); 32132305Sstevel } /* pcmcia_alloc_io */ 32142305Sstevel 32152305Sstevel /* 32162305Sstevel * Don't change the original base. Either we use 32172305Sstevel * the offset registers below (PCF_IO_REMAP is set) 32182305Sstevel * or it was allocated correctly anyway. 32192305Sstevel */ 32202305Sstevel winp->pcw_base = res.ra_addr_lo; 32212305Sstevel 32222305Sstevel #if defined(PCIC_DEBUG) 3223*7656SSherry.Moore@Sun.COM pcic_err(dip, 8, 32242305Sstevel "\tsetwindow: new base=%x orig base 0x%x\n", 32252305Sstevel (unsigned)winp->pcw_base, base); 32262305Sstevel #endif 32272305Sstevel 32282305Sstevel if ((which = pcmcia_map_reg(pcic->dip, 3229*7656SSherry.Moore@Sun.COM window->child, 3230*7656SSherry.Moore@Sun.COM &res, 3231*7656SSherry.Moore@Sun.COM (uint32_t)(window->state & 3232*7656SSherry.Moore@Sun.COM 0xffff) | 3233*7656SSherry.Moore@Sun.COM (window->socket << 16), 3234*7656SSherry.Moore@Sun.COM (caddr_t *)&winp->pcw_hostmem, 3235*7656SSherry.Moore@Sun.COM &winp->pcw_handle, 3236*7656SSherry.Moore@Sun.COM &window->attr, 3237*7656SSherry.Moore@Sun.COM base)) != DDI_SUCCESS) { 3238*7656SSherry.Moore@Sun.COM 3239*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "pcmcia_map_reg()" 3240*7656SSherry.Moore@Sun.COM "failed\n"); 3241*7656SSherry.Moore@Sun.COM 3242*7656SSherry.Moore@Sun.COM res.ra_addr_lo = winp->pcw_base; 3243*7656SSherry.Moore@Sun.COM res.ra_len = winp->pcw_len; 3244*7656SSherry.Moore@Sun.COM (void) pcmcia_free_io(winp->res_dip, 3245*7656SSherry.Moore@Sun.COM &res); 3246*7656SSherry.Moore@Sun.COM 3247*7656SSherry.Moore@Sun.COM mutex_exit(&pcic->pc_lock); 3248*7656SSherry.Moore@Sun.COM return (BAD_WINDOW); 32492305Sstevel } 32502305Sstevel 32512305Sstevel window->handle = winp->pcw_handle; 32522305Sstevel winp->pcw_status |= PCW_MAPPED; 32532305Sstevel 32542305Sstevel /* find the register set offset */ 32552305Sstevel select = win * PCIC_IO_OFFSET; 32562305Sstevel 32572305Sstevel #if defined(PCIC_DEBUG) 32582305Sstevel if (pcic_debug) { 32592305Sstevel cmn_err(CE_CONT, 3260*7656SSherry.Moore@Sun.COM "\tenable: window=%d, select=%x, " 3261*7656SSherry.Moore@Sun.COM "base=%x, handle=%p\n", 3262*7656SSherry.Moore@Sun.COM win, select, 3263*7656SSherry.Moore@Sun.COM (unsigned)window->base, 3264*7656SSherry.Moore@Sun.COM (void *)window->handle); 32652305Sstevel } 32662305Sstevel #endif 32672305Sstevel /* 32682305Sstevel * at this point, the register window indicator has 32692305Sstevel * been converted to be an offset from the first 32702305Sstevel * set of registers that are used for programming 32712305Sstevel * the window mapping and the offset used to select 32722305Sstevel * the correct set of registers to access the 32732305Sstevel * specified socket. This allows basing everything 32742305Sstevel * off the _0 window 32752305Sstevel */ 32762305Sstevel 32772305Sstevel /* map the I/O base in */ 32782305Sstevel pcic_putb(pcic, socket, 3279*7656SSherry.Moore@Sun.COM PCIC_IO_ADDR_0_STARTLOW + select, 3280*7656SSherry.Moore@Sun.COM LOW_BYTE((uint32_t)winp->pcw_base)); 32812305Sstevel pcic_putb(pcic, socket, 3282*7656SSherry.Moore@Sun.COM PCIC_IO_ADDR_0_STARTHI + select, 3283*7656SSherry.Moore@Sun.COM HIGH_BYTE((uint32_t)winp->pcw_base)); 32842305Sstevel 32852305Sstevel pcic_putb(pcic, socket, 3286*7656SSherry.Moore@Sun.COM PCIC_IO_ADDR_0_STOPLOW + select, 3287*7656SSherry.Moore@Sun.COM LOW_BYTE((uint32_t)winp->pcw_base + 3288*7656SSherry.Moore@Sun.COM window->WindowSize - 1)); 32892305Sstevel pcic_putb(pcic, socket, 3290*7656SSherry.Moore@Sun.COM PCIC_IO_ADDR_0_STOPHI + select, 3291*7656SSherry.Moore@Sun.COM HIGH_BYTE((uint32_t)winp->pcw_base + 3292*7656SSherry.Moore@Sun.COM window->WindowSize - 1)); 32932305Sstevel 32942305Sstevel /* 32952305Sstevel * We've got the requested IO space, now see if we 32962305Sstevel * need to adjust the IO window offset registers 32972305Sstevel * so that the correct IO address is generated 32982305Sstevel * at the socket. If this window doesn't have 32992305Sstevel * this capability, then we're all done setting 33002305Sstevel * up the IO resources. 33012305Sstevel */ 33022305Sstevel if (pcic->pc_flags & PCF_IO_REMAP) { 33032305Sstevel 33042305Sstevel 33052305Sstevel /* 33062305Sstevel * Note that only 16 bits are used to program 33072305Sstevel * the registers but leave 32 bits on pcw_offset 33082305Sstevel * so that we can generate the original base 33092305Sstevel * in get_window() 33102305Sstevel */ 33112305Sstevel winp->pcw_offset = (base - winp->pcw_base); 33122305Sstevel 33132305Sstevel pcic_putb(pcic, socket, 3314*7656SSherry.Moore@Sun.COM PCIC_IO_OFFSET_LOW + 3315*7656SSherry.Moore@Sun.COM (win * PCIC_IO_OFFSET_OFFSET), 3316*7656SSherry.Moore@Sun.COM winp->pcw_offset & 0x0ff); 33172305Sstevel pcic_putb(pcic, socket, 3318*7656SSherry.Moore@Sun.COM PCIC_IO_OFFSET_HI + 3319*7656SSherry.Moore@Sun.COM (win * PCIC_IO_OFFSET_OFFSET), 3320*7656SSherry.Moore@Sun.COM (winp->pcw_offset >> 8) & 0x0ff); 33212305Sstevel 33222305Sstevel } /* PCF_IO_REMAP */ 33232305Sstevel 33242305Sstevel /* now get the other details (size, etc) right */ 33252305Sstevel 33262305Sstevel /* 33272305Sstevel * Set the data size control bits here. Most of the 33282305Sstevel * adapters will ignore IOMEM_16BIT when 33292305Sstevel * IOMEM_IOCS16 is set, except for the Intel 33302305Sstevel * 82092, which only pays attention to the 33312305Sstevel * IOMEM_16BIT bit. Sigh... Intel can't even 33322305Sstevel * make a proper clone of their own chip. 33332305Sstevel * The 82092 also apparently can't set the timing 33342305Sstevel * of I/O windows. 33352305Sstevel */ 33362305Sstevel which = (window->state & WS_16BIT) ? 3337*7656SSherry.Moore@Sun.COM (IOMEM_16BIT | IOMEM_IOCS16) : 0; 33382305Sstevel 33392305Sstevel switch (pcic->pc_type) { 33402305Sstevel case PCIC_CL_PD6729: 33412305Sstevel case PCIC_CL_PD6730: 33422305Sstevel case PCIC_CL_PD6710: 33432305Sstevel case PCIC_CL_PD6722: 33442305Sstevel case PCIC_CL_PD6832: 33452305Sstevel /* 33462305Sstevel * Select Timer Set 1 - this will take 33472305Sstevel * effect when the PCIC_IO_CONTROL 33482305Sstevel * register is written to later on; 33492305Sstevel * the call to pcic_set_cdtimers 33502305Sstevel * just sets up the timer itself. 33512305Sstevel */ 33522305Sstevel which |= IOMEM_CLTIMER_SET_1; 33532305Sstevel pcic_set_cdtimers(pcic, socket, 3354*7656SSherry.Moore@Sun.COM window->speed, 3355*7656SSherry.Moore@Sun.COM IOMEM_CLTIMER_SET_1); 33562305Sstevel which |= IOMEM_IOCS16; 33572305Sstevel break; 33582305Sstevel case PCIC_TI_PCI1031: 33592305Sstevel 33602305Sstevel if (window->state & WS_16BIT) 3361*7656SSherry.Moore@Sun.COM which |= IOMEM_WAIT16; 33622305Sstevel 33632305Sstevel break; 33642305Sstevel case PCIC_TI_PCI1130: 33652305Sstevel 33662305Sstevel if (window->state & WS_16BIT) 3367*7656SSherry.Moore@Sun.COM which |= IOMEM_WAIT16; 33682305Sstevel 33692305Sstevel break; 33702305Sstevel case PCIC_INTEL_i82092: 33712305Sstevel break; 33722305Sstevel default: 33732305Sstevel if (window->speed > 3374*7656SSherry.Moore@Sun.COM mhztons(pcic->bus_speed) * 3) 3375*7656SSherry.Moore@Sun.COM which |= IOMEM_WAIT16; 33762305Sstevel #ifdef notdef 33772305Sstevel if (window->speed < 3378*7656SSherry.Moore@Sun.COM mhztons(pcic->bus_speed) * 6) 3379*7656SSherry.Moore@Sun.COM which |= IOMEM_ZERO_WAIT; 33802305Sstevel #endif 33812305Sstevel break; 33822305Sstevel } /* switch (pc_type) */ 33832305Sstevel 33842305Sstevel /* 33852305Sstevel * Setup the data width and timing 33862305Sstevel */ 33872305Sstevel select = pcic_getb(pcic, socket, PCIC_IO_CONTROL); 33882305Sstevel select &= ~(PCIC_IO_WIN_MASK << (win * 4)); 33892305Sstevel select |= IOMEM_SETWIN(win, which); 33902305Sstevel pcic_putb(pcic, socket, PCIC_IO_CONTROL, select); 33912305Sstevel 33922305Sstevel /* 33932305Sstevel * Enable the IO window 33942305Sstevel */ 33952305Sstevel select = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE); 33962305Sstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, 3397*7656SSherry.Moore@Sun.COM select | IOMEM_WINDOW(win)); 33982305Sstevel 33992305Sstevel winp->pcw_status |= PCW_ENABLED; 34002305Sstevel 34012305Sstevel #if defined(PCIC_DEBUG) 34022305Sstevel if (pcic_debug) { 34032305Sstevel cmn_err(CE_CONT, 3404*7656SSherry.Moore@Sun.COM "\twhich = %x, select = %x (%x)\n", 3405*7656SSherry.Moore@Sun.COM which, select, 3406*7656SSherry.Moore@Sun.COM IOMEM_SETWIN(win, which)); 34072305Sstevel xxdmp_all_regs(pcic, window->socket * 0x40, 24); 34082305Sstevel } 34092305Sstevel #endif 34102305Sstevel } else { 34112305Sstevel /* 34122305Sstevel * not only do we unmap the IO space, the 34132305Sstevel * window has been turned off. 34142305Sstevel */ 34152305Sstevel if (winp->pcw_status & PCW_MAPPED) { 34162305Sstevel ddi_regs_map_free(&winp->pcw_handle); 34172305Sstevel res.ra_addr_lo = winp->pcw_base; 34182305Sstevel res.ra_len = winp->pcw_len; 34193664Srw148561 (void) pcmcia_free_io(winp->res_dip, &res); 34202305Sstevel winp->pcw_status &= ~PCW_MAPPED; 34212305Sstevel } 34222305Sstevel 34232305Sstevel /* disable current mapping */ 34242305Sstevel select = pcic_getb(pcic, socket, 3425*7656SSherry.Moore@Sun.COM PCIC_MAPPING_ENABLE); 34262305Sstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, 3427*7656SSherry.Moore@Sun.COM select &= ~IOMEM_WINDOW(win)); 34282305Sstevel winp->pcw_status &= ~PCW_ENABLED; 34292305Sstevel 34302305Sstevel winp->pcw_base = 0; 34312305Sstevel winp->pcw_len = 0; 34322305Sstevel winp->pcw_offset = 0; 34332305Sstevel window->base = 0; 34342305Sstevel /* now make sure we don't accidentally re-enable */ 34352305Sstevel /* find the register set offset */ 34362305Sstevel select = win * PCIC_IO_OFFSET; 34372305Sstevel pcic_putb(pcic, socket, 3438*7656SSherry.Moore@Sun.COM PCIC_IO_ADDR_0_STARTLOW + select, 0); 34392305Sstevel pcic_putb(pcic, socket, 3440*7656SSherry.Moore@Sun.COM PCIC_IO_ADDR_0_STARTHI + select, 0); 34412305Sstevel pcic_putb(pcic, socket, 3442*7656SSherry.Moore@Sun.COM PCIC_IO_ADDR_0_STOPLOW + select, 0); 34432305Sstevel pcic_putb(pcic, socket, 3444*7656SSherry.Moore@Sun.COM PCIC_IO_ADDR_0_STOPHI + select, 0); 34452305Sstevel } 34462305Sstevel } 34472305Sstevel mutex_exit(&pcic->pc_lock); 34482305Sstevel 34492305Sstevel return (SUCCESS); 34502305Sstevel } 34512305Sstevel 34522305Sstevel /* 34532305Sstevel * pcic_card_state() 34542305Sstevel * compute the instantaneous Card State information 34552305Sstevel */ 34562305Sstevel static int 34572305Sstevel pcic_card_state(pcicdev_t *pcic, pcic_socket_t *sockp) 34582305Sstevel { 34592305Sstevel int value, result; 34602305Sstevel #if defined(PCIC_DEBUG) 34612305Sstevel int orig_value; 34622305Sstevel #endif 34632305Sstevel 34642305Sstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 34652305Sstevel 34662305Sstevel value = pcic_getb(pcic, sockp->pcs_socket, PCIC_INTERFACE_STATUS); 34672305Sstevel 34682305Sstevel #if defined(PCIC_DEBUG) 34692305Sstevel orig_value = value; 34702305Sstevel if (pcic_debug >= 8) 34712305Sstevel cmn_err(CE_CONT, "pcic_card_state(%p) if status = %b for %d\n", 3472*7656SSherry.Moore@Sun.COM (void *)sockp, 3473*7656SSherry.Moore@Sun.COM value, 3474*7656SSherry.Moore@Sun.COM "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI", 3475*7656SSherry.Moore@Sun.COM sockp->pcs_socket); 34762305Sstevel #endif 34772305Sstevel /* 34782305Sstevel * Lie to socket services if we are not ready. 34792305Sstevel * This is when we are starting up or during debounce timeouts 34802305Sstevel * or if the card is a cardbus card. 34812305Sstevel */ 34822305Sstevel if (!(sockp->pcs_flags & (PCS_STARTING|PCS_CARD_ISCARDBUS)) && 34832305Sstevel !sockp->pcs_debounce_id && 34842305Sstevel (value & PCIC_ISTAT_CD_MASK) == PCIC_CD_PRESENT_OK) { 34852305Sstevel result = SBM_CD; 34862305Sstevel 34872305Sstevel if (value & PCIC_WRITE_PROTECT || !(value & PCIC_POWER_ON)) 34882305Sstevel result |= SBM_WP; 34892305Sstevel if (value & PCIC_POWER_ON) { 34902305Sstevel if (value & PCIC_READY) 34912305Sstevel result |= SBM_RDYBSY; 34922305Sstevel value = (~value) & (PCIC_BVD1 | PCIC_BVD2); 34932305Sstevel if (value & PCIC_BVD1) 34942305Sstevel result |= SBM_BVD1; 34952305Sstevel if (value & PCIC_BVD2) 34962305Sstevel result |= SBM_BVD2; 34972305Sstevel } 34982305Sstevel } else 34992305Sstevel result = 0; 35002305Sstevel 35012305Sstevel mutex_exit(&pcic->pc_lock); 35022305Sstevel 35032305Sstevel #if defined(PCIC_DEBUG) 35042305Sstevel pcic_err(pcic->dip, 8, 35052305Sstevel "pcic_card_state(%p) if status = %b for %d (rval=0x%x)\n", 35062305Sstevel (void *) sockp, orig_value, 35072305Sstevel "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI", 35082305Sstevel sockp->pcs_socket, result); 35092305Sstevel #endif 35102305Sstevel 35112305Sstevel return (result); 35122305Sstevel } 35132305Sstevel 35142305Sstevel /* 35152305Sstevel * pcic_set_page() 35162305Sstevel * SocketServices SetPage function 35172305Sstevel * set the page of PC Card memory that should be in the mapped 35182305Sstevel * window 35192305Sstevel */ 35202305Sstevel /*ARGSUSED*/ 35212305Sstevel static int 35222305Sstevel pcic_set_page(dev_info_t *dip, set_page_t *page) 35232305Sstevel { 35242305Sstevel anp_t *anp = ddi_get_driver_private(dip); 35252305Sstevel pcicdev_t *pcic = anp->an_private; 35262305Sstevel int select; 35272305Sstevel int which, socket, window; 35282305Sstevel uint32_t base; 35292305Sstevel pcs_memwin_t *memp; 35302305Sstevel 35312305Sstevel /* get real socket/window numbers */ 35322305Sstevel window = page->window % PCIC_NUMWINSOCK; 35332305Sstevel socket = page->window / PCIC_NUMWINSOCK; 35342305Sstevel 35352305Sstevel #if defined(PCIC_DEBUG) 35362305Sstevel if (pcic_debug) { 35372305Sstevel cmn_err(CE_CONT, 3538*7656SSherry.Moore@Sun.COM "pcic_set_page: window=%d, socket=%d, page=%d\n", 3539*7656SSherry.Moore@Sun.COM window, socket, page->page); 35402305Sstevel } 35412305Sstevel #endif 35422305Sstevel /* only windows 2-6 work on memory */ 35432305Sstevel if (window < PCIC_IOWINDOWS) 35442305Sstevel return (BAD_WINDOW); 35452305Sstevel 35462305Sstevel /* only one page supported (but any size) */ 35472305Sstevel if (page->page != 0) 35482305Sstevel return (BAD_PAGE); 35492305Sstevel 35502305Sstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 35512305Sstevel 35522305Sstevel memp = &pcic->pc_sockets[socket].pcs_windows[window].mem; 35532305Sstevel window -= PCIC_IOWINDOWS; 35542305Sstevel 35552305Sstevel #if defined(PCIC_DEBUG) 35562305Sstevel if (pcic_debug) 35572305Sstevel cmn_err(CE_CONT, "\tpcw_base=%x, pcw_hostmem=%p, pcw_len=%x\n", 3558*7656SSherry.Moore@Sun.COM (uint32_t)memp->pcw_base, 3559*7656SSherry.Moore@Sun.COM (void *)memp->pcw_hostmem, memp->pcw_len); 35602305Sstevel #endif 35612305Sstevel 35622305Sstevel /* window must be enabled */ 35632305Sstevel if (!(memp->pcw_status & PCW_ENABLED)) 35642305Sstevel return (BAD_ATTRIBUTE); 35652305Sstevel 35662305Sstevel /* find the register set offset */ 35672305Sstevel select = window * PCIC_MEM_1_OFFSET; 35682305Sstevel #if defined(PCIC_DEBUG) 35692305Sstevel if (pcic_debug) 35702305Sstevel cmn_err(CE_CONT, "\tselect=%x\n", select); 35712305Sstevel #endif 35722305Sstevel 35732305Sstevel /* 35742305Sstevel * now map the card's memory pages - we start with page 0 35752305Sstevel */ 35762305Sstevel 35772305Sstevel which = 0; /* assume simple case */ 35782305Sstevel if (page->state & PS_ATTRIBUTE) { 35792305Sstevel which |= CARDMEM_REG_ACTIVE; 35802305Sstevel memp->pcw_status |= PCW_ATTRIBUTE; 35812305Sstevel } else { 35822305Sstevel memp->pcw_status &= ~PCW_ATTRIBUTE; 35832305Sstevel } 35842305Sstevel 35852305Sstevel /* 35862305Sstevel * if caller says Write Protect, enforce it. 35872305Sstevel */ 35882305Sstevel if (page->state & PS_WP) { 35892305Sstevel which |= CARDMEM_WRITE_PROTECT; 35902305Sstevel memp->pcw_status |= PCW_WP; 35912305Sstevel } else { 35922305Sstevel memp->pcw_status &= ~PCW_WP; 35932305Sstevel } 35942305Sstevel #if defined(PCIC_DEBUG) 35952305Sstevel if (pcic_debug) { 35962305Sstevel cmn_err(CE_CONT, "\tmemory type = %s\n", 3597*7656SSherry.Moore@Sun.COM (which & CARDMEM_REG_ACTIVE) ? "attribute" : "common"); 35982305Sstevel if (which & CARDMEM_WRITE_PROTECT) 35992305Sstevel cmn_err(CE_CONT, "\twrite protect\n"); 36002305Sstevel cmn_err(CE_CONT, "\tpage offset=%x pcw_base=%x (%x)\n", 3601*7656SSherry.Moore@Sun.COM (unsigned)page->offset, 3602*7656SSherry.Moore@Sun.COM (unsigned)memp->pcw_base, 3603*7656SSherry.Moore@Sun.COM (int)page->offset - (int)memp->pcw_base & 0xffffff); 36042305Sstevel } 36052305Sstevel #endif 36062305Sstevel /* address computation based on 64MB range and not larger */ 36072305Sstevel base = (uint32_t)memp->pcw_base & 0x3ffffff; 36082305Sstevel pcic_putb(pcic, socket, PCIC_CARDMEM_0_LOW + select, 36092305Sstevel CARDMEM_LOW((int)page->offset - (int)base)); 36102305Sstevel (void) pcic_getb(pcic, socket, PCIC_CARDMEM_0_LOW + select); 36112305Sstevel pcic_putb(pcic, socket, PCIC_CARDMEM_0_HI + select, 36122305Sstevel CARDMEM_HIGH((int)page->offset - base) | which); 36132305Sstevel (void) pcic_getb(pcic, socket, PCIC_CARDMEM_0_HI + select); 36142305Sstevel 36152305Sstevel /* 36162305Sstevel * while not really necessary, this just makes sure 36172305Sstevel * nothing turned the window off behind our backs 36182305Sstevel */ 36192305Sstevel which = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE); 36202305Sstevel which |= SYSMEM_WINDOW(window); 36212305Sstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, which); 36222305Sstevel (void) pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE); 36232305Sstevel 36242305Sstevel memp->pcw_offset = (off_t)page->offset; 36252305Sstevel 36262305Sstevel #if defined(PCIC_DEBUG) 36272305Sstevel if (pcic_debug) { 36282305Sstevel cmn_err(CE_CONT, "\tbase=%p, *base=%x\n", 3629*7656SSherry.Moore@Sun.COM (void *)memp->pcw_hostmem, 3630*7656SSherry.Moore@Sun.COM (uint32_t)*memp->pcw_hostmem); 36312305Sstevel 36322305Sstevel xxdmp_all_regs(pcic, socket, -1); 36332305Sstevel 36342305Sstevel cmn_err(CE_CONT, "\tbase=%p, *base=%x\n", 3635*7656SSherry.Moore@Sun.COM (void *)memp->pcw_hostmem, 3636*7656SSherry.Moore@Sun.COM (uint32_t)*memp->pcw_hostmem); 36372305Sstevel } 36382305Sstevel #endif 36392305Sstevel 36402305Sstevel if (which & PCW_ATTRIBUTE) 36412305Sstevel pcic_mswait(pcic, socket, 2); 36422305Sstevel 36432305Sstevel mutex_exit(&pcic->pc_lock); 36442305Sstevel 36452305Sstevel return (SUCCESS); 36462305Sstevel } 36472305Sstevel 36482305Sstevel /* 36492305Sstevel * pcic_set_vcc_level() 36502305Sstevel * 36512305Sstevel * set voltage based on adapter information 36522305Sstevel * 36532305Sstevel * this routine implements a limited solution for support of 3.3v cards. 36542305Sstevel * the general solution, which would fully support the pcmcia spec 36552305Sstevel * as far as allowing client drivers to request which voltage levels 36562305Sstevel * to be set, requires more framework support and driver changes - ess 36572305Sstevel */ 36582305Sstevel static int 36592305Sstevel pcic_set_vcc_level(pcicdev_t *pcic, set_socket_t *socket) 36602305Sstevel { 36612305Sstevel uint32_t socket_present_state; 36622305Sstevel 36632305Sstevel #if defined(PCIC_DEBUG) 36642305Sstevel if (pcic_debug) { 36652305Sstevel cmn_err(CE_CONT, 3666*7656SSherry.Moore@Sun.COM "pcic_set_vcc_level(pcic=%p, VccLevel=%d)\n", 3667*7656SSherry.Moore@Sun.COM (void *)pcic, socket->VccLevel); 36682305Sstevel } 36692305Sstevel #endif 36702305Sstevel 36712305Sstevel /* 36722305Sstevel * check VccLevel 36732305Sstevel * if this is zero, power is being turned off 36742305Sstevel * if it is non-zero, power is being turned on. 36752305Sstevel */ 36762305Sstevel if (socket->VccLevel == 0) { 36772305Sstevel return (0); 36782305Sstevel } 36792305Sstevel 36802305Sstevel /* 36812305Sstevel * range checking for sanity's sake 36822305Sstevel */ 36832305Sstevel if (socket->VccLevel >= pcic->pc_numpower) { 36842305Sstevel return (BAD_VCC); 36852305Sstevel } 36862305Sstevel 36872305Sstevel switch (pcic->pc_io_type) { 36882305Sstevel /* 36892305Sstevel * Yenta-compliant adapters have vcc info in the extended registers 36902305Sstevel * Other adapters can be added as needed, but the 'default' case 36912305Sstevel * has been left as it was previously so as not to break existing 36922305Sstevel * adapters. 36932305Sstevel */ 36942305Sstevel case PCIC_IO_TYPE_YENTA: 36952305Sstevel /* 36962305Sstevel * Here we ignore the VccLevel passed in and read the 36972305Sstevel * card type from the adapter socket present state register 36982305Sstevel */ 36992305Sstevel socket_present_state = 3700*7656SSherry.Moore@Sun.COM ddi_get32(pcic->handle, (uint32_t *)(pcic->ioaddr + 3701*7656SSherry.Moore@Sun.COM PCIC_PRESENT_STATE_REG)); 37022305Sstevel #if defined(PCIC_DEBUG) 37032305Sstevel if (pcic_debug) { 37042305Sstevel cmn_err(CE_CONT, 3705*7656SSherry.Moore@Sun.COM "socket present state = 0x%x\n", 3706*7656SSherry.Moore@Sun.COM socket_present_state); 37072305Sstevel } 37082305Sstevel #endif 37092305Sstevel switch (socket_present_state & PCIC_VCC_MASK) { 37102305Sstevel case PCIC_VCC_3VCARD: 37112305Sstevel /* fall through */ 37122305Sstevel case PCIC_VCC_3VCARD|PCIC_VCC_5VCARD: 37132305Sstevel socket->VccLevel = PCIC_VCC_3VLEVEL; 37142305Sstevel return 37152305Sstevel (POWER_3VCARD_ENABLE|POWER_OUTPUT_ENABLE); 37162305Sstevel case PCIC_VCC_5VCARD: 37172305Sstevel socket->VccLevel = PCIC_VCC_5VLEVEL; 37182305Sstevel return 37192305Sstevel (POWER_CARD_ENABLE|POWER_OUTPUT_ENABLE); 37202305Sstevel default: 37212305Sstevel /* 37222305Sstevel * if no card is present, this can be the 37232305Sstevel * case of a client making a SetSocket call 37242305Sstevel * after card removal. In this case we return 37252305Sstevel * the current power level 37262305Sstevel */ 37272305Sstevel return ((unsigned)ddi_get8(pcic->handle, 37282305Sstevel pcic->ioaddr + CB_R2_OFFSET + 3729*7656SSherry.Moore@Sun.COM PCIC_POWER_CONTROL)); 37302305Sstevel } 37312305Sstevel 37322305Sstevel default: 37332305Sstevel 37342305Sstevel switch (socket->VccLevel) { 37352305Sstevel case PCIC_VCC_3VLEVEL: 37362305Sstevel return (BAD_VCC); 37372305Sstevel case PCIC_VCC_5VLEVEL: 37382305Sstevel /* enable Vcc */ 37392305Sstevel return (POWER_CARD_ENABLE|POWER_OUTPUT_ENABLE); 37402305Sstevel default: 37412305Sstevel return (BAD_VCC); 37422305Sstevel } 37432305Sstevel } 37442305Sstevel } 37452305Sstevel 37462305Sstevel 37472305Sstevel /* 37482305Sstevel * pcic_set_socket() 37492305Sstevel * Socket Services SetSocket call 37502305Sstevel * sets basic socket configuration 37512305Sstevel */ 37522305Sstevel static int 37532305Sstevel pcic_set_socket(dev_info_t *dip, set_socket_t *socket) 37542305Sstevel { 37552305Sstevel anp_t *anp = ddi_get_driver_private(dip); 37562305Sstevel pcicdev_t *pcic = anp->an_private; 37572305Sstevel pcic_socket_t *sockp = &pcic->pc_sockets[socket->socket]; 37582305Sstevel int irq, interrupt, mirq; 37592305Sstevel int powerlevel = 0; 37602305Sstevel int ind, value, orig_pwrctl; 37612305Sstevel 37622305Sstevel #if defined(PCIC_DEBUG) 37632305Sstevel if (pcic_debug) { 37642305Sstevel cmn_err(CE_CONT, 37652305Sstevel "pcic_set_socket(dip=%p, socket=%d)" 37662305Sstevel " Vcc=%d Vpp1=%d Vpp2=%d\n", (void *)dip, 37672305Sstevel socket->socket, socket->VccLevel, socket->Vpp1Level, 37682305Sstevel socket->Vpp2Level); 37692305Sstevel } 37702305Sstevel #endif 37712305Sstevel /* 37722305Sstevel * check VccLevel, etc. before setting mutex 37732305Sstevel * if this is zero, power is being turned off 37742305Sstevel * if it is non-zero, power is being turned on. 37752305Sstevel * the default case is to assume Vcc only. 37762305Sstevel */ 37772305Sstevel 37782305Sstevel /* this appears to be very implementation specific */ 37792305Sstevel 37802305Sstevel if (socket->Vpp1Level != socket->Vpp2Level) 37812305Sstevel return (BAD_VPP); 37822305Sstevel 37832305Sstevel if (socket->VccLevel == 0 || !(sockp->pcs_flags & PCS_CARD_PRESENT)) { 37842305Sstevel powerlevel = 0; 37852305Sstevel sockp->pcs_vcc = 0; 37862305Sstevel sockp->pcs_vpp1 = 0; 37872305Sstevel sockp->pcs_vpp2 = 0; 37882305Sstevel } else { 37892305Sstevel #if defined(PCIC_DEBUG) 37902305Sstevel pcic_err(dip, 9, "\tVcc=%d Vpp1Level=%d, Vpp2Level=%d\n", 37912305Sstevel socket->VccLevel, socket->Vpp1Level, socket->Vpp2Level); 37922305Sstevel #endif 37932305Sstevel /* valid Vcc power level? */ 37942305Sstevel if (socket->VccLevel >= pcic->pc_numpower) 37952305Sstevel return (BAD_VCC); 37962305Sstevel 37972305Sstevel switch (pcic_power[socket->VccLevel].PowerLevel) { 37982305Sstevel case 33: /* 3.3V */ 37992305Sstevel case 60: /* for bad CIS in Option GPRS card */ 38002305Sstevel if (!(pcic->pc_flags & PCF_33VCAP)) { 38012305Sstevel cmn_err(CE_WARN, 38022305Sstevel "%s%d: Bad Request for 3.3V " 38032305Sstevel "(Controller incapable)\n", 38042305Sstevel ddi_get_name(pcic->dip), 38052305Sstevel ddi_get_instance(pcic->dip)); 38062305Sstevel return (BAD_VCC); 38072305Sstevel } 38082305Sstevel /* FALLTHROUGH */ 38092305Sstevel case 50: /* 5V */ 38102305Sstevel if ((pcic->pc_io_type == PCIC_IO_TYPE_YENTA) && 38112305Sstevel pcic_getcb(pcic, CB_PRESENT_STATE) & 38122305Sstevel CB_PS_33VCARD) { 38132305Sstevel /* 38142305Sstevel * This is actually a 3.3V card. 38152305Sstevel * Solaris Card Services 38162305Sstevel * doesn't understand 3.3V 38172305Sstevel * so we cheat and change 38182305Sstevel * the setting to the one appropriate to 3.3V. 38192305Sstevel * Note that this is the entry number 38202305Sstevel * in the pcic_power[] array. 38212305Sstevel */ 38222305Sstevel sockp->pcs_vcc = PCIC_VCC_3VLEVEL; 38232305Sstevel } else 38242305Sstevel sockp->pcs_vcc = socket->VccLevel; 38252305Sstevel break; 38262305Sstevel default: 38272305Sstevel return (BAD_VCC); 38282305Sstevel } 38292305Sstevel 38302305Sstevel /* enable Vcc */ 38312305Sstevel powerlevel = POWER_CARD_ENABLE; 38322305Sstevel 38332305Sstevel #if defined(PCIC_DEBUG) 38342305Sstevel if (pcic_debug) { 38352305Sstevel cmn_err(CE_CONT, "\tVcc=%d powerlevel=%x\n", 38362305Sstevel socket->VccLevel, powerlevel); 38372305Sstevel } 38382305Sstevel #endif 38392305Sstevel ind = 0; /* default index to 0 power */ 38402305Sstevel if ((int)socket->Vpp1Level >= 0 && 38412305Sstevel socket->Vpp1Level < pcic->pc_numpower) { 38422305Sstevel if (!(pcic_power[socket->Vpp1Level].ValidSignals 38432305Sstevel & VPP1)) { 38442305Sstevel return (BAD_VPP); 38452305Sstevel } 38462305Sstevel ind = pcic_power[socket->Vpp1Level].PowerLevel/10; 38472305Sstevel powerlevel |= pcic_vpp_levels[ind]; 38482305Sstevel sockp->pcs_vpp1 = socket->Vpp1Level; 38492305Sstevel } 38502305Sstevel if ((int)socket->Vpp2Level >= 0 && 38512305Sstevel socket->Vpp2Level < pcic->pc_numpower) { 38522305Sstevel if (!(pcic_power[socket->Vpp2Level].ValidSignals 38532305Sstevel & VPP2)) { 38542305Sstevel return (BAD_VPP); 38552305Sstevel } 38562305Sstevel ind = pcic_power[socket->Vpp2Level].PowerLevel/10; 38572305Sstevel powerlevel |= (pcic_vpp_levels[ind] << 2); 38582305Sstevel sockp->pcs_vpp2 = socket->Vpp2Level; 38592305Sstevel } 38602305Sstevel 38612305Sstevel if (pcic->pc_flags & PCF_VPPX) { 38622305Sstevel /* 38632305Sstevel * this adapter doesn't allow separate Vpp1/Vpp2 38642305Sstevel * if one is turned on, both are turned on and only 38652305Sstevel * the Vpp1 bits should be set 38662305Sstevel */ 38672305Sstevel if (sockp->pcs_vpp2 != sockp->pcs_vpp1) { 38682305Sstevel /* must be the same if one not zero */ 38692305Sstevel if (sockp->pcs_vpp1 != 0 && 38702305Sstevel sockp->pcs_vpp2 != 0) { 38712305Sstevel cmn_err(CE_WARN, 38722305Sstevel "%s%d: Bad Power Request " 38732305Sstevel "(Vpp1/2 not the same)\n", 38742305Sstevel ddi_get_name(pcic->dip), 38752305Sstevel ddi_get_instance(pcic->dip)); 38762305Sstevel return (BAD_VPP); 38772305Sstevel } 38782305Sstevel } 38792305Sstevel powerlevel &= ~(3<<2); 38802305Sstevel } 38812305Sstevel 38822305Sstevel #if defined(PCIC_DEBUG) 38832305Sstevel if (pcic_debug) { 38842305Sstevel cmn_err(CE_CONT, "\tpowerlevel=%x, ind=%x\n", 38852305Sstevel powerlevel, ind); 38862305Sstevel } 38872305Sstevel #endif 38882305Sstevel } 38892305Sstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 38902305Sstevel 38912305Sstevel /* turn socket->IREQRouting off while programming */ 38922305Sstevel interrupt = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT); 38932305Sstevel interrupt &= ~PCIC_INTR_MASK; 38942305Sstevel if (pcic->pc_flags & PCF_USE_SMI) 38952305Sstevel interrupt |= PCIC_INTR_ENABLE; 38962305Sstevel pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, interrupt); 38972305Sstevel 38982305Sstevel switch (pcic->pc_type) { 3899*7656SSherry.Moore@Sun.COM case PCIC_INTEL_i82092: 39002305Sstevel pcic_82092_smiirq_ctl(pcic, socket->socket, PCIC_82092_CTL_IRQ, 3901*7656SSherry.Moore@Sun.COM PCIC_82092_INT_DISABLE); 39022305Sstevel break; 3903*7656SSherry.Moore@Sun.COM default: 39042305Sstevel break; 39052305Sstevel } /* switch */ 39062305Sstevel 39072305Sstevel /* the SCIntMask specifies events to detect */ 39082305Sstevel mirq = pcic_getb(pcic, socket->socket, PCIC_MANAGEMENT_INT); 39092305Sstevel 39102305Sstevel #if defined(PCIC_DEBUG) 39112305Sstevel if (pcic_debug) 39122305Sstevel cmn_err(CE_CONT, 3913*7656SSherry.Moore@Sun.COM "\tSCIntMask=%x, interrupt=%x, mirq=%x\n", 3914*7656SSherry.Moore@Sun.COM socket->SCIntMask, interrupt, mirq); 39152305Sstevel #endif 39162305Sstevel mirq &= ~(PCIC_BD_DETECT|PCIC_BW_DETECT|PCIC_RD_DETECT); 39172305Sstevel pcic_putb(pcic, socket->socket, PCIC_MANAGEMENT_INT, 39182305Sstevel mirq & ~PCIC_CHANGE_MASK); 39192305Sstevel 39202305Sstevel /* save the mask we want to use */ 39212305Sstevel sockp->pcs_intmask = socket->SCIntMask; 39222305Sstevel 39232305Sstevel /* 39242305Sstevel * Until there is a card present it's not worth enabling 39252305Sstevel * any interrupts except "Card detect". This is done 39262305Sstevel * elsewhere in the driver so don't change things if 39272305Sstevel * there is no card! 39282305Sstevel */ 39292305Sstevel if (sockp->pcs_flags & PCS_CARD_PRESENT) { 39302305Sstevel 39312305Sstevel /* now update the hardware to reflect events desired */ 39322305Sstevel if (sockp->pcs_intmask & SBM_BVD1 || socket->IFType == IF_IO) 39332305Sstevel mirq |= PCIC_BD_DETECT; 39342305Sstevel 39352305Sstevel if (sockp->pcs_intmask & SBM_BVD2) 39362305Sstevel mirq |= PCIC_BW_DETECT; 39372305Sstevel 39382305Sstevel if (sockp->pcs_intmask & SBM_RDYBSY) 39392305Sstevel mirq |= PCIC_RD_DETECT; 39402305Sstevel 39412305Sstevel if (sockp->pcs_intmask & SBM_CD) 39422305Sstevel mirq |= PCIC_CD_DETECT; 39432305Sstevel } 39442305Sstevel 39452305Sstevel if (sockp->pcs_flags & PCS_READY) { 39462305Sstevel /* 39472305Sstevel * card just came ready. 39482305Sstevel * make sure enough time elapses 39492305Sstevel * before touching it. 39502305Sstevel */ 39512305Sstevel sockp->pcs_flags &= ~PCS_READY; 39522305Sstevel pcic_mswait(pcic, socket->socket, 10); 39532305Sstevel } 39542305Sstevel 39552305Sstevel #if defined(PCIC_DEBUG) 39562305Sstevel if (pcic_debug) { 39572305Sstevel cmn_err(CE_CONT, "\tstatus change set to %x\n", mirq); 39582305Sstevel } 39592305Sstevel #endif 39602305Sstevel 39612305Sstevel switch (pcic->pc_type) { 3962*7656SSherry.Moore@Sun.COM case PCIC_I82365SL: 3963*7656SSherry.Moore@Sun.COM case PCIC_VADEM: 3964*7656SSherry.Moore@Sun.COM case PCIC_VADEM_VG469: 39652305Sstevel /* 39662305Sstevel * The Intel version has different options. This is a 39672305Sstevel * special case of GPI which might be used for eject 39682305Sstevel */ 39692305Sstevel 39702305Sstevel irq = pcic_getb(pcic, socket->socket, PCIC_CARD_DETECT); 39712305Sstevel if (sockp->pcs_intmask & (SBM_EJECT|SBM_INSERT) && 39722305Sstevel pcic->pc_flags & PCF_GPI_EJECT) { 39732305Sstevel irq |= PCIC_GPI_ENABLE; 39742305Sstevel } else { 39752305Sstevel irq &= ~PCIC_GPI_ENABLE; 39762305Sstevel } 39772305Sstevel pcic_putb(pcic, socket->socket, PCIC_CARD_DETECT, irq); 39782305Sstevel break; 3979*7656SSherry.Moore@Sun.COM case PCIC_CL_PD6710: 3980*7656SSherry.Moore@Sun.COM case PCIC_CL_PD6722: 39812305Sstevel if (socket->IFType == IF_IO) { 39822305Sstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_2, 0x0); 39832305Sstevel value = pcic_getb(pcic, socket->socket, 3984*7656SSherry.Moore@Sun.COM PCIC_MISC_CTL_1); 39852305Sstevel if (pcic->pc_flags & PCF_AUDIO) 39862305Sstevel value |= PCIC_MC_SPEAKER_ENB; 39872305Sstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1, 3988*7656SSherry.Moore@Sun.COM value); 39892305Sstevel } else { 39902305Sstevel value = pcic_getb(pcic, socket->socket, 3991*7656SSherry.Moore@Sun.COM PCIC_MISC_CTL_1); 39922305Sstevel value &= ~PCIC_MC_SPEAKER_ENB; 39932305Sstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1, 3994*7656SSherry.Moore@Sun.COM value); 39952305Sstevel } 39962305Sstevel break; 3997*7656SSherry.Moore@Sun.COM case PCIC_CL_PD6729: 3998*7656SSherry.Moore@Sun.COM case PCIC_CL_PD6730: 3999*7656SSherry.Moore@Sun.COM case PCIC_CL_PD6832: 40002305Sstevel value = pcic_getb(pcic, socket->socket, PCIC_MISC_CTL_1); 40012305Sstevel if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) { 4002*7656SSherry.Moore@Sun.COM value |= PCIC_MC_SPEAKER_ENB; 40032305Sstevel } else { 4004*7656SSherry.Moore@Sun.COM value &= ~PCIC_MC_SPEAKER_ENB; 40052305Sstevel } 40062305Sstevel 40072305Sstevel if (pcic_power[sockp->pcs_vcc].PowerLevel == 33) 40082305Sstevel value |= PCIC_MC_3VCC; 40092305Sstevel else 40102305Sstevel value &= ~PCIC_MC_3VCC; 40112305Sstevel 40122305Sstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1, value); 40132305Sstevel break; 40142305Sstevel 4015*7656SSherry.Moore@Sun.COM case PCIC_O2_OZ6912: 40162305Sstevel value = pcic_getcb(pcic, CB_MISCCTRL); 40172305Sstevel if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) 40182305Sstevel value |= (1<<25); 40192305Sstevel else 40202305Sstevel value &= ~(1<<25); 40212305Sstevel pcic_putcb(pcic, CB_MISCCTRL, value); 40222305Sstevel if (pcic_power[sockp->pcs_vcc].PowerLevel == 33) 40232305Sstevel powerlevel |= 0x08; 40242305Sstevel break; 40252305Sstevel 4026*7656SSherry.Moore@Sun.COM case PCIC_TI_PCI1250: 4027*7656SSherry.Moore@Sun.COM case PCIC_TI_PCI1221: 4028*7656SSherry.Moore@Sun.COM case PCIC_TI_PCI1225: 4029*7656SSherry.Moore@Sun.COM case PCIC_TI_PCI1410: 4030*7656SSherry.Moore@Sun.COM case PCIC_ENE_1410: 4031*7656SSherry.Moore@Sun.COM case PCIC_TI_PCI1510: 4032*7656SSherry.Moore@Sun.COM case PCIC_TI_PCI1520: 4033*7656SSherry.Moore@Sun.COM case PCIC_TI_PCI1420: 4034*7656SSherry.Moore@Sun.COM case PCIC_ENE_1420: 40352305Sstevel value = ddi_get8(pcic->cfg_handle, 40362305Sstevel pcic->cfgaddr + PCIC_CRDCTL_REG); 40372305Sstevel if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) { 40382305Sstevel value |= PCIC_CRDCTL_SPKR_ENBL; 40392305Sstevel } else { 40402305Sstevel value &= ~PCIC_CRDCTL_SPKR_ENBL; 40412305Sstevel } 40422305Sstevel ddi_put8(pcic->cfg_handle, 40432305Sstevel pcic->cfgaddr + PCIC_CRDCTL_REG, value); 40442305Sstevel if (pcic_power[sockp->pcs_vcc].PowerLevel == 33) 40452305Sstevel powerlevel |= 0x08; 40462305Sstevel break; 40472305Sstevel } 40482305Sstevel 40492305Sstevel /* 40502305Sstevel * ctlind processing -- we can ignore this 40512305Sstevel * there aren't any outputs on the chip for this and 40522305Sstevel * the GUI will display what it thinks is correct 40532305Sstevel */ 40542305Sstevel 40552305Sstevel /* 40562305Sstevel * If outputs are enabled and the power is going off 40572305Sstevel * turn off outputs first. 40582305Sstevel */ 40592305Sstevel 40602305Sstevel /* power setup -- if necessary */ 40612305Sstevel orig_pwrctl = pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL); 40622305Sstevel if ((orig_pwrctl & POWER_OUTPUT_ENABLE) && sockp->pcs_vcc == 0) { 40632305Sstevel orig_pwrctl &= ~POWER_OUTPUT_ENABLE; 40642305Sstevel pcic_putb(pcic, socket->socket, 40652305Sstevel PCIC_POWER_CONTROL, orig_pwrctl); 40662305Sstevel (void) pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL); 40672305Sstevel } 40682305Sstevel 40692305Sstevel if (pcic->pc_flags & PCF_CBPWRCTL) { 40702305Sstevel value = pcic_cbus_powerctl(pcic, socket->socket); 40712305Sstevel powerlevel = 0; 40722305Sstevel } else 40732305Sstevel value = pcic_exca_powerctl(pcic, socket->socket, powerlevel); 40742305Sstevel 40752305Sstevel if (value != SUCCESS) { 40762305Sstevel mutex_exit(&pcic->pc_lock); 40772305Sstevel return (value); 40782305Sstevel } 40792305Sstevel 40802305Sstevel /* 40812305Sstevel * If outputs were disabled and the power is going on 40822305Sstevel * turn on outputs afterwards. 40832305Sstevel */ 40842305Sstevel if (!(orig_pwrctl & POWER_OUTPUT_ENABLE) && sockp->pcs_vcc != 0) { 40852305Sstevel orig_pwrctl = pcic_getb(pcic, socket->socket, 40862305Sstevel PCIC_POWER_CONTROL); 40872305Sstevel orig_pwrctl |= POWER_OUTPUT_ENABLE; 40882305Sstevel pcic_putb(pcic, socket->socket, 40892305Sstevel PCIC_POWER_CONTROL, orig_pwrctl); 40902305Sstevel (void) pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL); 40912305Sstevel } 40922305Sstevel 40932305Sstevel /* 40942305Sstevel * Once we have done the power stuff can re-enable management 40952305Sstevel * interrupts. 40962305Sstevel */ 40972305Sstevel pcic_putb(pcic, socket->socket, PCIC_MANAGEMENT_INT, mirq); 40982305Sstevel 40992305Sstevel #if defined(PCIC_DEBUG) 41002305Sstevel pcic_err(dip, 8, "\tmanagement int set to %x pwrctl to 0x%x " 41012305Sstevel "cbctl 0x%x\n", 41022305Sstevel mirq, pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL), 41032305Sstevel pcic_getcb(pcic, CB_CONTROL)); 41042305Sstevel #endif 41052305Sstevel 41062305Sstevel /* irq processing */ 41072305Sstevel if (socket->IFType == IF_IO) { 41082305Sstevel /* IRQ only for I/O */ 41092305Sstevel irq = socket->IREQRouting & PCIC_INTR_MASK; 41102305Sstevel value = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT); 41112305Sstevel value &= ~PCIC_INTR_MASK; 41122305Sstevel 41132305Sstevel /* to enable I/O operation */ 41142305Sstevel value |= PCIC_IO_CARD | PCIC_RESET; 41152305Sstevel sockp->pcs_flags |= PCS_CARD_IO; 41162305Sstevel if (irq != sockp->pcs_irq) { 41172305Sstevel if (sockp->pcs_irq != 0) 41182305Sstevel cmn_err(CE_CONT, 4119*7656SSherry.Moore@Sun.COM "SetSocket: IRQ mismatch %x != %x!\n", 4120*7656SSherry.Moore@Sun.COM irq, sockp->pcs_irq); 41212305Sstevel else 41222305Sstevel sockp->pcs_irq = irq; 41232305Sstevel } 41242305Sstevel irq = sockp->pcs_irq; 41252305Sstevel 41262305Sstevel pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, value); 41272305Sstevel if (socket->IREQRouting & IRQ_ENABLE) { 41282305Sstevel pcic_enable_io_intr(pcic, socket->socket, irq); 41292305Sstevel sockp->pcs_flags |= PCS_IRQ_ENABLED; 41302305Sstevel } else { 41312305Sstevel pcic_disable_io_intr(pcic, socket->socket); 41322305Sstevel sockp->pcs_flags &= ~PCS_IRQ_ENABLED; 41332305Sstevel } 41342305Sstevel #if defined(PCIC_DEBUG) 41352305Sstevel if (pcic_debug) { 41362305Sstevel cmn_err(CE_CONT, 4137*7656SSherry.Moore@Sun.COM "\tsocket type is I/O and irq %x is %s\n", irq, 4138*7656SSherry.Moore@Sun.COM (socket->IREQRouting & IRQ_ENABLE) ? 4139*7656SSherry.Moore@Sun.COM "enabled" : "not enabled"); 41402305Sstevel xxdmp_all_regs(pcic, socket->socket, 20); 41412305Sstevel } 41422305Sstevel #endif 41432305Sstevel } else { 41442305Sstevel /* make sure I/O mode is off */ 41452305Sstevel 41462305Sstevel sockp->pcs_irq = 0; 41472305Sstevel 41482305Sstevel value = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT); 41492305Sstevel value &= ~PCIC_IO_CARD; 41502305Sstevel pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, value); 41512305Sstevel pcic_disable_io_intr(pcic, socket->socket); 41522305Sstevel sockp->pcs_flags &= ~(PCS_CARD_IO|PCS_IRQ_ENABLED); 41532305Sstevel } 41542305Sstevel 41552305Sstevel sockp->pcs_state &= ~socket->State; 41562305Sstevel 41572305Sstevel mutex_exit(&pcic->pc_lock); 41582305Sstevel return (SUCCESS); 41592305Sstevel } 41602305Sstevel 41612305Sstevel /* 41622305Sstevel * pcic_inquire_socket() 41632305Sstevel * SocketServices InquireSocket function 41642305Sstevel * returns basic characteristics of the socket 41652305Sstevel */ 41662305Sstevel /*ARGSUSED*/ 41672305Sstevel static int 41682305Sstevel pcic_inquire_socket(dev_info_t *dip, inquire_socket_t *socket) 41692305Sstevel { 41702305Sstevel anp_t *anp = ddi_get_driver_private(dip); 41712305Sstevel pcicdev_t *pcic = anp->an_private; 41722305Sstevel int value; 41732305Sstevel 41742305Sstevel socket->SCIntCaps = PCIC_DEFAULT_INT_CAPS; 41752305Sstevel socket->SCRptCaps = PCIC_DEFAULT_RPT_CAPS; 41762305Sstevel socket->CtlIndCaps = PCIC_DEFAULT_CTL_CAPS; 41772305Sstevel value = pcic->pc_sockets[socket->socket].pcs_flags; 41782305Sstevel socket->SocketCaps = (value & PCS_SOCKET_IO) ? IF_IO : IF_MEMORY; 41792305Sstevel socket->ActiveHigh = 0; 41802305Sstevel /* these are the usable IRQs */ 41812305Sstevel socket->ActiveLow = 0xfff0; 41822305Sstevel return (SUCCESS); 41832305Sstevel } 41842305Sstevel 41852305Sstevel /* 41862305Sstevel * pcic_inquire_window() 41872305Sstevel * SocketServices InquireWindow function 41882305Sstevel * returns detailed characteristics of the window 41892305Sstevel * this is where windows get tied to sockets 41902305Sstevel */ 41912305Sstevel /*ARGSUSED*/ 41922305Sstevel static int 41932305Sstevel pcic_inquire_window(dev_info_t *dip, inquire_window_t *window) 41942305Sstevel { 41952305Sstevel int type, socket; 41962305Sstevel 41972305Sstevel type = window->window % PCIC_NUMWINSOCK; 41982305Sstevel socket = window->window / PCIC_NUMWINSOCK; 41992305Sstevel 42002305Sstevel #if defined(PCIC_DEBUG) 42012305Sstevel if (pcic_debug >= 8) 42022305Sstevel cmn_err(CE_CONT, 4203*7656SSherry.Moore@Sun.COM "pcic_inquire_window: window = %d/%d socket=%d\n", 4204*7656SSherry.Moore@Sun.COM window->window, type, socket); 42052305Sstevel #endif 42062305Sstevel if (type < PCIC_IOWINDOWS) { 42072305Sstevel window->WndCaps = WC_IO|WC_WAIT; 42082305Sstevel type = IF_IO; 42092305Sstevel } else { 42102305Sstevel window->WndCaps = WC_COMMON|WC_ATTRIBUTE|WC_WAIT; 42112305Sstevel type = IF_MEMORY; 42122305Sstevel } 42132305Sstevel 42142305Sstevel /* initialize the socket map - one socket per window */ 42152305Sstevel PR_ZERO(window->Sockets); 42162305Sstevel PR_SET(window->Sockets, socket); 42172305Sstevel 42182305Sstevel if (type == IF_IO) { 42192305Sstevel iowin_char_t *io; 42202305Sstevel io = &window->iowin_char; 42212305Sstevel io->IOWndCaps = WC_BASE|WC_SIZE|WC_WENABLE|WC_8BIT| 4222*7656SSherry.Moore@Sun.COM WC_16BIT; 42232305Sstevel io->FirstByte = (baseaddr_t)IOMEM_FIRST; 42242305Sstevel io->LastByte = (baseaddr_t)IOMEM_LAST; 42252305Sstevel io->MinSize = IOMEM_MIN; 42262305Sstevel io->MaxSize = IOMEM_MAX; 42272305Sstevel io->ReqGran = IOMEM_GRAN; 42282305Sstevel io->AddrLines = IOMEM_DECODE; 42292305Sstevel io->EISASlot = 0; 42302305Sstevel } else { 42312305Sstevel mem_win_char_t *mem; 42322305Sstevel mem = &window->mem_win_char; 42332305Sstevel mem->MemWndCaps = WC_BASE|WC_SIZE|WC_WENABLE|WC_8BIT| 4234*7656SSherry.Moore@Sun.COM WC_16BIT|WC_WP; 42352305Sstevel 42362305Sstevel mem->FirstByte = (baseaddr_t)MEM_FIRST; 42372305Sstevel mem->LastByte = (baseaddr_t)MEM_LAST; 42382305Sstevel 42392305Sstevel mem->MinSize = MEM_MIN; 42402305Sstevel mem->MaxSize = MEM_MAX; 42412305Sstevel mem->ReqGran = PCIC_PAGE; 42422305Sstevel mem->ReqBase = 0; 42432305Sstevel mem->ReqOffset = PCIC_PAGE; 42442305Sstevel mem->Slowest = MEM_SPEED_MAX; 42452305Sstevel mem->Fastest = MEM_SPEED_MIN; 42462305Sstevel } 42472305Sstevel return (SUCCESS); 42482305Sstevel } 42492305Sstevel 42502305Sstevel /* 42512305Sstevel * pcic_get_adapter() 42522305Sstevel * SocketServices GetAdapter function 42532305Sstevel * this is nearly a no-op. 42542305Sstevel */ 42552305Sstevel /*ARGSUSED*/ 42562305Sstevel static int 42572305Sstevel pcic_get_adapter(dev_info_t *dip, get_adapter_t *adapt) 42582305Sstevel { 42592305Sstevel anp_t *anp = ddi_get_driver_private(dip); 42602305Sstevel pcicdev_t *pcic = anp->an_private; 42612305Sstevel 42622305Sstevel if (pcic->pc_flags & PCF_INTRENAB) 42632305Sstevel adapt->SCRouting = IRQ_ENABLE; 42642305Sstevel adapt->state = 0; 42652305Sstevel return (SUCCESS); 42662305Sstevel } 42672305Sstevel 42682305Sstevel /* 42692305Sstevel * pcic_get_page() 42702305Sstevel * SocketServices GetPage function 42712305Sstevel * returns info about the window 42722305Sstevel */ 42732305Sstevel /*ARGSUSED*/ 42742305Sstevel static int 42752305Sstevel pcic_get_page(dev_info_t *dip, get_page_t *page) 42762305Sstevel { 42772305Sstevel anp_t *anp = ddi_get_driver_private(dip); 42782305Sstevel pcicdev_t *pcic = anp->an_private; 42792305Sstevel int socket, window; 42802305Sstevel pcs_memwin_t *winp; 42812305Sstevel 42822305Sstevel socket = page->window / PCIC_NUMWINSOCK; 42832305Sstevel window = page->window % PCIC_NUMWINSOCK; 42842305Sstevel 42852305Sstevel /* I/O windows are the first two */ 42862305Sstevel if (window < PCIC_IOWINDOWS || socket >= pcic->pc_numsockets) { 42872305Sstevel return (BAD_WINDOW); 42882305Sstevel } 42892305Sstevel 42902305Sstevel winp = &pcic->pc_sockets[socket].pcs_windows[window].mem; 42912305Sstevel 42922305Sstevel if (page->page != 0) 42932305Sstevel return (BAD_PAGE); 42942305Sstevel 42952305Sstevel page->state = 0; 42962305Sstevel if (winp->pcw_status & PCW_ENABLED) 42972305Sstevel page->state |= PS_ENABLED; 42982305Sstevel if (winp->pcw_status & PCW_ATTRIBUTE) 42992305Sstevel page->state |= PS_ATTRIBUTE; 43002305Sstevel if (winp->pcw_status & PCW_WP) 43012305Sstevel page->state |= PS_WP; 43022305Sstevel 43032305Sstevel page->offset = (off_t)winp->pcw_offset; 43042305Sstevel 43052305Sstevel return (SUCCESS); 43062305Sstevel } 43072305Sstevel 43082305Sstevel /* 43092305Sstevel * pcic_get_socket() 43102305Sstevel * SocketServices GetSocket 43112305Sstevel * returns information about the current socket setting 43122305Sstevel */ 43132305Sstevel /*ARGSUSED*/ 43142305Sstevel static int 43152305Sstevel pcic_get_socket(dev_info_t *dip, get_socket_t *socket) 43162305Sstevel { 43172305Sstevel anp_t *anp = ddi_get_driver_private(dip); 43182305Sstevel pcicdev_t *pcic = anp->an_private; 43192305Sstevel int socknum, irq_enabled; 43202305Sstevel pcic_socket_t *sockp; 43212305Sstevel 43222305Sstevel socknum = socket->socket; 43232305Sstevel sockp = &pcic->pc_sockets[socknum]; 43242305Sstevel 43252305Sstevel socket->SCIntMask = sockp->pcs_intmask; 43262305Sstevel sockp->pcs_state = pcic_card_state(pcic, sockp); 43272305Sstevel 43282305Sstevel socket->state = sockp->pcs_state; 43292305Sstevel if (socket->state & SBM_CD) { 43302305Sstevel socket->VccLevel = sockp->pcs_vcc; 43312305Sstevel socket->Vpp1Level = sockp->pcs_vpp1; 43322305Sstevel socket->Vpp2Level = sockp->pcs_vpp2; 43332305Sstevel irq_enabled = (sockp->pcs_flags & PCS_IRQ_ENABLED) ? 43342305Sstevel IRQ_ENABLE : 0; 43352305Sstevel socket->IRQRouting = sockp->pcs_irq | irq_enabled; 43362305Sstevel socket->IFType = (sockp->pcs_flags & PCS_CARD_IO) ? 43372305Sstevel IF_IO : IF_MEMORY; 43382305Sstevel } else { 43392305Sstevel socket->VccLevel = 0; 43402305Sstevel socket->Vpp1Level = 0; 43412305Sstevel socket->Vpp2Level = 0; 43422305Sstevel socket->IRQRouting = 0; 43432305Sstevel socket->IFType = IF_MEMORY; 43442305Sstevel } 43452305Sstevel socket->CtlInd = 0; /* no indicators */ 43462305Sstevel 43472305Sstevel return (SUCCESS); 43482305Sstevel } 43492305Sstevel 43502305Sstevel /* 43512305Sstevel * pcic_get_status() 43522305Sstevel * SocketServices GetStatus 43532305Sstevel * returns status information about the PC Card in 43542305Sstevel * the selected socket 43552305Sstevel */ 43562305Sstevel /*ARGSUSED*/ 43572305Sstevel static int 43582305Sstevel pcic_get_status(dev_info_t *dip, get_ss_status_t *status) 43592305Sstevel { 43602305Sstevel anp_t *anp = ddi_get_driver_private(dip); 43612305Sstevel pcicdev_t *pcic = anp->an_private; 43622305Sstevel int socknum, irq_enabled; 43632305Sstevel pcic_socket_t *sockp; 43642305Sstevel 43652305Sstevel socknum = status->socket; 43662305Sstevel sockp = &pcic->pc_sockets[socknum]; 43672305Sstevel 43682305Sstevel status->CardState = pcic_card_state(pcic, sockp); 43692305Sstevel status->SocketState = sockp->pcs_state; 43702305Sstevel status->CtlInd = 0; /* no indicators */ 43712305Sstevel 43722305Sstevel if (sockp->pcs_flags & PCS_CARD_PRESENT) 43732305Sstevel status->SocketState |= SBM_CD; 43742305Sstevel if (status->CardState & SBM_CD) { 43752305Sstevel irq_enabled = (sockp->pcs_flags & PCS_CARD_ENABLED) ? 43762305Sstevel IRQ_ENABLE : 0; 43772305Sstevel status->IRQRouting = sockp->pcs_irq | irq_enabled; 43782305Sstevel status->IFType = (sockp->pcs_flags & PCS_CARD_IO) ? 43792305Sstevel IF_IO : IF_MEMORY; 43802305Sstevel } else { 43812305Sstevel status->IRQRouting = 0; 43822305Sstevel status->IFType = IF_MEMORY; 43832305Sstevel } 43842305Sstevel 43852305Sstevel #if defined(PCIC_DEBUG) 43862305Sstevel if (pcic_debug >= 8) 43872305Sstevel cmn_err(CE_CONT, "pcic_get_status: socket=%d, CardState=%x," 4388*7656SSherry.Moore@Sun.COM "SocketState=%x\n", 4389*7656SSherry.Moore@Sun.COM socknum, status->CardState, status->SocketState); 43902305Sstevel #endif 43912305Sstevel switch (pcic->pc_type) { 43922305Sstevel uint32_t present_state; 43932305Sstevel case PCIC_TI_PCI1410: 43942305Sstevel case PCIC_TI_PCI1520: 43952305Sstevel case PCIC_TI_PCI1420: 43962305Sstevel case PCIC_ENE_1420: 43972305Sstevel case PCIC_TOSHIBA_TOPIC100: 43982305Sstevel case PCIC_TOSHIBA_TOPIC95: 43992305Sstevel case PCIC_TOSHIBA_VENDOR: 44002305Sstevel case PCIC_O2MICRO_VENDOR: 44012305Sstevel case PCIC_TI_VENDOR: 44022305Sstevel case PCIC_RICOH_VENDOR: 44032305Sstevel present_state = pcic_getcb(pcic, CB_PRESENT_STATE); 44042305Sstevel if (present_state & PCIC_CB_CARD) 44052305Sstevel status->IFType = IF_CARDBUS; 44062305Sstevel #if defined(PCIC_DEBUG) 44072305Sstevel if (pcic_debug >= 8) 4408*7656SSherry.Moore@Sun.COM cmn_err(CE_CONT, 4409*7656SSherry.Moore@Sun.COM "pcic_get_status: present_state=0x%x\n", 4410*7656SSherry.Moore@Sun.COM present_state); 44112305Sstevel #endif 44122305Sstevel break; 44132305Sstevel default: 44142305Sstevel break; 44152305Sstevel } 44162305Sstevel 44172305Sstevel return (SUCCESS); 44182305Sstevel } 44192305Sstevel 44202305Sstevel /* 44212305Sstevel * pcic_get_window() 44222305Sstevel * SocketServices GetWindow function 44232305Sstevel * returns state information about the specified window 44242305Sstevel */ 44252305Sstevel /*ARGSUSED*/ 44262305Sstevel static int 44272305Sstevel pcic_get_window(dev_info_t *dip, get_window_t *window) 44282305Sstevel { 44292305Sstevel anp_t *anp = ddi_get_driver_private(dip); 44302305Sstevel pcicdev_t *pcic = anp->an_private; 44312305Sstevel int socket, win; 44322305Sstevel pcic_socket_t *sockp; 44332305Sstevel pcs_memwin_t *winp; 44342305Sstevel 44352305Sstevel socket = window->window / PCIC_NUMWINSOCK; 44362305Sstevel win = window->window % PCIC_NUMWINSOCK; 44372305Sstevel #if defined(PCIC_DEBUG) 44382305Sstevel if (pcic_debug) { 44392305Sstevel cmn_err(CE_CONT, "pcic_get_window(socket=%d, window=%d)\n", 4440*7656SSherry.Moore@Sun.COM socket, win); 44412305Sstevel } 44422305Sstevel #endif 44432305Sstevel 44442305Sstevel if (socket > pcic->pc_numsockets) 44452305Sstevel return (BAD_WINDOW); 44462305Sstevel 44472305Sstevel sockp = &pcic->pc_sockets[socket]; 44482305Sstevel winp = &sockp->pcs_windows[win].mem; 44492305Sstevel 44502305Sstevel window->socket = socket; 44512305Sstevel window->size = winp->pcw_len; 44522305Sstevel window->speed = winp->pcw_speed; 44532305Sstevel window->handle = (ddi_acc_handle_t)winp->pcw_handle; 44542305Sstevel window->base = (uint32_t)winp->pcw_base + winp->pcw_offset; 44552305Sstevel 44562305Sstevel if (win >= PCIC_IOWINDOWS) { 44572305Sstevel window->state = 0; 44582305Sstevel } else { 44592305Sstevel window->state = WS_IO; 44602305Sstevel } 44612305Sstevel if (winp->pcw_status & PCW_ENABLED) 44622305Sstevel window->state |= WS_ENABLED; 44632305Sstevel 44642305Sstevel if (winp->pcw_status & PCS_CARD_16BIT) 44652305Sstevel window->state |= WS_16BIT; 44662305Sstevel #if defined(PCIC_DEBUG) 44672305Sstevel if (pcic_debug) 44682305Sstevel cmn_err(CE_CONT, "\tsize=%d, speed=%d, base=%p, state=%x\n", 4469*7656SSherry.Moore@Sun.COM window->size, (unsigned)window->speed, 4470*7656SSherry.Moore@Sun.COM (void *)window->handle, window->state); 44712305Sstevel #endif 44722305Sstevel 44732305Sstevel return (SUCCESS); 44742305Sstevel } 44752305Sstevel 44762305Sstevel /* 44772305Sstevel * pcic_ll_reset 44782305Sstevel * low level reset 44792305Sstevel * separated out so it can be called when already locked 44802305Sstevel * 44812305Sstevel * There are two variables that control the RESET timing: 44822305Sstevel * pcic_prereset_time - time in mS before asserting RESET 44832305Sstevel * pcic_reset_time - time in mS to assert RESET 44842305Sstevel * 44852305Sstevel */ 44862305Sstevel int pcic_prereset_time = 1; 44872305Sstevel int pcic_reset_time = 10; 44882305Sstevel int pcic_postreset_time = 20; 44892305Sstevel int pcic_vpp_is_vcc_during_reset = 0; 44902305Sstevel 44912305Sstevel static int 44922305Sstevel pcic_ll_reset(pcicdev_t *pcic, int socket) 44932305Sstevel { 44942305Sstevel int windowbits, iobits; 44952305Sstevel uint32_t pwr; 44962305Sstevel 44972305Sstevel /* save windows that were on */ 44982305Sstevel windowbits = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE); 44992305Sstevel if (pcic_reset_time == 0) 4500*7656SSherry.Moore@Sun.COM return (windowbits); 45012305Sstevel /* turn all windows off */ 45022305Sstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, 0); 45032305Sstevel 45042305Sstevel #if defined(PCIC_DEBUG) 45052305Sstevel pcic_err(pcic->dip, 6, 4506*7656SSherry.Moore@Sun.COM "pcic_ll_reset(socket %d) powerlevel=%x cbctl 0x%x cbps 0x%x\n", 4507*7656SSherry.Moore@Sun.COM socket, pcic_getb(pcic, socket, PCIC_POWER_CONTROL), 4508*7656SSherry.Moore@Sun.COM pcic_getcb(pcic, CB_CONTROL), 4509*7656SSherry.Moore@Sun.COM pcic_getcb(pcic, CB_PRESENT_STATE)); 45102305Sstevel #endif 45112305Sstevel 45122305Sstevel if (pcic_vpp_is_vcc_during_reset) { 45132305Sstevel 45142305Sstevel /* 45152305Sstevel * Set VPP to VCC for the duration of the reset - for aironet 45162305Sstevel * card. 45172305Sstevel */ 4518*7656SSherry.Moore@Sun.COM if (pcic->pc_flags & PCF_CBPWRCTL) { 45192305Sstevel pwr = pcic_getcb(pcic, CB_CONTROL); 45202305Sstevel pcic_putcb(pcic, CB_CONTROL, (pwr&~CB_C_VPPMASK)|CB_C_VPPVCC); 45212305Sstevel (void) pcic_getcb(pcic, CB_CONTROL); 4522*7656SSherry.Moore@Sun.COM } else { 45232305Sstevel pwr = pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 45242305Sstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, 45252305Sstevel pwr | 1); 45262305Sstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 4527*7656SSherry.Moore@Sun.COM } 45282305Sstevel } 45292305Sstevel 45302305Sstevel if (pcic_prereset_time > 0) { 45312305Sstevel pcic_err(pcic->dip, 8, "pcic_ll_reset pre_wait %d mS\n", 45322305Sstevel pcic_prereset_time); 45332305Sstevel pcic_mswait(pcic, socket, pcic_prereset_time); 45342305Sstevel } 45352305Sstevel 45362305Sstevel /* turn interrupts off and start a reset */ 45372305Sstevel pcic_err(pcic->dip, 8, 4538*7656SSherry.Moore@Sun.COM "pcic_ll_reset turn interrupts off and start a reset\n"); 45392305Sstevel iobits = pcic_getb(pcic, socket, PCIC_INTERRUPT); 45402305Sstevel iobits &= ~(PCIC_INTR_MASK | PCIC_RESET); 45412305Sstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits); 45422305Sstevel (void) pcic_getb(pcic, socket, PCIC_INTERRUPT); 45432305Sstevel 45442305Sstevel switch (pcic->pc_type) { 4545*7656SSherry.Moore@Sun.COM case PCIC_INTEL_i82092: 45462305Sstevel pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ, 4547*7656SSherry.Moore@Sun.COM PCIC_82092_INT_DISABLE); 45482305Sstevel break; 4549*7656SSherry.Moore@Sun.COM default: 45502305Sstevel break; 45512305Sstevel } /* switch */ 45522305Sstevel 45532305Sstevel pcic->pc_sockets[socket].pcs_state = 0; 45542305Sstevel 45552305Sstevel if (pcic_reset_time > 0) { 45562305Sstevel pcic_err(pcic->dip, 8, "pcic_ll_reset reset_wait %d mS\n", 45572305Sstevel pcic_reset_time); 45582305Sstevel pcic_mswait(pcic, socket, pcic_reset_time); 45592305Sstevel } 45602305Sstevel 45612305Sstevel pcic_err(pcic->dip, 8, "pcic_ll_reset take it out of reset now\n"); 45622305Sstevel 45632305Sstevel /* take it out of RESET now */ 45642305Sstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, PCIC_RESET | iobits); 45652305Sstevel (void) pcic_getb(pcic, socket, PCIC_INTERRUPT); 45662305Sstevel 45672305Sstevel /* 45682305Sstevel * can't access the card for 20ms, but we really don't 45692305Sstevel * want to sit around that long. The pcic is still usable. 45702305Sstevel * memory accesses must wait for RDY to come up. 45712305Sstevel */ 45722305Sstevel if (pcic_postreset_time > 0) { 45732305Sstevel pcic_err(pcic->dip, 8, "pcic_ll_reset post_wait %d mS\n", 45742305Sstevel pcic_postreset_time); 45752305Sstevel pcic_mswait(pcic, socket, pcic_postreset_time); 45762305Sstevel } 45772305Sstevel 45782305Sstevel if (pcic_vpp_is_vcc_during_reset > 1) { 45792305Sstevel 45802305Sstevel /* 45812305Sstevel * Return VPP power to whatever it was before. 45822305Sstevel */ 4583*7656SSherry.Moore@Sun.COM if (pcic->pc_flags & PCF_CBPWRCTL) { 45842305Sstevel pcic_putcb(pcic, CB_CONTROL, pwr); 45852305Sstevel (void) pcic_getcb(pcic, CB_CONTROL); 4586*7656SSherry.Moore@Sun.COM } else { 45872305Sstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, pwr); 45882305Sstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 4589*7656SSherry.Moore@Sun.COM } 45902305Sstevel } 45912305Sstevel 45922305Sstevel pcic_err(pcic->dip, 7, "pcic_ll_reset returning 0x%x\n", windowbits); 45932305Sstevel 45942305Sstevel return (windowbits); 45952305Sstevel } 45962305Sstevel 45972305Sstevel /* 45982305Sstevel * pcic_reset_socket() 45992305Sstevel * SocketServices ResetSocket function 46002305Sstevel * puts the PC Card in the socket into the RESET state 46012305Sstevel * and then takes it out after the the cycle time 46022305Sstevel * The socket is back to initial state when done 46032305Sstevel */ 46042305Sstevel static int 46052305Sstevel pcic_reset_socket(dev_info_t *dip, int socket, int mode) 46062305Sstevel { 46072305Sstevel anp_t *anp = ddi_get_driver_private(dip); 46082305Sstevel pcicdev_t *pcic = anp->an_private; 46092305Sstevel int value; 46102305Sstevel int i, mint; 46112305Sstevel pcic_socket_t *sockp; 46122305Sstevel 46132305Sstevel #if defined(PCIC_DEBUG) 46142305Sstevel if (pcic_debug >= 8) 46152305Sstevel cmn_err(CE_CONT, "pcic_reset_socket(%p, %d, %d/%s)\n", 46162305Sstevel (void *)dip, socket, mode, 4617*7656SSherry.Moore@Sun.COM mode == RESET_MODE_FULL ? "full" : "partial"); 46182305Sstevel #endif 46192305Sstevel 46202305Sstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 46212305Sstevel 46222305Sstevel /* Turn off management interupts. */ 46232305Sstevel mint = pcic_getb(pcic, socket, PCIC_MANAGEMENT_INT); 46242305Sstevel pcic_putb(pcic, socket, PCIC_MANAGEMENT_INT, mint & ~PCIC_CHANGE_MASK); 46252305Sstevel 46262305Sstevel sockp = &pcic->pc_sockets[socket]; 46272305Sstevel 46282305Sstevel value = pcic_ll_reset(pcic, socket); 46292305Sstevel if (mode == RESET_MODE_FULL) { 46302305Sstevel /* disable and unmap all mapped windows */ 46312305Sstevel for (i = 0; i < PCIC_NUMWINSOCK; i++) { 46322305Sstevel if (i < PCIC_IOWINDOWS) { 46332305Sstevel if (sockp->pcs_windows[i].io.pcw_status & 46342305Sstevel PCW_MAPPED) { 46352305Sstevel pcs_iowin_t *io; 46362305Sstevel io = &sockp->pcs_windows[i].io; 46372305Sstevel io->pcw_status &= ~PCW_ENABLED; 46382305Sstevel } 46392305Sstevel } else { 46402305Sstevel if (sockp->pcs_windows[i].mem.pcw_status & 46412305Sstevel PCW_MAPPED) { 46422305Sstevel pcs_memwin_t *mem; 46432305Sstevel mem = &sockp->pcs_windows[i].mem; 46442305Sstevel mem->pcw_status &= ~PCW_ENABLED; 46452305Sstevel } 46462305Sstevel } 46472305Sstevel } 46482305Sstevel } else { 46492305Sstevel /* turn windows back on */ 46502305Sstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, value); 46512305Sstevel /* wait the rest of the time here */ 46522305Sstevel pcic_mswait(pcic, socket, 10); 46532305Sstevel } 46542305Sstevel pcic_putb(pcic, socket, PCIC_MANAGEMENT_INT, mint); 46552305Sstevel mutex_exit(&pcic->pc_lock); 46562305Sstevel return (SUCCESS); 46572305Sstevel } 46582305Sstevel 46592305Sstevel /* 46602305Sstevel * pcic_set_interrupt() 46612305Sstevel * SocketServices SetInterrupt function 46622305Sstevel */ 46632305Sstevel static int 46642305Sstevel pcic_set_interrupt(dev_info_t *dip, set_irq_handler_t *handler) 46652305Sstevel { 46662305Sstevel anp_t *anp = ddi_get_driver_private(dip); 46672305Sstevel pcicdev_t *pcic = anp->an_private; 46682305Sstevel int value = DDI_SUCCESS; 46692305Sstevel inthandler_t *intr; 46702305Sstevel 46712305Sstevel #if defined(PCIC_DEBUG) 46722305Sstevel if (pcic_debug) { 46732305Sstevel cmn_err(CE_CONT, 4674*7656SSherry.Moore@Sun.COM "pcic_set_interrupt: entered pc_intr_mode=0x%x\n", 4675*7656SSherry.Moore@Sun.COM pcic->pc_intr_mode); 46762305Sstevel cmn_err(CE_CONT, 4677*7656SSherry.Moore@Sun.COM "\t irq_top=%p handler=%p handler_id=%x\n", 4678*7656SSherry.Moore@Sun.COM (void *)pcic->irq_top, (void *)handler->handler, 4679*7656SSherry.Moore@Sun.COM handler->handler_id); 46802305Sstevel } 46812305Sstevel #endif 46822305Sstevel 46832305Sstevel /* 46842305Sstevel * If we're on a PCI bus, we route all IO IRQs through a single 46852305Sstevel * PCI interrupt (typically INT A#) so we don't have to do 46862305Sstevel * much other than add the caller to general interrupt handler 46872305Sstevel * and set some state. 46882305Sstevel */ 46892305Sstevel 46902305Sstevel intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP); 46912305Sstevel if (intr == NULL) 46922305Sstevel return (NO_RESOURCE); 46932305Sstevel 46942305Sstevel switch (pcic->pc_intr_mode) { 46952305Sstevel case PCIC_INTR_MODE_PCI_1: 46962305Sstevel /* 46972305Sstevel * We only allow above-lock-level IO IRQ handlers 46982305Sstevel * in the PCI bus case. 46992305Sstevel */ 47002305Sstevel 47012305Sstevel mutex_enter(&pcic->intr_lock); 47022305Sstevel 47032305Sstevel if (pcic->irq_top == NULL) { 4704*7656SSherry.Moore@Sun.COM pcic->irq_top = intr; 4705*7656SSherry.Moore@Sun.COM pcic->irq_current = pcic->irq_top; 47062305Sstevel } else { 4707*7656SSherry.Moore@Sun.COM while (pcic->irq_current->next != NULL) 47082305Sstevel pcic->irq_current = pcic->irq_current->next; 4709*7656SSherry.Moore@Sun.COM pcic->irq_current->next = intr; 4710*7656SSherry.Moore@Sun.COM pcic->irq_current = pcic->irq_current->next; 47112305Sstevel } 47122305Sstevel 47132305Sstevel pcic->irq_current->intr = 47142305Sstevel (ddi_intr_handler_t *)handler->handler; 47152305Sstevel pcic->irq_current->handler_id = handler->handler_id; 47162305Sstevel pcic->irq_current->arg1 = handler->arg1; 47172305Sstevel pcic->irq_current->arg2 = handler->arg2; 47182305Sstevel pcic->irq_current->socket = handler->socket; 47192305Sstevel 47202305Sstevel mutex_exit(&pcic->intr_lock); 47212305Sstevel 47222305Sstevel handler->iblk_cookie = &pcic->pc_pri; 47232305Sstevel handler->idev_cookie = &pcic->pc_dcookie; 47242305Sstevel break; 47252305Sstevel 47262305Sstevel default: 47272305Sstevel intr->intr = (ddi_intr_handler_t *)handler->handler; 47282305Sstevel intr->handler_id = handler->handler_id; 47292305Sstevel intr->arg1 = handler->arg1; 47302305Sstevel intr->arg2 = handler->arg2; 47312305Sstevel intr->socket = handler->socket; 47322305Sstevel intr->irq = handler->irq; 47332305Sstevel 47342305Sstevel /* 47352305Sstevel * need to revisit this to see if interrupts can be 47362305Sstevel * shared someday. Note that IRQ is set in the common 47372305Sstevel * code. 47382305Sstevel */ 47392305Sstevel mutex_enter(&pcic->pc_lock); 47402305Sstevel if (pcic->pc_handlers == NULL) { 47412305Sstevel pcic->pc_handlers = intr; 47422305Sstevel intr->next = intr->prev = intr; 47432305Sstevel } else { 47442305Sstevel insque(intr, pcic->pc_handlers); 47452305Sstevel } 47462305Sstevel mutex_exit(&pcic->pc_lock); 47472305Sstevel 47482305Sstevel break; 47492305Sstevel } 47502305Sstevel 47512305Sstevel /* 47522305Sstevel * need to fill in cookies in event of multiple high priority 47532305Sstevel * interrupt handlers on same IRQ 47542305Sstevel */ 47552305Sstevel 47562305Sstevel #if defined(PCIC_DEBUG) 47572305Sstevel if (pcic_debug) { 47582305Sstevel cmn_err(CE_CONT, 4759*7656SSherry.Moore@Sun.COM "pcic_set_interrupt: exit irq_top=%p value=%d\n", 4760*7656SSherry.Moore@Sun.COM (void *)pcic->irq_top, value); 47612305Sstevel } 47622305Sstevel #endif 47632305Sstevel 47642305Sstevel if (value == DDI_SUCCESS) { 47652305Sstevel return (SUCCESS); 47662305Sstevel } else { 47672305Sstevel return (BAD_IRQ); 47682305Sstevel } 47692305Sstevel } 47702305Sstevel 47712305Sstevel /* 47722305Sstevel * pcic_clear_interrupt() 47732305Sstevel * SocketServices ClearInterrupt function 47742305Sstevel * 47752305Sstevel * Interrupts for PCIC are complicated by the fact that we must 47762305Sstevel * follow several different models for interrupts. 47772305Sstevel * ISA: there is an interrupt per adapter and per socket and 47782305Sstevel * they can't be shared. 47792305Sstevel * PCI: some adapters have one PCI interrupt available while others 47802305Sstevel * have up to 4. Solaris may or may not allow us to use more 47812305Sstevel * than 1 so we essentially share them all at this point. 47822305Sstevel * Hybrid: PCI bridge but interrupts wired to host interrupt controller. 47832305Sstevel * This is like ISA but we have to fudge and create an intrspec 47842305Sstevel * that PCI's parent understands and bypass the PCI nexus. 47852305Sstevel * multifunction: this requires sharing the interrupts on a per-socket 47862305Sstevel * basis. 47872305Sstevel */ 47882305Sstevel static int 47892305Sstevel pcic_clear_interrupt(dev_info_t *dip, clear_irq_handler_t *handler) 47902305Sstevel { 47912305Sstevel anp_t *anp = ddi_get_driver_private(dip); 47922305Sstevel pcicdev_t *pcic = anp->an_private; 47932305Sstevel inthandler_t *intr, *prev, *current; 47942305Sstevel int i; 47952305Sstevel 47962305Sstevel /* 47972305Sstevel * If we're on a PCI bus, we route all IO IRQs through a single 47982305Sstevel * PCI interrupt (typically INT A#) so we don't have to do 47992305Sstevel * much other than remove the caller from the general 48002305Sstevel * interrupt handler callout list. 48012305Sstevel */ 48022305Sstevel 48032305Sstevel #if defined(PCIC_DEBUG) 48042305Sstevel if (pcic_debug) { 48052305Sstevel cmn_err(CE_CONT, 4806*7656SSherry.Moore@Sun.COM "pcic_clear_interrupt: entered pc_intr_mode=0x%x\n", 4807*7656SSherry.Moore@Sun.COM pcic->pc_intr_mode); 48082305Sstevel cmn_err(CE_CONT, 4809*7656SSherry.Moore@Sun.COM "\t irq_top=%p handler=%p handler_id=%x\n", 4810*7656SSherry.Moore@Sun.COM (void *)pcic->irq_top, (void *)handler->handler, 4811*7656SSherry.Moore@Sun.COM handler->handler_id); 48122305Sstevel } 48132305Sstevel #endif 48142305Sstevel 48152305Sstevel switch (pcic->pc_intr_mode) { 48162305Sstevel case PCIC_INTR_MODE_PCI_1: 48172305Sstevel 48182305Sstevel mutex_enter(&pcic->intr_lock); 48192305Sstevel if (pcic->irq_top == NULL) { 48202305Sstevel mutex_exit(&pcic->intr_lock); 48212305Sstevel return (BAD_IRQ); 48222305Sstevel } 48232305Sstevel 48242305Sstevel intr = NULL; 48252305Sstevel pcic->irq_current = pcic->irq_top; 48262305Sstevel 48272305Sstevel while ((pcic->irq_current != NULL) && 4828*7656SSherry.Moore@Sun.COM (pcic->irq_current->handler_id != 4829*7656SSherry.Moore@Sun.COM handler->handler_id)) { 48302305Sstevel intr = pcic->irq_current; 48312305Sstevel pcic->irq_current = pcic->irq_current->next; 48322305Sstevel } 48332305Sstevel 48342305Sstevel if (pcic->irq_current == NULL) { 48352305Sstevel mutex_exit(&pcic->intr_lock); 48362305Sstevel return (BAD_IRQ); 48372305Sstevel } 48382305Sstevel 48392305Sstevel if (intr != NULL) { 48402305Sstevel intr->next = pcic->irq_current->next; 48412305Sstevel } else { 48422305Sstevel pcic->irq_top = pcic->irq_current->next; 48432305Sstevel } 48442305Sstevel 48452305Sstevel current = pcic->irq_current; 48462305Sstevel pcic->irq_current = pcic->irq_top; 48472305Sstevel mutex_exit(&pcic->intr_lock); 48482305Sstevel kmem_free(current, sizeof (inthandler_t)); 48492305Sstevel 48502305Sstevel break; 48512305Sstevel 48522305Sstevel default: 48532305Sstevel 48542305Sstevel mutex_enter(&pcic->pc_lock); 48552305Sstevel intr = pcic_handlers; 48562305Sstevel prev = (inthandler_t *)&pcic_handlers; 48572305Sstevel 48582305Sstevel while (intr != NULL) { 4859*7656SSherry.Moore@Sun.COM if (intr->handler_id == handler->handler_id) { 48602305Sstevel i = intr->irq & PCIC_INTR_MASK; 48612305Sstevel if (--pcic_irq_map[i].count == 0) { 48622305Sstevel /* multi-handler form */ 48632305Sstevel (void) ddi_intr_disable(pcic->pc_intr_htblp[i]); 48642305Sstevel (void) ddi_intr_remove_handler( 48652305Sstevel pcic->pc_intr_htblp[i]); 48662305Sstevel (void) ddi_intr_free(pcic->pc_intr_htblp[i]); 48672305Sstevel (void) pcmcia_return_intr(pcic->dip, i); 48682305Sstevel #if defined(PCIC_DEBUG) 48692305Sstevel if (pcic_debug) { 48702305Sstevel cmn_err(CE_CONT, 4871*7656SSherry.Moore@Sun.COM "removing interrupt %d at %s " 4872*7656SSherry.Moore@Sun.COM "priority\n", i, "high"); 48732305Sstevel cmn_err(CE_CONT, 4874*7656SSherry.Moore@Sun.COM "ddi_remove_intr(%p, %x, %p)\n", 4875*7656SSherry.Moore@Sun.COM (void *)dip, 4876*7656SSherry.Moore@Sun.COM 0, 4877*7656SSherry.Moore@Sun.COM (void *)intr->iblk_cookie); 48782305Sstevel } 48792305Sstevel #endif 48802305Sstevel } 48812305Sstevel prev->next = intr->next; 48822305Sstevel kmem_free(intr, sizeof (inthandler_t)); 48832305Sstevel intr = prev->next; 4884*7656SSherry.Moore@Sun.COM } else { 48852305Sstevel prev = intr; 48862305Sstevel intr = intr->next; 4887*7656SSherry.Moore@Sun.COM } /* if (handler_id) */ 48882305Sstevel } /* while */ 48892305Sstevel 48902305Sstevel mutex_exit(&pcic->pc_lock); 48912305Sstevel } 48922305Sstevel 48932305Sstevel #if defined(PCIC_DEBUG) 48942305Sstevel if (pcic_debug) { 48952305Sstevel cmn_err(CE_CONT, 4896*7656SSherry.Moore@Sun.COM "pcic_clear_interrupt: exit irq_top=%p\n", 4897*7656SSherry.Moore@Sun.COM (void *)pcic->irq_top); 48982305Sstevel } 48992305Sstevel #endif 49002305Sstevel 49012305Sstevel 49022305Sstevel return (SUCCESS); 49032305Sstevel } 49042305Sstevel 49052305Sstevel struct intel_regs { 49062305Sstevel char *name; 49072305Sstevel int off; 49082305Sstevel char *fmt; 49092305Sstevel } iregs[] = { 49102305Sstevel {"ident ", 0}, 49112305Sstevel {"if-status ", 1, "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI"}, 49122305Sstevel {"power ", 2, "\020\1Vpp1c0\2Vpp1c1\3Vpp2c0\4Vpp2c1\5PE\6AUTO" 49132305Sstevel "\7DRD\10OE"}, 49142305Sstevel {"cardstatus", 4, "\020\1BD\2BW\3RC\4CD\5GPI\6R1\7R2\010R3"}, 49152305Sstevel {"enable ", 6, "\020\1MW0\2MW1\3MW2\4MW3\5MW4\6MEM16\7IO0\10IO1"}, 49162305Sstevel {"cd-gcr ", 0x16, "\020\1MDI16\2CRE\3GPIE\4GPIT\5CDR\6S/W"}, 49172305Sstevel {"GCR ", 0x1e, "\020\1PD\2LEVEL\3WCSC\4PLS14"}, 49182305Sstevel {"int-gcr ", 3, "\020\5INTR\6IO\7~RST\10RI"}, 49192305Sstevel {"management", 5, "\020\1BDE\2BWE\3RE\4CDE"}, 49202305Sstevel {"volt-sense", 0x1f, "\020\1A_VS1\2A_VS2\3B_VS1\4B_VS2"}, 49212305Sstevel {"volt-sel ", 0x2f, "\020\5EXTCONF\6BUSSELECT\7MIXEDV\10ISAV"}, 49222305Sstevel {"VG ext A ", 0x3c, "\20\3IVS\4CABLE\5CSTEP\6TEST\7RIO"}, 49232305Sstevel {"io-ctrl ", 7, "\020\1DS0\2IOCS0\3ZWS0\4WS0\5DS1\6IOS1\7ZWS1\10WS1"}, 49242305Sstevel {"io0-slow ", 8}, 49252305Sstevel {"io0-shi ", 9}, 49262305Sstevel {"io0-elow ", 0xa}, 49272305Sstevel {"io0-ehi ", 0xb}, 49282305Sstevel {"io1-slow ", 0xc}, 49292305Sstevel {"io1-shi ", 0xd}, 49302305Sstevel {"io1-elow ", 0xe}, 49312305Sstevel {"io1-ehi ", 0xf}, 49322305Sstevel {"mem0-slow ", 0x10}, 49332305Sstevel {"mem0-shi ", 0x11, "\020\7ZW\10DS"}, 49342305Sstevel {"mem0-elow ", 0x12}, 49352305Sstevel {"mem0-ehi ", 0x13, "\020\7WS0\10WS1"}, 49362305Sstevel {"card0-low ", 0x14}, 49372305Sstevel {"card0-hi ", 0x15, "\020\7AM\10WP"}, 49382305Sstevel {"mem1-slow ", 0x18}, 49392305Sstevel {"mem1-shi ", 0x19, "\020\7ZW\10DS"}, 49402305Sstevel {"mem1-elow ", 0x1a}, 49412305Sstevel {"mem1-ehi ", 0x1b, "\020\7WS0\10WS1"}, 49422305Sstevel {"card1-low ", 0x1c}, 49432305Sstevel {"card1-hi ", 0x1d, "\020\7AM\10WP"}, 49442305Sstevel {"mem2-slow ", 0x20}, 49452305Sstevel {"mem2-shi ", 0x21, "\020\7ZW\10DS"}, 49462305Sstevel {"mem2-elow ", 0x22}, 49472305Sstevel {"mem2-ehi ", 0x23, "\020\7WS0\10WS1"}, 49482305Sstevel {"card2-low ", 0x24}, 49492305Sstevel {"card2-hi ", 0x25, "\020\7AM\10WP"}, 49502305Sstevel {"mem3-slow ", 0x28}, 49512305Sstevel {"mem3-shi ", 0x29, "\020\7ZW\10DS"}, 49522305Sstevel {"mem3-elow ", 0x2a}, 49532305Sstevel {"mem3-ehi ", 0x2b, "\020\7WS0\10WS1"}, 49542305Sstevel {"card3-low ", 0x2c}, 49552305Sstevel {"card3-hi ", 0x2d, "\020\7AM\10WP"}, 49562305Sstevel 49572305Sstevel {"mem4-slow ", 0x30}, 49582305Sstevel {"mem4-shi ", 0x31, "\020\7ZW\10DS"}, 49592305Sstevel {"mem4-elow ", 0x32}, 49602305Sstevel {"mem4-ehi ", 0x33, "\020\7WS0\10WS1"}, 49612305Sstevel {"card4-low ", 0x34}, 49622305Sstevel {"card4-hi ", 0x35, "\020\7AM\10WP"}, 49632305Sstevel {"mpage0 ", 0x40}, 49642305Sstevel {"mpage1 ", 0x41}, 49652305Sstevel {"mpage2 ", 0x42}, 49662305Sstevel {"mpage3 ", 0x43}, 49672305Sstevel {"mpage4 ", 0x44}, 49682305Sstevel {NULL}, 49692305Sstevel }; 49702305Sstevel 49712305Sstevel static struct intel_regs cregs[] = { 49722305Sstevel {"misc-ctl1 ", 0x16, "\20\2VCC3\3PMI\4PSI\5SPKR\10INPACK"}, 49732305Sstevel {"fifo ", 0x17, "\20\6DIOP\7DMEMP\10EMPTY"}, 49742305Sstevel {"misc-ctl2 ", 0x1e, "\20\1XCLK\2LOW\3SUSP\4CORE5V\5TCD\10RIOUT"}, 49752305Sstevel {"chip-info ", 0x1f, "\20\6DUAL"}, 49762305Sstevel {"IO-offlow0", 0x36}, 49772305Sstevel {"IO-offhi0 ", 0x37}, 49782305Sstevel {"IO-offlow1", 0x38}, 49792305Sstevel {"IO-offhi1 ", 0x39}, 49802305Sstevel NULL, 49812305Sstevel }; 49822305Sstevel 49832305Sstevel static struct intel_regs cxregs[] = { 49842305Sstevel {"ext-ctl-1 ", 0x03, 49852305Sstevel "\20\1VCCLCK\2AUTOCLR\3LED\4INVIRQC\5INVIRQM\6PUC"}, 49862305Sstevel {"misc-ctl3 ", 0x25, "\20\5HWSUSP"}, 49872305Sstevel {"mem0-up ", 0x05}, 49882305Sstevel {"mem1-up ", 0x06}, 49892305Sstevel {"mem2-up ", 0x07}, 49902305Sstevel {"mem3-up ", 0x08}, 49912305Sstevel {"mem4-up ", 0x09}, 49922305Sstevel {NULL} 49932305Sstevel }; 49942305Sstevel 49952305Sstevel void 49962305Sstevel xxdmp_cl_regs(pcicdev_t *pcic, int socket, uint32_t len) 49972305Sstevel { 49982305Sstevel int i, value, j; 49992305Sstevel char buff[256]; 50002305Sstevel char *fmt; 50012305Sstevel 50022305Sstevel cmn_err(CE_CONT, "--------- Cirrus Logic Registers --------\n"); 50032305Sstevel for (buff[0] = '\0', i = 0; cregs[i].name != NULL && len-- != 0; i++) { 50042305Sstevel int sval; 50052305Sstevel if (cregs[i].off == PCIC_MISC_CTL_2) 50062305Sstevel sval = 0; 50072305Sstevel else 50082305Sstevel sval = socket; 50092305Sstevel value = pcic_getb(pcic, sval, cregs[i].off); 50102305Sstevel if (i & 1) { 50112305Sstevel if (cregs[i].fmt) 50122305Sstevel fmt = "%s\t%s\t%b\n"; 50132305Sstevel else 50142305Sstevel fmt = "%s\t%s\t%x\n"; 50152305Sstevel cmn_err(CE_CONT, fmt, buff, 5016*7656SSherry.Moore@Sun.COM cregs[i].name, value, cregs[i].fmt); 50172305Sstevel buff[0] = '\0'; 50182305Sstevel } else { 50192305Sstevel if (cregs[i].fmt) 50202305Sstevel fmt = "\t%s\t%b"; 50212305Sstevel else 50222305Sstevel fmt = "\t%s\t%x"; 50232305Sstevel (void) sprintf(buff, fmt, 5024*7656SSherry.Moore@Sun.COM cregs[i].name, value, cregs[i].fmt); 50252305Sstevel for (j = strlen(buff); j < 40; j++) 50262305Sstevel buff[j] = ' '; 50272305Sstevel buff[40] = '\0'; 50282305Sstevel } 50292305Sstevel } 50302305Sstevel cmn_err(CE_CONT, "%s\n", buff); 50312305Sstevel 50322305Sstevel i = pcic_getb(pcic, socket, PCIC_TIME_SETUP_0); 50332305Sstevel j = pcic_getb(pcic, socket, PCIC_TIME_SETUP_1); 50342305Sstevel cmn_err(CE_CONT, "\tsetup-tim0\t%x\tsetup-tim1\t%x\n", i, j); 50352305Sstevel 50362305Sstevel i = pcic_getb(pcic, socket, PCIC_TIME_COMMAND_0); 50372305Sstevel j = pcic_getb(pcic, socket, PCIC_TIME_COMMAND_1); 50382305Sstevel cmn_err(CE_CONT, "\tcmd-tim0 \t%x\tcmd-tim1 \t%x\n", i, j); 50392305Sstevel 50402305Sstevel i = pcic_getb(pcic, socket, PCIC_TIME_RECOVER_0); 50412305Sstevel j = pcic_getb(pcic, socket, PCIC_TIME_RECOVER_1); 50422305Sstevel cmn_err(CE_CONT, "\trcvr-tim0 \t%x\trcvr-tim1 \t%x\n", i, j); 50432305Sstevel 50442305Sstevel cmn_err(CE_CONT, "--------- Extended Registers --------\n"); 50452305Sstevel 50462305Sstevel for (buff[0] = '\0', i = 0; cxregs[i].name != NULL && len-- != 0; i++) { 50472305Sstevel value = clext_reg_read(pcic, socket, cxregs[i].off); 50482305Sstevel if (i & 1) { 50492305Sstevel if (cxregs[i].fmt) 50502305Sstevel fmt = "%s\t%s\t%b\n"; 50512305Sstevel else 50522305Sstevel fmt = "%s\t%s\t%x\n"; 50532305Sstevel cmn_err(CE_CONT, fmt, buff, 5054*7656SSherry.Moore@Sun.COM cxregs[i].name, value, cxregs[i].fmt); 50552305Sstevel buff[0] = '\0'; 50562305Sstevel } else { 50572305Sstevel if (cxregs[i].fmt) 50582305Sstevel fmt = "\t%s\t%b"; 50592305Sstevel else 50602305Sstevel fmt = "\t%s\t%x"; 50612305Sstevel (void) sprintf(buff, fmt, 5062*7656SSherry.Moore@Sun.COM cxregs[i].name, value, cxregs[i].fmt); 50632305Sstevel for (j = strlen(buff); j < 40; j++) 50642305Sstevel buff[j] = ' '; 50652305Sstevel buff[40] = '\0'; 50662305Sstevel } 50672305Sstevel } 50682305Sstevel } 50692305Sstevel 50702305Sstevel #if defined(PCIC_DEBUG) 50712305Sstevel static void 50722305Sstevel xxdmp_all_regs(pcicdev_t *pcic, int socket, uint32_t len) 50732305Sstevel { 50742305Sstevel int i, value, j; 50752305Sstevel char buff[256]; 50762305Sstevel char *fmt; 50772305Sstevel 50782305Sstevel #if defined(PCIC_DEBUG) 50792305Sstevel if (pcic_debug < 2) 50802305Sstevel return; 50812305Sstevel #endif 50822305Sstevel cmn_err(CE_CONT, 5083*7656SSherry.Moore@Sun.COM "----------- PCIC Registers for socket %d---------\n", 5084*7656SSherry.Moore@Sun.COM socket); 50852305Sstevel cmn_err(CE_CONT, 5086*7656SSherry.Moore@Sun.COM "\tname value name value\n"); 50872305Sstevel 50882305Sstevel for (buff[0] = '\0', i = 0; iregs[i].name != NULL && len-- != 0; i++) { 50892305Sstevel value = pcic_getb(pcic, socket, iregs[i].off); 50902305Sstevel if (i & 1) { 50912305Sstevel if (iregs[i].fmt) 50922305Sstevel fmt = "%s\t%s\t%b\n"; 50932305Sstevel else 50942305Sstevel fmt = "%s\t%s\t%x\n"; 50952305Sstevel cmn_err(CE_CONT, fmt, buff, 5096*7656SSherry.Moore@Sun.COM iregs[i].name, value, iregs[i].fmt); 50972305Sstevel buff[0] = '\0'; 50982305Sstevel } else { 50992305Sstevel if (iregs[i].fmt) 51002305Sstevel fmt = "\t%s\t%b"; 51012305Sstevel else 51022305Sstevel fmt = "\t%s\t%x"; 51032305Sstevel (void) sprintf(buff, fmt, 5104*7656SSherry.Moore@Sun.COM iregs[i].name, value, iregs[i].fmt); 51052305Sstevel for (j = strlen(buff); j < 40; j++) 51062305Sstevel buff[j] = ' '; 51072305Sstevel buff[40] = '\0'; 51082305Sstevel } 51092305Sstevel } 51102305Sstevel switch (pcic->pc_type) { 51112305Sstevel case PCIC_CL_PD6710: 51122305Sstevel case PCIC_CL_PD6722: 51132305Sstevel case PCIC_CL_PD6729: 51142305Sstevel case PCIC_CL_PD6832: 51152305Sstevel (void) xxdmp_cl_regs(pcic, socket, 0xFFFF); 51162305Sstevel break; 51172305Sstevel } 51182305Sstevel cmn_err(CE_CONT, "%s\n", buff); 51192305Sstevel } 51202305Sstevel #endif 51212305Sstevel 51222305Sstevel /* 51232305Sstevel * pcic_mswait(ms) 51242305Sstevel * sleep ms milliseconds 51252305Sstevel * call drv_usecwait once for each ms 51262305Sstevel */ 51272305Sstevel static void 51282305Sstevel pcic_mswait(pcicdev_t *pcic, int socket, int ms) 51292305Sstevel { 51302305Sstevel if (ms) { 51312305Sstevel pcic->pc_sockets[socket].pcs_flags |= PCS_WAITING; 51322305Sstevel pcic_mutex_exit(&pcic->pc_lock); 51332305Sstevel delay(drv_usectohz(ms*1000)); 51342305Sstevel pcic_mutex_enter(&pcic->pc_lock); 51352305Sstevel pcic->pc_sockets[socket].pcs_flags &= ~PCS_WAITING; 51362305Sstevel } 51372305Sstevel } 51382305Sstevel 51392305Sstevel /* 51402305Sstevel * pcic_check_ready(pcic, index, off) 51412305Sstevel * Wait for card to come ready 51422305Sstevel * We only wait if the card is NOT in RESET 51432305Sstevel * and power is on. 51442305Sstevel */ 51452305Sstevel static boolean_t 51462305Sstevel pcic_check_ready(pcicdev_t *pcic, int socket) 51472305Sstevel { 51482305Sstevel int ifstate, intstate; 51492305Sstevel 51502305Sstevel intstate = pcic_getb(pcic, socket, PCIC_INTERRUPT); 51512305Sstevel ifstate = pcic_getb(pcic, socket, PCIC_INTERFACE_STATUS); 51522305Sstevel 51532305Sstevel if ((intstate & PCIC_RESET) && 51542305Sstevel ((ifstate & (PCIC_READY|PCIC_POWER_ON|PCIC_ISTAT_CD_MASK)) == 51552305Sstevel (PCIC_READY|PCIC_POWER_ON|PCIC_CD_PRESENT_OK))) 51562305Sstevel return (B_TRUE); 51572305Sstevel 51582305Sstevel #ifdef PCIC_DEBUG 51592305Sstevel pcic_err(NULL, 5, "pcic_check_read: Card not ready, intstate = 0x%x, " 51602305Sstevel "ifstate = 0x%x\n", intstate, ifstate); 51612305Sstevel if (pcic_debug) { 51622305Sstevel pcic_debug += 4; 51632305Sstevel xxdmp_all_regs(pcic, socket, -1); 51642305Sstevel pcic_debug -= 4; 51652305Sstevel } 51662305Sstevel #endif 51672305Sstevel return (B_FALSE); 51682305Sstevel } 51692305Sstevel 51702305Sstevel /* 51712305Sstevel * Cirrus Logic extended register read/write routines 51722305Sstevel */ 51732305Sstevel static int 51742305Sstevel clext_reg_read(pcicdev_t *pcic, int sn, uchar_t ext_reg) 51752305Sstevel { 51762305Sstevel int val; 51772305Sstevel 51782305Sstevel switch (pcic->pc_io_type) { 51792305Sstevel case PCIC_IO_TYPE_YENTA: 51802305Sstevel val = ddi_get8(pcic->handle, 51812305Sstevel pcic->ioaddr + CB_CLEXT_OFFSET + ext_reg); 51822305Sstevel break; 51832305Sstevel default: 51842305Sstevel pcic_putb(pcic, sn, PCIC_CL_EXINDEX, ext_reg); 51852305Sstevel val = pcic_getb(pcic, sn, PCIC_CL_EXINDEX + 1); 51862305Sstevel break; 51872305Sstevel } 51882305Sstevel 51892305Sstevel return (val); 51902305Sstevel } 51912305Sstevel 51922305Sstevel static void 51932305Sstevel clext_reg_write(pcicdev_t *pcic, int sn, uchar_t ext_reg, uchar_t value) 51942305Sstevel { 51952305Sstevel switch (pcic->pc_io_type) { 51962305Sstevel case PCIC_IO_TYPE_YENTA: 51972305Sstevel ddi_put8(pcic->handle, 51982305Sstevel pcic->ioaddr + CB_CLEXT_OFFSET + ext_reg, value); 51992305Sstevel break; 52002305Sstevel default: 52012305Sstevel pcic_putb(pcic, sn, PCIC_CL_EXINDEX, ext_reg); 52022305Sstevel pcic_putb(pcic, sn, PCIC_CL_EXINDEX + 1, value); 52032305Sstevel break; 52042305Sstevel } 52052305Sstevel } 52062305Sstevel 52072305Sstevel /* 52082305Sstevel * Misc PCI functions 52092305Sstevel */ 52102305Sstevel static void 52112305Sstevel pcic_iomem_pci_ctl(ddi_acc_handle_t handle, uchar_t *cfgaddr, unsigned flags) 52122305Sstevel { 52132305Sstevel unsigned cmd; 52142305Sstevel 52152305Sstevel if (flags & (PCIC_ENABLE_IO | PCIC_ENABLE_MEM)) { 52162305Sstevel cmd = ddi_get16(handle, (ushort_t *)(cfgaddr + 4)); 52172305Sstevel if ((cmd & (PCI_COMM_IO|PCI_COMM_MAE)) == 52182305Sstevel (PCI_COMM_IO|PCI_COMM_MAE)) 52192305Sstevel return; 52202305Sstevel 52212305Sstevel if (flags & PCIC_ENABLE_IO) 5222*7656SSherry.Moore@Sun.COM cmd |= PCI_COMM_IO; 52232305Sstevel 52242305Sstevel if (flags & PCIC_ENABLE_MEM) 5225*7656SSherry.Moore@Sun.COM cmd |= PCI_COMM_MAE; 52262305Sstevel 52272305Sstevel ddi_put16(handle, (ushort_t *)(cfgaddr + 4), cmd); 52282305Sstevel } /* if (PCIC_ENABLE_IO | PCIC_ENABLE_MEM) */ 52292305Sstevel } 52302305Sstevel 52312305Sstevel /* 52322305Sstevel * pcic_find_pci_type - Find and return PCI-PCMCIA adapter type 52332305Sstevel */ 52342305Sstevel static int 52352305Sstevel pcic_find_pci_type(pcicdev_t *pcic) 52362305Sstevel { 52372305Sstevel uint32_t vend, device; 52382305Sstevel 52392305Sstevel vend = ddi_getprop(DDI_DEV_T_ANY, pcic->dip, 5240*7656SSherry.Moore@Sun.COM DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS, 5241*7656SSherry.Moore@Sun.COM "vendor-id", -1); 52422305Sstevel device = ddi_getprop(DDI_DEV_T_ANY, pcic->dip, 5243*7656SSherry.Moore@Sun.COM DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS, 5244*7656SSherry.Moore@Sun.COM "device-id", -1); 52452305Sstevel 52462305Sstevel device = PCI_ID(vend, device); 52472305Sstevel pcic->pc_type = device; 52482305Sstevel pcic->pc_chipname = "PCI:unknown"; 52492305Sstevel 52502305Sstevel switch (device) { 52512305Sstevel case PCIC_INTEL_i82092: 52522305Sstevel pcic->pc_chipname = PCIC_TYPE_i82092; 52532305Sstevel break; 52542305Sstevel case PCIC_CL_PD6729: 52552305Sstevel pcic->pc_chipname = PCIC_TYPE_PD6729; 52562305Sstevel /* 52572305Sstevel * Some 6730's incorrectly identify themselves 52582305Sstevel * as a 6729, so we need to do some more tests 52592305Sstevel * here to see if the device that's claiming 52602305Sstevel * to be a 6729 is really a 6730. 52612305Sstevel */ 52622305Sstevel if ((clext_reg_read(pcic, 0, PCIC_CLEXT_MISC_CTL_3) & 5263*7656SSherry.Moore@Sun.COM PCIC_CLEXT_MISC_CTL_3_REV_MASK) == 5264*7656SSherry.Moore@Sun.COM 0) { 52652305Sstevel pcic->pc_chipname = PCIC_TYPE_PD6730; 52662305Sstevel pcic->pc_type = PCIC_CL_PD6730; 52672305Sstevel } 52682305Sstevel break; 52692305Sstevel case PCIC_CL_PD6730: 52702305Sstevel pcic->pc_chipname = PCIC_TYPE_PD6730; 52712305Sstevel break; 52722305Sstevel case PCIC_CL_PD6832: 52732305Sstevel pcic->pc_chipname = PCIC_TYPE_PD6832; 52742305Sstevel break; 52752305Sstevel case PCIC_SMC_34C90: 52762305Sstevel pcic->pc_chipname = PCIC_TYPE_34C90; 52772305Sstevel break; 52782305Sstevel case PCIC_TOSHIBA_TOPIC95: 52792305Sstevel pcic->pc_chipname = PCIC_TYPE_TOPIC95; 52802305Sstevel break; 52812305Sstevel case PCIC_TOSHIBA_TOPIC100: 52822305Sstevel pcic->pc_chipname = PCIC_TYPE_TOPIC100; 52832305Sstevel break; 52842305Sstevel case PCIC_TI_PCI1031: 52852305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1031; 52862305Sstevel break; 52872305Sstevel case PCIC_TI_PCI1130: 52882305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1130; 52892305Sstevel break; 52902305Sstevel case PCIC_TI_PCI1131: 52912305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1131; 52922305Sstevel break; 52932305Sstevel case PCIC_TI_PCI1250: 52942305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1250; 52952305Sstevel break; 52962305Sstevel case PCIC_TI_PCI1225: 52972305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1225; 52982305Sstevel break; 52992305Sstevel case PCIC_TI_PCI1410: 53002305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1410; 53012305Sstevel break; 53022305Sstevel case PCIC_TI_PCI1510: 53032305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1510; 53042305Sstevel break; 53052305Sstevel case PCIC_TI_PCI1520: 53062305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1520; 53072305Sstevel break; 53082305Sstevel case PCIC_TI_PCI1221: 53092305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1221; 53102305Sstevel break; 53112305Sstevel case PCIC_TI_PCI1050: 53122305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1050; 53132305Sstevel break; 53142305Sstevel case PCIC_ENE_1410: 53152305Sstevel pcic->pc_chipname = PCIC_TYPE_1410; 53162305Sstevel break; 53172305Sstevel case PCIC_O2_OZ6912: 53182305Sstevel pcic->pc_chipname = PCIC_TYPE_OZ6912; 53192305Sstevel break; 53202305Sstevel case PCIC_RICOH_RL5C466: 53212305Sstevel pcic->pc_chipname = PCIC_TYPE_RL5C466; 53222305Sstevel break; 53232305Sstevel case PCIC_TI_PCI1420: 53242305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1420; 53252305Sstevel break; 53262305Sstevel case PCIC_ENE_1420: 53272305Sstevel pcic->pc_chipname = PCIC_TYPE_1420; 53282305Sstevel break; 53292305Sstevel default: 53302305Sstevel switch (PCI_ID(vend, (uint32_t)0)) { 53312305Sstevel case PCIC_TOSHIBA_VENDOR: 53322305Sstevel pcic->pc_chipname = PCIC_TYPE_TOSHIBA; 53332305Sstevel pcic->pc_type = PCIC_TOSHIBA_VENDOR; 53342305Sstevel break; 53352305Sstevel case PCIC_TI_VENDOR: 53362305Sstevel pcic->pc_chipname = PCIC_TYPE_TI; 53372305Sstevel pcic->pc_type = PCIC_TI_VENDOR; 53382305Sstevel break; 53392305Sstevel case PCIC_O2MICRO_VENDOR: 53402305Sstevel pcic->pc_chipname = PCIC_TYPE_O2MICRO; 53412305Sstevel pcic->pc_type = PCIC_O2MICRO_VENDOR; 53422305Sstevel break; 53432305Sstevel case PCIC_RICOH_VENDOR: 53442305Sstevel pcic->pc_chipname = PCIC_TYPE_RICOH; 53452305Sstevel pcic->pc_type = PCIC_RICOH_VENDOR; 53462305Sstevel break; 53472305Sstevel default: 53482305Sstevel if (!(pcic->pc_flags & PCF_CARDBUS)) 53492305Sstevel return (DDI_FAILURE); 53502305Sstevel pcic->pc_chipname = PCIC_TYPE_YENTA; 53512305Sstevel break; 53522305Sstevel } 53532305Sstevel } 53542305Sstevel return (DDI_SUCCESS); 53552305Sstevel } 53562305Sstevel 53572305Sstevel static void 53582305Sstevel pcic_82092_smiirq_ctl(pcicdev_t *pcic, int socket, int intr, int state) 53592305Sstevel { 53602305Sstevel uchar_t ppirr = ddi_get8(pcic->cfg_handle, 5361*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_82092_PPIRR); 53622305Sstevel uchar_t val; 53632305Sstevel 53642305Sstevel if (intr == PCIC_82092_CTL_SMI) { 53652305Sstevel val = PCIC_82092_SMI_CTL(socket, 5366*7656SSherry.Moore@Sun.COM PCIC_82092_INT_DISABLE); 53672305Sstevel ppirr &= ~val; 53682305Sstevel val = PCIC_82092_SMI_CTL(socket, state); 53692305Sstevel ppirr |= val; 53702305Sstevel } else { 53712305Sstevel val = PCIC_82092_IRQ_CTL(socket, 5372*7656SSherry.Moore@Sun.COM PCIC_82092_INT_DISABLE); 53732305Sstevel ppirr &= ~val; 53742305Sstevel val = PCIC_82092_IRQ_CTL(socket, state); 53752305Sstevel ppirr |= val; 53762305Sstevel } 53772305Sstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_82092_PPIRR, 5378*7656SSherry.Moore@Sun.COM ppirr); 53792305Sstevel } 53802305Sstevel 53812305Sstevel static uint_t 53822305Sstevel pcic_cd_softint(caddr_t arg1, caddr_t arg2) 53832305Sstevel { 53842305Sstevel pcic_socket_t *sockp = (pcic_socket_t *)arg1; 53852305Sstevel uint_t rc = DDI_INTR_UNCLAIMED; 53862305Sstevel 53872305Sstevel _NOTE(ARGUNUSED(arg2)) 53882305Sstevel 53892305Sstevel mutex_enter(&sockp->pcs_pcic->pc_lock); 53902305Sstevel if (sockp->pcs_cd_softint_flg) { 53912305Sstevel uint8_t status; 53922305Sstevel sockp->pcs_cd_softint_flg = 0; 53932305Sstevel rc = DDI_INTR_CLAIMED; 53942305Sstevel status = pcic_getb(sockp->pcs_pcic, sockp->pcs_socket, 5395*7656SSherry.Moore@Sun.COM PCIC_INTERFACE_STATUS); 53962305Sstevel pcic_handle_cd_change(sockp->pcs_pcic, sockp, status); 53972305Sstevel } 53982305Sstevel mutex_exit(&sockp->pcs_pcic->pc_lock); 53992305Sstevel return (rc); 54002305Sstevel } 54012305Sstevel 54022305Sstevel int pcic_debounce_cnt = PCIC_REM_DEBOUNCE_CNT; 54032305Sstevel int pcic_debounce_intr_time = PCIC_REM_DEBOUNCE_TIME; 54042305Sstevel int pcic_debounce_cnt_ok = PCIC_DEBOUNCE_OK_CNT; 54052305Sstevel 54062305Sstevel #ifdef CARDBUS 54072305Sstevel static uint32_t pcic_cbps_on = 0; 54082305Sstevel static uint32_t pcic_cbps_off = CB_PS_NOTACARD | CB_PS_CCDMASK | 54092305Sstevel CB_PS_XVCARD | CB_PS_YVCARD; 54102305Sstevel #else 54112305Sstevel static uint32_t pcic_cbps_on = CB_PS_16BITCARD; 54122305Sstevel static uint32_t pcic_cbps_off = CB_PS_NOTACARD | CB_PS_CCDMASK | 54132305Sstevel CB_PS_CBCARD | 54142305Sstevel CB_PS_XVCARD | CB_PS_YVCARD; 54152305Sstevel #endif 54162305Sstevel static void 54172305Sstevel pcic_handle_cd_change(pcicdev_t *pcic, pcic_socket_t *sockp, uint8_t status) 54182305Sstevel { 54192305Sstevel boolean_t do_debounce = B_FALSE; 54202305Sstevel int debounce_time = drv_usectohz(pcic_debounce_time); 54212305Sstevel uint8_t irq; 54222305Sstevel timeout_id_t debounce; 54232305Sstevel 54242305Sstevel /* 54252305Sstevel * Always reset debounce but may need to check original state later. 54262305Sstevel */ 54272305Sstevel debounce = sockp->pcs_debounce_id; 54282305Sstevel sockp->pcs_debounce_id = 0; 54292305Sstevel 54302305Sstevel /* 54312305Sstevel * Check to see whether a card is present or not. There are 54322305Sstevel * only two states that we are concerned with - the state 54332305Sstevel * where both CD pins are asserted, which means that the 54342305Sstevel * card is fully seated, and the state where neither CD 54352305Sstevel * pin is asserted, which means that the card is not 54362305Sstevel * present. 54372305Sstevel * The CD signals are generally very noisy and cause a lot of 54382305Sstevel * contact bounce as the card is being inserted and 54392305Sstevel * removed, so we need to do some software debouncing. 54402305Sstevel */ 54412305Sstevel 54422305Sstevel #ifdef PCIC_DEBUG 5443*7656SSherry.Moore@Sun.COM pcic_err(pcic->dip, 6, 54442305Sstevel "pcic%d handle_cd_change: socket %d card status 0x%x" 54452305Sstevel " deb 0x%p\n", ddi_get_instance(pcic->dip), 54462305Sstevel sockp->pcs_socket, status, debounce); 54472305Sstevel #endif 54482305Sstevel switch (status & PCIC_ISTAT_CD_MASK) { 54492305Sstevel case PCIC_CD_PRESENT_OK: 5450*7656SSherry.Moore@Sun.COM sockp->pcs_flags &= ~(PCS_CARD_REMOVED|PCS_CARD_CBREM); 5451*7656SSherry.Moore@Sun.COM if (!(sockp->pcs_flags & PCS_CARD_PRESENT)) { 54522305Sstevel uint32_t cbps; 54532305Sstevel #ifdef PCIC_DEBUG 54542305Sstevel pcic_err(pcic->dip, 8, "New card (0x%x)\n", sockp->pcs_flags); 54552305Sstevel #endif 54562305Sstevel cbps = pcic_getcb(pcic, CB_PRESENT_STATE); 54572305Sstevel #ifdef PCIC_DEBUG 54582305Sstevel pcic_err(pcic->dip, 8, "CBus PS (0x%x)\n", cbps); 54592305Sstevel #endif 54602305Sstevel /* 54612305Sstevel * Check the CB bits are sane. 54622305Sstevel */ 54632305Sstevel if ((cbps & pcic_cbps_on) != pcic_cbps_on || 54642305Sstevel cbps & pcic_cbps_off) { 5465*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, 54662305Sstevel "%s%d: Odd Cardbus Present State 0x%x\n", 54672305Sstevel ddi_get_name(pcic->dip), 54682305Sstevel ddi_get_instance(pcic->dip), 54692305Sstevel cbps); 5470*7656SSherry.Moore@Sun.COM pcic_putcb(pcic, CB_EVENT_FORCE, CB_EF_CVTEST); 5471*7656SSherry.Moore@Sun.COM debounce = 0; 5472*7656SSherry.Moore@Sun.COM debounce_time = drv_usectohz(1000000); 54732305Sstevel } 54742305Sstevel if (debounce) { 5475*7656SSherry.Moore@Sun.COM sockp->pcs_flags |= PCS_CARD_PRESENT; 5476*7656SSherry.Moore@Sun.COM if (pcic_do_insertion) { 5477*7656SSherry.Moore@Sun.COM 5478*7656SSherry.Moore@Sun.COM cbps = pcic_getcb(pcic, CB_PRESENT_STATE); 5479*7656SSherry.Moore@Sun.COM 5480*7656SSherry.Moore@Sun.COM if (cbps & CB_PS_16BITCARD) { 5481*7656SSherry.Moore@Sun.COM pcic_err(pcic->dip, 5482*7656SSherry.Moore@Sun.COM 8, "16 bit card inserted\n"); 5483*7656SSherry.Moore@Sun.COM sockp->pcs_flags |= PCS_CARD_IS16BIT; 5484*7656SSherry.Moore@Sun.COM /* calls pcm_adapter_callback() */ 5485*7656SSherry.Moore@Sun.COM if (pcic->pc_callback) { 5486*7656SSherry.Moore@Sun.COM 5487*7656SSherry.Moore@Sun.COM (void) ddi_prop_update_string( 5488*7656SSherry.Moore@Sun.COM DDI_DEV_T_NONE, 5489*7656SSherry.Moore@Sun.COM pcic->dip, PCM_DEVICETYPE, 5490*7656SSherry.Moore@Sun.COM "pccard"); 5491*7656SSherry.Moore@Sun.COM PC_CALLBACK(pcic->dip, 5492*7656SSherry.Moore@Sun.COM pcic->pc_cb_arg, 5493*7656SSherry.Moore@Sun.COM PCE_CARD_INSERT, 5494*7656SSherry.Moore@Sun.COM sockp->pcs_socket); 5495*7656SSherry.Moore@Sun.COM } 5496*7656SSherry.Moore@Sun.COM } else if (cbps & CB_PS_CBCARD) { 5497*7656SSherry.Moore@Sun.COM pcic_err(pcic->dip, 5498*7656SSherry.Moore@Sun.COM 8, "32 bit card inserted\n"); 5499*7656SSherry.Moore@Sun.COM 5500*7656SSherry.Moore@Sun.COM if (pcic->pc_flags & PCF_CARDBUS) { 5501*7656SSherry.Moore@Sun.COM sockp->pcs_flags |= 5502*7656SSherry.Moore@Sun.COM PCS_CARD_ISCARDBUS; 55032305Sstevel #ifdef CARDBUS 5504*7656SSherry.Moore@Sun.COM if (!pcic_load_cardbus(pcic, 5505*7656SSherry.Moore@Sun.COM sockp)) { 5506*7656SSherry.Moore@Sun.COM pcic_unload_cardbus( 5507*7656SSherry.Moore@Sun.COM pcic, sockp); 5508*7656SSherry.Moore@Sun.COM } 55092305Sstevel 55102305Sstevel #else 5511*7656SSherry.Moore@Sun.COM cmn_err(CE_NOTE, 5512*7656SSherry.Moore@Sun.COM "32 bit Cardbus not" 5513*7656SSherry.Moore@Sun.COM " supported in" 5514*7656SSherry.Moore@Sun.COM " this device driver\n"); 55152305Sstevel #endif 5516*7656SSherry.Moore@Sun.COM } else { 5517*7656SSherry.Moore@Sun.COM /* 5518*7656SSherry.Moore@Sun.COM * Ignore the card 5519*7656SSherry.Moore@Sun.COM */ 5520*7656SSherry.Moore@Sun.COM cmn_err(CE_NOTE, 5521*7656SSherry.Moore@Sun.COM "32 bit Cardbus not" 5522*7656SSherry.Moore@Sun.COM " supported on this" 5523*7656SSherry.Moore@Sun.COM " device\n"); 5524*7656SSherry.Moore@Sun.COM } 5525*7656SSherry.Moore@Sun.COM } else { 5526*7656SSherry.Moore@Sun.COM cmn_err(CE_NOTE, 5527*7656SSherry.Moore@Sun.COM "Unsupported PCMCIA card" 5528*7656SSherry.Moore@Sun.COM " inserted\n"); 5529*7656SSherry.Moore@Sun.COM } 55302305Sstevel } 55312305Sstevel } else { 5532*7656SSherry.Moore@Sun.COM do_debounce = B_TRUE; 55332305Sstevel } 5534*7656SSherry.Moore@Sun.COM } else { 55352305Sstevel /* 55362305Sstevel * It is possible to come through here if the system 55372305Sstevel * starts up with cards already inserted. Do nothing 55382305Sstevel * and don't worry about it. 55392305Sstevel */ 55402305Sstevel #ifdef PCIC_DEBUG 55412305Sstevel pcic_err(pcic->dip, 5, 5542*7656SSherry.Moore@Sun.COM "pcic%d: Odd card insertion indication on socket %d\n", 5543*7656SSherry.Moore@Sun.COM ddi_get_instance(pcic->dip), 5544*7656SSherry.Moore@Sun.COM sockp->pcs_socket); 55452305Sstevel #endif 5546*7656SSherry.Moore@Sun.COM } 5547*7656SSherry.Moore@Sun.COM break; 55482305Sstevel 55492305Sstevel default: 5550*7656SSherry.Moore@Sun.COM if (!(sockp->pcs_flags & PCS_CARD_PRESENT)) { 55512305Sstevel /* 55522305Sstevel * Someone has started to insert a card so delay a while. 55532305Sstevel */ 55542305Sstevel do_debounce = B_TRUE; 55552305Sstevel break; 5556*7656SSherry.Moore@Sun.COM } 55572305Sstevel /* 55582305Sstevel * Otherwise this is basically the same as not present 55592305Sstevel * so fall through. 55602305Sstevel */ 55612305Sstevel 55622305Sstevel /* FALLTHRU */ 55632305Sstevel case 0: 5564*7656SSherry.Moore@Sun.COM if (sockp->pcs_flags & PCS_CARD_PRESENT) { 5565*7656SSherry.Moore@Sun.COM if (pcic->pc_flags & PCF_CBPWRCTL) { 5566*7656SSherry.Moore@Sun.COM pcic_putcb(pcic, CB_CONTROL, 0); 5567*7656SSherry.Moore@Sun.COM } else { 5568*7656SSherry.Moore@Sun.COM pcic_putb(pcic, sockp->pcs_socket, 5569*7656SSherry.Moore@Sun.COM PCIC_POWER_CONTROL, 0); 5570*7656SSherry.Moore@Sun.COM (void) pcic_getb(pcic, sockp->pcs_socket, 5571*7656SSherry.Moore@Sun.COM PCIC_POWER_CONTROL); 55722305Sstevel } 55732305Sstevel #ifdef PCIC_DEBUG 55742305Sstevel pcic_err(pcic->dip, 8, "Card removed\n"); 55752305Sstevel #endif 55762305Sstevel sockp->pcs_flags &= ~PCS_CARD_PRESENT; 55772305Sstevel 55782305Sstevel if (sockp->pcs_flags & PCS_CARD_IS16BIT) { 5579*7656SSherry.Moore@Sun.COM sockp->pcs_flags &= ~PCS_CARD_IS16BIT; 5580*7656SSherry.Moore@Sun.COM if (pcic_do_removal && pcic->pc_callback) { 5581*7656SSherry.Moore@Sun.COM PC_CALLBACK(pcic->dip, pcic->pc_cb_arg, 55822305Sstevel PCE_CARD_REMOVAL, sockp->pcs_socket); 5583*7656SSherry.Moore@Sun.COM } 55842305Sstevel } 55852305Sstevel if (sockp->pcs_flags & PCS_CARD_ISCARDBUS) { 5586*7656SSherry.Moore@Sun.COM sockp->pcs_flags &= ~PCS_CARD_ISCARDBUS; 5587*7656SSherry.Moore@Sun.COM sockp->pcs_flags |= PCS_CARD_CBREM; 55882305Sstevel } 55892305Sstevel sockp->pcs_flags |= PCS_CARD_REMOVED; 55902305Sstevel 55912305Sstevel do_debounce = B_TRUE; 5592*7656SSherry.Moore@Sun.COM } 5593*7656SSherry.Moore@Sun.COM if (debounce && (sockp->pcs_flags & PCS_CARD_REMOVED)) { 5594*7656SSherry.Moore@Sun.COM if (sockp->pcs_flags & PCS_CARD_CBREM) { 55952305Sstevel /* 55962305Sstevel * Ensure that we do the unloading in the 55972305Sstevel * debounce handler, that way we're not doing 55982305Sstevel * nasty things in an interrupt handler. e.g. 55992305Sstevel * a USB device will wait for data which will 56002305Sstevel * obviously never come because we've 56012305Sstevel * unplugged the device, but the wait will 56022305Sstevel * wait forever because no interrupts can 56032305Sstevel * come in... 56042305Sstevel */ 56052305Sstevel #ifdef CARDBUS 5606*7656SSherry.Moore@Sun.COM pcic_unload_cardbus(pcic, sockp); 5607*7656SSherry.Moore@Sun.COM /* pcic_dump_all(pcic); */ 56082305Sstevel #endif 5609*7656SSherry.Moore@Sun.COM sockp->pcs_flags &= ~PCS_CARD_CBREM; 5610*7656SSherry.Moore@Sun.COM } 5611*7656SSherry.Moore@Sun.COM sockp->pcs_flags &= ~PCS_CARD_REMOVED; 56122305Sstevel } 5613*7656SSherry.Moore@Sun.COM break; 56142305Sstevel } /* switch */ 56152305Sstevel 56162305Sstevel if (do_debounce) { 56172305Sstevel /* 56182305Sstevel * Delay doing 56192305Sstevel * anything for a while so that things can settle 56202305Sstevel * down a little. Interrupts are already disabled. 56212305Sstevel * Reset the state and we'll reevaluate the 56222305Sstevel * whole kit 'n kaboodle when the timeout fires 56232305Sstevel */ 56242305Sstevel #ifdef PCIC_DEBUG 56252305Sstevel pcic_err(pcic->dip, 8, "Queueing up debounce timeout for " 5626*7656SSherry.Moore@Sun.COM "socket %d.%d\n", 5627*7656SSherry.Moore@Sun.COM ddi_get_instance(pcic->dip), 5628*7656SSherry.Moore@Sun.COM sockp->pcs_socket); 56292305Sstevel #endif 5630*7656SSherry.Moore@Sun.COM sockp->pcs_debounce_id = 5631*7656SSherry.Moore@Sun.COM pcic_add_debqueue(sockp, debounce_time); 56322305Sstevel 56332305Sstevel /* 56342305Sstevel * We bug out here without re-enabling interrupts. They will 56352305Sstevel * be re-enabled when the debounce timeout swings through 56362305Sstevel * here. 56372305Sstevel */ 5638*7656SSherry.Moore@Sun.COM return; 56392305Sstevel } 56402305Sstevel 56412305Sstevel /* 56422305Sstevel * Turn on Card detect interrupts. Other interrupts will be 56432305Sstevel * enabled during set_socket calls. 56442305Sstevel * 56452305Sstevel * Note that set_socket only changes interrupt settings when there 56462305Sstevel * is a card present. 56472305Sstevel */ 56482305Sstevel irq = pcic_getb(pcic, sockp->pcs_socket, PCIC_MANAGEMENT_INT); 56492305Sstevel irq |= PCIC_CD_DETECT; 56502305Sstevel pcic_putb(pcic, sockp->pcs_socket, PCIC_MANAGEMENT_INT, irq); 56512325Srw148561 pcic_putcb(pcic, CB_STATUS_MASK, CB_SE_CCDMASK); 56522305Sstevel 56532451Srw148561 /* Out from debouncing state */ 56542451Srw148561 sockp->pcs_flags &= ~PCS_DEBOUNCING; 56552451Srw148561 56562305Sstevel pcic_err(pcic->dip, 7, "Leaving pcic_handle_cd_change\n"); 56572305Sstevel } 56582305Sstevel 56592305Sstevel /* 56602305Sstevel * pcic_getb() 56612305Sstevel * get an I/O byte based on the yardware decode method 56622305Sstevel */ 56632305Sstevel static uint8_t 56642305Sstevel pcic_getb(pcicdev_t *pcic, int socket, int reg) 56652305Sstevel { 56662305Sstevel int work; 56672305Sstevel 56682305Sstevel #if defined(PCIC_DEBUG) 56692305Sstevel if (pcic_debug == 0x7fff) { 56702305Sstevel cmn_err(CE_CONT, "pcic_getb0: pcic=%p socket=%d reg=%d\n", 5671*7656SSherry.Moore@Sun.COM (void *)pcic, socket, reg); 56722305Sstevel cmn_err(CE_CONT, "pcic_getb1: type=%d handle=%p ioaddr=%p \n", 5673*7656SSherry.Moore@Sun.COM pcic->pc_io_type, (void *)pcic->handle, 5674*7656SSherry.Moore@Sun.COM (void *)pcic->ioaddr); 56752305Sstevel } 56762305Sstevel #endif 56772305Sstevel 56782305Sstevel switch (pcic->pc_io_type) { 56792305Sstevel case PCIC_IO_TYPE_YENTA: 56802305Sstevel return (ddi_get8(pcic->handle, 56812305Sstevel pcic->ioaddr + CB_R2_OFFSET + reg)); 56822305Sstevel default: 56832305Sstevel work = (socket * PCIC_SOCKET_1) | reg; 56842305Sstevel ddi_put8(pcic->handle, pcic->ioaddr, work); 56852305Sstevel return (ddi_get8(pcic->handle, pcic->ioaddr + 1)); 56862305Sstevel } 56872305Sstevel } 56882305Sstevel 56892305Sstevel static void 56902305Sstevel pcic_putb(pcicdev_t *pcic, int socket, int reg, int8_t value) 56912305Sstevel { 56922305Sstevel int work; 56932305Sstevel 56942305Sstevel #if defined(PCIC_DEBUG) 56952305Sstevel if (pcic_debug == 0x7fff) { 56962305Sstevel cmn_err(CE_CONT, 5697*7656SSherry.Moore@Sun.COM "pcic_putb0: pcic=%p socket=%d reg=%d value=%x \n", 5698*7656SSherry.Moore@Sun.COM (void *)pcic, socket, reg, value); 56992305Sstevel cmn_err(CE_CONT, 5700*7656SSherry.Moore@Sun.COM "pcic_putb1: type=%d handle=%p ioaddr=%p \n", 5701*7656SSherry.Moore@Sun.COM pcic->pc_io_type, (void *)pcic->handle, 5702*7656SSherry.Moore@Sun.COM (void *)pcic->ioaddr); 57032305Sstevel } 57042305Sstevel #endif 57052305Sstevel 57062305Sstevel 57072305Sstevel switch (pcic->pc_io_type) { 57082305Sstevel case PCIC_IO_TYPE_YENTA: 57092305Sstevel ddi_put8(pcic->handle, pcic->ioaddr + CB_R2_OFFSET + reg, 5710*7656SSherry.Moore@Sun.COM value); 57112305Sstevel break; 57122305Sstevel default: 57132305Sstevel work = (socket * PCIC_SOCKET_1) | reg; 57142305Sstevel ddi_put8(pcic->handle, pcic->ioaddr, work); 57152305Sstevel ddi_put8(pcic->handle, pcic->ioaddr + 1, value); 57162305Sstevel break; 57172305Sstevel } 57182305Sstevel } 57192305Sstevel 57202305Sstevel /* 57212305Sstevel * chip identification functions 57222305Sstevel */ 57232305Sstevel 57242305Sstevel /* 57252305Sstevel * chip identification: Cirrus Logic PD6710/6720/6722 57262305Sstevel */ 57272305Sstevel static int 57282305Sstevel pcic_ci_cirrus(pcicdev_t *pcic) 57292305Sstevel { 57302305Sstevel int value1, value2; 57312305Sstevel 57322305Sstevel /* Init the CL id mode */ 57332305Sstevel value1 = pcic_getb(pcic, 0, PCIC_CHIP_INFO); 57342305Sstevel pcic_putb(pcic, 0, PCIC_CHIP_INFO, 0); 57352305Sstevel value1 = pcic_getb(pcic, 0, PCIC_CHIP_INFO); 57362305Sstevel value2 = pcic_getb(pcic, 0, PCIC_CHIP_INFO); 57372305Sstevel 57382305Sstevel if ((value1 & PCIC_CI_ID) == PCIC_CI_ID && 57392305Sstevel (value2 & PCIC_CI_ID) == 0) { 57402305Sstevel /* chip is a Cirrus Logic and not Intel */ 57412305Sstevel pcic->pc_type = PCIC_CL_PD6710; 57422305Sstevel if (value1 & PCIC_CI_SLOTS) 57432305Sstevel pcic->pc_chipname = PCIC_TYPE_PD6720; 57442305Sstevel else 57452305Sstevel pcic->pc_chipname = PCIC_TYPE_PD6710; 57462305Sstevel /* now fine tune things just in case a 6722 */ 57472305Sstevel value1 = clext_reg_read(pcic, 0, PCIC_CLEXT_DMASK_0); 57482305Sstevel if (value1 == 0) { 57492305Sstevel clext_reg_write(pcic, 0, PCIC_CLEXT_SCRATCH, 0x55); 57502305Sstevel value1 = clext_reg_read(pcic, 0, PCIC_CLEXT_SCRATCH); 57512305Sstevel if (value1 == 0x55) { 57522305Sstevel pcic->pc_chipname = PCIC_TYPE_PD6722; 57532305Sstevel pcic->pc_type = PCIC_CL_PD6722; 57542305Sstevel clext_reg_write(pcic, 0, PCIC_CLEXT_SCRATCH, 0); 57552305Sstevel } 57562305Sstevel } 57572305Sstevel return (1); 57582305Sstevel } 57592305Sstevel return (0); 57602305Sstevel } 57612305Sstevel 57622305Sstevel /* 57632305Sstevel * chip identification: Vadem (VG365/465/468/469) 57642305Sstevel */ 57652305Sstevel 57662305Sstevel static void 57672305Sstevel pcic_vadem_enable(pcicdev_t *pcic) 57682305Sstevel { 57692305Sstevel ddi_put8(pcic->handle, pcic->ioaddr, PCIC_VADEM_P1); 57702305Sstevel ddi_put8(pcic->handle, pcic->ioaddr, PCIC_VADEM_P2); 57712305Sstevel ddi_put8(pcic->handle, pcic->ioaddr, pcic->pc_lastreg); 57722305Sstevel } 57732305Sstevel 57742305Sstevel static int 57752305Sstevel pcic_ci_vadem(pcicdev_t *pcic) 57762305Sstevel { 57772305Sstevel int value; 57782305Sstevel 57792305Sstevel pcic_vadem_enable(pcic); 57802305Sstevel value = pcic_getb(pcic, 0, PCIC_CHIP_REVISION); 57812305Sstevel pcic_putb(pcic, 0, PCIC_CHIP_REVISION, 0xFF); 57822305Sstevel if (pcic_getb(pcic, 0, PCIC_CHIP_REVISION) == 57832305Sstevel (value | PCIC_VADEM_D3) || 57842305Sstevel (pcic_getb(pcic, 0, PCIC_CHIP_REVISION) & PCIC_REV_MASK) == 57852305Sstevel PCIC_VADEM_469) { 57862305Sstevel int vadem, new; 57872305Sstevel pcic_vadem_enable(pcic); 57882305Sstevel vadem = pcic_getb(pcic, 0, PCIC_VG_DMA) & 5789*7656SSherry.Moore@Sun.COM ~(PCIC_V_UNLOCK | PCIC_V_VADEMREV); 57902305Sstevel new = vadem | (PCIC_V_VADEMREV|PCIC_V_UNLOCK); 57912305Sstevel pcic_putb(pcic, 0, PCIC_VG_DMA, new); 57922305Sstevel value = pcic_getb(pcic, 0, PCIC_CHIP_REVISION); 57932305Sstevel 57942305Sstevel /* want to lock but leave mouse or other on */ 57952305Sstevel pcic_putb(pcic, 0, PCIC_VG_DMA, vadem); 57962305Sstevel switch (value & PCIC_REV_MASK) { 57972305Sstevel case PCIC_VADEM_365: 57982305Sstevel pcic->pc_chipname = PCIC_VG_365; 57992305Sstevel pcic->pc_type = PCIC_VADEM; 58002305Sstevel break; 58012305Sstevel case PCIC_VADEM_465: 58022305Sstevel pcic->pc_chipname = PCIC_VG_465; 58032305Sstevel pcic->pc_type = PCIC_VADEM; 58042305Sstevel pcic->pc_flags |= PCF_1SOCKET; 58052305Sstevel break; 58062305Sstevel case PCIC_VADEM_468: 58072305Sstevel pcic->pc_chipname = PCIC_VG_468; 58082305Sstevel pcic->pc_type = PCIC_VADEM; 58092305Sstevel break; 58102305Sstevel case PCIC_VADEM_469: 58112305Sstevel pcic->pc_chipname = PCIC_VG_469; 58122305Sstevel pcic->pc_type = PCIC_VADEM_VG469; 58132305Sstevel break; 58142305Sstevel } 58152305Sstevel return (1); 58162305Sstevel } 58172305Sstevel return (0); 58182305Sstevel } 58192305Sstevel 58202305Sstevel /* 58212305Sstevel * chip identification: Ricoh 58222305Sstevel */ 58232305Sstevel static int 58242305Sstevel pcic_ci_ricoh(pcicdev_t *pcic) 58252305Sstevel { 58262305Sstevel int value; 58272305Sstevel 58282305Sstevel value = pcic_getb(pcic, 0, PCIC_RF_CHIP_IDENT); 58292305Sstevel switch (value) { 58302305Sstevel case PCIC_RF_296: 58312305Sstevel pcic->pc_type = PCIC_RICOH; 58322305Sstevel pcic->pc_chipname = PCIC_TYPE_RF5C296; 58332305Sstevel return (1); 58342305Sstevel case PCIC_RF_396: 58352305Sstevel pcic->pc_type = PCIC_RICOH; 58362305Sstevel pcic->pc_chipname = PCIC_TYPE_RF5C396; 58372305Sstevel return (1); 58382305Sstevel } 58392305Sstevel return (0); 58402305Sstevel } 58412305Sstevel 58422305Sstevel 58432305Sstevel /* 58442305Sstevel * set up available address spaces in busra 58452305Sstevel */ 58462305Sstevel static void 58472305Sstevel pcic_init_assigned(dev_info_t *dip) 58482305Sstevel { 58492305Sstevel pcm_regs_t *pcic_avail_p; 58502305Sstevel pci_regspec_t *pci_avail_p, *regs; 58512305Sstevel int len, entries, rlen; 58522305Sstevel dev_info_t *pdip; 58532305Sstevel 58542305Sstevel if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 58552305Sstevel "available", (caddr_t)&pcic_avail_p, &len) == DDI_PROP_SUCCESS) { 58562305Sstevel /* 58572305Sstevel * found "available" property at the cardbus/pcmcia node 58582305Sstevel * need to translate address space entries from pcmcia 58592305Sstevel * format to pci format 58602305Sstevel */ 58612305Sstevel entries = len / sizeof (pcm_regs_t); 58622305Sstevel pci_avail_p = kmem_alloc(sizeof (pci_regspec_t) * entries, 5863*7656SSherry.Moore@Sun.COM KM_SLEEP); 58642305Sstevel if (pcic_apply_avail_ranges(dip, pcic_avail_p, pci_avail_p, 58652305Sstevel entries) == DDI_SUCCESS) 58662305Sstevel (void) pci_resource_setup_avail(dip, pci_avail_p, 5867*7656SSherry.Moore@Sun.COM entries); 58682305Sstevel kmem_free(pcic_avail_p, len); 58692305Sstevel kmem_free(pci_avail_p, entries * sizeof (pci_regspec_t)); 58702305Sstevel return; 58712305Sstevel } 58722305Sstevel 58732305Sstevel /* 58742305Sstevel * "legacy" platforms will have "available" property in pci node 58752305Sstevel */ 58762305Sstevel for (pdip = ddi_get_parent(dip); pdip; pdip = ddi_get_parent(pdip)) { 58772305Sstevel if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 58782305Sstevel "available", (caddr_t)&pci_avail_p, &len) == 58792305Sstevel DDI_PROP_SUCCESS) { 58802305Sstevel /* (void) pci_resource_setup(pdip); */ 58812305Sstevel kmem_free(pci_avail_p, len); 58822305Sstevel break; 58832305Sstevel } 58842305Sstevel } 58852305Sstevel 58862305Sstevel if (pdip == NULL) { 58872305Sstevel int len; 58882305Sstevel char bus_type[16] = "(unknown)"; 58892305Sstevel dev_info_t *par; 58902305Sstevel 58912305Sstevel cmn_err(CE_CONT, 58922305Sstevel "?pcic_init_assigned: no available property for pcmcia\n"); 58932305Sstevel 58942305Sstevel /* 58952305Sstevel * This code is taken from pci_resource_setup() but does 58962305Sstevel * not attempt to use the "available" property to populate 58972305Sstevel * the ndi maps that are created. 58982305Sstevel * The fact that we will actually 58992305Sstevel * free some resource below (that was allocated by OBP) 59002305Sstevel * should be enough to be going on with. 59012305Sstevel */ 59022305Sstevel for (par = dip; par != NULL; par = ddi_get_parent(par)) { 59032305Sstevel len = sizeof (bus_type); 59042305Sstevel 59052305Sstevel if ((ddi_prop_op(DDI_DEV_T_ANY, par, 59062305Sstevel PROP_LEN_AND_VAL_BUF, 59072305Sstevel DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, 59082305Sstevel "device_type", 59092305Sstevel (caddr_t)&bus_type, &len) == DDI_SUCCESS) && 59103664Srw148561 (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0 || 5911*7656SSherry.Moore@Sun.COM strcmp(bus_type, DEVI_PCIEX_NEXNAME) == 0)) 59122305Sstevel break; 59132305Sstevel } 59142305Sstevel if (par != NULL && 59152305Sstevel (ndi_ra_map_setup(par, NDI_RA_TYPE_MEM) != NDI_SUCCESS || 59162305Sstevel ndi_ra_map_setup(par, NDI_RA_TYPE_IO) != NDI_SUCCESS)) 59172305Sstevel par = NULL; 59182305Sstevel } else { 59192305Sstevel #ifdef CARDBUS 59202305Sstevel cardbus_bus_range_t *bus_range; 59212305Sstevel int k; 59222305Sstevel 59232305Sstevel if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "bus-range", 59242305Sstevel (caddr_t)&bus_range, &k) == DDI_PROP_SUCCESS) { 59252305Sstevel if (bus_range->lo != bus_range->hi) 59262305Sstevel pcic_err(pdip, 9, "allowable bus range is " 59272305Sstevel "%u->%u\n", bus_range->lo, bus_range->hi); 59282305Sstevel else { 59292305Sstevel pcic_err(pdip, 0, 59302305Sstevel "!No spare PCI bus numbers, range is " 59312305Sstevel "%u->%u, cardbus isn't usable\n", 59322305Sstevel bus_range->lo, bus_range->hi); 59332305Sstevel } 59342305Sstevel kmem_free(bus_range, k); 59352305Sstevel } else 59362305Sstevel pcic_err(pdip, 0, "!No bus-range property seems to " 59372305Sstevel "have been set up\n"); 59382305Sstevel #endif 59392305Sstevel /* 59402305Sstevel * Have a valid parent with the "available" property 59412305Sstevel */ 59422305Sstevel (void) pci_resource_setup(pdip); 59432305Sstevel } 59442305Sstevel 59452305Sstevel if ((strcmp(ddi_get_name(dip), "pcma") == 0) && 59462305Sstevel ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 59472305Sstevel "assigned-addresses", 59482305Sstevel (caddr_t)®s, &rlen) == DDI_SUCCESS) { 59492305Sstevel ra_return_t ra; 59502305Sstevel 59512305Sstevel /* 59522305Sstevel * On the UltraBook IIi the ranges are assigned under 59532305Sstevel * openboot. If we don't free them here the first I/O 59542305Sstevel * space that can be used is up above 0x10000 which 59552305Sstevel * doesn't work for this driver due to restrictions 59562305Sstevel * on the PCI I/O addresses the controllers can cope with. 59572305Sstevel * They are never going to be used by anything else 59582305Sstevel * so free them up to the general pool. AG. 59592305Sstevel */ 59602305Sstevel pcic_err(dip, 1, "Free assigned addresses\n"); 59612305Sstevel 59622305Sstevel if ((PCI_REG_ADDR_G(regs[0].pci_phys_hi) == 59632305Sstevel PCI_REG_ADDR_G(PCI_ADDR_MEM32)) && 59642305Sstevel regs[0].pci_size_low == 0x1000000) { 59652305Sstevel ra.ra_addr_lo = regs[0].pci_phys_low; 59662305Sstevel ra.ra_len = regs[0].pci_size_low; 59672305Sstevel (void) pcmcia_free_mem(dip, &ra); 59682305Sstevel } 59692305Sstevel if ((PCI_REG_ADDR_G(regs[1].pci_phys_hi) == 59702305Sstevel PCI_REG_ADDR_G(PCI_ADDR_IO)) && 59712305Sstevel (regs[1].pci_size_low == 0x8000 || 59722305Sstevel regs[1].pci_size_low == 0x4000)) /* UB-IIi || UB-I */ 59732305Sstevel { 59742305Sstevel ra.ra_addr_lo = regs[1].pci_phys_low; 59752305Sstevel ra.ra_len = regs[1].pci_size_low; 59762305Sstevel (void) pcmcia_free_io(dip, &ra); 59772305Sstevel } 59782305Sstevel kmem_free((caddr_t)regs, rlen); 59792305Sstevel } 59802305Sstevel } 59812305Sstevel 59822305Sstevel /* 59832305Sstevel * translate "available" from pcmcia format to pci format 59842305Sstevel */ 59852305Sstevel static int 59862305Sstevel pcic_apply_avail_ranges(dev_info_t *dip, pcm_regs_t *pcic_p, 59872305Sstevel pci_regspec_t *pci_p, int entries) 59882305Sstevel { 59892305Sstevel int i, range_len, range_entries; 59902305Sstevel pcic_ranges_t *pcic_range_p; 59912305Sstevel 59922305Sstevel if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", 5993*7656SSherry.Moore@Sun.COM (caddr_t)&pcic_range_p, &range_len) != DDI_PROP_SUCCESS) { 59942305Sstevel cmn_err(CE_CONT, "?pcic_apply_avail_ranges: " 5995*7656SSherry.Moore@Sun.COM "no ranges property for pcmcia\n"); 59962305Sstevel return (DDI_FAILURE); 59972305Sstevel } 59982305Sstevel 59992305Sstevel range_entries = range_len / sizeof (pcic_ranges_t); 60002305Sstevel 60012305Sstevel /* for each "available" entry to be translated */ 60022305Sstevel for (i = 0; i < entries; i++, pcic_p++, pci_p++) { 60032305Sstevel int j; 60042305Sstevel pcic_ranges_t *range_p = pcic_range_p; 60052305Sstevel pci_p->pci_phys_hi = -1u; /* default invalid value */ 60062305Sstevel 60072305Sstevel /* for each "ranges" entry to be searched */ 60082305Sstevel for (j = 0; j < range_entries; j++, range_p++) { 60092305Sstevel uint64_t range_end = range_p->pcic_range_caddrlo + 6010*7656SSherry.Moore@Sun.COM range_p->pcic_range_size; 60112305Sstevel uint64_t avail_end = pcic_p->phys_lo + pcic_p->phys_len; 60122305Sstevel 60132305Sstevel if ((range_p->pcic_range_caddrhi != pcic_p->phys_hi) || 60142305Sstevel (range_p->pcic_range_caddrlo > pcic_p->phys_lo) || 60152305Sstevel (range_end < avail_end)) 60162305Sstevel continue; 60172305Sstevel 60182305Sstevel pci_p->pci_phys_hi = range_p->pcic_range_paddrhi; 60192305Sstevel pci_p->pci_phys_mid = range_p->pcic_range_paddrmid; 60202305Sstevel pci_p->pci_phys_low = range_p->pcic_range_paddrlo 60212305Sstevel + (pcic_p->phys_lo - range_p->pcic_range_caddrlo); 60222305Sstevel pci_p->pci_size_hi = 0; 60232305Sstevel pci_p->pci_size_low = pcic_p->phys_len; 60242305Sstevel } 60252305Sstevel } 60262305Sstevel kmem_free(pcic_range_p, range_len); 60272305Sstevel return (DDI_SUCCESS); 60282305Sstevel } 60292305Sstevel 60302305Sstevel static int 60312305Sstevel pcic_open(dev_t *dev, int flag, int otyp, cred_t *cred) 60322305Sstevel { 60332305Sstevel #ifdef CARDBUS 60342305Sstevel if (cardbus_is_cb_minor(*dev)) 60352305Sstevel return (cardbus_open(dev, flag, otyp, cred)); 60362305Sstevel #endif 60372305Sstevel return (EINVAL); 60382305Sstevel } 60392305Sstevel 60402305Sstevel static int 60412305Sstevel pcic_close(dev_t dev, int flag, int otyp, cred_t *cred) 60422305Sstevel { 60432305Sstevel #ifdef CARDBUS 60442305Sstevel if (cardbus_is_cb_minor(dev)) 60452305Sstevel return (cardbus_close(dev, flag, otyp, cred)); 60462305Sstevel #endif 60472305Sstevel return (EINVAL); 60482305Sstevel } 60492305Sstevel 60502305Sstevel static int 60512305Sstevel pcic_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, 60522305Sstevel int *rval) 60532305Sstevel { 60542305Sstevel #ifdef CARDBUS 60552305Sstevel if (cardbus_is_cb_minor(dev)) 60562305Sstevel return (cardbus_ioctl(dev, cmd, arg, mode, cred, rval)); 60572305Sstevel #endif 60582305Sstevel return (EINVAL); 60592305Sstevel } 60602305Sstevel 60612305Sstevel 60622305Sstevel static boolean_t 60632305Sstevel pcic_load_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp) 60642305Sstevel { 60652305Sstevel uint32_t present_state; 60662305Sstevel dev_info_t *dip = pcic->dip; 60672305Sstevel set_socket_t s; 60682305Sstevel get_socket_t g; 60692305Sstevel boolean_t retval; 60702305Sstevel unsigned vccLevel; 60712305Sstevel 60722305Sstevel pcic_err(dip, 8, "entering pcic_load_cardbus\n"); 60732305Sstevel 60742305Sstevel pcic_mutex_exit(&pcic->pc_lock); 60752305Sstevel 60762305Sstevel bzero(&s, sizeof (set_socket_t)); 60772305Sstevel s.socket = sockp->pcs_socket; 60782305Sstevel s.SCIntMask = SBM_CD|SBM_RDYBSY; 60792305Sstevel s.IFType = IF_CARDBUS; 60802305Sstevel s.State = (unsigned)~0; 60812305Sstevel 60822305Sstevel present_state = pcic_getcb(pcic, CB_PRESENT_STATE); 60832305Sstevel if (present_state & PCIC_VCC_3VCARD) 60842305Sstevel s.VccLevel = PCIC_VCC_3VLEVEL; 60852305Sstevel else if (present_state & PCIC_VCC_5VCARD) 60862305Sstevel s.VccLevel = PCIC_VCC_5VLEVEL; 60872305Sstevel else { 60882305Sstevel cmn_err(CE_CONT, 60892305Sstevel "pcic_load_cardbus: unsupported card voltage\n"); 60902305Sstevel goto failure; 60912305Sstevel } 60922305Sstevel vccLevel = s.VccLevel; 60932305Sstevel s.Vpp1Level = s.Vpp2Level = 0; 60942305Sstevel 60952305Sstevel if (pcic_set_socket(dip, &s) != SUCCESS) 60962305Sstevel goto failure; 60972305Sstevel 60982305Sstevel if (pcic_reset_socket(dip, sockp->pcs_socket, 60992305Sstevel RESET_MODE_CARD_ONLY) != SUCCESS) 61002305Sstevel goto failure; 61012305Sstevel 61022305Sstevel bzero(&g, sizeof (get_socket_t)); 61032305Sstevel g.socket = sockp->pcs_socket; 61042305Sstevel if (pcic_get_socket(dip, &g) != SUCCESS) 61052305Sstevel goto failure; 61062305Sstevel 61072305Sstevel bzero(&s, sizeof (set_socket_t)); 61082305Sstevel s.socket = sockp->pcs_socket; 61092305Sstevel s.SCIntMask = SBM_CD; 61102305Sstevel s.IREQRouting = g.IRQRouting; 61112305Sstevel s.IFType = g.IFType; 61122305Sstevel s.CtlInd = g.CtlInd; 61132305Sstevel s.State = (unsigned)~0; 61142305Sstevel s.VccLevel = vccLevel; 61152305Sstevel s.Vpp1Level = s.Vpp2Level = 0; 61162305Sstevel 61177151Srw148561 retval = pcic_set_socket(dip, &s); 61187151Srw148561 pcmcia_cb_resumed(s.socket); 61197151Srw148561 if (retval != SUCCESS) 61202305Sstevel goto failure; 61212305Sstevel 61222305Sstevel retval = cardbus_load_cardbus(dip, sockp->pcs_socket, pcic->pc_base); 61232305Sstevel goto exit; 61242305Sstevel 61252305Sstevel failure: 61262305Sstevel retval = B_FALSE; 61272305Sstevel 61282305Sstevel exit: 61292305Sstevel pcic_mutex_enter(&pcic->pc_lock); 61302305Sstevel pcic_err(dip, 8, "exit pcic_load_cardbus (%s)\n", 61312305Sstevel retval ? "success" : "failure"); 61322305Sstevel return (retval); 61332305Sstevel } 61342305Sstevel 61352305Sstevel static void 61362305Sstevel pcic_unload_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp) 61372305Sstevel { 61382305Sstevel dev_info_t *dip = pcic->dip; 61392305Sstevel set_socket_t s; 61402305Sstevel 61412305Sstevel pcic_mutex_exit(&pcic->pc_lock); 61422305Sstevel 61432305Sstevel cardbus_unload_cardbus(dip); 61442305Sstevel 61452305Sstevel bzero(&s, sizeof (set_socket_t)); 61462305Sstevel s.socket = sockp->pcs_socket; 61472305Sstevel s.SCIntMask = SBM_CD|SBM_RDYBSY; 61482305Sstevel s.IREQRouting = 0; 61492305Sstevel s.IFType = IF_MEMORY; 61502305Sstevel s.CtlInd = 0; 61512305Sstevel s.State = 0; 61522305Sstevel s.VccLevel = s.Vpp1Level = s.Vpp2Level = 0; 61532305Sstevel 61542305Sstevel (void) pcic_set_socket(dip, &s); 61552305Sstevel 61562305Sstevel pcic_mutex_enter(&pcic->pc_lock); 61572305Sstevel } 61582305Sstevel 61592305Sstevel static uint32_t 61602305Sstevel pcic_getcb(pcicdev_t *pcic, int reg) 61612305Sstevel { 61622305Sstevel ASSERT(pcic->pc_io_type == PCIC_IO_TYPE_YENTA); 61632305Sstevel 61642305Sstevel return (ddi_get32(pcic->handle, 61652305Sstevel (uint32_t *)(pcic->ioaddr + CB_CB_OFFSET + reg))); 61662305Sstevel } 61672305Sstevel 61682305Sstevel static void 61692305Sstevel pcic_putcb(pcicdev_t *pcic, int reg, uint32_t value) 61702305Sstevel { 61712305Sstevel ASSERT(pcic->pc_io_type == PCIC_IO_TYPE_YENTA); 61722305Sstevel 61732305Sstevel ddi_put32(pcic->handle, 61742305Sstevel (uint32_t *)(pcic->ioaddr + CB_CB_OFFSET + reg), value); 61752305Sstevel } 61762305Sstevel 61772305Sstevel static void 61782305Sstevel pcic_enable_io_intr(pcicdev_t *pcic, int socket, int irq) 61792305Sstevel { 61802305Sstevel uint8_t value; 61812305Sstevel uint16_t brdgctl; 61822305Sstevel 61832305Sstevel value = pcic_getb(pcic, socket, PCIC_INTERRUPT) & ~PCIC_INTR_MASK; 61842305Sstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, value | irq); 61852305Sstevel 61862305Sstevel switch (pcic->pc_type) { 61872305Sstevel case PCIC_INTEL_i82092: 61882305Sstevel pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ, 61892305Sstevel PCIC_82092_INT_ENABLE); 61902305Sstevel break; 61912305Sstevel case PCIC_O2_OZ6912: 61922305Sstevel value = pcic_getb(pcic, 0, PCIC_CENTDMA); 61932305Sstevel value |= 0x8; 61942305Sstevel pcic_putb(pcic, 0, PCIC_CENTDMA, value); 61952305Sstevel break; 61962305Sstevel case PCIC_CL_PD6832: 61972305Sstevel case PCIC_TI_PCI1250: 61982305Sstevel case PCIC_TI_PCI1221: 61992305Sstevel case PCIC_TI_PCI1225: 62002305Sstevel case PCIC_TI_PCI1410: 62012305Sstevel case PCIC_ENE_1410: 62022305Sstevel case PCIC_TI_PCI1510: 62032305Sstevel case PCIC_TI_PCI1520: 62042305Sstevel case PCIC_TI_PCI1420: 62052305Sstevel case PCIC_ENE_1420: 62062305Sstevel /* route card functional interrupts to PCI interrupts */ 62072305Sstevel brdgctl = ddi_get16(pcic->cfg_handle, 62082305Sstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL)); 62092305Sstevel pcic_err(NULL, 1, 62102305Sstevel "pcic_enable_io_intr brdgctl(0x%x) was: 0x%x\n", 62112305Sstevel PCI_CBUS_BRIDGE_CTRL, brdgctl); 62122305Sstevel brdgctl &= ~PCIC_BRDGCTL_INTR_MASK; 62132305Sstevel ddi_put16(pcic->cfg_handle, 62142305Sstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL), 62152305Sstevel brdgctl); 62162305Sstevel /* Flush the write */ 62172305Sstevel (void) ddi_get16(pcic->cfg_handle, 62182305Sstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL)); 62192305Sstevel break; 62202305Sstevel default: 62212305Sstevel break; 62222305Sstevel } 62232305Sstevel } 62242305Sstevel 62252305Sstevel static void 62262305Sstevel pcic_disable_io_intr(pcicdev_t *pcic, int socket) 62272305Sstevel { 62282305Sstevel uint8_t value; 62292305Sstevel uint16_t brdgctl; 62302305Sstevel 62312305Sstevel value = pcic_getb(pcic, socket, PCIC_INTERRUPT) & ~PCIC_INTR_MASK; 62322305Sstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, value); 62332305Sstevel 62342305Sstevel switch (pcic->pc_type) { 62352305Sstevel case PCIC_INTEL_i82092: 62362305Sstevel pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ, 62372305Sstevel PCIC_82092_INT_DISABLE); 62382305Sstevel break; 62392305Sstevel case PCIC_O2_OZ6912: 62402305Sstevel value = pcic_getb(pcic, 0, PCIC_CENTDMA); 62412305Sstevel value &= ~0x8; 62422305Sstevel pcic_putb(pcic, 0, PCIC_CENTDMA, value); 62432305Sstevel /* Flush the write */ 62442305Sstevel (void) pcic_getb(pcic, 0, PCIC_CENTDMA); 62452305Sstevel break; 62462305Sstevel case PCIC_CL_PD6832: 62472305Sstevel case PCIC_TI_PCI1250: 62482305Sstevel case PCIC_TI_PCI1221: 62492305Sstevel case PCIC_TI_PCI1225: 62502305Sstevel case PCIC_TI_PCI1410: 62512305Sstevel case PCIC_ENE_1410: 62522305Sstevel case PCIC_TI_PCI1510: 62532305Sstevel case PCIC_TI_PCI1520: 62542305Sstevel case PCIC_TI_PCI1420: 62552305Sstevel case PCIC_ENE_1420: 62562305Sstevel /* 62572305Sstevel * This maps I/O interrupts to ExCA which 62582305Sstevel * have been turned off by the write to 62592305Sstevel * PCIC_INTERRUPT above. It would appear to 62602305Sstevel * be the only way to actually turn I/O Ints off 62612305Sstevel * while retaining CS Ints. 62622305Sstevel */ 62632305Sstevel brdgctl = ddi_get16(pcic->cfg_handle, 62642305Sstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL)); 62652305Sstevel pcic_err(NULL, 1, 62662305Sstevel "pcic_disable_io_intr brdgctl(0x%x) was: 0x%x\n", 62672305Sstevel PCI_CBUS_BRIDGE_CTRL, brdgctl); 62682305Sstevel brdgctl |= PCIC_BRDGCTL_INTR_MASK; 62692305Sstevel ddi_put16(pcic->cfg_handle, 62702305Sstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL), 62712305Sstevel brdgctl); 62722305Sstevel /* Flush the write */ 62732305Sstevel (void) ddi_get16(pcic->cfg_handle, 62742305Sstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL)); 62752305Sstevel break; 62762305Sstevel default: 62772305Sstevel break; 62782305Sstevel } 62792305Sstevel } 62802305Sstevel 62812305Sstevel static void 62822305Sstevel pcic_cb_enable_intr(dev_info_t *dip) 62832305Sstevel { 62842305Sstevel anp_t *anp = ddi_get_driver_private(dip); 62852305Sstevel pcicdev_t *pcic = anp->an_private; 62862305Sstevel 62872305Sstevel mutex_enter(&pcic->pc_lock); 62882305Sstevel pcic_enable_io_intr(pcic, 0, pcic->pc_sockets[0].pcs_irq); 62892305Sstevel mutex_exit(&pcic->pc_lock); 62902305Sstevel } 62912305Sstevel 62922305Sstevel static void 62932305Sstevel pcic_cb_disable_intr(dev_info_t *dip) 62942305Sstevel { 62952305Sstevel anp_t *anp = ddi_get_driver_private(dip); 62962305Sstevel pcicdev_t *pcic = anp->an_private; 62972305Sstevel 62982305Sstevel mutex_enter(&pcic->pc_lock); 62992305Sstevel pcic_disable_io_intr(pcic, 0); 63002305Sstevel mutex_exit(&pcic->pc_lock); 63012305Sstevel } 63022305Sstevel 63032305Sstevel static int 63042305Sstevel log_pci_cfg_err(ushort_t e, int bridge_secondary) 63052305Sstevel { 63062305Sstevel int nerr = 0; 63072305Sstevel if (e & PCI_STAT_PERROR) { 63082305Sstevel nerr++; 63092305Sstevel cmn_err(CE_CONT, "detected parity error.\n"); 63102305Sstevel } 63112305Sstevel if (e & PCI_STAT_S_SYSERR) { 63122305Sstevel nerr++; 63132305Sstevel if (bridge_secondary) 63142305Sstevel cmn_err(CE_CONT, "received system error.\n"); 63152305Sstevel else 63162305Sstevel cmn_err(CE_CONT, "signalled system error.\n"); 63172305Sstevel } 63182305Sstevel if (e & PCI_STAT_R_MAST_AB) { 63192305Sstevel nerr++; 63202305Sstevel cmn_err(CE_CONT, "received master abort.\n"); 63212305Sstevel } 63222305Sstevel if (e & PCI_STAT_R_TARG_AB) 63232305Sstevel cmn_err(CE_CONT, "received target abort.\n"); 63242305Sstevel if (e & PCI_STAT_S_TARG_AB) 63252305Sstevel cmn_err(CE_CONT, "signalled target abort\n"); 63262305Sstevel if (e & PCI_STAT_S_PERROR) { 63272305Sstevel nerr++; 63282305Sstevel cmn_err(CE_CONT, "signalled parity error\n"); 63292305Sstevel } 63302305Sstevel return (nerr); 63312305Sstevel } 63322305Sstevel 63332305Sstevel #if defined(__sparc) 63342305Sstevel static int 63352305Sstevel pcic_fault(enum pci_fault_ops op, void *arg) 63362305Sstevel { 63372305Sstevel pcicdev_t *pcic = (pcicdev_t *)arg; 63382305Sstevel ushort_t pci_cfg_stat = 63392305Sstevel pci_config_get16(pcic->cfg_handle, PCI_CONF_STAT); 63402305Sstevel ushort_t pci_cfg_sec_stat = 63412305Sstevel pci_config_get16(pcic->cfg_handle, 0x16); 63422305Sstevel char nm[24]; 63432305Sstevel int nerr = 0; 63442305Sstevel 63452305Sstevel cardbus_dump_pci_config(pcic->dip); 63462305Sstevel 63472305Sstevel switch (op) { 63482305Sstevel case FAULT_LOG: 63492305Sstevel (void) sprintf(nm, "%s-%d", ddi_driver_name(pcic->dip), 63502305Sstevel ddi_get_instance(pcic->dip)); 63512305Sstevel 63522305Sstevel cmn_err(CE_WARN, "%s: PCIC fault log start:\n", nm); 63532305Sstevel cmn_err(CE_WARN, "%s: primary err (%x):\n", nm, pci_cfg_stat); 63542305Sstevel nerr += log_pci_cfg_err(pci_cfg_stat, 0); 63552305Sstevel cmn_err(CE_WARN, "%s: sec err (%x):\n", nm, pci_cfg_sec_stat); 63562305Sstevel nerr += log_pci_cfg_err(pci_cfg_sec_stat, 1); 63572305Sstevel cmn_err(CE_CONT, "%s: PCI fault log end.\n", nm); 63582305Sstevel return (nerr); 63592305Sstevel case FAULT_POKEFINI: 63602305Sstevel case FAULT_RESET: 63612305Sstevel pci_config_put16(pcic->cfg_handle, 63622305Sstevel PCI_CONF_STAT, pci_cfg_stat); 63632305Sstevel pci_config_put16(pcic->cfg_handle, 0x16, pci_cfg_sec_stat); 63642305Sstevel break; 63652305Sstevel case FAULT_POKEFLT: 63662305Sstevel if (!(pci_cfg_stat & PCI_STAT_S_SYSERR)) 63672305Sstevel return (1); 63682305Sstevel if (!(pci_cfg_sec_stat & PCI_STAT_R_MAST_AB)) 63692305Sstevel return (1); 63702305Sstevel break; 63712305Sstevel default: 63722305Sstevel break; 63732305Sstevel } 63742305Sstevel return (DDI_SUCCESS); 63752305Sstevel } 63762305Sstevel #endif 63772305Sstevel 63782305Sstevel static void 63797151Srw148561 pcic_do_resume(pcicdev_t *pcic) 63802305Sstevel { 63817151Srw148561 int i, interrupt; 63827151Srw148561 uint8_t cfg; 63837151Srw148561 63842305Sstevel 63852305Sstevel #if defined(PCIC_DEBUG) 63867151Srw148561 pcic_err(NULL, 6, "pcic_do_resume(): entered\n"); 63872305Sstevel #endif 63887151Srw148561 63897151Srw148561 pcic_mutex_enter(&pcic->pc_lock); /* protect the registers */ 63907151Srw148561 for (i = 0; i < pcic->pc_numsockets; i++) { 63917151Srw148561 /* Enable interrupts on PCI if needs be */ 63927151Srw148561 interrupt = pcic_getb(pcic, i, PCIC_INTERRUPT); 63937151Srw148561 if (pcic->pc_flags & PCF_USE_SMI) 63947151Srw148561 interrupt |= PCIC_INTR_ENABLE; 63957151Srw148561 pcic_putb(pcic, i, PCIC_INTERRUPT, 63967151Srw148561 PCIC_RESET | interrupt); 63977151Srw148561 pcic->pc_sockets[i].pcs_debounce_id = 63987151Srw148561 pcic_add_debqueue(&pcic->pc_sockets[i], 63997151Srw148561 drv_usectohz(pcic_debounce_time)); 64007151Srw148561 } 64017151Srw148561 pcic_mutex_exit(&pcic->pc_lock); /* protect the registers */ 64027151Srw148561 if (pcic_do_pcmcia_sr) 64037151Srw148561 (void) pcmcia_wait_insert(pcic->dip); 64047151Srw148561 /* 64057151Srw148561 * The CardBus controller may be in RESET state after the 64067151Srw148561 * system is resumed from sleeping. The RESET bit is in 64077151Srw148561 * the Bridge Control register. This is true for all(TI, 64087151Srw148561 * Toshiba ToPIC95/97, RICOH, and O2Micro) CardBus 64097151Srw148561 * controllers. Need to clear the RESET bit explicitly. 64107151Srw148561 */ 64117151Srw148561 cfg = ddi_get8(pcic->cfg_handle, 6412*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG); 64137151Srw148561 if (cfg & (1<<6)) { 64147151Srw148561 cfg &= ~(1<<6); 64157151Srw148561 ddi_put8(pcic->cfg_handle, 6416*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG, 6417*7656SSherry.Moore@Sun.COM cfg); 64187151Srw148561 cfg = ddi_get8(pcic->cfg_handle, 6419*7656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG); 64207151Srw148561 if (cfg & (1<<6)) { 6421*7656SSherry.Moore@Sun.COM pcic_err(pcic->dip, 1, 6422*7656SSherry.Moore@Sun.COM "Failed to take pcic out of reset"); 64232305Sstevel } 64242305Sstevel } 64257151Srw148561 64262305Sstevel } 64272305Sstevel 64282305Sstevel static void 64292305Sstevel pcic_debounce(pcic_socket_t *pcs) 64302305Sstevel { 64312305Sstevel uint8_t status, stschng; 64322305Sstevel 64332305Sstevel pcic_mutex_enter(&pcs->pcs_pcic->pc_lock); 64342305Sstevel pcs->pcs_flags &= ~PCS_STARTING; 64352305Sstevel stschng = pcic_getb(pcs->pcs_pcic, pcs->pcs_socket, 64362305Sstevel PCIC_CARD_STATUS_CHANGE); 64372305Sstevel status = pcic_getb(pcs->pcs_pcic, pcs->pcs_socket, 64382305Sstevel PCIC_INTERFACE_STATUS); 64392305Sstevel #ifdef PCIC_DEBUG 64402305Sstevel pcic_err(pcs->pcs_pcic->dip, 8, 64412305Sstevel "pcic_debounce(0x%p, dip=0x%p) socket %d st 0x%x " 64422305Sstevel "chg 0x%x flg 0x%x\n", 64432305Sstevel (void *)pcs, (void *) pcs->pcs_pcic->dip, pcs->pcs_socket, 64442305Sstevel status, stschng, pcs->pcs_flags); 64452305Sstevel #endif 64462305Sstevel 64472305Sstevel pcic_putb(pcs->pcs_pcic, pcs->pcs_socket, PCIC_CARD_STATUS_CHANGE, 64482305Sstevel PCIC_CD_DETECT); 64492305Sstevel pcic_handle_cd_change(pcs->pcs_pcic, pcs, status); 64502305Sstevel pcic_mutex_exit(&pcs->pcs_pcic->pc_lock); 64512305Sstevel } 64522305Sstevel 64532305Sstevel static void 64542305Sstevel pcic_deb_thread() 64552305Sstevel { 64562305Sstevel callb_cpr_t cprinfo; 64572305Sstevel struct debounce *debp; 64582305Sstevel clock_t lastt; 64592305Sstevel 64602305Sstevel CALLB_CPR_INIT(&cprinfo, &pcic_deb_mtx, 64612305Sstevel callb_generic_cpr, "pcic debounce thread"); 64622305Sstevel mutex_enter(&pcic_deb_mtx); 64632305Sstevel while (pcic_deb_threadid) { 64642305Sstevel while (pcic_deb_queue) { 64652305Sstevel #ifdef PCIC_DEBUG 64662305Sstevel pcic_dump_debqueue("Thread"); 64672305Sstevel #endif 64682305Sstevel debp = pcic_deb_queue; 64692305Sstevel (void) drv_getparm(LBOLT, &lastt); 64702305Sstevel if (lastt >= debp->expire) { 64712305Sstevel pcic_deb_queue = debp->next; 64722305Sstevel mutex_exit(&pcic_deb_mtx); 64732305Sstevel pcic_debounce(debp->pcs); 64742305Sstevel mutex_enter(&pcic_deb_mtx); 64752305Sstevel kmem_free(debp, sizeof (*debp)); 64762305Sstevel } else { 64772305Sstevel (void) cv_timedwait(&pcic_deb_cv, 64782305Sstevel &pcic_deb_mtx, debp->expire); 64792305Sstevel } 64802305Sstevel } 64812305Sstevel CALLB_CPR_SAFE_BEGIN(&cprinfo); 64822305Sstevel cv_wait(&pcic_deb_cv, &pcic_deb_mtx); 64832305Sstevel CALLB_CPR_SAFE_END(&cprinfo, &pcic_deb_mtx); 64842305Sstevel } 64852305Sstevel pcic_deb_threadid = (kthread_t *)1; 64862305Sstevel cv_signal(&pcic_deb_cv); 64872305Sstevel CALLB_CPR_EXIT(&cprinfo); /* Also exits the mutex */ 64882305Sstevel thread_exit(); 64892305Sstevel } 64902305Sstevel 64912305Sstevel static void * 64922305Sstevel pcic_add_debqueue(pcic_socket_t *pcs, int clocks) 64932305Sstevel { 64942305Sstevel clock_t lbolt; 64952305Sstevel struct debounce *dbp, **dbpp = &pcic_deb_queue; 64962305Sstevel 64972305Sstevel (void) drv_getparm(LBOLT, &lbolt); 64983664Srw148561 dbp = kmem_alloc(sizeof (struct debounce), KM_SLEEP); 64992305Sstevel 65002305Sstevel dbp->expire = lbolt + clocks; 65012305Sstevel dbp->pcs = pcs; 65022305Sstevel mutex_enter(&pcic_deb_mtx); 65032305Sstevel while (*dbpp) { 65042305Sstevel if (dbp->expire > (*dbpp)->expire) 65052305Sstevel dbpp = &((*dbpp)->next); 65062305Sstevel else 65072305Sstevel break; 65082305Sstevel } 65092305Sstevel dbp->next = *dbpp; 65102305Sstevel *dbpp = dbp; 65112305Sstevel #ifdef PCIC_DEBUG 65122305Sstevel pcic_dump_debqueue("Add"); 65132305Sstevel #endif 65142305Sstevel cv_signal(&pcic_deb_cv); 65152305Sstevel mutex_exit(&pcic_deb_mtx); 65162305Sstevel return (dbp); 65172305Sstevel } 65182305Sstevel 65192305Sstevel static void 65202305Sstevel pcic_rm_debqueue(void *id) 65212305Sstevel { 65222305Sstevel struct debounce *dbp, **dbpp = &pcic_deb_queue; 65232305Sstevel 65242305Sstevel dbp = (struct debounce *)id; 65252305Sstevel mutex_enter(&pcic_deb_mtx); 65262305Sstevel while (*dbpp) { 65272305Sstevel if (*dbpp == dbp) { 65282305Sstevel *dbpp = dbp->next; 65292305Sstevel kmem_free(dbp, sizeof (*dbp)); 65302305Sstevel #ifdef PCIC_DEBUG 65312305Sstevel pcic_dump_debqueue("Remove"); 65322305Sstevel #endif 65332305Sstevel cv_signal(&pcic_deb_cv); 65342305Sstevel mutex_exit(&pcic_deb_mtx); 65352305Sstevel return; 65362305Sstevel } 65372305Sstevel dbpp = &((*dbpp)->next); 65382305Sstevel } 65392305Sstevel pcic_err(NULL, 6, "pcic: Failed to find debounce id 0x%p\n", id); 65402305Sstevel mutex_exit(&pcic_deb_mtx); 65412305Sstevel } 65422305Sstevel 65432305Sstevel 65442305Sstevel static int pcic_powerdelay = 0; 65452305Sstevel 65462305Sstevel static int 65472305Sstevel pcic_exca_powerctl(pcicdev_t *pcic, int socket, int powerlevel) 65482305Sstevel { 65492305Sstevel int ind, value, orig_pwrctl; 65502305Sstevel 65512305Sstevel /* power setup -- if necessary */ 65522305Sstevel orig_pwrctl = pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 65532305Sstevel 65542305Sstevel #if defined(PCIC_DEBUG) 65552305Sstevel pcic_err(pcic->dip, 6, 65562305Sstevel "pcic_exca_powerctl(socket %d) powerlevel=%x orig 0x%x\n", 65572305Sstevel socket, powerlevel, orig_pwrctl); 65582305Sstevel #endif 65592305Sstevel /* Preserve the PCIC_OUTPUT_ENABLE (control lines output enable) bit. */ 65602305Sstevel powerlevel = (powerlevel & ~POWER_OUTPUT_ENABLE) | 65612305Sstevel (orig_pwrctl & POWER_OUTPUT_ENABLE); 65622305Sstevel if (powerlevel != orig_pwrctl) { 65632305Sstevel if (powerlevel & ~POWER_OUTPUT_ENABLE) { 65642305Sstevel int ifs; 65652305Sstevel /* 65662305Sstevel * set power to socket 65672305Sstevel * note that the powerlevel was calculated earlier 65682305Sstevel */ 65692305Sstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel); 65702305Sstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 65712305Sstevel 65722305Sstevel /* 65732305Sstevel * this second write to the power control register 65742305Sstevel * is needed to resolve a problem on 65752305Sstevel * the IBM ThinkPad 750 65762305Sstevel * where the first write doesn't latch. 65772305Sstevel * The second write appears to always work and 65782305Sstevel * doesn't hurt the operation of other chips 65792305Sstevel * so we can just use it -- this is good since we can't 65802305Sstevel * determine what chip the 750 actually uses 65812305Sstevel * (I suspect an early Ricoh). 65822305Sstevel */ 65832305Sstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel); 65842305Sstevel 65852305Sstevel value = pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 65862305Sstevel pcic_mswait(pcic, socket, pcic_powerdelay); 65872305Sstevel #if defined(PCIC_DEBUG) 65882305Sstevel pcic_err(pcic->dip, 8, 65892305Sstevel "\tpowerlevel reg = %x (ifs %x)\n", 65902305Sstevel value, pcic_getb(pcic, socket, 65912305Sstevel PCIC_INTERFACE_STATUS)); 65922305Sstevel pcic_err(pcic->dip, 8, 65932305Sstevel "CBus regs: PS 0x%x, Control 0x%x\n", 65942305Sstevel pcic_getcb(pcic, CB_PRESENT_STATE), 65952305Sstevel pcic_getcb(pcic, CB_CONTROL)); 65962305Sstevel #endif 65972305Sstevel /* 65982305Sstevel * since power was touched, make sure it says it 65992305Sstevel * is on. This lets it become stable. 66002305Sstevel */ 66012305Sstevel for (ind = 0; ind < 20; ind++) { 66022305Sstevel ifs = pcic_getb(pcic, socket, 66032305Sstevel PCIC_INTERFACE_STATUS); 66042305Sstevel if (ifs & PCIC_POWER_ON) 66052305Sstevel break; 66062305Sstevel else { 66072305Sstevel pcic_putb(pcic, socket, 66082305Sstevel PCIC_POWER_CONTROL, 0); 66092305Sstevel (void) pcic_getb(pcic, socket, 66102305Sstevel PCIC_POWER_CONTROL); 66112305Sstevel pcic_mswait(pcic, socket, 40); 66122305Sstevel if (ind == 10) { 66132305Sstevel pcic_putcb(pcic, CB_EVENT_FORCE, 66142305Sstevel CB_EF_CVTEST); 66152305Sstevel pcic_mswait(pcic, socket, 100); 66162305Sstevel } 66172305Sstevel pcic_putb(pcic, socket, 66182305Sstevel PCIC_POWER_CONTROL, 66192305Sstevel powerlevel & ~POWER_OUTPUT_ENABLE); 66202305Sstevel (void) pcic_getb(pcic, socket, 66212305Sstevel PCIC_POWER_CONTROL); 66222305Sstevel pcic_mswait(pcic, socket, 66232305Sstevel pcic_powerdelay); 66242305Sstevel pcic_putb(pcic, socket, 66252305Sstevel PCIC_POWER_CONTROL, powerlevel); 66262305Sstevel (void) pcic_getb(pcic, socket, 66272305Sstevel PCIC_POWER_CONTROL); 66282305Sstevel pcic_mswait(pcic, socket, 66292305Sstevel pcic_powerdelay); 66302305Sstevel } 66312305Sstevel } 66322305Sstevel 66332305Sstevel if (!(ifs & PCIC_POWER_ON)) { 66342305Sstevel cmn_err(CE_WARN, 66352305Sstevel "pcic socket %d: Power didn't get turned" 66362305Sstevel "on!\nif status 0x%x pwrc 0x%x(x%x) " 66372305Sstevel "misc1 0x%x igc 0x%x ind %d\n", 66382305Sstevel socket, ifs, 66392305Sstevel pcic_getb(pcic, socket, PCIC_POWER_CONTROL), 66402305Sstevel orig_pwrctl, 66412305Sstevel pcic_getb(pcic, socket, PCIC_MISC_CTL_1), 66422305Sstevel pcic_getb(pcic, socket, PCIC_INTERRUPT), 66432305Sstevel ind); 66442305Sstevel return (BAD_VCC); 66452305Sstevel } 66462305Sstevel #if defined(PCIC_DEBUG) 66472305Sstevel pcic_err(pcic->dip, 8, 66482305Sstevel "\tind = %d, if status %x pwrc 0x%x " 66492305Sstevel "misc1 0x%x igc 0x%x\n", 66502305Sstevel ind, ifs, 66512305Sstevel pcic_getb(pcic, socket, PCIC_POWER_CONTROL), 66522305Sstevel pcic_getb(pcic, socket, PCIC_MISC_CTL_1), 66532305Sstevel pcic_getb(pcic, socket, PCIC_INTERRUPT)); 66542305Sstevel #endif 66552305Sstevel } else { 66562305Sstevel /* explicitly turned off the power */ 66572305Sstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel); 66582305Sstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 66592305Sstevel } 66602305Sstevel } 66612305Sstevel return (SUCCESS); 66622305Sstevel } 66632305Sstevel 66642305Sstevel static int pcic_cbdoreset_during_poweron = 1; 66652305Sstevel static int 66662305Sstevel pcic_cbus_powerctl(pcicdev_t *pcic, int socket) 66672305Sstevel { 66682305Sstevel uint32_t cbctl = 0, orig_cbctl, cbstev, cbps; 66692305Sstevel int ind, iobits; 66702305Sstevel pcic_socket_t *sockp = &pcic->pc_sockets[socket]; 66712305Sstevel 66722305Sstevel pcic_putcb(pcic, CB_STATUS_EVENT, CB_SE_POWER_CYCLE); 66732305Sstevel 66742305Sstevel ind = pcic_power[sockp->pcs_vpp1].PowerLevel/10; 66752305Sstevel cbctl |= pcic_cbv_levels[ind]; 66762305Sstevel 66772305Sstevel ind = pcic_power[sockp->pcs_vcc].PowerLevel/10; 66782305Sstevel cbctl |= (pcic_cbv_levels[ind]<<4); 66792305Sstevel 66802305Sstevel orig_cbctl = pcic_getcb(pcic, CB_CONTROL); 66812305Sstevel 66822305Sstevel #if defined(PCIC_DEBUG) 66832305Sstevel pcic_err(pcic->dip, 6, 66842305Sstevel "pcic_cbus_powerctl(socket %d) vcc %d vpp1 %d " 66852305Sstevel "cbctl 0x%x->0x%x\n", 66862305Sstevel socket, sockp->pcs_vcc, sockp->pcs_vpp1, orig_cbctl, cbctl); 66872305Sstevel #endif 66882305Sstevel if (cbctl != orig_cbctl) { 6689*7656SSherry.Moore@Sun.COM if (pcic_cbdoreset_during_poweron && 6690*7656SSherry.Moore@Sun.COM (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) { 6691*7656SSherry.Moore@Sun.COM iobits = pcic_getb(pcic, socket, PCIC_INTERRUPT); 6692*7656SSherry.Moore@Sun.COM pcic_putb(pcic, socket, PCIC_INTERRUPT, 6693*7656SSherry.Moore@Sun.COM iobits & ~PCIC_RESET); 6694*7656SSherry.Moore@Sun.COM } 6695*7656SSherry.Moore@Sun.COM pcic_putcb(pcic, CB_CONTROL, cbctl); 6696*7656SSherry.Moore@Sun.COM 6697*7656SSherry.Moore@Sun.COM if ((cbctl & CB_C_VCCMASK) == (orig_cbctl & CB_C_VCCMASK)) { 66982305Sstevel pcic_mswait(pcic, socket, pcic_powerdelay); 66992305Sstevel return (SUCCESS); 6700*7656SSherry.Moore@Sun.COM } 6701*7656SSherry.Moore@Sun.COM for (ind = 0; ind < 20; ind++) { 67022305Sstevel cbstev = pcic_getcb(pcic, CB_STATUS_EVENT); 67032305Sstevel 67042305Sstevel if (cbstev & CB_SE_POWER_CYCLE) { 67052305Sstevel 67062305Sstevel /* 67072305Sstevel * delay 400 ms: though the standard defines that the Vcc 67082305Sstevel * set-up time is 20 ms, some PC-Card bridge requires longer 67092305Sstevel * duration. 67102305Sstevel * Note: We should check the status AFTER the delay to give time 67112305Sstevel * for things to stabilize. 67122305Sstevel */ 6713*7656SSherry.Moore@Sun.COM pcic_mswait(pcic, socket, 400); 6714*7656SSherry.Moore@Sun.COM 6715*7656SSherry.Moore@Sun.COM cbps = pcic_getcb(pcic, CB_PRESENT_STATE); 6716*7656SSherry.Moore@Sun.COM if (cbctl && !(cbps & CB_PS_POWER_CYCLE)) { 67172305Sstevel /* break; */ 67182305Sstevel cmn_err(CE_WARN, "cbus_powerctl: power off??\n"); 6719*7656SSherry.Moore@Sun.COM } 6720*7656SSherry.Moore@Sun.COM if (cbctl & CB_PS_BADVCC) { 67212305Sstevel cmn_err(CE_WARN, "cbus_powerctl: bad power request\n"); 67222305Sstevel break; 6723*7656SSherry.Moore@Sun.COM } 67242305Sstevel 67252305Sstevel #if defined(PCIC_DEBUG) 6726*7656SSherry.Moore@Sun.COM pcic_err(pcic->dip, 8, 6727*7656SSherry.Moore@Sun.COM "cbstev = 0x%x cbps = 0x%x cbctl 0x%x(0x%x)", 6728*7656SSherry.Moore@Sun.COM cbstev, pcic_getcb(pcic, CB_PRESENT_STATE), 6729*7656SSherry.Moore@Sun.COM cbctl, orig_cbctl); 67302305Sstevel #endif 6731*7656SSherry.Moore@Sun.COM if (pcic_cbdoreset_during_poweron && 6732*7656SSherry.Moore@Sun.COM (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) { 6733*7656SSherry.Moore@Sun.COM pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits); 6734*7656SSherry.Moore@Sun.COM } 6735*7656SSherry.Moore@Sun.COM return (SUCCESS); 67362305Sstevel } 67372305Sstevel pcic_mswait(pcic, socket, 40); 6738*7656SSherry.Moore@Sun.COM } 6739*7656SSherry.Moore@Sun.COM if (pcic_cbdoreset_during_poweron && 6740*7656SSherry.Moore@Sun.COM (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) { 6741*7656SSherry.Moore@Sun.COM pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits); 6742*7656SSherry.Moore@Sun.COM } 6743*7656SSherry.Moore@Sun.COM cmn_err(CE_WARN, 67442305Sstevel "pcic socket %d: Power didn't get turned on/off!\n" 67452305Sstevel "cbstev = 0x%x cbps = 0x%x cbctl 0x%x(0x%x) " 67462305Sstevel "vcc %d vpp1 %d", socket, cbstev, 67472305Sstevel pcic_getcb(pcic, CB_PRESENT_STATE), 67482305Sstevel cbctl, orig_cbctl, sockp->pcs_vcc, sockp->pcs_vpp1); 6749*7656SSherry.Moore@Sun.COM return (BAD_VCC); 67502305Sstevel } 67512305Sstevel return (SUCCESS); 67522305Sstevel } 67532305Sstevel 67542305Sstevel static int pcic_do_pprintf = 0; 67552305Sstevel 67562305Sstevel static void 67572305Sstevel pcic_dump_debqueue(char *msg) 67582305Sstevel { 67592305Sstevel struct debounce *debp = pcic_deb_queue; 67602305Sstevel clock_t lbolt; 67612305Sstevel 67622305Sstevel (void) drv_getparm(LBOLT, &lbolt); 67632305Sstevel pcic_err(NULL, 6, debp ? "pcic debounce list (%s) lbolt 0x%x:\n" : 67642305Sstevel "pcic debounce_list (%s) EMPTY lbolt 0x%x\n", msg, lbolt); 67652305Sstevel while (debp) { 67662305Sstevel pcic_err(NULL, 6, "%p: exp 0x%x next 0x%p id 0x%p\n", 67672305Sstevel (void *) debp, (int)debp->expire, (void *) debp->next, 67682305Sstevel debp->pcs->pcs_debounce_id); 67692305Sstevel debp = debp->next; 67702305Sstevel } 67712305Sstevel } 67722305Sstevel 67732305Sstevel 67742305Sstevel /* PRINTFLIKE3 */ 67752305Sstevel static void 67762305Sstevel pcic_err(dev_info_t *dip, int level, const char *fmt, ...) 67772305Sstevel { 67782305Sstevel if (pcic_debug && (level <= pcic_debug)) { 67792305Sstevel va_list adx; 67802305Sstevel int instance; 67812305Sstevel char buf[256]; 67822305Sstevel const char *name; 67832305Sstevel #if !defined(PCIC_DEBUG) 67842305Sstevel int ce; 67852305Sstevel char qmark = 0; 67862305Sstevel 67872305Sstevel if (level <= 3) 67882305Sstevel ce = CE_WARN; 67892305Sstevel else 67902305Sstevel ce = CE_CONT; 67912305Sstevel if (level == 4) 67922305Sstevel qmark = 1; 67932305Sstevel #endif 67942305Sstevel 67952305Sstevel if (dip) { 67962305Sstevel instance = ddi_get_instance(dip); 67972305Sstevel /* name = ddi_binding_name(dip); */ 67982305Sstevel name = ddi_driver_name(dip); 67992305Sstevel } else { 68002305Sstevel instance = 0; 68012305Sstevel name = ""; 68022305Sstevel } 68032305Sstevel 68042305Sstevel va_start(adx, fmt); 68052305Sstevel (void) vsprintf(buf, fmt, adx); 68062305Sstevel va_end(adx); 68072305Sstevel 68082305Sstevel #if defined(PCIC_DEBUG) 68092305Sstevel if (pcic_do_pprintf) { 68102305Sstevel if (dip) { 68112305Sstevel if (instance >= 0) 68122305Sstevel prom_printf("%s(%d),0x%p: %s", name, 68137240Srh87107 instance, (void *)dip, buf); 68142305Sstevel else 68152305Sstevel prom_printf("%s,0x%p: %s", 68167240Srh87107 name, (void *)dip, buf); 68172305Sstevel } else 68182305Sstevel prom_printf(buf); 68192305Sstevel } else { 68202305Sstevel if (dip) { 68212305Sstevel if (instance >= 0) 68222305Sstevel cmn_err(CE_CONT, "%s(%d),0x%p: %s", 68232305Sstevel name, instance, (void *) dip, buf); 68242305Sstevel else 68252305Sstevel cmn_err(CE_CONT, "%s,0x%p: %s", 68262305Sstevel name, (void *) dip, buf); 68272305Sstevel } else 68282305Sstevel cmn_err(CE_CONT, buf); 68292305Sstevel } 68302305Sstevel #else 68312305Sstevel if (dip) 68322305Sstevel cmn_err(ce, qmark ? "?%s%d: %s" : "%s%d: %s", name, 68332305Sstevel instance, buf); 68342305Sstevel else 68352305Sstevel cmn_err(ce, qmark ? "?%s" : buf, buf); 68362305Sstevel #endif 68372305Sstevel } 68382305Sstevel } 6839