13db86aabSstevel /*
23db86aabSstevel * CDDL HEADER START
33db86aabSstevel *
43db86aabSstevel * The contents of this file are subject to the terms of the
53db86aabSstevel * Common Development and Distribution License (the "License").
63db86aabSstevel * You may not use this file except in compliance with the License.
73db86aabSstevel *
83db86aabSstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93db86aabSstevel * or http://www.opensolaris.org/os/licensing.
103db86aabSstevel * See the License for the specific language governing permissions
113db86aabSstevel * and limitations under the License.
123db86aabSstevel *
133db86aabSstevel * When distributing Covered Code, include this CDDL HEADER in each
143db86aabSstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153db86aabSstevel * If applicable, add the following below this CDDL HEADER, with the
163db86aabSstevel * fields enclosed by brackets "[]" replaced with your own identifying
173db86aabSstevel * information: Portions Copyright [yyyy] [name of copyright owner]
183db86aabSstevel *
193db86aabSstevel * CDDL HEADER END
203db86aabSstevel */
213db86aabSstevel
223db86aabSstevel /*
2311c2b4c0Srw148561 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
243db86aabSstevel * Use is subject to license terms.
253db86aabSstevel */
263db86aabSstevel
273db86aabSstevel /*
283db86aabSstevel * PCIC device/interrupt handler
293db86aabSstevel * The "pcic" driver handles the Intel 82365SL, Cirrus Logic
303db86aabSstevel * and Toshiba (and possibly other clones) PCMCIA adapter chip
313db86aabSstevel * sets. It implements a subset of Socket Services as defined
323db86aabSstevel * in the Solaris PCMCIA design documents
333db86aabSstevel */
343db86aabSstevel
353db86aabSstevel /*
363db86aabSstevel * currently defined "properties"
373db86aabSstevel *
383db86aabSstevel * clock-frequency bus clock frequency
393db86aabSstevel * smi system management interrupt override
403db86aabSstevel * need-mult-irq need status IRQ for each pair of sockets
413db86aabSstevel * disable-audio don't route audio signal to speaker
423db86aabSstevel */
433db86aabSstevel
443db86aabSstevel
453db86aabSstevel #include <sys/types.h>
463db86aabSstevel #include <sys/inttypes.h>
473db86aabSstevel #include <sys/param.h>
483db86aabSstevel #include <sys/systm.h>
493db86aabSstevel #include <sys/user.h>
503db86aabSstevel #include <sys/buf.h>
513db86aabSstevel #include <sys/file.h>
523db86aabSstevel #include <sys/uio.h>
533db86aabSstevel #include <sys/conf.h>
543db86aabSstevel #include <sys/stat.h>
553db86aabSstevel #include <sys/autoconf.h>
563db86aabSstevel #include <sys/vtoc.h>
573db86aabSstevel #include <sys/dkio.h>
583db86aabSstevel #include <sys/ddi.h>
593db86aabSstevel #include <sys/sunddi.h>
603db86aabSstevel #include <sys/sunndi.h>
613db86aabSstevel #include <sys/var.h>
623db86aabSstevel #include <sys/callb.h>
633db86aabSstevel #include <sys/open.h>
643db86aabSstevel #include <sys/ddidmareq.h>
653db86aabSstevel #include <sys/dma_engine.h>
663db86aabSstevel #include <sys/kstat.h>
673db86aabSstevel #include <sys/kmem.h>
683db86aabSstevel #include <sys/modctl.h>
693db86aabSstevel #include <sys/pci.h>
703db86aabSstevel #include <sys/pci_impl.h>
713db86aabSstevel
723db86aabSstevel #include <sys/pctypes.h>
733db86aabSstevel #include <sys/pcmcia.h>
743db86aabSstevel #include <sys/sservice.h>
753db86aabSstevel
763db86aabSstevel #include <sys/note.h>
773db86aabSstevel
783db86aabSstevel #include <sys/pcic_reg.h>
793db86aabSstevel #include <sys/pcic_var.h>
803db86aabSstevel
81e12b469aSrui wang - Sun Microsystems - Beijing China #if defined(__i386) || defined(__amd64)
82e12b469aSrui wang - Sun Microsystems - Beijing China #include <sys/pci_cfgspace.h>
83e12b469aSrui wang - Sun Microsystems - Beijing China #endif
84e12b469aSrui wang - Sun Microsystems - Beijing China
853db86aabSstevel #if defined(__sparc)
863db86aabSstevel #include <sys/pci/pci_nexus.h>
873db86aabSstevel #endif
883db86aabSstevel
890d282d13Srw148561 #include <sys/hotplug/hpcsvc.h>
903db86aabSstevel #include "cardbus/cardbus.h"
913db86aabSstevel
923db86aabSstevel #define SOFTC_SIZE (sizeof (anp_t))
933db86aabSstevel
943db86aabSstevel static int pcic_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
953db86aabSstevel static int pcic_attach(dev_info_t *, ddi_attach_cmd_t);
963db86aabSstevel static int pcic_detach(dev_info_t *, ddi_detach_cmd_t);
97*5644143aSQuaker Fang static int32_t pcic_quiesce(dev_info_t *);
983db86aabSstevel static uint_t pcic_intr(caddr_t, caddr_t);
993db86aabSstevel static int pcic_do_io_intr(pcicdev_t *, uint32_t);
1003db86aabSstevel static int pcic_probe(dev_info_t *);
1013db86aabSstevel
1023db86aabSstevel static int pcic_open(dev_t *, int, int, cred_t *);
1033db86aabSstevel static int pcic_close(dev_t, int, int, cred_t *);
1043db86aabSstevel static int pcic_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
1053db86aabSstevel
1063db86aabSstevel typedef struct pcm_regs pcm_regs_t;
1073db86aabSstevel
1083db86aabSstevel static void pcic_init_assigned(dev_info_t *);
1093db86aabSstevel static int pcic_apply_avail_ranges(dev_info_t *, pcm_regs_t *,
1103db86aabSstevel pci_regspec_t *, int);
1113db86aabSstevel int pci_resource_setup_avail(dev_info_t *, pci_regspec_t *, int);
1123db86aabSstevel
1133db86aabSstevel /*
1143db86aabSstevel * On x86 platforms the ddi_iobp_alloc(9F) and ddi_mem_alloc(9F) calls
1153db86aabSstevel * are xlated into DMA ctlops. To make this nexus work on x86, we
1163db86aabSstevel * need to have the default ddi_dma_mctl ctlops in the bus_ops
1173db86aabSstevel * structure, just to pass the request to the parent. The correct
1183db86aabSstevel * ctlops should be ddi_no_dma_mctl because so far we don't do DMA.
1193db86aabSstevel */
1203db86aabSstevel static
1213db86aabSstevel struct bus_ops pcmciabus_ops = {
1223db86aabSstevel BUSO_REV,
1233db86aabSstevel pcmcia_bus_map,
1243db86aabSstevel NULL,
1253db86aabSstevel NULL,
1263db86aabSstevel NULL,
1273db86aabSstevel i_ddi_map_fault,
1283db86aabSstevel ddi_no_dma_map,
1293db86aabSstevel ddi_no_dma_allochdl,
1303db86aabSstevel ddi_no_dma_freehdl,
1313db86aabSstevel ddi_no_dma_bindhdl,
1323db86aabSstevel ddi_no_dma_unbindhdl,
1333db86aabSstevel ddi_no_dma_flush,
1343db86aabSstevel ddi_no_dma_win,
1353db86aabSstevel ddi_dma_mctl,
1363db86aabSstevel pcmcia_ctlops,
1373db86aabSstevel pcmcia_prop_op,
1383db86aabSstevel NULL, /* (*bus_get_eventcookie)(); */
1393db86aabSstevel NULL, /* (*bus_add_eventcall)(); */
1403db86aabSstevel NULL, /* (*bus_remove_eventcall)(); */
1413db86aabSstevel NULL, /* (*bus_post_event)(); */
1423db86aabSstevel NULL, /* (*bus_intr_ctl)(); */
1433db86aabSstevel NULL, /* (*bus_config)(); */
1443db86aabSstevel NULL, /* (*bus_unconfig)(); */
1453db86aabSstevel NULL, /* (*bus_fm_init)(); */
1463db86aabSstevel NULL, /* (*bus_fm_fini)(); */
1473db86aabSstevel NULL, /* (*bus_enter)() */
1483db86aabSstevel NULL, /* (*bus_exit)() */
1493db86aabSstevel NULL, /* (*bus_power)() */
1503db86aabSstevel pcmcia_intr_ops /* (*bus_intr_op)(); */
1513db86aabSstevel };
1523db86aabSstevel
1533db86aabSstevel static struct cb_ops pcic_cbops = {
1543db86aabSstevel pcic_open,
1553db86aabSstevel pcic_close,
1563db86aabSstevel nodev,
1573db86aabSstevel nodev,
1583db86aabSstevel nodev,
1593db86aabSstevel nodev,
1603db86aabSstevel nodev,
1613db86aabSstevel pcic_ioctl,
1623db86aabSstevel nodev,
1633db86aabSstevel nodev,
1643db86aabSstevel nodev,
1653db86aabSstevel nochpoll,
1663db86aabSstevel ddi_prop_op,
1673db86aabSstevel NULL,
1683db86aabSstevel #ifdef CARDBUS
1693db86aabSstevel D_NEW | D_MP | D_HOTPLUG
1703db86aabSstevel #else
1713db86aabSstevel D_NEW | D_MP
1723db86aabSstevel #endif
1733db86aabSstevel };
1743db86aabSstevel
1753db86aabSstevel static struct dev_ops pcic_devops = {
1763db86aabSstevel DEVO_REV,
1773db86aabSstevel 0,
1783db86aabSstevel pcic_getinfo,
1793db86aabSstevel nulldev,
1803db86aabSstevel pcic_probe,
1813db86aabSstevel pcic_attach,
1823db86aabSstevel pcic_detach,
1833db86aabSstevel nulldev,
1843db86aabSstevel &pcic_cbops,
1853db86aabSstevel &pcmciabus_ops,
18619397407SSherry Moore NULL,
187*5644143aSQuaker Fang pcic_quiesce, /* devo_quiesce */
1883db86aabSstevel };
1893db86aabSstevel
1903db86aabSstevel void *pcic_soft_state_p = NULL;
1913db86aabSstevel static int pcic_maxinst = -1;
1923db86aabSstevel
1933db86aabSstevel int pcic_do_insertion = 1;
1943db86aabSstevel int pcic_do_removal = 1;
1953db86aabSstevel
1963db86aabSstevel struct irqmap {
1973db86aabSstevel int irq;
1983db86aabSstevel int count;
1993db86aabSstevel } pcic_irq_map[16];
2003db86aabSstevel
2013db86aabSstevel
2023db86aabSstevel int pcic_debug = 0x0;
2033db86aabSstevel static void pcic_err(dev_info_t *dip, int level, const char *fmt, ...);
2043db86aabSstevel extern void cardbus_dump_pci_config(dev_info_t *dip);
2053db86aabSstevel extern void cardbus_dump_socket(dev_info_t *dip);
2063db86aabSstevel extern int cardbus_validate_iline(dev_info_t *dip, ddi_acc_handle_t handle);
2073db86aabSstevel static void pcic_dump_debqueue(char *msg);
2083db86aabSstevel
2093db86aabSstevel #if defined(PCIC_DEBUG)
2103db86aabSstevel static void xxdmp_all_regs(pcicdev_t *, int, uint32_t);
2113db86aabSstevel
2123db86aabSstevel #define pcic_mutex_enter(a) \
2133db86aabSstevel { \
2143db86aabSstevel pcic_err(NULL, 10, "Set lock at %d\n", __LINE__); \
2153db86aabSstevel mutex_enter(a); \
2163db86aabSstevel };
2173db86aabSstevel
2183db86aabSstevel #define pcic_mutex_exit(a) \
2193db86aabSstevel { \
2203db86aabSstevel pcic_err(NULL, 10, "Clear lock at %d\n", __LINE__); \
2213db86aabSstevel mutex_exit(a); \
2223db86aabSstevel };
2233db86aabSstevel
2243db86aabSstevel #else
2253db86aabSstevel #define pcic_mutex_enter(a) mutex_enter(a)
2263db86aabSstevel #define pcic_mutex_exit(a) mutex_exit(a)
2273db86aabSstevel #endif
2283db86aabSstevel
2293db86aabSstevel #define PCIC_VCC_3VLEVEL 1
2303db86aabSstevel #define PCIC_VCC_5VLEVEL 2
2313db86aabSstevel #define PCIC_VCC_12LEVEL 3
2323db86aabSstevel
2333db86aabSstevel /* bit patterns to select voltage levels */
2343db86aabSstevel int pcic_vpp_levels[13] = {
2353db86aabSstevel 0, 0, 0,
2363db86aabSstevel 1, /* 3.3V */
2373db86aabSstevel 0,
2383db86aabSstevel 1, /* 5V */
2393db86aabSstevel 0, 0, 0, 0, 0, 0,
2403db86aabSstevel 2 /* 12V */
2413db86aabSstevel };
2423db86aabSstevel
2433db86aabSstevel uint8_t pcic_cbv_levels[13] = {
2443db86aabSstevel 0, 0, 0,
2453db86aabSstevel 3, /* 3.3V */
2463db86aabSstevel 0,
2473db86aabSstevel 2, /* 5V */
2483db86aabSstevel 0, 0, 0, 0, 0, 0,
2493db86aabSstevel 1 /* 12V */
2503db86aabSstevel };
2513db86aabSstevel
2523db86aabSstevel struct power_entry pcic_power[4] = {
2533db86aabSstevel {
2543db86aabSstevel 0, VCC|VPP1|VPP2
2553db86aabSstevel },
2563db86aabSstevel {
2573db86aabSstevel 33, /* 3.3Volt */
2583db86aabSstevel VCC|VPP1|VPP2
2593db86aabSstevel },
2603db86aabSstevel {
2613db86aabSstevel 5*10, /* 5Volt */
2623db86aabSstevel VCC|VPP1|VPP2 /* currently only know about this */
2633db86aabSstevel },
2643db86aabSstevel {
2653db86aabSstevel 12*10, /* 12Volt */
2663db86aabSstevel VPP1|VPP2
2673db86aabSstevel }
2683db86aabSstevel };
2693db86aabSstevel
2703db86aabSstevel /*
2713db86aabSstevel * Base used to allocate ranges of PCI memory on x86 systems
2723db86aabSstevel * Each instance gets a chunk above the base that is used to map
2733db86aabSstevel * in the memory and I/O windows for that device.
2743db86aabSstevel * Pages below the base are also allocated for the EXCA registers,
2753db86aabSstevel * one per instance.
2763db86aabSstevel */
2773db86aabSstevel #define PCIC_PCI_MEMCHUNK 0x1000000
2783db86aabSstevel
2793db86aabSstevel static int pcic_wait_insert_time = 5000000; /* In micro-seconds */
2803db86aabSstevel static int pcic_debounce_time = 200000; /* In micro-seconds */
2813db86aabSstevel
2823db86aabSstevel struct debounce {
2833db86aabSstevel pcic_socket_t *pcs;
2843db86aabSstevel clock_t expire;
2853db86aabSstevel struct debounce *next;
2863db86aabSstevel };
2873db86aabSstevel
2883db86aabSstevel static struct debounce *pcic_deb_queue = NULL;
2893db86aabSstevel static kmutex_t pcic_deb_mtx;
2903db86aabSstevel static kcondvar_t pcic_deb_cv;
2913db86aabSstevel static kthread_t *pcic_deb_threadid;
2923db86aabSstevel
2933db86aabSstevel static inthandler_t *pcic_handlers;
2943db86aabSstevel
2953db86aabSstevel static void pcic_setup_adapter(pcicdev_t *);
2963db86aabSstevel static int pcic_change(pcicdev_t *, int);
2973db86aabSstevel static int pcic_ll_reset(pcicdev_t *, int);
2983db86aabSstevel static void pcic_mswait(pcicdev_t *, int, int);
2993db86aabSstevel static boolean_t pcic_check_ready(pcicdev_t *, int);
3003db86aabSstevel static void pcic_set_cdtimers(pcicdev_t *, int, uint32_t, int);
3013db86aabSstevel static void pcic_ready_wait(pcicdev_t *, int);
3023db86aabSstevel extern int pcmcia_get_intr(dev_info_t *, int);
3033db86aabSstevel extern int pcmcia_return_intr(dev_info_t *, int);
30411c2b4c0Srw148561 extern void pcmcia_cb_suspended(int);
30511c2b4c0Srw148561 extern void pcmcia_cb_resumed(int);
3063db86aabSstevel
3073db86aabSstevel static int pcic_callback(dev_info_t *, int (*)(), int);
3083db86aabSstevel static int pcic_inquire_adapter(dev_info_t *, inquire_adapter_t *);
3093db86aabSstevel static int pcic_get_adapter(dev_info_t *, get_adapter_t *);
3103db86aabSstevel static int pcic_get_page(dev_info_t *, get_page_t *);
3113db86aabSstevel static int pcic_get_socket(dev_info_t *, get_socket_t *);
3123db86aabSstevel static int pcic_get_status(dev_info_t *, get_ss_status_t *);
3133db86aabSstevel static int pcic_get_window(dev_info_t *, get_window_t *);
3143db86aabSstevel static int pcic_inquire_socket(dev_info_t *, inquire_socket_t *);
3153db86aabSstevel static int pcic_inquire_window(dev_info_t *, inquire_window_t *);
3163db86aabSstevel static int pcic_reset_socket(dev_info_t *, int, int);
3173db86aabSstevel static int pcic_set_page(dev_info_t *, set_page_t *);
3183db86aabSstevel static int pcic_set_window(dev_info_t *, set_window_t *);
3193db86aabSstevel static int pcic_set_socket(dev_info_t *, set_socket_t *);
3203db86aabSstevel static int pcic_set_interrupt(dev_info_t *, set_irq_handler_t *);
3213db86aabSstevel static int pcic_clear_interrupt(dev_info_t *, clear_irq_handler_t *);
3223db86aabSstevel static void pcic_pm_detection(void *);
3233db86aabSstevel static void pcic_iomem_pci_ctl(ddi_acc_handle_t, uchar_t *, unsigned);
3243db86aabSstevel static int clext_reg_read(pcicdev_t *, int, uchar_t);
3253db86aabSstevel static void clext_reg_write(pcicdev_t *, int, uchar_t, uchar_t);
3263db86aabSstevel static int pcic_calc_speed(pcicdev_t *, uint32_t);
3273db86aabSstevel static int pcic_card_state(pcicdev_t *, pcic_socket_t *);
3283db86aabSstevel static int pcic_find_pci_type(pcicdev_t *);
3293db86aabSstevel static void pcic_82092_smiirq_ctl(pcicdev_t *, int, int, int);
3303db86aabSstevel static void pcic_handle_cd_change(pcicdev_t *, pcic_socket_t *, uint8_t);
3313db86aabSstevel static uint_t pcic_cd_softint(caddr_t, caddr_t);
3323db86aabSstevel static uint8_t pcic_getb(pcicdev_t *, int, int);
3333db86aabSstevel static void pcic_putb(pcicdev_t *, int, int, int8_t);
3343db86aabSstevel static int pcic_set_vcc_level(pcicdev_t *, set_socket_t *);
3353db86aabSstevel static uint_t pcic_softintr(caddr_t, caddr_t);
3363db86aabSstevel
3373db86aabSstevel static void pcic_debounce(pcic_socket_t *);
33811c2b4c0Srw148561 static void pcic_do_resume(pcicdev_t *);
3393db86aabSstevel static void *pcic_add_debqueue(pcic_socket_t *, int);
3403db86aabSstevel static void pcic_rm_debqueue(void *);
3413db86aabSstevel static void pcic_deb_thread();
3423db86aabSstevel
3433db86aabSstevel static boolean_t pcic_load_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp);
3443db86aabSstevel static void pcic_unload_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp);
3453db86aabSstevel static uint32_t pcic_getcb(pcicdev_t *pcic, int reg);
3463db86aabSstevel static void pcic_putcb(pcicdev_t *pcic, int reg, uint32_t value);
3473db86aabSstevel static void pcic_cb_enable_intr(dev_info_t *);
3483db86aabSstevel static void pcic_cb_disable_intr(dev_info_t *);
3493db86aabSstevel static void pcic_enable_io_intr(pcicdev_t *pcic, int socket, int irq);
3503db86aabSstevel static void pcic_disable_io_intr(pcicdev_t *pcic, int socket);
3513db86aabSstevel
3523db86aabSstevel static cb_nexus_cb_t pcic_cbnexus_ops = {
3533db86aabSstevel pcic_cb_enable_intr,
3543db86aabSstevel pcic_cb_disable_intr
3553db86aabSstevel };
3563db86aabSstevel
3573db86aabSstevel static int pcic_exca_powerctl(pcicdev_t *pcic, int socket, int powerlevel);
3583db86aabSstevel static int pcic_cbus_powerctl(pcicdev_t *pcic, int socket);
3593db86aabSstevel
3603db86aabSstevel #if defined(__sparc)
3613db86aabSstevel static int pcic_fault(enum pci_fault_ops op, void *arg);
3623db86aabSstevel #endif
3633db86aabSstevel
3643db86aabSstevel
3653db86aabSstevel /*
3663db86aabSstevel * pcmcia interface operations structure
3673db86aabSstevel * this is the private interface that is exported to the nexus
3683db86aabSstevel */
3693db86aabSstevel pcmcia_if_t pcic_if_ops = {
3703db86aabSstevel PCIF_MAGIC,
3713db86aabSstevel PCIF_VERSION,
3723db86aabSstevel pcic_callback,
3733db86aabSstevel pcic_get_adapter,
3743db86aabSstevel pcic_get_page,
3753db86aabSstevel pcic_get_socket,
3763db86aabSstevel pcic_get_status,
3773db86aabSstevel pcic_get_window,
3783db86aabSstevel pcic_inquire_adapter,
3793db86aabSstevel pcic_inquire_socket,
3803db86aabSstevel pcic_inquire_window,
3813db86aabSstevel pcic_reset_socket,
3823db86aabSstevel pcic_set_page,
3833db86aabSstevel pcic_set_window,
3843db86aabSstevel pcic_set_socket,
3853db86aabSstevel pcic_set_interrupt,
3863db86aabSstevel pcic_clear_interrupt,
3873db86aabSstevel NULL,
3883db86aabSstevel };
3893db86aabSstevel
3903db86aabSstevel /*
3913db86aabSstevel * chip type identification routines
3923db86aabSstevel * this list of functions is searched until one of them succeeds
3933db86aabSstevel * or all fail. i82365SL is assumed if failed.
3943db86aabSstevel */
3953db86aabSstevel static int pcic_ci_cirrus(pcicdev_t *);
3963db86aabSstevel static int pcic_ci_vadem(pcicdev_t *);
3973db86aabSstevel static int pcic_ci_ricoh(pcicdev_t *);
3983db86aabSstevel
3993db86aabSstevel int (*pcic_ci_funcs[])(pcicdev_t *) = {
4003db86aabSstevel pcic_ci_cirrus,
4013db86aabSstevel pcic_ci_vadem,
4023db86aabSstevel pcic_ci_ricoh,
4033db86aabSstevel NULL
4043db86aabSstevel };
4053db86aabSstevel
4063db86aabSstevel static struct modldrv modldrv = {
4073db86aabSstevel &mod_driverops, /* Type of module. This one is a driver */
408903a11ebSrh87107 "PCIC PCMCIA adapter driver", /* Name of the module. */
4093db86aabSstevel &pcic_devops, /* driver ops */
4103db86aabSstevel };
4113db86aabSstevel
4123db86aabSstevel static struct modlinkage modlinkage = {
4133db86aabSstevel MODREV_1, (void *)&modldrv, NULL
4143db86aabSstevel };
4153db86aabSstevel
4163db86aabSstevel int
_init()4173db86aabSstevel _init()
4183db86aabSstevel {
4193db86aabSstevel int stat;
4203db86aabSstevel
4213db86aabSstevel /* Allocate soft state */
4223db86aabSstevel if ((stat = ddi_soft_state_init(&pcic_soft_state_p,
4233db86aabSstevel SOFTC_SIZE, 2)) != DDI_SUCCESS)
4243db86aabSstevel return (stat);
4253db86aabSstevel
4263db86aabSstevel if ((stat = mod_install(&modlinkage)) != 0)
4273db86aabSstevel ddi_soft_state_fini(&pcic_soft_state_p);
4283db86aabSstevel
4293db86aabSstevel return (stat);
4303db86aabSstevel }
4313db86aabSstevel
4323db86aabSstevel int
_fini()4333db86aabSstevel _fini()
4343db86aabSstevel {
4353db86aabSstevel int stat = 0;
4363db86aabSstevel
4373db86aabSstevel if ((stat = mod_remove(&modlinkage)) != 0)
4383db86aabSstevel return (stat);
4393db86aabSstevel
4403db86aabSstevel if (pcic_deb_threadid) {
4413db86aabSstevel mutex_enter(&pcic_deb_mtx);
4423db86aabSstevel pcic_deb_threadid = 0;
4433db86aabSstevel while (!pcic_deb_threadid)
4443db86aabSstevel cv_wait(&pcic_deb_cv, &pcic_deb_mtx);
4453db86aabSstevel pcic_deb_threadid = 0;
4463db86aabSstevel mutex_exit(&pcic_deb_mtx);
4473db86aabSstevel
4483db86aabSstevel mutex_destroy(&pcic_deb_mtx);
4493db86aabSstevel cv_destroy(&pcic_deb_cv);
4503db86aabSstevel }
4513db86aabSstevel
4523db86aabSstevel ddi_soft_state_fini(&pcic_soft_state_p);
4533db86aabSstevel
4543db86aabSstevel return (stat);
4553db86aabSstevel }
4563db86aabSstevel
4573db86aabSstevel int
_info(struct modinfo * modinfop)4583db86aabSstevel _info(struct modinfo *modinfop)
4593db86aabSstevel {
4603db86aabSstevel return (mod_info(&modlinkage, modinfop));
4613db86aabSstevel }
4623db86aabSstevel
4633db86aabSstevel /*
4643db86aabSstevel * pcic_getinfo()
4653db86aabSstevel * provide instance/device information about driver
4663db86aabSstevel */
4673db86aabSstevel /*ARGSUSED*/
4683db86aabSstevel static int
pcic_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)4693db86aabSstevel pcic_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
4703db86aabSstevel {
4713db86aabSstevel anp_t *anp;
4723db86aabSstevel int error = DDI_SUCCESS;
4733db86aabSstevel minor_t minor;
4743db86aabSstevel
4753db86aabSstevel switch (cmd) {
4763db86aabSstevel case DDI_INFO_DEVT2DEVINFO:
4773db86aabSstevel minor = getminor((dev_t)arg);
4783db86aabSstevel minor &= 0x7f;
4793db86aabSstevel if (!(anp = ddi_get_soft_state(pcic_soft_state_p, minor)))
4803db86aabSstevel *result = NULL;
4813db86aabSstevel else
4823db86aabSstevel *result = anp->an_dip;
4833db86aabSstevel break;
4843db86aabSstevel case DDI_INFO_DEVT2INSTANCE:
4853db86aabSstevel minor = getminor((dev_t)arg);
4863db86aabSstevel minor &= 0x7f;
4873db86aabSstevel *result = (void *)((long)minor);
4883db86aabSstevel break;
4893db86aabSstevel default:
4903db86aabSstevel error = DDI_FAILURE;
4913db86aabSstevel break;
4923db86aabSstevel }
4933db86aabSstevel return (error);
4943db86aabSstevel }
4953db86aabSstevel
4963db86aabSstevel static int
pcic_probe(dev_info_t * dip)4973db86aabSstevel pcic_probe(dev_info_t *dip)
4983db86aabSstevel {
4993db86aabSstevel int value;
5003db86aabSstevel ddi_device_acc_attr_t attr;
5013db86aabSstevel ddi_acc_handle_t handle;
5023db86aabSstevel uchar_t *index, *data;
5033db86aabSstevel
5043db86aabSstevel if (ddi_dev_is_sid(dip) == DDI_SUCCESS)
5053db86aabSstevel return (DDI_PROBE_DONTCARE);
5063db86aabSstevel
5073db86aabSstevel /*
5083db86aabSstevel * find a PCIC device (any vendor)
5093db86aabSstevel * while there can be up to 4 such devices in
5103db86aabSstevel * a system, we currently only look for 1
5113db86aabSstevel * per probe. There will be up to 2 chips per
5123db86aabSstevel * instance since they share I/O space
5133db86aabSstevel */
5143db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
5153db86aabSstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
5163db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
5173db86aabSstevel
5183db86aabSstevel if (ddi_regs_map_setup(dip, PCIC_ISA_CONTROL_REG_NUM,
5193db86aabSstevel (caddr_t *)&index,
5203db86aabSstevel PCIC_ISA_CONTROL_REG_OFFSET,
5213db86aabSstevel PCIC_ISA_CONTROL_REG_LENGTH,
5223db86aabSstevel &attr, &handle) != DDI_SUCCESS)
5233db86aabSstevel return (DDI_PROBE_FAILURE);
5243db86aabSstevel
5253db86aabSstevel data = index + 1;
5263db86aabSstevel
5273db86aabSstevel #if defined(PCIC_DEBUG)
5283db86aabSstevel if (pcic_debug)
5293db86aabSstevel cmn_err(CE_CONT, "pcic_probe: entered\n");
5303db86aabSstevel if (pcic_debug)
5313db86aabSstevel cmn_err(CE_CONT, "\tindex=%p\n", (void *)index);
5323db86aabSstevel #endif
5333db86aabSstevel ddi_put8(handle, index, PCIC_CHIP_REVISION);
5343db86aabSstevel ddi_put8(handle, data, 0);
5353db86aabSstevel value = ddi_get8(handle, data);
5363db86aabSstevel #if defined(PCIC_DEBUG)
5373db86aabSstevel if (pcic_debug)
5383db86aabSstevel cmn_err(CE_CONT, "\tchip revision register = %x\n", value);
5393db86aabSstevel #endif
5403db86aabSstevel if ((value & PCIC_REV_MASK) >= PCIC_REV_LEVEL_LOW &&
5413db86aabSstevel (value & 0x30) == 0) {
5423db86aabSstevel /*
5433db86aabSstevel * we probably have a PCIC chip in the system
5443db86aabSstevel * do a little more checking. If we find one,
5453db86aabSstevel * reset everything in case of softboot
5463db86aabSstevel */
5473db86aabSstevel ddi_put8(handle, index, PCIC_MAPPING_ENABLE);
5483db86aabSstevel ddi_put8(handle, data, 0);
5493db86aabSstevel value = ddi_get8(handle, data);
5503db86aabSstevel #if defined(PCIC_DEBUG)
5513db86aabSstevel if (pcic_debug)
5523db86aabSstevel cmn_err(CE_CONT, "\tzero test = %x\n", value);
5533db86aabSstevel #endif
5543db86aabSstevel /* should read back as zero */
5553db86aabSstevel if (value == 0) {
5563db86aabSstevel /*
5573db86aabSstevel * we do have one and it is off the bus
5583db86aabSstevel */
5593db86aabSstevel #if defined(PCIC_DEBUG)
5603db86aabSstevel if (pcic_debug)
5613db86aabSstevel cmn_err(CE_CONT, "pcic_probe: success\n");
5623db86aabSstevel #endif
5633db86aabSstevel ddi_regs_map_free(&handle);
5643db86aabSstevel return (DDI_PROBE_SUCCESS);
5653db86aabSstevel }
5663db86aabSstevel }
5673db86aabSstevel #if defined(PCIC_DEBUG)
5683db86aabSstevel if (pcic_debug)
5693db86aabSstevel cmn_err(CE_CONT, "pcic_probe: failed\n");
5703db86aabSstevel #endif
5713db86aabSstevel ddi_regs_map_free(&handle);
5723db86aabSstevel return (DDI_PROBE_FAILURE);
5733db86aabSstevel }
5743db86aabSstevel
5753db86aabSstevel /*
5763db86aabSstevel * These are just defaults they can also be changed via a property in the
5773db86aabSstevel * conf file.
5783db86aabSstevel */
5793db86aabSstevel static int pci_config_reg_num = PCIC_PCI_CONFIG_REG_NUM;
5803db86aabSstevel static int pci_control_reg_num = PCIC_PCI_CONTROL_REG_NUM;
58111c2b4c0Srw148561 static int pcic_do_pcmcia_sr = 1;
5823db86aabSstevel static int pcic_use_cbpwrctl = PCF_CBPWRCTL;
5833db86aabSstevel
5843db86aabSstevel /*
5853db86aabSstevel * enable insertion/removal interrupt for 32bit cards
5863db86aabSstevel */
5873db86aabSstevel static int
cardbus_enable_cd_intr(dev_info_t * dip)5883db86aabSstevel cardbus_enable_cd_intr(dev_info_t *dip)
5893db86aabSstevel {
5903db86aabSstevel ddi_acc_handle_t iohandle;
5913db86aabSstevel caddr_t ioaddr;
5923db86aabSstevel ddi_device_acc_attr_t attr;
5933db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
5943db86aabSstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
5953db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
5963db86aabSstevel (void) ddi_regs_map_setup(dip, 1,
5973db86aabSstevel (caddr_t *)&ioaddr,
5983db86aabSstevel 0,
5993db86aabSstevel 4096,
6003db86aabSstevel &attr, &iohandle);
6013db86aabSstevel
6023db86aabSstevel /* CSC Interrupt: Card detect interrupt on */
6033db86aabSstevel ddi_put32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_MASK),
6043db86aabSstevel ddi_get32(iohandle,
6053db86aabSstevel (uint32_t *)(ioaddr+CB_STATUS_MASK)) | CB_SE_CCDMASK);
6063db86aabSstevel
6073db86aabSstevel ddi_put32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT),
6083db86aabSstevel ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT)));
6093db86aabSstevel
6103db86aabSstevel ddi_regs_map_free(&iohandle);
6113db86aabSstevel return (1);
6123db86aabSstevel }
6133db86aabSstevel
6143db86aabSstevel /*
615*5644143aSQuaker Fang * quiesce(9E) entry point.
616*5644143aSQuaker Fang *
617*5644143aSQuaker Fang * This function is called when the system is single-threaded at high
618*5644143aSQuaker Fang * PIL with preemption disabled. Therefore, this function must not be
619*5644143aSQuaker Fang * blocked.
620*5644143aSQuaker Fang *
621*5644143aSQuaker Fang * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
622*5644143aSQuaker Fang * DDI_FAILURE indicates an error condition and should almost never happen.
623*5644143aSQuaker Fang */
624*5644143aSQuaker Fang static int32_t
pcic_quiesce(dev_info_t * dip)625*5644143aSQuaker Fang pcic_quiesce(dev_info_t *dip)
626*5644143aSQuaker Fang {
627*5644143aSQuaker Fang anp_t *anp = ddi_get_driver_private(dip);
628*5644143aSQuaker Fang pcicdev_t *pcic = anp->an_private;
629*5644143aSQuaker Fang int i;
630*5644143aSQuaker Fang
631*5644143aSQuaker Fang for (i = 0; i < pcic->pc_numsockets; i++) {
632*5644143aSQuaker Fang pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0);
633*5644143aSQuaker Fang pcic_putb(pcic, i, PCIC_CARD_DETECT, 0);
634*5644143aSQuaker Fang pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
635*5644143aSQuaker Fang /* disable interrupts and put card into RESET */
636*5644143aSQuaker Fang pcic_putb(pcic, i, PCIC_INTERRUPT, 0);
637*5644143aSQuaker Fang /* poweroff socket */
638*5644143aSQuaker Fang pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0);
639*5644143aSQuaker Fang pcic_putcb(pcic, CB_CONTROL, 0);
640*5644143aSQuaker Fang }
641*5644143aSQuaker Fang
642*5644143aSQuaker Fang return (DDI_SUCCESS);
643*5644143aSQuaker Fang }
644*5644143aSQuaker Fang
645*5644143aSQuaker Fang /*
6463db86aabSstevel * pcic_attach()
6473db86aabSstevel * attach the PCIC (Intel 82365SL/CirrusLogic/Toshiba) driver
6483db86aabSstevel * to the system. This is a child of "sysbus" since that is where
6493db86aabSstevel * the hardware lives, but it provides services to the "pcmcia"
6503db86aabSstevel * nexus driver. It gives a pointer back via its private data
6513db86aabSstevel * structure which contains both the dip and socket services entry
6523db86aabSstevel * points
6533db86aabSstevel */
6543db86aabSstevel static int
pcic_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)6553db86aabSstevel pcic_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
6563db86aabSstevel {
6573db86aabSstevel anp_t *pcic_nexus;
6583db86aabSstevel pcicdev_t *pcic;
6593db86aabSstevel int irqlevel, value;
6603db86aabSstevel int pci_cfrn, pci_ctrn;
6613db86aabSstevel int i, j, smi, actual;
6623db86aabSstevel char *typename;
6633db86aabSstevel char bus_type[16] = "(unknown)";
6643db86aabSstevel int len = sizeof (bus_type);
6653db86aabSstevel ddi_device_acc_attr_t attr;
6663db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
6673db86aabSstevel uint_t pri;
6683db86aabSstevel
6693db86aabSstevel #if defined(PCIC_DEBUG)
6703db86aabSstevel if (pcic_debug) {
6713db86aabSstevel cmn_err(CE_CONT, "pcic_attach: entered\n");
6723db86aabSstevel }
6733db86aabSstevel #endif
6743db86aabSstevel switch (cmd) {
6753db86aabSstevel case DDI_ATTACH:
6763db86aabSstevel break;
6773db86aabSstevel case DDI_RESUME:
6783db86aabSstevel pcic = anp->an_private;
6793db86aabSstevel /*
6803db86aabSstevel * for now, this is a simulated resume.
6813db86aabSstevel * a real one may need different things.
6823db86aabSstevel */
6833db86aabSstevel if (pcic != NULL && pcic->pc_flags & PCF_SUSPENDED) {
6843db86aabSstevel mutex_enter(&pcic->pc_lock);
6853db86aabSstevel /* should probe for new sockets showing up */
6863db86aabSstevel pcic_setup_adapter(pcic);
6873db86aabSstevel pcic->pc_flags &= ~PCF_SUSPENDED;
6883db86aabSstevel mutex_exit(&pcic->pc_lock);
6893db86aabSstevel (void) pcmcia_begin_resume(dip);
69011c2b4c0Srw148561
69111c2b4c0Srw148561 pcic_do_resume(pcic);
69211c2b4c0Srw148561 #ifdef CARDBUS
69311c2b4c0Srw148561 cardbus_restore_children(ddi_get_child(dip));
69411c2b4c0Srw148561 #endif
6953db86aabSstevel
6963db86aabSstevel /*
6973db86aabSstevel * for complete implementation need END_RESUME (later)
6983db86aabSstevel */
6993db86aabSstevel return (DDI_SUCCESS);
7003db86aabSstevel
7013db86aabSstevel }
7023db86aabSstevel return (DDI_SUCCESS);
7033db86aabSstevel default:
7043db86aabSstevel return (DDI_FAILURE);
7053db86aabSstevel }
7063db86aabSstevel
7073db86aabSstevel /*
7083db86aabSstevel * Allocate soft state associated with this instance.
7093db86aabSstevel */
7103db86aabSstevel if (ddi_soft_state_zalloc(pcic_soft_state_p,
7113db86aabSstevel ddi_get_instance(dip)) != DDI_SUCCESS) {
7123db86aabSstevel cmn_err(CE_CONT, "pcic%d: Unable to alloc state\n",
7133db86aabSstevel ddi_get_instance(dip));
7143db86aabSstevel return (DDI_FAILURE);
7153db86aabSstevel }
7163db86aabSstevel
7173db86aabSstevel pcic_nexus = ddi_get_soft_state(pcic_soft_state_p,
7183db86aabSstevel ddi_get_instance(dip));
7193db86aabSstevel
7203db86aabSstevel pcic = kmem_zalloc(sizeof (pcicdev_t), KM_SLEEP);
7213db86aabSstevel
7223db86aabSstevel pcic->dip = dip;
7233db86aabSstevel pcic_nexus->an_dip = dip;
7243db86aabSstevel pcic_nexus->an_if = &pcic_if_ops;
7253db86aabSstevel pcic_nexus->an_private = pcic;
7263db86aabSstevel pcic->pc_numpower = sizeof (pcic_power)/sizeof (pcic_power[0]);
7273db86aabSstevel pcic->pc_power = pcic_power;
7283db86aabSstevel
7293db86aabSstevel pci_ctrn = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
7303db86aabSstevel "pci-control-reg-number", pci_control_reg_num);
7313db86aabSstevel pci_cfrn = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
7323db86aabSstevel "pci-config-reg-number", pci_config_reg_num);
7333db86aabSstevel
7343db86aabSstevel ddi_set_driver_private(dip, pcic_nexus);
7353db86aabSstevel
7363db86aabSstevel /*
7373db86aabSstevel * pcic->pc_irq is really the IPL level we want to run at
7383db86aabSstevel * set the default values here and override from intr spec
7393db86aabSstevel */
7403db86aabSstevel pcic->pc_irq = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
7413db86aabSstevel "interrupt-priorities", -1);
7423db86aabSstevel
7433db86aabSstevel if (pcic->pc_irq == -1) {
7443db86aabSstevel int actual;
7453db86aabSstevel uint_t pri;
7463db86aabSstevel ddi_intr_handle_t hdl;
7473db86aabSstevel
7483db86aabSstevel /* see if intrspec tells us different */
7493db86aabSstevel if (ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED,
7503db86aabSstevel 0, 1, &actual, DDI_INTR_ALLOC_NORMAL) == DDI_SUCCESS) {
7513db86aabSstevel if (ddi_intr_get_pri(hdl, &pri) == DDI_SUCCESS)
7523db86aabSstevel pcic->pc_irq = pri;
7533db86aabSstevel else
7543db86aabSstevel pcic->pc_irq = LOCK_LEVEL + 1;
7553db86aabSstevel (void) ddi_intr_free(hdl);
7563db86aabSstevel }
7573db86aabSstevel }
7583db86aabSstevel pcic_nexus->an_ipl = pcic->pc_irq;
7593db86aabSstevel
7603db86aabSstevel /*
7613db86aabSstevel * Check our parent bus type. We do different things based on which
7623db86aabSstevel * bus we're on.
7633db86aabSstevel */
7643db86aabSstevel if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip),
7653db86aabSstevel PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP,
7663db86aabSstevel "device_type", (caddr_t)&bus_type[0], &len) !=
7673db86aabSstevel DDI_PROP_SUCCESS) {
7683db86aabSstevel if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip),
7693db86aabSstevel PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP,
7703db86aabSstevel "bus-type", (caddr_t)&bus_type[0], &len) !=
7713db86aabSstevel DDI_PROP_SUCCESS) {
7723db86aabSstevel
7733db86aabSstevel cmn_err(CE_CONT,
7743db86aabSstevel "pcic%d: can't find parent bus type\n",
7753db86aabSstevel ddi_get_instance(dip));
7763db86aabSstevel
7773db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t));
778b8a60a54Srw148561 ddi_soft_state_free(pcic_soft_state_p,
779b8a60a54Srw148561 ddi_get_instance(dip));
7803db86aabSstevel return (DDI_FAILURE);
7813db86aabSstevel }
7823db86aabSstevel } /* ddi_prop_op("device_type") */
7833db86aabSstevel
7848134ee03Srw148561 if (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0 ||
7858134ee03Srw148561 strcmp(bus_type, DEVI_PCIEX_NEXNAME) == 0) {
7863db86aabSstevel pcic->pc_flags = PCF_PCIBUS;
7873db86aabSstevel } else {
788b8a60a54Srw148561 cmn_err(CE_WARN, "!pcic%d: non-pci mode (%s) not supported, "
789b8a60a54Srw148561 "set BIOS to yenta mode if applicable\n",
7903db86aabSstevel ddi_get_instance(dip), bus_type);
7913db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t));
792b8a60a54Srw148561 ddi_soft_state_free(pcic_soft_state_p,
793b8a60a54Srw148561 ddi_get_instance(dip));
7943db86aabSstevel return (DDI_FAILURE);
7953db86aabSstevel }
7963db86aabSstevel
7973db86aabSstevel if ((pcic->bus_speed = ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip),
7983db86aabSstevel DDI_PROP_CANSLEEP,
7993db86aabSstevel "clock-frequency", 0)) == 0) {
8003db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS)
8013db86aabSstevel pcic->bus_speed = PCIC_PCI_DEF_SYSCLK;
8023db86aabSstevel else
8033db86aabSstevel pcic->bus_speed = PCIC_ISA_DEF_SYSCLK;
8043db86aabSstevel } else {
8053db86aabSstevel /*
8063db86aabSstevel * OBP can declare the speed in Hz...
8073db86aabSstevel */
8083db86aabSstevel if (pcic->bus_speed > 1000000)
8093db86aabSstevel pcic->bus_speed /= 1000000;
8103db86aabSstevel } /* ddi_prop_op("clock-frequency") */
8113db86aabSstevel
8123db86aabSstevel pcic->pc_io_type = PCIC_IO_TYPE_82365SL; /* default mode */
8133db86aabSstevel
8143db86aabSstevel #ifdef PCIC_DEBUG
8153db86aabSstevel if (pcic_debug) {
8163db86aabSstevel cmn_err(CE_CONT,
8173db86aabSstevel "pcic%d: parent bus type = [%s], speed = %d MHz\n",
8183db86aabSstevel ddi_get_instance(dip),
8193db86aabSstevel bus_type, pcic->bus_speed);
8203db86aabSstevel }
8213db86aabSstevel #endif
8223db86aabSstevel
8233db86aabSstevel /*
8243db86aabSstevel * The reg properties on a PCI node are different than those
8253db86aabSstevel * on a non-PCI node. Handle that difference here.
8263db86aabSstevel * If it turns out to be a CardBus chip, we have even more
8273db86aabSstevel * differences.
8283db86aabSstevel */
8293db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS) {
8303db86aabSstevel int class_code;
8313db86aabSstevel #if defined(__i386) || defined(__amd64)
8323db86aabSstevel pcic->pc_base = 0x1000000;
8333db86aabSstevel pcic->pc_bound = (uint32_t)~0;
8343db86aabSstevel pcic->pc_iobase = 0x1000;
8353db86aabSstevel pcic->pc_iobound = 0xefff;
8363db86aabSstevel #elif defined(__sparc)
8373db86aabSstevel pcic->pc_base = 0x0;
8383db86aabSstevel pcic->pc_bound = (uint32_t)~0;
8393db86aabSstevel pcic->pc_iobase = 0x00000;
8403db86aabSstevel pcic->pc_iobound = 0xffff;
8413db86aabSstevel #endif
8423db86aabSstevel
8433db86aabSstevel /* usually need to get at config space so map first */
8443db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
8453db86aabSstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
8463db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
8473db86aabSstevel
8483db86aabSstevel if (ddi_regs_map_setup(dip, pci_cfrn,
8493db86aabSstevel (caddr_t *)&pcic->cfgaddr,
8503db86aabSstevel PCIC_PCI_CONFIG_REG_OFFSET,
8513db86aabSstevel PCIC_PCI_CONFIG_REG_LENGTH,
8523db86aabSstevel &attr,
8533db86aabSstevel &pcic->cfg_handle) !=
8543db86aabSstevel DDI_SUCCESS) {
8553db86aabSstevel cmn_err(CE_CONT,
8563db86aabSstevel "pcic%d: unable to map config space"
8573db86aabSstevel "regs\n",
8583db86aabSstevel ddi_get_instance(dip));
8593db86aabSstevel
8603db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t));
8613db86aabSstevel return (DDI_FAILURE);
8623db86aabSstevel } /* ddi_regs_map_setup */
8633db86aabSstevel
8643db86aabSstevel class_code = ddi_getprop(DDI_DEV_T_ANY, dip,
8653db86aabSstevel DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
8663db86aabSstevel "class-code", -1);
8673db86aabSstevel #ifdef PCIC_DEBUG
8683db86aabSstevel if (pcic_debug) {
8693db86aabSstevel cmn_err(CE_CONT, "pcic_attach class_code=%x\n",
8703db86aabSstevel class_code);
8713db86aabSstevel }
8723db86aabSstevel #endif
8733db86aabSstevel
8743db86aabSstevel switch (class_code) {
8753db86aabSstevel case PCIC_PCI_CARDBUS:
8763db86aabSstevel pcic->pc_flags |= PCF_CARDBUS;
8773db86aabSstevel pcic->pc_io_type = PCIC_IO_TYPE_YENTA;
8783db86aabSstevel /*
8793db86aabSstevel * Get access to the adapter registers on the
8803db86aabSstevel * PCI bus. A 4K memory page
8813db86aabSstevel */
8823db86aabSstevel #if defined(PCIC_DEBUG)
8833db86aabSstevel pcic_err(dip, 8, "Is Cardbus device\n");
8843db86aabSstevel if (pcic_debug) {
8853db86aabSstevel int nr;
8863db86aabSstevel long rs;
8873db86aabSstevel (void) ddi_dev_nregs(dip, &nr);
8883db86aabSstevel pcic_err(dip, 9, "\tdev, cfgaddr 0x%p,"
8893db86aabSstevel "cfghndl 0x%p nregs %d",
8903db86aabSstevel (void *)pcic->cfgaddr,
8913db86aabSstevel (void *)pcic->cfg_handle, nr);
8923db86aabSstevel
8933db86aabSstevel (void) ddi_dev_regsize(dip,
8943db86aabSstevel PCIC_PCI_CONTROL_REG_NUM, &rs);
8953db86aabSstevel
8963db86aabSstevel pcic_err(dip, 9, "\tsize of reg %d is 0x%x\n",
8973db86aabSstevel PCIC_PCI_CONTROL_REG_NUM, (int)rs);
8983db86aabSstevel }
8993db86aabSstevel #endif
9003db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
9013db86aabSstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
9023db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
9033db86aabSstevel
9043db86aabSstevel if (ddi_regs_map_setup(dip, pci_ctrn,
9053db86aabSstevel (caddr_t *)&pcic->ioaddr,
9063db86aabSstevel PCIC_PCI_CONTROL_REG_OFFSET,
9073db86aabSstevel PCIC_CB_CONTROL_REG_LENGTH,
9083db86aabSstevel &attr, &pcic->handle) !=
9093db86aabSstevel DDI_SUCCESS) {
9103db86aabSstevel cmn_err(CE_CONT,
9113db86aabSstevel "pcic%d: unable to map PCI regs\n",
9123db86aabSstevel ddi_get_instance(dip));
9133db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle);
9143db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t));
9153db86aabSstevel return (DDI_FAILURE);
9163db86aabSstevel } /* ddi_regs_map_setup */
9173db86aabSstevel
9183db86aabSstevel /*
9193db86aabSstevel * Find out the chip type - If we're on a PCI bus,
9203db86aabSstevel * the adapter has that information in the PCI
9213db86aabSstevel * config space.
9223db86aabSstevel * Note that we call pcic_find_pci_type here since
9233db86aabSstevel * it needs a valid mapped pcic->handle to
9243db86aabSstevel * access some of the adapter registers in
9253db86aabSstevel * some cases.
9263db86aabSstevel */
9273db86aabSstevel if (pcic_find_pci_type(pcic) != DDI_SUCCESS) {
9283db86aabSstevel ddi_regs_map_free(&pcic->handle);
9293db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle);
9303db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t));
9313db86aabSstevel cmn_err(CE_WARN, "pcic: %s: unsupported "
93219397407SSherry Moore "bridge\n", ddi_get_name_addr(dip));
9333db86aabSstevel return (DDI_FAILURE);
9343db86aabSstevel }
9353db86aabSstevel break;
9363db86aabSstevel
9373db86aabSstevel default:
9383db86aabSstevel case PCIC_PCI_PCMCIA:
9393db86aabSstevel /*
9403db86aabSstevel * Get access to the adapter IO registers on the
9413db86aabSstevel * PCI bus config space.
9423db86aabSstevel */
9433db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
9443db86aabSstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
9453db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
9463db86aabSstevel
9473db86aabSstevel /*
9483db86aabSstevel * We need a default mapping to the adapter's IO
9493db86aabSstevel * control register space. For most adapters
9503db86aabSstevel * that are of class PCIC_PCI_PCMCIA (or of
9513db86aabSstevel * a default class) the control registers
9523db86aabSstevel * will be using the 82365-type control/data
9533db86aabSstevel * format.
9543db86aabSstevel */
9553db86aabSstevel if (ddi_regs_map_setup(dip, pci_ctrn,
9563db86aabSstevel (caddr_t *)&pcic->ioaddr,
9573db86aabSstevel PCIC_PCI_CONTROL_REG_OFFSET,
9583db86aabSstevel PCIC_PCI_CONTROL_REG_LENGTH,
9593db86aabSstevel &attr,
9603db86aabSstevel &pcic->handle) != DDI_SUCCESS) {
9613db86aabSstevel cmn_err(CE_CONT,
9623db86aabSstevel "pcic%d: unable to map PCI regs\n",
9633db86aabSstevel ddi_get_instance(dip));
9643db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle);
9653db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t));
9663db86aabSstevel return (DDI_FAILURE);
9673db86aabSstevel } /* ddi_regs_map_setup */
9683db86aabSstevel
9693db86aabSstevel /*
9703db86aabSstevel * Find out the chip type - If we're on a PCI bus,
9713db86aabSstevel * the adapter has that information in the PCI
9723db86aabSstevel * config space.
9733db86aabSstevel * Note that we call pcic_find_pci_type here since
9743db86aabSstevel * it needs a valid mapped pcic->handle to
9753db86aabSstevel * access some of the adapter registers in
9763db86aabSstevel * some cases.
9773db86aabSstevel */
9783db86aabSstevel if (pcic_find_pci_type(pcic) != DDI_SUCCESS) {
9793db86aabSstevel ddi_regs_map_free(&pcic->handle);
9803db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle);
9813db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t));
9823db86aabSstevel cmn_err(CE_WARN, "pcic: %s: unsupported "
9833db86aabSstevel "bridge\n",
9843db86aabSstevel ddi_get_name_addr(dip));
9853db86aabSstevel return (DDI_FAILURE);
9863db86aabSstevel }
9873db86aabSstevel
9883db86aabSstevel /*
9893db86aabSstevel * Some PCI-PCMCIA(R2) adapters are Yenta-compliant
9903db86aabSstevel * for extended registers even though they are
9913db86aabSstevel * not CardBus adapters. For those adapters,
9923db86aabSstevel * re-map pcic->handle to be large enough to
9933db86aabSstevel * encompass the Yenta registers.
9943db86aabSstevel */
9953db86aabSstevel switch (pcic->pc_type) {
9963db86aabSstevel case PCIC_TI_PCI1031:
9973db86aabSstevel ddi_regs_map_free(&pcic->handle);
9983db86aabSstevel
9993db86aabSstevel if (ddi_regs_map_setup(dip,
10003db86aabSstevel PCIC_PCI_CONTROL_REG_NUM,
10013db86aabSstevel (caddr_t *)&pcic->ioaddr,
10023db86aabSstevel PCIC_PCI_CONTROL_REG_OFFSET,
10033db86aabSstevel PCIC_CB_CONTROL_REG_LENGTH,
10043db86aabSstevel &attr,
10053db86aabSstevel &pcic->handle) != DDI_SUCCESS) {
10063db86aabSstevel cmn_err(CE_CONT,
10073db86aabSstevel "pcic%d: unable to map "
10083db86aabSstevel "PCI regs\n",
10093db86aabSstevel ddi_get_instance(dip));
10103db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle);
10113db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t));
10123db86aabSstevel return (DDI_FAILURE);
10133db86aabSstevel } /* ddi_regs_map_setup */
10143db86aabSstevel break;
10153db86aabSstevel default:
10163db86aabSstevel break;
10173db86aabSstevel } /* switch (pcic->pc_type) */
10183db86aabSstevel break;
10193db86aabSstevel } /* switch (class_code) */
10203db86aabSstevel } else {
10213db86aabSstevel /*
10223db86aabSstevel * We're not on a PCI bus, so assume an ISA bus type
10233db86aabSstevel * register property. Get access to the adapter IO
10243db86aabSstevel * registers on a non-PCI bus.
10253db86aabSstevel */
10263db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
10273db86aabSstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
10283db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
10293db86aabSstevel pcic->mem_reg_num = PCIC_ISA_MEM_REG_NUM;
10303db86aabSstevel pcic->io_reg_num = PCIC_ISA_IO_REG_NUM;
10313db86aabSstevel
10323db86aabSstevel if (ddi_regs_map_setup(dip, PCIC_ISA_CONTROL_REG_NUM,
10333db86aabSstevel (caddr_t *)&pcic->ioaddr,
10343db86aabSstevel PCIC_ISA_CONTROL_REG_OFFSET,
10353db86aabSstevel PCIC_ISA_CONTROL_REG_LENGTH,
10363db86aabSstevel &attr,
10373db86aabSstevel &pcic->handle) != DDI_SUCCESS) {
10383db86aabSstevel cmn_err(CE_CONT,
10393db86aabSstevel "pcic%d: unable to map ISA registers\n",
10403db86aabSstevel ddi_get_instance(dip));
10413db86aabSstevel
10423db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t));
10433db86aabSstevel return (DDI_FAILURE);
10443db86aabSstevel } /* ddi_regs_map_setup */
10453db86aabSstevel
10463db86aabSstevel /* ISA bus is limited to 24-bits, but not first 640K */
10473db86aabSstevel pcic->pc_base = 0xd0000;
10483db86aabSstevel pcic->pc_bound = (uint32_t)~0;
10493db86aabSstevel pcic->pc_iobase = 0x1000;
10503db86aabSstevel pcic->pc_iobound = 0xefff;
10513db86aabSstevel } /* !PCF_PCIBUS */
10523db86aabSstevel
10533db86aabSstevel #ifdef PCIC_DEBUG
10543db86aabSstevel if (pcic_debug) {
10553db86aabSstevel cmn_err(CE_CONT, "pcic_attach pc_flags=%x pc_type=%x\n",
10563db86aabSstevel pcic->pc_flags, pcic->pc_type);
10573db86aabSstevel }
10583db86aabSstevel #endif
10593db86aabSstevel
10603db86aabSstevel /*
10613db86aabSstevel * Setup various adapter registers for the PCI case. For the
10623db86aabSstevel * non-PCI case, find out the chip type.
10633db86aabSstevel */
10643db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS) {
10653db86aabSstevel int iline;
10663db86aabSstevel #if defined(__sparc)
10673db86aabSstevel iline = 0;
10683db86aabSstevel #else
10693db86aabSstevel iline = cardbus_validate_iline(dip, pcic->cfg_handle);
10703db86aabSstevel #endif
10713db86aabSstevel
10723db86aabSstevel /* set flags and socket counts based on chip type */
10733db86aabSstevel switch (pcic->pc_type) {
10743db86aabSstevel uint32_t cfg;
10753db86aabSstevel case PCIC_INTEL_i82092:
10763db86aabSstevel cfg = ddi_get8(pcic->cfg_handle,
10773db86aabSstevel pcic->cfgaddr + PCIC_82092_PCICON);
10783db86aabSstevel /* we can only support 4 Socket version */
10793db86aabSstevel if (cfg & PCIC_82092_4_SOCKETS) {
10803db86aabSstevel pcic->pc_numsockets = 4;
10813db86aabSstevel pcic->pc_type = PCIC_INTEL_i82092;
10823db86aabSstevel if (iline != 0xFF)
108319397407SSherry Moore pcic->pc_intr_mode =
108419397407SSherry Moore PCIC_INTR_MODE_PCI_1;
10853db86aabSstevel else
10863db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_ISA;
10873db86aabSstevel } else {
10883db86aabSstevel cmn_err(CE_CONT,
10893db86aabSstevel "pcic%d: Intel 82092 adapter "
10903db86aabSstevel "in unsupported configuration: 0x%x",
10913db86aabSstevel ddi_get_instance(pcic->dip), cfg);
10923db86aabSstevel pcic->pc_numsockets = 0;
10933db86aabSstevel } /* PCIC_82092_4_SOCKETS */
10943db86aabSstevel break;
10953db86aabSstevel case PCIC_CL_PD6730:
10963db86aabSstevel case PCIC_CL_PD6729:
10973db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1;
10983db86aabSstevel cfg = ddi_getprop(DDI_DEV_T_ANY, dip,
10993db86aabSstevel DDI_PROP_CANSLEEP,
11003db86aabSstevel "interrupts", 0);
11013db86aabSstevel /* if not interrupt pin then must use ISA style IRQs */
11023db86aabSstevel if (cfg == 0 || iline == 0xFF)
11033db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_ISA;
11043db86aabSstevel else {
11053db86aabSstevel /*
11063db86aabSstevel * we have the option to use PCI interrupts.
11073db86aabSstevel * this might not be optimal but in some cases
11083db86aabSstevel * is the only thing possible (sparc case).
11093db86aabSstevel * we now deterine what is possible.
11103db86aabSstevel */
11113db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1;
11123db86aabSstevel }
11133db86aabSstevel pcic->pc_numsockets = 2;
11143db86aabSstevel pcic->pc_flags |= PCF_IO_REMAP;
11153db86aabSstevel break;
11163db86aabSstevel case PCIC_TI_PCI1031:
11173db86aabSstevel /* this chip doesn't do CardBus but looks like one */
11183db86aabSstevel pcic->pc_flags &= ~PCF_CARDBUS;
11193db86aabSstevel /* FALLTHROUGH */
11203db86aabSstevel default:
11213db86aabSstevel pcic->pc_flags |= PCF_IO_REMAP;
11223db86aabSstevel /* FALLTHROUGH */
11233db86aabSstevel /* indicate feature even if not supported */
11243db86aabSstevel pcic->pc_flags |= PCF_DMA | PCF_ZV;
11253db86aabSstevel /* Not sure if these apply to all these chips */
11263db86aabSstevel pcic->pc_flags |= (PCF_VPPX|PCF_33VCAP);
11273db86aabSstevel pcic->pc_flags |= pcic_use_cbpwrctl;
11283db86aabSstevel
11293db86aabSstevel pcic->pc_numsockets = 1; /* one per function */
11303db86aabSstevel if (iline != 0xFF) {
11313db86aabSstevel uint8_t cfg;
11323db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1;
11333db86aabSstevel
11343db86aabSstevel cfg = ddi_get8(pcic->cfg_handle,
11353db86aabSstevel (pcic->cfgaddr + PCIC_BRIDGE_CTL_REG));
11363db86aabSstevel cfg &= (~PCIC_FUN_INT_MOD_ISA);
11373db86aabSstevel ddi_put8(pcic->cfg_handle, (pcic->cfgaddr +
11383db86aabSstevel PCIC_BRIDGE_CTL_REG), cfg);
11393db86aabSstevel }
11403db86aabSstevel else
11413db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_ISA;
11423db86aabSstevel pcic->pc_io_type = PCIC_IOTYPE_YENTA;
11433db86aabSstevel break;
11443db86aabSstevel }
11453db86aabSstevel } else {
11463db86aabSstevel /*
11473db86aabSstevel * We're not on a PCI bus so do some more
11483db86aabSstevel * checking for adapter type here.
11493db86aabSstevel * For the non-PCI bus case:
11503db86aabSstevel * It could be any one of a number of different chips
11513db86aabSstevel * If we can't determine anything else, it is assumed
11523db86aabSstevel * to be an Intel 82365SL. The Cirrus Logic PD6710
11533db86aabSstevel * has an extension register that provides unique
11543db86aabSstevel * identification. Toshiba chip isn't detailed as yet.
11553db86aabSstevel */
11563db86aabSstevel
11573db86aabSstevel /* Init the CL id mode */
11583db86aabSstevel pcic_putb(pcic, 0, PCIC_CHIP_INFO, 0);
11593db86aabSstevel value = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
11603db86aabSstevel
11613db86aabSstevel /* default to Intel i82365SL and then refine */
11623db86aabSstevel pcic->pc_type = PCIC_I82365SL;
11633db86aabSstevel pcic->pc_chipname = PCIC_TYPE_I82365SL;
11643db86aabSstevel for (value = 0; pcic_ci_funcs[value] != NULL; value++) {
11653db86aabSstevel /* go until one succeeds or none left */
11663db86aabSstevel if (pcic_ci_funcs[value](pcic))
11673db86aabSstevel break;
11683db86aabSstevel }
11693db86aabSstevel
11703db86aabSstevel /* any chip specific flags get set here */
11713db86aabSstevel switch (pcic->pc_type) {
11723db86aabSstevel case PCIC_CL_PD6722:
11733db86aabSstevel pcic->pc_flags |= PCF_DMA;
11743db86aabSstevel }
11753db86aabSstevel
11763db86aabSstevel for (i = 0; i < PCIC_MAX_SOCKETS; i++) {
11773db86aabSstevel /*
11783db86aabSstevel * look for total number of sockets.
11793db86aabSstevel * basically check each possible socket for
11803db86aabSstevel * presence like in probe
11813db86aabSstevel */
11823db86aabSstevel
11833db86aabSstevel /* turn all windows off */
11843db86aabSstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
11853db86aabSstevel value = pcic_getb(pcic, i, PCIC_MAPPING_ENABLE);
11863db86aabSstevel
11873db86aabSstevel /*
11883db86aabSstevel * if a zero is read back, then this socket
11893db86aabSstevel * might be present. It would be except for
11903db86aabSstevel * some systems that map the secondary PCIC
11913db86aabSstevel * chip space back to the first.
11923db86aabSstevel */
11933db86aabSstevel if (value != 0) {
11943db86aabSstevel /* definitely not so skip */
11953db86aabSstevel /* note: this is for Compaq support */
11963db86aabSstevel continue;
11973db86aabSstevel }
11983db86aabSstevel
11993db86aabSstevel /* further tests */
12003db86aabSstevel value = pcic_getb(pcic, i, PCIC_CHIP_REVISION) &
12013db86aabSstevel PCIC_REV_MASK;
12023db86aabSstevel if (!(value >= PCIC_REV_LEVEL_LOW &&
12033db86aabSstevel value <= PCIC_REV_LEVEL_HI))
12043db86aabSstevel break;
12053db86aabSstevel
12063db86aabSstevel pcic_putb(pcic, i, PCIC_SYSMEM_0_STARTLOW, 0xaa);
12073db86aabSstevel pcic_putb(pcic, i, PCIC_SYSMEM_1_STARTLOW, 0x55);
12083db86aabSstevel value = pcic_getb(pcic, i, PCIC_SYSMEM_0_STARTLOW);
12093db86aabSstevel
12103db86aabSstevel j = pcic_getb(pcic, i, PCIC_SYSMEM_1_STARTLOW);
12113db86aabSstevel if (value != 0xaa || j != 0x55)
12123db86aabSstevel break;
12133db86aabSstevel
12143db86aabSstevel /*
12153db86aabSstevel * at this point we know if we have hardware
12163db86aabSstevel * of some type and not just the bus holding
12173db86aabSstevel * a pattern for us. We still have to determine
12183db86aabSstevel * the case where more than 2 sockets are
12193db86aabSstevel * really the same due to peculiar mappings of
12203db86aabSstevel * hardware.
12213db86aabSstevel */
12223db86aabSstevel j = pcic->pc_numsockets++;
12233db86aabSstevel pcic->pc_sockets[j].pcs_flags = 0;
12243db86aabSstevel pcic->pc_sockets[j].pcs_io = pcic->ioaddr;
12253db86aabSstevel pcic->pc_sockets[j].pcs_socket = i;
12263db86aabSstevel
12273db86aabSstevel /* put PC Card into RESET, just in case */
12283db86aabSstevel value = pcic_getb(pcic, i, PCIC_INTERRUPT);
12293db86aabSstevel pcic_putb(pcic, i, PCIC_INTERRUPT,
12303db86aabSstevel value & ~PCIC_RESET);
12313db86aabSstevel }
12323db86aabSstevel
12333db86aabSstevel #if defined(PCIC_DEBUG)
12343db86aabSstevel if (pcic_debug)
12353db86aabSstevel cmn_err(CE_CONT, "num sockets = %d\n",
12363db86aabSstevel pcic->pc_numsockets);
12373db86aabSstevel #endif
12383db86aabSstevel if (pcic->pc_numsockets == 0) {
12393db86aabSstevel ddi_regs_map_free(&pcic->handle);
12403db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t));
12413db86aabSstevel return (DDI_FAILURE);
12423db86aabSstevel }
12433db86aabSstevel
12443db86aabSstevel /*
12453db86aabSstevel * need to think this through again in light of
12463db86aabSstevel * Compaq not following the model that all the
12473db86aabSstevel * chip vendors recommend. IBM 755 seems to be
12483db86aabSstevel * afflicted as well. Basically, if the vendor
12493db86aabSstevel * wired things wrong, socket 0 responds for socket 2
12503db86aabSstevel * accesses, etc.
12513db86aabSstevel */
12523db86aabSstevel if (pcic->pc_numsockets > 2) {
12533db86aabSstevel int count = pcic->pc_numsockets / 4;
12543db86aabSstevel for (i = 0; i < count; i++) {
12553db86aabSstevel /* put pattern into socket 0 */
12563db86aabSstevel pcic_putb(pcic, i,
12573db86aabSstevel PCIC_SYSMEM_0_STARTLOW, 0x11);
12583db86aabSstevel
12593db86aabSstevel /* put pattern into socket 2 */
12603db86aabSstevel pcic_putb(pcic, i + 2,
12613db86aabSstevel PCIC_SYSMEM_0_STARTLOW, 0x33);
12623db86aabSstevel
12633db86aabSstevel /* read back socket 0 */
12643db86aabSstevel value = pcic_getb(pcic, i,
12653db86aabSstevel PCIC_SYSMEM_0_STARTLOW);
12663db86aabSstevel
12673db86aabSstevel /* read back chip 1 socket 0 */
12683db86aabSstevel j = pcic_getb(pcic, i + 2,
12693db86aabSstevel PCIC_SYSMEM_0_STARTLOW);
12703db86aabSstevel if (j == value) {
12713db86aabSstevel pcic->pc_numsockets -= 2;
12723db86aabSstevel }
12733db86aabSstevel }
12743db86aabSstevel }
12753db86aabSstevel
12763db86aabSstevel smi = 0xff; /* no more override */
12773db86aabSstevel
12783db86aabSstevel if (ddi_getprop(DDI_DEV_T_NONE, dip,
12793db86aabSstevel DDI_PROP_DONTPASS, "need-mult-irq",
12803db86aabSstevel 0xffff) != 0xffff)
12813db86aabSstevel pcic->pc_flags |= PCF_MULT_IRQ;
12823db86aabSstevel
12833db86aabSstevel } /* !PCF_PCIBUS */
12843db86aabSstevel
12853db86aabSstevel /*
12863db86aabSstevel * some platforms/busses need to have resources setup
12873db86aabSstevel * this is temporary until a real resource allocator is
12883db86aabSstevel * implemented.
12893db86aabSstevel */
12903db86aabSstevel
12913db86aabSstevel pcic_init_assigned(dip);
12923db86aabSstevel
12933db86aabSstevel typename = pcic->pc_chipname;
12943db86aabSstevel
12953db86aabSstevel #ifdef PCIC_DEBUG
12963db86aabSstevel if (pcic_debug) {
12973db86aabSstevel int nregs, nintrs;
12983db86aabSstevel
12993db86aabSstevel if (ddi_dev_nregs(dip, &nregs) != DDI_SUCCESS)
13003db86aabSstevel nregs = 0;
13013db86aabSstevel
13023db86aabSstevel if (ddi_dev_nintrs(dip, &nintrs) != DDI_SUCCESS)
13033db86aabSstevel nintrs = 0;
13043db86aabSstevel
13053db86aabSstevel cmn_err(CE_CONT,
13063db86aabSstevel "pcic%d: %d register sets, %d interrupts\n",
13073db86aabSstevel ddi_get_instance(dip), nregs, nintrs);
13083db86aabSstevel
13093db86aabSstevel nintrs = 0;
13103db86aabSstevel while (nregs--) {
13113db86aabSstevel off_t size;
13123db86aabSstevel
13133db86aabSstevel if (ddi_dev_regsize(dip, nintrs, &size) ==
13143db86aabSstevel DDI_SUCCESS) {
13153db86aabSstevel cmn_err(CE_CONT,
13163db86aabSstevel "\tregnum %d size %ld (0x%lx)"
13173db86aabSstevel "bytes",
13183db86aabSstevel nintrs, size, size);
13193db86aabSstevel if (nintrs ==
13203db86aabSstevel (pcic->pc_io_type == PCIC_IO_TYPE_82365SL ?
13213db86aabSstevel PCIC_ISA_CONTROL_REG_NUM :
13223db86aabSstevel PCIC_PCI_CONTROL_REG_NUM))
13233db86aabSstevel cmn_err(CE_CONT,
13243db86aabSstevel " mapped at: 0x%p\n",
13253db86aabSstevel (void *)pcic->ioaddr);
13263db86aabSstevel else
13273db86aabSstevel cmn_err(CE_CONT, "\n");
13283db86aabSstevel } else {
13293db86aabSstevel cmn_err(CE_CONT,
13303db86aabSstevel "\tddi_dev_regsize(rnumber"
13313db86aabSstevel "= %d) returns DDI_FAILURE\n",
13323db86aabSstevel nintrs);
13333db86aabSstevel }
13343db86aabSstevel nintrs++;
13353db86aabSstevel } /* while */
13363db86aabSstevel } /* if (pcic_debug) */
13373db86aabSstevel #endif
13383db86aabSstevel
13393db86aabSstevel cv_init(&pcic->pm_cv, NULL, CV_DRIVER, NULL);
13403db86aabSstevel
13413db86aabSstevel if (!ddi_getprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
13423db86aabSstevel "disable-audio", 0))
13433db86aabSstevel pcic->pc_flags |= PCF_AUDIO;
13443db86aabSstevel
13453db86aabSstevel if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
13463db86aabSstevel "disable-cardbus", 0))
13473db86aabSstevel pcic->pc_flags &= ~PCF_CARDBUS;
13483db86aabSstevel
13493db86aabSstevel (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, PCICPROP_CTL,
13503db86aabSstevel typename);
13513db86aabSstevel
13523db86aabSstevel /*
13533db86aabSstevel * Init all socket SMI levels to 0 (no SMI)
13543db86aabSstevel */
13553db86aabSstevel for (i = 0; i < PCIC_MAX_SOCKETS; i++) {
13563db86aabSstevel pcic->pc_sockets[i].pcs_smi = 0;
13573db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id = 0;
13583db86aabSstevel pcic->pc_sockets[i].pcs_pcic = pcic;
13593db86aabSstevel }
13603db86aabSstevel pcic->pc_lastreg = -1; /* just to make sure we are in sync */
13613db86aabSstevel
13623db86aabSstevel /*
13633db86aabSstevel * Setup the IRQ handler(s)
13643db86aabSstevel */
13653db86aabSstevel switch (pcic->pc_intr_mode) {
13663db86aabSstevel int xx;
13673db86aabSstevel case PCIC_INTR_MODE_ISA:
13683db86aabSstevel /*
13693db86aabSstevel * On a non-PCI bus, we just use whatever SMI IRQ level was
13703db86aabSstevel * specified above, and the IO IRQ levels are allocated
13713db86aabSstevel * dynamically.
13723db86aabSstevel */
13733db86aabSstevel for (xx = 15, smi = 0; xx >= 0; xx--) {
13743db86aabSstevel if (PCIC_IRQ(xx) &
13753db86aabSstevel PCIC_AVAIL_IRQS) {
13763db86aabSstevel smi = pcmcia_get_intr(dip, xx);
13773db86aabSstevel if (smi >= 0)
13783db86aabSstevel break;
13793db86aabSstevel }
13803db86aabSstevel }
13813db86aabSstevel #if defined(PCIC_DEBUG)
13823db86aabSstevel if (pcic_debug)
13833db86aabSstevel cmn_err(CE_NOTE, "\tselected IRQ %d as SMI\n", smi);
13843db86aabSstevel #endif
13853db86aabSstevel /* init to same so share is easy */
13863db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++)
13873db86aabSstevel pcic->pc_sockets[i].pcs_smi = smi;
13883db86aabSstevel /* any special handling of IRQ levels */
13893db86aabSstevel if (pcic->pc_flags & PCF_MULT_IRQ) {
13903db86aabSstevel for (i = 2; i < pcic->pc_numsockets; i++) {
13913db86aabSstevel if ((i & 1) == 0) {
13923db86aabSstevel int xx;
13933db86aabSstevel for (xx = 15, smi = 0; xx >= 0; xx--) {
13943db86aabSstevel if (PCIC_IRQ(xx) &
13953db86aabSstevel PCIC_AVAIL_IRQS) {
13963db86aabSstevel smi =
13973db86aabSstevel pcmcia_get_intr(dip,
13983db86aabSstevel xx);
13993db86aabSstevel if (smi >= 0)
14003db86aabSstevel break;
14013db86aabSstevel }
14023db86aabSstevel }
14033db86aabSstevel }
14043db86aabSstevel if (smi >= 0)
14053db86aabSstevel pcic->pc_sockets[i].pcs_smi = smi;
14063db86aabSstevel }
14073db86aabSstevel }
14083db86aabSstevel pcic->pc_intr_htblp = kmem_alloc(pcic->pc_numsockets *
14093db86aabSstevel sizeof (ddi_intr_handle_t), KM_SLEEP);
14103db86aabSstevel for (i = 0, irqlevel = -1; i < pcic->pc_numsockets; i++) {
14113db86aabSstevel struct intrspec *ispecp;
14123db86aabSstevel struct ddi_parent_private_data *pdp;
14133db86aabSstevel
14143db86aabSstevel if (irqlevel == pcic->pc_sockets[i].pcs_smi)
14153db86aabSstevel continue;
14163db86aabSstevel else {
14173db86aabSstevel irqlevel = pcic->pc_sockets[i].pcs_smi;
14183db86aabSstevel }
14193db86aabSstevel /*
14203db86aabSstevel * now convert the allocated IRQ into an intrspec
14213db86aabSstevel * and ask our parent to add it. Don't use
14223db86aabSstevel * the ddi_add_intr since we don't have a
14233db86aabSstevel * default intrspec in all cases.
14243db86aabSstevel *
14253db86aabSstevel * note: this sort of violates DDI but we don't
14263db86aabSstevel * get hardware intrspecs for many of the devices.
14273db86aabSstevel * at the same time, we know how to allocate them
14283db86aabSstevel * so we do the right thing.
14293db86aabSstevel */
14303db86aabSstevel if (ddi_intr_alloc(dip, &pcic->pc_intr_htblp[i],
14313db86aabSstevel DDI_INTR_TYPE_FIXED, 0, 1, &actual,
14323db86aabSstevel DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) {
14333db86aabSstevel cmn_err(CE_WARN, "%s: ddi_intr_alloc failed",
14343db86aabSstevel ddi_get_name(dip));
14353db86aabSstevel goto isa_exit1;
14363db86aabSstevel }
14373db86aabSstevel
14383db86aabSstevel /*
14393db86aabSstevel * See earlier note:
14403db86aabSstevel * Since some devices don't have 'intrspec'
14413db86aabSstevel * we make one up in rootnex.
14423db86aabSstevel *
14433db86aabSstevel * However, it is not properly initialized as
14443db86aabSstevel * the data it needs is present in this driver
14453db86aabSstevel * and there is no interface to pass that up.
14463db86aabSstevel * Specially 'irqlevel' is very important and
14473db86aabSstevel * it is part of pcic struct.
14483db86aabSstevel *
14493db86aabSstevel * Set 'intrspec' up here; otherwise adding the
14503db86aabSstevel * interrupt will fail.
14513db86aabSstevel */
14523db86aabSstevel pdp = ddi_get_parent_data(dip);
14533db86aabSstevel ispecp = (struct intrspec *)&pdp->par_intr[0];
14543db86aabSstevel ispecp->intrspec_vec = irqlevel;
14553db86aabSstevel ispecp->intrspec_pri = pcic->pc_irq;
14563db86aabSstevel
14573db86aabSstevel /* Stay compatible w/ PCMCIA */
14583db86aabSstevel pcic->pc_pri = (ddi_iblock_cookie_t)
14593db86aabSstevel (uintptr_t)pcic->pc_irq;
14603db86aabSstevel pcic->pc_dcookie.idev_priority =
14613db86aabSstevel (uintptr_t)pcic->pc_pri;
14623db86aabSstevel pcic->pc_dcookie.idev_vector = (ushort_t)irqlevel;
14633db86aabSstevel
14643db86aabSstevel (void) ddi_intr_set_pri(pcic->pc_intr_htblp[i],
14653db86aabSstevel pcic->pc_irq);
14663db86aabSstevel
14673db86aabSstevel if (i == 0) {
14683db86aabSstevel mutex_init(&pcic->intr_lock, NULL, MUTEX_DRIVER,
14693db86aabSstevel DDI_INTR_PRI(pcic->pc_irq));
14703db86aabSstevel mutex_init(&pcic->pc_lock, NULL, MUTEX_DRIVER,
14713db86aabSstevel NULL);
14723db86aabSstevel }
14733db86aabSstevel
14743db86aabSstevel if (ddi_intr_add_handler(pcic->pc_intr_htblp[i],
14753db86aabSstevel pcic_intr, (caddr_t)pcic, NULL)) {
14763db86aabSstevel cmn_err(CE_WARN,
14773db86aabSstevel "%s: ddi_intr_add_handler failed",
14783db86aabSstevel ddi_get_name(dip));
14793db86aabSstevel goto isa_exit2;
14803db86aabSstevel }
14813db86aabSstevel
14823db86aabSstevel if (ddi_intr_enable(pcic->pc_intr_htblp[i])) {
14833db86aabSstevel cmn_err(CE_WARN, "%s: ddi_intr_enable failed",
14843db86aabSstevel ddi_get_name(dip));
14853db86aabSstevel for (j = i; j < 0; j--)
14863db86aabSstevel (void) ddi_intr_remove_handler(
14873db86aabSstevel pcic->pc_intr_htblp[j]);
14883db86aabSstevel goto isa_exit2;
14893db86aabSstevel }
14903db86aabSstevel }
14913db86aabSstevel break;
14923db86aabSstevel case PCIC_INTR_MODE_PCI_1:
14933db86aabSstevel case PCIC_INTR_MODE_PCI:
14943db86aabSstevel /*
14953db86aabSstevel * If we're on a PCI bus, we route all interrupts, both SMI
14963db86aabSstevel * and IO interrupts, through a single interrupt line.
14973db86aabSstevel * Assign the SMI IRQ level to the IO IRQ level here.
14983db86aabSstevel */
14993db86aabSstevel pcic->pc_pci_intr_hdlp = kmem_alloc(sizeof (ddi_intr_handle_t),
15003db86aabSstevel KM_SLEEP);
15013db86aabSstevel if (ddi_intr_alloc(dip, pcic->pc_pci_intr_hdlp,
15023db86aabSstevel DDI_INTR_TYPE_FIXED, 0, 1, &actual,
15033db86aabSstevel DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS)
15043db86aabSstevel goto pci_exit1;
15053db86aabSstevel
15063db86aabSstevel if (ddi_intr_get_pri(pcic->pc_pci_intr_hdlp[0],
15073db86aabSstevel &pri) != DDI_SUCCESS) {
15083db86aabSstevel (void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]);
15093db86aabSstevel goto pci_exit1;
15103db86aabSstevel }
15113db86aabSstevel
15123db86aabSstevel pcic->pc_pri = (void *)(uintptr_t)pri;
15133db86aabSstevel mutex_init(&pcic->intr_lock, NULL, MUTEX_DRIVER, pcic->pc_pri);
15143db86aabSstevel mutex_init(&pcic->pc_lock, NULL, MUTEX_DRIVER, NULL);
15153db86aabSstevel
15163db86aabSstevel if (ddi_intr_add_handler(pcic->pc_pci_intr_hdlp[0],
15173db86aabSstevel pcic_intr, (caddr_t)pcic, NULL))
15183db86aabSstevel goto pci_exit2;
15193db86aabSstevel
15203db86aabSstevel if (ddi_intr_enable(pcic->pc_pci_intr_hdlp[0])) {
15213db86aabSstevel (void) ddi_intr_remove_handler(
15223db86aabSstevel pcic->pc_pci_intr_hdlp[0]);
15233db86aabSstevel goto pci_exit2;
15243db86aabSstevel }
15253db86aabSstevel
15263db86aabSstevel /* Stay compatible w/ PCMCIA */
15273db86aabSstevel pcic->pc_dcookie.idev_priority = (ushort_t)pri;
15283db86aabSstevel
15293db86aabSstevel /* init to same (PCI) so share is easy */
15303db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++)
15313db86aabSstevel pcic->pc_sockets[i].pcs_smi = 0xF; /* any valid */
15323db86aabSstevel break;
15333db86aabSstevel }
15343db86aabSstevel
15353db86aabSstevel /*
15363db86aabSstevel * Setup the adapter hardware to some reasonable defaults.
15373db86aabSstevel */
15383db86aabSstevel mutex_enter(&pcic->pc_lock);
15393db86aabSstevel /* mark the driver state as attached */
15403db86aabSstevel pcic->pc_flags |= PCF_ATTACHED;
15413db86aabSstevel pcic_setup_adapter(pcic);
15423db86aabSstevel
15433db86aabSstevel for (j = 0; j < pcic->pc_numsockets; j++)
15443db86aabSstevel if (ddi_intr_add_softint(dip,
15453db86aabSstevel &pcic->pc_sockets[j].pcs_cd_softint_hdl,
15463db86aabSstevel PCIC_SOFTINT_PRI_VAL, pcic_cd_softint,
15473db86aabSstevel (caddr_t)&pcic->pc_sockets[j]) != DDI_SUCCESS)
15483db86aabSstevel goto pci_exit2;
15493db86aabSstevel
15503db86aabSstevel #if defined(PCIC_DEBUG)
15513db86aabSstevel if (pcic_debug)
15523db86aabSstevel cmn_err(CE_CONT, "type = %s sockets = %d\n", typename,
15533db86aabSstevel pcic->pc_numsockets);
15543db86aabSstevel #endif
15553db86aabSstevel
15563db86aabSstevel pcic_nexus->an_iblock = &pcic->pc_pri;
15573db86aabSstevel pcic_nexus->an_idev = &pcic->pc_dcookie;
15583db86aabSstevel
15593db86aabSstevel mutex_exit(&pcic->pc_lock);
15603db86aabSstevel
15613db86aabSstevel #ifdef CARDBUS
15623db86aabSstevel (void) cardbus_enable_cd_intr(dip);
15633db86aabSstevel if (pcic_debug) {
15643db86aabSstevel
15653db86aabSstevel cardbus_dump_pci_config(dip);
15663db86aabSstevel cardbus_dump_socket(dip);
15673db86aabSstevel }
15683db86aabSstevel
15693db86aabSstevel /*
15703db86aabSstevel * Give the Cardbus misc module a chance to do it's per-adapter
15713db86aabSstevel * instance setup. Note that there is no corresponding detach()
15723db86aabSstevel * call.
15733db86aabSstevel */
15743db86aabSstevel if (pcic->pc_flags & PCF_CARDBUS)
15753db86aabSstevel if (cardbus_attach(dip, &pcic_cbnexus_ops) != DDI_SUCCESS) {
15763db86aabSstevel cmn_err(CE_CONT,
15773db86aabSstevel "pcic_attach: cardbus_attach failed\n");
15783db86aabSstevel goto pci_exit2;
15793db86aabSstevel }
15803db86aabSstevel #endif
15813db86aabSstevel
15823db86aabSstevel /*
15833db86aabSstevel * Give the PCMCIA misc module a chance to do it's per-adapter
15843db86aabSstevel * instance setup.
15853db86aabSstevel */
15863db86aabSstevel if ((i = pcmcia_attach(dip, pcic_nexus)) != DDI_SUCCESS)
15873db86aabSstevel goto pci_exit2;
15883db86aabSstevel
15893db86aabSstevel if (pcic_maxinst == -1) {
15903db86aabSstevel /* This assumes that all instances run at the same IPL. */
15913db86aabSstevel mutex_init(&pcic_deb_mtx, NULL, MUTEX_DRIVER, NULL);
15923db86aabSstevel cv_init(&pcic_deb_cv, NULL, CV_DRIVER, NULL);
15933db86aabSstevel pcic_deb_threadid = thread_create((caddr_t)NULL, 0,
15943db86aabSstevel pcic_deb_thread, (caddr_t)NULL, 0, &p0, TS_RUN,
15953db86aabSstevel v.v_maxsyspri - 2);
15963db86aabSstevel }
15973db86aabSstevel pcic_maxinst = max(pcic_maxinst, ddi_get_instance(dip));
15983db86aabSstevel /*
15993db86aabSstevel * Setup a debounce timeout to do an initial card detect
16003db86aabSstevel * and enable interrupts.
16013db86aabSstevel */
16023db86aabSstevel for (j = 0; j < pcic->pc_numsockets; j++) {
16033db86aabSstevel pcic->pc_sockets[j].pcs_debounce_id =
16043db86aabSstevel pcic_add_debqueue(&pcic->pc_sockets[j],
16053db86aabSstevel drv_usectohz(pcic_debounce_time));
16063db86aabSstevel }
16073db86aabSstevel
16083db86aabSstevel return (i);
16093db86aabSstevel
16103db86aabSstevel isa_exit2:
16113db86aabSstevel mutex_destroy(&pcic->intr_lock);
16123db86aabSstevel mutex_destroy(&pcic->pc_lock);
16133db86aabSstevel for (j = i; j < 0; j--)
16143db86aabSstevel (void) ddi_intr_free(pcic->pc_intr_htblp[j]);
16153db86aabSstevel isa_exit1:
16163db86aabSstevel (void) pcmcia_return_intr(dip, pcic->pc_sockets[i].pcs_smi);
16173db86aabSstevel ddi_regs_map_free(&pcic->handle);
16183db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS)
16193db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle);
16203db86aabSstevel kmem_free(pcic->pc_intr_htblp, pcic->pc_numsockets *
16213db86aabSstevel sizeof (ddi_intr_handle_t));
16223db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t));
16233db86aabSstevel return (DDI_FAILURE);
16243db86aabSstevel
16253db86aabSstevel pci_exit2:
16263db86aabSstevel mutex_destroy(&pcic->intr_lock);
16273db86aabSstevel mutex_destroy(&pcic->pc_lock);
16283db86aabSstevel (void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]);
16293db86aabSstevel pci_exit1:
16303db86aabSstevel ddi_regs_map_free(&pcic->handle);
16313db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS)
16323db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle);
16333db86aabSstevel kmem_free(pcic->pc_pci_intr_hdlp, sizeof (ddi_intr_handle_t));
16343db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t));
16353db86aabSstevel return (DDI_FAILURE);
16363db86aabSstevel }
16373db86aabSstevel
16383db86aabSstevel /*
16393db86aabSstevel * pcic_detach()
16403db86aabSstevel * request to detach from the system
16413db86aabSstevel */
16423db86aabSstevel static int
pcic_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)16433db86aabSstevel pcic_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
16443db86aabSstevel {
16453db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
16463db86aabSstevel pcicdev_t *pcic = anp->an_private;
16473db86aabSstevel int i;
16483db86aabSstevel
16493db86aabSstevel switch (cmd) {
16503db86aabSstevel case DDI_DETACH:
16513db86aabSstevel /* don't detach if the nexus still talks to us */
16523db86aabSstevel if (pcic->pc_callback != NULL)
16533db86aabSstevel return (DDI_FAILURE);
16543db86aabSstevel
16553db86aabSstevel /* kill off the pm simulation */
16563db86aabSstevel if (pcic->pc_pmtimer)
16573db86aabSstevel (void) untimeout(pcic->pc_pmtimer);
16583db86aabSstevel
16593db86aabSstevel /* turn everything off for all sockets and chips */
16603db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) {
16613db86aabSstevel if (pcic->pc_sockets[i].pcs_debounce_id)
16623db86aabSstevel pcic_rm_debqueue(
16633db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id);
16643db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id = 0;
16653db86aabSstevel
16663db86aabSstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0);
16673db86aabSstevel pcic_putb(pcic, i, PCIC_CARD_DETECT, 0);
16683db86aabSstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
16693db86aabSstevel /* disable interrupts and put card into RESET */
16703db86aabSstevel pcic_putb(pcic, i, PCIC_INTERRUPT, 0);
16713db86aabSstevel }
16723db86aabSstevel (void) ddi_intr_disable(pcic->pc_pci_intr_hdlp[0]);
16733db86aabSstevel (void) ddi_intr_remove_handler(pcic->pc_pci_intr_hdlp[0]);
16743db86aabSstevel (void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]);
16753db86aabSstevel kmem_free(pcic->pc_pci_intr_hdlp, sizeof (ddi_intr_handle_t));
16763db86aabSstevel pcic->pc_flags = 0;
16773db86aabSstevel mutex_destroy(&pcic->pc_lock);
16783db86aabSstevel mutex_destroy(&pcic->intr_lock);
16793db86aabSstevel cv_destroy(&pcic->pm_cv);
16803db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS)
16813db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle);
16823db86aabSstevel if (pcic->handle)
16833db86aabSstevel ddi_regs_map_free(&pcic->handle);
16843db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t));
16853db86aabSstevel ddi_soft_state_free(pcic_soft_state_p, ddi_get_instance(dip));
16863db86aabSstevel return (DDI_SUCCESS);
16873db86aabSstevel
16883db86aabSstevel case DDI_SUSPEND:
16893db86aabSstevel case DDI_PM_SUSPEND:
16903db86aabSstevel /*
16913db86aabSstevel * we got a suspend event (either real or imagined)
16923db86aabSstevel * so notify the nexus proper that all existing cards
16933db86aabSstevel * should go away.
16943db86aabSstevel */
16953db86aabSstevel mutex_enter(&pcic->pc_lock);
16963db86aabSstevel #ifdef CARDBUS
169711c2b4c0Srw148561 if (pcic->pc_flags & PCF_CARDBUS) {
169811c2b4c0Srw148561 for (i = 0; i < pcic->pc_numsockets; i++) {
16993db86aabSstevel if ((pcic->pc_sockets[i].pcs_flags &
17003db86aabSstevel (PCS_CARD_PRESENT|PCS_CARD_ISCARDBUS)) ==
170111c2b4c0Srw148561 (PCS_CARD_PRESENT|PCS_CARD_ISCARDBUS)) {
170211c2b4c0Srw148561
170311c2b4c0Srw148561 pcmcia_cb_suspended(
170411c2b4c0Srw148561 pcic->pc_sockets[i].pcs_socket);
170511c2b4c0Srw148561 }
170611c2b4c0Srw148561 }
170711c2b4c0Srw148561
170811c2b4c0Srw148561 cardbus_save_children(ddi_get_child(dip));
17093db86aabSstevel }
17103db86aabSstevel #endif
17113db86aabSstevel /* turn everything off for all sockets and chips */
17123db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) {
17133db86aabSstevel if (pcic->pc_sockets[i].pcs_debounce_id)
17143db86aabSstevel pcic_rm_debqueue(
17153db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id);
17163db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id = 0;
17173db86aabSstevel
17183db86aabSstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0);
17193db86aabSstevel pcic_putb(pcic, i, PCIC_CARD_DETECT, 0);
17203db86aabSstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
17213db86aabSstevel /* disable interrupts and put card into RESET */
17223db86aabSstevel pcic_putb(pcic, i, PCIC_INTERRUPT, 0);
17233db86aabSstevel pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0);
17243db86aabSstevel if (pcic->pc_flags & PCF_CBPWRCTL)
17253db86aabSstevel pcic_putcb(pcic, CB_CONTROL, 0);
17263db86aabSstevel
17273db86aabSstevel if (pcic->pc_sockets[i].pcs_flags & PCS_CARD_PRESENT) {
17283db86aabSstevel pcic->pc_sockets[i].pcs_flags = PCS_STARTING;
17293db86aabSstevel /*
17303db86aabSstevel * Because we are half way through a save
17313db86aabSstevel * all this does is schedule a removal event
17323db86aabSstevel * to cs for when the system comes back.
17333db86aabSstevel * This doesn't actually matter.
17343db86aabSstevel */
17353db86aabSstevel if (!pcic_do_pcmcia_sr && pcic_do_removal &&
17363db86aabSstevel pcic->pc_callback) {
17373db86aabSstevel PC_CALLBACK(pcic->dip, pcic->pc_cb_arg,
17383db86aabSstevel PCE_CARD_REMOVAL,
17393db86aabSstevel pcic->pc_sockets[i].pcs_socket);
17403db86aabSstevel }
17413db86aabSstevel }
17423db86aabSstevel }
17433db86aabSstevel
17443db86aabSstevel pcic->pc_flags |= PCF_SUSPENDED;
17453db86aabSstevel mutex_exit(&pcic->pc_lock);
17463db86aabSstevel
17473db86aabSstevel /*
17483db86aabSstevel * when true power management exists, save the adapter
17493db86aabSstevel * state here to enable a recovery. For the emulation
17503db86aabSstevel * condition, the state is gone
17513db86aabSstevel */
17523db86aabSstevel return (DDI_SUCCESS);
17533db86aabSstevel
17543db86aabSstevel default:
17553db86aabSstevel return (EINVAL);
17563db86aabSstevel }
17573db86aabSstevel }
17583db86aabSstevel
17593db86aabSstevel static uint32_t pcic_tisysctl_onbits = ((1<<27) | (1<<15) | (1<<14));
17603db86aabSstevel static uint32_t pcic_tisysctl_offbits = 0;
17613db86aabSstevel static uint32_t pcic_default_latency = 0x40;
17623db86aabSstevel
17633db86aabSstevel static void
pcic_setup_adapter(pcicdev_t * pcic)17643db86aabSstevel pcic_setup_adapter(pcicdev_t *pcic)
17653db86aabSstevel {
17663db86aabSstevel int i;
17673db86aabSstevel int value, flags;
17683db86aabSstevel
1769e12b469aSrui wang - Sun Microsystems - Beijing China #if defined(__i386) || defined(__amd64)
1770e12b469aSrui wang - Sun Microsystems - Beijing China pci_regspec_t *reg;
1771e12b469aSrui wang - Sun Microsystems - Beijing China uchar_t bus, dev, func;
1772e12b469aSrui wang - Sun Microsystems - Beijing China uint_t classcode;
1773e12b469aSrui wang - Sun Microsystems - Beijing China int length;
1774e12b469aSrui wang - Sun Microsystems - Beijing China #endif
1775e12b469aSrui wang - Sun Microsystems - Beijing China
17763db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS) {
17773db86aabSstevel /*
17783db86aabSstevel * all PCI-to-PCMCIA bus bridges need memory and I/O enabled
17793db86aabSstevel */
17803db86aabSstevel flags = (PCIC_ENABLE_IO | PCIC_ENABLE_MEM);
17813db86aabSstevel pcic_iomem_pci_ctl(pcic->cfg_handle, pcic->cfgaddr, flags);
17823db86aabSstevel }
17833db86aabSstevel /* enable each socket */
17843db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) {
17853db86aabSstevel pcic->pc_sockets[i].pcs_flags = 0;
17863db86aabSstevel /* find out the socket capabilities (I/O vs memory) */
17873db86aabSstevel value = pcic_getb(pcic, i,
17883db86aabSstevel PCIC_CHIP_REVISION) & PCIC_REV_ID_MASK;
17893db86aabSstevel if (value == PCIC_REV_ID_IO || value == PCIC_REV_ID_BOTH)
17903db86aabSstevel pcic->pc_sockets[i].pcs_flags |= PCS_SOCKET_IO;
17913db86aabSstevel
17923db86aabSstevel /* disable all windows just in case */
17933db86aabSstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
17943db86aabSstevel
17953db86aabSstevel switch (pcic->pc_type) {
17963db86aabSstevel uint32_t cfg32;
17973db86aabSstevel uint16_t cfg16;
17983db86aabSstevel uint8_t cfg;
17993db86aabSstevel
18003db86aabSstevel /* enable extended registers for Vadem */
18013db86aabSstevel case PCIC_VADEM_VG469:
18023db86aabSstevel case PCIC_VADEM:
18033db86aabSstevel
18043db86aabSstevel /* enable card status change interrupt for socket */
18053db86aabSstevel break;
18063db86aabSstevel
18073db86aabSstevel case PCIC_I82365SL:
18083db86aabSstevel break;
18093db86aabSstevel
18103db86aabSstevel case PCIC_CL_PD6710:
18113db86aabSstevel pcic_putb(pcic, 0, PCIC_MISC_CTL_2, PCIC_LED_ENABLE);
18123db86aabSstevel break;
18133db86aabSstevel
18143db86aabSstevel /*
18153db86aabSstevel * On the CL_6730, we need to set up the interrupt
18163db86aabSstevel * signalling mode (PCI mode) and set the SMI and
18173db86aabSstevel * IRQ interrupt lines to PCI/level-mode.
18183db86aabSstevel */
18193db86aabSstevel case PCIC_CL_PD6730:
18203db86aabSstevel switch (pcic->pc_intr_mode) {
18213db86aabSstevel case PCIC_INTR_MODE_PCI_1:
18223db86aabSstevel clext_reg_write(pcic, i, PCIC_CLEXT_MISC_CTL_3,
18233db86aabSstevel ((clext_reg_read(pcic, i,
18243db86aabSstevel PCIC_CLEXT_MISC_CTL_3) &
18253db86aabSstevel ~PCIC_CLEXT_INT_PCI) |
18263db86aabSstevel PCIC_CLEXT_INT_PCI));
18273db86aabSstevel clext_reg_write(pcic, i, PCIC_CLEXT_EXT_CTL_1,
18283db86aabSstevel (PCIC_CLEXT_IRQ_LVL_MODE |
18293db86aabSstevel PCIC_CLEXT_SMI_LVL_MODE));
18303db86aabSstevel cfg = PCIC_CL_LP_DYN_MODE;
18313db86aabSstevel pcic_putb(pcic, i, PCIC_MISC_CTL_2, cfg);
18323db86aabSstevel break;
18333db86aabSstevel case PCIC_INTR_MODE_ISA:
18343db86aabSstevel break;
18353db86aabSstevel }
18363db86aabSstevel break;
18373db86aabSstevel /*
18383db86aabSstevel * On the CL_6729, we set the SMI and IRQ interrupt
18393db86aabSstevel * lines to PCI/level-mode. as well as program the
18403db86aabSstevel * correct clock speed divider bit.
18413db86aabSstevel */
18423db86aabSstevel case PCIC_CL_PD6729:
18433db86aabSstevel switch (pcic->pc_intr_mode) {
18443db86aabSstevel case PCIC_INTR_MODE_PCI_1:
18453db86aabSstevel clext_reg_write(pcic, i, PCIC_CLEXT_EXT_CTL_1,
18463db86aabSstevel (PCIC_CLEXT_IRQ_LVL_MODE |
18473db86aabSstevel PCIC_CLEXT_SMI_LVL_MODE));
18483db86aabSstevel
18493db86aabSstevel break;
18503db86aabSstevel case PCIC_INTR_MODE_ISA:
18513db86aabSstevel break;
18523db86aabSstevel }
18533db86aabSstevel if (pcic->bus_speed > PCIC_PCI_25MHZ && i == 0) {
18543db86aabSstevel cfg = 0;
18553db86aabSstevel cfg |= PCIC_CL_TIMER_CLK_DIV;
18563db86aabSstevel pcic_putb(pcic, i, PCIC_MISC_CTL_2, cfg);
18573db86aabSstevel }
18583db86aabSstevel break;
18593db86aabSstevel case PCIC_INTEL_i82092:
18603db86aabSstevel cfg = PCIC_82092_EN_TIMING;
18613db86aabSstevel if (pcic->bus_speed < PCIC_SYSCLK_33MHZ)
18623db86aabSstevel cfg |= PCIC_82092_PCICLK_25MHZ;
18633db86aabSstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr +
18643db86aabSstevel PCIC_82092_PCICON, cfg);
18653db86aabSstevel break;
18663db86aabSstevel case PCIC_TI_PCI1130:
18673db86aabSstevel case PCIC_TI_PCI1131:
18683db86aabSstevel case PCIC_TI_PCI1250:
18693db86aabSstevel case PCIC_TI_PCI1031:
18703db86aabSstevel cfg = ddi_get8(pcic->cfg_handle,
18713db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG);
18723db86aabSstevel cfg &= ~PCIC_DEVCTL_INTR_MASK;
18733db86aabSstevel switch (pcic->pc_intr_mode) {
18743db86aabSstevel case PCIC_INTR_MODE_ISA:
18753db86aabSstevel cfg |= PCIC_DEVCTL_INTR_ISA;
18763db86aabSstevel break;
18773db86aabSstevel }
18783db86aabSstevel #ifdef PCIC_DEBUG
18793db86aabSstevel if (pcic_debug) {
18803db86aabSstevel cmn_err(CE_CONT, "pcic_setup_adapter: "
18813db86aabSstevel "write reg 0x%x=%x \n",
18823db86aabSstevel PCIC_DEVCTL_REG, cfg);
18833db86aabSstevel }
18843db86aabSstevel #endif
18853db86aabSstevel ddi_put8(pcic->cfg_handle,
18863db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG,
18873db86aabSstevel cfg);
18883db86aabSstevel
18893db86aabSstevel cfg = ddi_get8(pcic->cfg_handle,
18903db86aabSstevel pcic->cfgaddr + PCIC_CRDCTL_REG);
18913db86aabSstevel cfg &= ~(PCIC_CRDCTL_PCIINTR|PCIC_CRDCTL_PCICSC|
18923db86aabSstevel PCIC_CRDCTL_PCIFUNC);
18933db86aabSstevel switch (pcic->pc_intr_mode) {
18943db86aabSstevel case PCIC_INTR_MODE_PCI_1:
18953db86aabSstevel cfg |= PCIC_CRDCTL_PCIINTR |
18963db86aabSstevel PCIC_CRDCTL_PCICSC |
18973db86aabSstevel PCIC_CRDCTL_PCIFUNC;
18983db86aabSstevel pcic->pc_flags |= PCF_USE_SMI;
18993db86aabSstevel break;
19003db86aabSstevel }
19013db86aabSstevel #ifdef PCIC_DEBUG
19023db86aabSstevel if (pcic_debug) {
19033db86aabSstevel cmn_err(CE_CONT, "pcic_setup_adapter: "
19043db86aabSstevel " write reg 0x%x=%x \n",
19053db86aabSstevel PCIC_CRDCTL_REG, cfg);
19063db86aabSstevel }
19073db86aabSstevel #endif
19083db86aabSstevel ddi_put8(pcic->cfg_handle,
19093db86aabSstevel pcic->cfgaddr + PCIC_CRDCTL_REG,
19103db86aabSstevel cfg);
19113db86aabSstevel break;
19123db86aabSstevel case PCIC_TI_PCI1221:
19133db86aabSstevel case PCIC_TI_PCI1225:
19143db86aabSstevel cfg = ddi_get8(pcic->cfg_handle,
19153db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG);
19163db86aabSstevel cfg |= (PCIC_DEVCTL_INTR_DFLT | PCIC_DEVCTL_3VCAPABLE);
19173db86aabSstevel #ifdef PCIC_DEBUG
19183db86aabSstevel if (pcic_debug) {
19193db86aabSstevel cmn_err(CE_CONT, "pcic_setup_adapter: "
19203db86aabSstevel " write reg 0x%x=%x \n",
19213db86aabSstevel PCIC_DEVCTL_REG, cfg);
19223db86aabSstevel }
19233db86aabSstevel #endif
19243db86aabSstevel ddi_put8(pcic->cfg_handle,
19253db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG, cfg);
19263db86aabSstevel
19273db86aabSstevel cfg = ddi_get8(pcic->cfg_handle,
19283db86aabSstevel pcic->cfgaddr + PCIC_DIAG_REG);
19293db86aabSstevel if (pcic->pc_type == PCIC_TI_PCI1225) {
19303db86aabSstevel cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC);
19313db86aabSstevel } else {
19323db86aabSstevel cfg |= PCIC_DIAG_ASYNC;
19333db86aabSstevel }
19343db86aabSstevel pcic->pc_flags |= PCF_USE_SMI;
19353db86aabSstevel #ifdef PCIC_DEBUG
19363db86aabSstevel if (pcic_debug) {
19373db86aabSstevel cmn_err(CE_CONT, "pcic_setup_adapter: "
19383db86aabSstevel " write reg 0x%x=%x \n",
19393db86aabSstevel PCIC_DIAG_REG, cfg);
19403db86aabSstevel }
19413db86aabSstevel #endif
19423db86aabSstevel ddi_put8(pcic->cfg_handle,
19433db86aabSstevel pcic->cfgaddr + PCIC_DIAG_REG, cfg);
19443db86aabSstevel break;
19453db86aabSstevel case PCIC_TI_PCI1520:
19460e995c33Srw148561 case PCIC_TI_PCI1510:
19473db86aabSstevel case PCIC_TI_VENDOR:
19483db86aabSstevel if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) {
1949e12b469aSrui wang - Sun Microsystems - Beijing China /* functional intr routed by ExCA register */
19503db86aabSstevel cfg = ddi_get8(pcic->cfg_handle,
19513db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
19523db86aabSstevel cfg |= PCIC_FUN_INT_MOD_ISA;
19533db86aabSstevel ddi_put8(pcic->cfg_handle,
19543db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
19553db86aabSstevel cfg);
1956e12b469aSrui wang - Sun Microsystems - Beijing China
1957e12b469aSrui wang - Sun Microsystems - Beijing China /* IRQ serialized interrupts */
19583db86aabSstevel cfg = ddi_get8(pcic->cfg_handle,
19593db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG);
19603db86aabSstevel cfg &= ~PCIC_DEVCTL_INTR_MASK;
19613db86aabSstevel cfg |= PCIC_DEVCTL_INTR_ISA;
19623db86aabSstevel ddi_put8(pcic->cfg_handle,
19633db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG,
19643db86aabSstevel cfg);
1965e12b469aSrui wang - Sun Microsystems - Beijing China break;
1966e12b469aSrui wang - Sun Microsystems - Beijing China }
1967e12b469aSrui wang - Sun Microsystems - Beijing China
1968e12b469aSrui wang - Sun Microsystems - Beijing China /* CSC interrupt routed to PCI */
1969e12b469aSrui wang - Sun Microsystems - Beijing China cfg = ddi_get8(pcic->cfg_handle,
1970e12b469aSrui wang - Sun Microsystems - Beijing China pcic->cfgaddr + PCIC_DIAG_REG);
1971e12b469aSrui wang - Sun Microsystems - Beijing China cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC);
1972e12b469aSrui wang - Sun Microsystems - Beijing China ddi_put8(pcic->cfg_handle,
1973e12b469aSrui wang - Sun Microsystems - Beijing China pcic->cfgaddr + PCIC_DIAG_REG, cfg);
1974e12b469aSrui wang - Sun Microsystems - Beijing China
1975e12b469aSrui wang - Sun Microsystems - Beijing China #if defined(__i386) || defined(__amd64)
1976e12b469aSrui wang - Sun Microsystems - Beijing China /*
1977e12b469aSrui wang - Sun Microsystems - Beijing China * Some TI chips have 2 cardbus slots(function0 and
1978e12b469aSrui wang - Sun Microsystems - Beijing China * function1), and others may have just 1 cardbus slot.
1979e12b469aSrui wang - Sun Microsystems - Beijing China * The interrupt routing register is shared between the
1980e12b469aSrui wang - Sun Microsystems - Beijing China * 2 functions and can only be accessed through
1981e12b469aSrui wang - Sun Microsystems - Beijing China * function0. Here we check the presence of the second
1982e12b469aSrui wang - Sun Microsystems - Beijing China * cardbus slot and do the right thing.
1983e12b469aSrui wang - Sun Microsystems - Beijing China */
1984e12b469aSrui wang - Sun Microsystems - Beijing China
1985e12b469aSrui wang - Sun Microsystems - Beijing China if (ddi_getlongprop(DDI_DEV_T_ANY, pcic->dip,
1986e12b469aSrui wang - Sun Microsystems - Beijing China DDI_PROP_DONTPASS, "reg", (caddr_t)®,
1987e12b469aSrui wang - Sun Microsystems - Beijing China &length) != DDI_PROP_SUCCESS) {
198819397407SSherry Moore cmn_err(CE_WARN,
198919397407SSherry Moore "pcic_setup_adapter(), failed to"
1990e12b469aSrui wang - Sun Microsystems - Beijing China " read reg property\n");
1991e12b469aSrui wang - Sun Microsystems - Beijing China break;
1992e12b469aSrui wang - Sun Microsystems - Beijing China }
1993e12b469aSrui wang - Sun Microsystems - Beijing China
1994e12b469aSrui wang - Sun Microsystems - Beijing China bus = PCI_REG_BUS_G(reg->pci_phys_hi);
1995e12b469aSrui wang - Sun Microsystems - Beijing China dev = PCI_REG_DEV_G(reg->pci_phys_hi);
1996e12b469aSrui wang - Sun Microsystems - Beijing China func = PCI_REG_FUNC_G(reg->pci_phys_hi);
1997e12b469aSrui wang - Sun Microsystems - Beijing China kmem_free((caddr_t)reg, length);
1998e12b469aSrui wang - Sun Microsystems - Beijing China
1999e12b469aSrui wang - Sun Microsystems - Beijing China if (func != 0) {
2000e12b469aSrui wang - Sun Microsystems - Beijing China break;
2001e12b469aSrui wang - Sun Microsystems - Beijing China }
2002e12b469aSrui wang - Sun Microsystems - Beijing China
2003e12b469aSrui wang - Sun Microsystems - Beijing China classcode = (*pci_getl_func)(bus, dev, 1,
2004e12b469aSrui wang - Sun Microsystems - Beijing China PCI_CONF_REVID);
2005e12b469aSrui wang - Sun Microsystems - Beijing China classcode >>= 8;
2006e12b469aSrui wang - Sun Microsystems - Beijing China if (classcode != 0x060700 &&
2007e12b469aSrui wang - Sun Microsystems - Beijing China classcode != 0x060500) {
2008e12b469aSrui wang - Sun Microsystems - Beijing China break;
2009e12b469aSrui wang - Sun Microsystems - Beijing China }
2010e12b469aSrui wang - Sun Microsystems - Beijing China
2011e12b469aSrui wang - Sun Microsystems - Beijing China /* Parallel PCI interrupts only */
2012e12b469aSrui wang - Sun Microsystems - Beijing China cfg = ddi_get8(pcic->cfg_handle,
2013e12b469aSrui wang - Sun Microsystems - Beijing China pcic->cfgaddr + PCIC_DEVCTL_REG);
2014e12b469aSrui wang - Sun Microsystems - Beijing China cfg &= ~PCIC_DEVCTL_INTR_MASK;
2015e12b469aSrui wang - Sun Microsystems - Beijing China ddi_put8(pcic->cfg_handle,
2016e12b469aSrui wang - Sun Microsystems - Beijing China pcic->cfgaddr + PCIC_DEVCTL_REG,
2017e12b469aSrui wang - Sun Microsystems - Beijing China cfg);
20183db86aabSstevel
20193db86aabSstevel /* tie INTA and INTB together */
20203db86aabSstevel cfg = ddi_get8(pcic->cfg_handle,
20213db86aabSstevel (pcic->cfgaddr + PCIC_SYSCTL_REG + 3));
20223db86aabSstevel cfg |= PCIC_SYSCTL_INTRTIE;
20233db86aabSstevel ddi_put8(pcic->cfg_handle, (pcic->cfgaddr +
20243db86aabSstevel PCIC_SYSCTL_REG + 3), cfg);
2025e12b469aSrui wang - Sun Microsystems - Beijing China #endif
2026e12b469aSrui wang - Sun Microsystems - Beijing China
20273db86aabSstevel break;
20283db86aabSstevel case PCIC_TI_PCI1410:
20293db86aabSstevel cfg = ddi_get8(pcic->cfg_handle,
20303db86aabSstevel pcic->cfgaddr + PCIC_DIAG_REG);
20313db86aabSstevel cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC);
20323db86aabSstevel ddi_put8(pcic->cfg_handle,
20333db86aabSstevel pcic->cfgaddr + PCIC_DIAG_REG, cfg);
20343db86aabSstevel break;
20353db86aabSstevel case PCIC_TOSHIBA_TOPIC100:
20363db86aabSstevel case PCIC_TOSHIBA_TOPIC95:
20373db86aabSstevel case PCIC_TOSHIBA_VENDOR:
20383db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, pcic->cfgaddr +
20393db86aabSstevel PCIC_TOSHIBA_SLOT_CTL_REG);
20403db86aabSstevel cfg |= (PCIC_TOSHIBA_SCR_SLOTON |
20413db86aabSstevel PCIC_TOSHIBA_SCR_SLOTEN);
20423db86aabSstevel cfg &= (~PCIC_TOSHIBA_SCR_PRT_MASK);
20433db86aabSstevel cfg |= PCIC_TOSHIBA_SCR_PRT_3E2;
20443db86aabSstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr +
20453db86aabSstevel PCIC_TOSHIBA_SLOT_CTL_REG, cfg);
20463db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, pcic->cfgaddr +
20473db86aabSstevel PCIC_TOSHIBA_INTR_CTL_REG);
20483db86aabSstevel switch (pcic->pc_intr_mode) {
20493db86aabSstevel case PCIC_INTR_MODE_ISA:
20503db86aabSstevel cfg &= ~PCIC_TOSHIBA_ICR_SRC;
20513db86aabSstevel ddi_put8(pcic->cfg_handle,
20523db86aabSstevel pcic->cfgaddr +
20533db86aabSstevel PCIC_TOSHIBA_INTR_CTL_REG, cfg);
20543db86aabSstevel
20553db86aabSstevel cfg = ddi_get8(pcic->cfg_handle,
20563db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
20573db86aabSstevel cfg |= PCIC_FUN_INT_MOD_ISA;
20583db86aabSstevel ddi_put8(pcic->cfg_handle,
20593db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
20603db86aabSstevel cfg);
20613db86aabSstevel break;
20623db86aabSstevel case PCIC_INTR_MODE_PCI_1:
20633db86aabSstevel cfg |= PCIC_TOSHIBA_ICR_SRC;
20643db86aabSstevel cfg &= (~PCIC_TOSHIBA_ICR_PIN_MASK);
20653db86aabSstevel cfg |= PCIC_TOSHIBA_ICR_PIN_INTA;
20663db86aabSstevel ddi_put8(pcic->cfg_handle,
20673db86aabSstevel pcic->cfgaddr +
20683db86aabSstevel PCIC_TOSHIBA_INTR_CTL_REG, cfg);
20693db86aabSstevel break;
20703db86aabSstevel }
20713db86aabSstevel break;
20723db86aabSstevel case PCIC_O2MICRO_VENDOR:
20733db86aabSstevel cfg32 = ddi_get32(pcic->cfg_handle,
20743db86aabSstevel (uint32_t *)(pcic->cfgaddr +
20753db86aabSstevel PCIC_O2MICRO_MISC_CTL));
20763db86aabSstevel switch (pcic->pc_intr_mode) {
20773db86aabSstevel case PCIC_INTR_MODE_ISA:
20783db86aabSstevel cfg32 |= (PCIC_O2MICRO_ISA_LEGACY |
20793db86aabSstevel PCIC_O2MICRO_INT_MOD_PCI);
20803db86aabSstevel ddi_put32(pcic->cfg_handle,
20813db86aabSstevel (uint32_t *)(pcic->cfgaddr +
20823db86aabSstevel PCIC_O2MICRO_MISC_CTL),
20833db86aabSstevel cfg32);
20843db86aabSstevel cfg = ddi_get8(pcic->cfg_handle,
20853db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
20863db86aabSstevel cfg |= PCIC_FUN_INT_MOD_ISA;
20873db86aabSstevel ddi_put8(pcic->cfg_handle,
20883db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
20893db86aabSstevel cfg);
20903db86aabSstevel break;
20913db86aabSstevel case PCIC_INTR_MODE_PCI_1:
20923db86aabSstevel cfg32 &= ~PCIC_O2MICRO_ISA_LEGACY;
20933db86aabSstevel cfg32 |= PCIC_O2MICRO_INT_MOD_PCI;
20943db86aabSstevel ddi_put32(pcic->cfg_handle,
20953db86aabSstevel (uint32_t *)(pcic->cfgaddr +
20963db86aabSstevel PCIC_O2MICRO_MISC_CTL),
20973db86aabSstevel cfg32);
20983db86aabSstevel break;
20993db86aabSstevel }
21003db86aabSstevel break;
21013db86aabSstevel case PCIC_RICOH_VENDOR:
21023db86aabSstevel if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) {
21033db86aabSstevel cfg16 = ddi_get16(pcic->cfg_handle,
21043db86aabSstevel (uint16_t *)(pcic->cfgaddr +
21053db86aabSstevel PCIC_RICOH_MISC_CTL_2));
21063db86aabSstevel cfg16 |= (PCIC_RICOH_CSC_INT_MOD |
21073db86aabSstevel PCIC_RICOH_FUN_INT_MOD);
21083db86aabSstevel ddi_put16(pcic->cfg_handle,
21093db86aabSstevel (uint16_t *)(pcic->cfgaddr +
21103db86aabSstevel PCIC_RICOH_MISC_CTL_2),
21113db86aabSstevel cfg16);
21123db86aabSstevel
21133db86aabSstevel cfg16 = ddi_get16(pcic->cfg_handle,
21143db86aabSstevel (uint16_t *)(pcic->cfgaddr +
21153db86aabSstevel PCIC_RICOH_MISC_CTL));
21163db86aabSstevel cfg16 |= PCIC_RICOH_SIRQ_EN;
21173db86aabSstevel ddi_put16(pcic->cfg_handle,
21183db86aabSstevel (uint16_t *)(pcic->cfgaddr +
21193db86aabSstevel PCIC_RICOH_MISC_CTL),
21203db86aabSstevel cfg16);
21213db86aabSstevel
21223db86aabSstevel cfg = ddi_get8(pcic->cfg_handle,
21233db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
21243db86aabSstevel cfg |= PCIC_FUN_INT_MOD_ISA;
21253db86aabSstevel ddi_put8(pcic->cfg_handle,
21263db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
21273db86aabSstevel cfg);
21283db86aabSstevel }
21293db86aabSstevel break;
21303db86aabSstevel default:
21313db86aabSstevel break;
21323db86aabSstevel } /* switch */
21333db86aabSstevel
2134bb3a048dSrw148561 /*
2135bb3a048dSrw148561 * The default value in the EEPROM (loaded on reset) for
2136bb3a048dSrw148561 * MFUNC0/MFUNC1 may be incorrect. Here we make sure that
2137bb3a048dSrw148561 * MFUNC0 is connected to INTA, and MFUNC1 is connected to
2138bb3a048dSrw148561 * INTB. This applies to all TI CardBus controllers.
2139bb3a048dSrw148561 */
2140bb3a048dSrw148561 if ((pcic->pc_type >> 16) == PCIC_TI_VENDORID &&
2141bb3a048dSrw148561 pcic->pc_intr_mode == PCIC_INTR_MODE_PCI_1) {
2142bb3a048dSrw148561 value = ddi_get32(pcic->cfg_handle,
2143bb3a048dSrw148561 (uint32_t *)(pcic->cfgaddr + PCIC_MFROUTE_REG));
2144bb3a048dSrw148561 value &= ~0xff;
2145bb3a048dSrw148561 ddi_put32(pcic->cfg_handle, (uint32_t *)(pcic->cfgaddr +
21468134ee03Srw148561 PCIC_MFROUTE_REG), value|PCIC_TI_MFUNC_SEL);
2147bb3a048dSrw148561 }
2148bb3a048dSrw148561
21493db86aabSstevel /* setup general card status change interrupt */
21503db86aabSstevel switch (pcic->pc_type) {
21513db86aabSstevel case PCIC_TI_PCI1225:
21523db86aabSstevel case PCIC_TI_PCI1221:
21533db86aabSstevel case PCIC_TI_PCI1031:
21543db86aabSstevel case PCIC_TI_PCI1520:
21553db86aabSstevel case PCIC_TI_PCI1410:
21563db86aabSstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT,
21573db86aabSstevel PCIC_CHANGE_DEFAULT);
21583db86aabSstevel break;
21593db86aabSstevel default:
21603db86aabSstevel if (pcic->pc_intr_mode ==
21613db86aabSstevel PCIC_INTR_MODE_PCI_1) {
21623db86aabSstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT,
21633db86aabSstevel PCIC_CHANGE_DEFAULT);
21643db86aabSstevel break;
21653db86aabSstevel } else {
21663db86aabSstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT,
21673db86aabSstevel PCIC_CHANGE_DEFAULT |
21683db86aabSstevel (pcic->pc_sockets[i].pcs_smi << 4));
21693db86aabSstevel break;
21703db86aabSstevel }
21713db86aabSstevel }
21723db86aabSstevel
21733db86aabSstevel pcic->pc_flags |= PCF_INTRENAB;
21743db86aabSstevel
21753db86aabSstevel /* take card out of RESET */
21763db86aabSstevel pcic_putb(pcic, i, PCIC_INTERRUPT, PCIC_RESET);
21773db86aabSstevel /* turn power off and let CS do this */
21783db86aabSstevel pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0);
21793db86aabSstevel
21803db86aabSstevel /* final chip specific initialization */
21813db86aabSstevel switch (pcic->pc_type) {
21823db86aabSstevel case PCIC_VADEM:
21833db86aabSstevel pcic_putb(pcic, i, PCIC_VG_CONTROL,
21843db86aabSstevel PCIC_VC_DELAYENABLE);
21853db86aabSstevel pcic->pc_flags |= PCF_DEBOUNCE;
21863db86aabSstevel /* FALLTHROUGH */
21873db86aabSstevel case PCIC_I82365SL:
21883db86aabSstevel pcic_putb(pcic, i, PCIC_GLOBAL_CONTROL,
21893db86aabSstevel PCIC_GC_CSC_WRITE);
21903db86aabSstevel /* clear any pending interrupts */
21913db86aabSstevel value = pcic_getb(pcic, i, PCIC_CARD_STATUS_CHANGE);
21923db86aabSstevel pcic_putb(pcic, i, PCIC_CARD_STATUS_CHANGE, value);
21933db86aabSstevel break;
21943db86aabSstevel /* The 82092 uses PCI config space to enable interrupts */
21953db86aabSstevel case PCIC_INTEL_i82092:
21963db86aabSstevel pcic_82092_smiirq_ctl(pcic, i, PCIC_82092_CTL_SMI,
21973db86aabSstevel PCIC_82092_INT_ENABLE);
21983db86aabSstevel break;
21993db86aabSstevel case PCIC_CL_PD6729:
22003db86aabSstevel if (pcic->bus_speed >= PCIC_PCI_DEF_SYSCLK && i == 0) {
22013db86aabSstevel value = pcic_getb(pcic, i, PCIC_MISC_CTL_2);
22023db86aabSstevel pcic_putb(pcic, i, PCIC_MISC_CTL_2,
22033db86aabSstevel value | PCIC_CL_TIMER_CLK_DIV);
22043db86aabSstevel }
22053db86aabSstevel break;
22063db86aabSstevel } /* switch */
22073db86aabSstevel
22083db86aabSstevel #if defined(PCIC_DEBUG)
22093db86aabSstevel if (pcic_debug)
22103db86aabSstevel cmn_err(CE_CONT,
22113db86aabSstevel "socket %d value=%x, flags = %x (%s)\n",
22123db86aabSstevel i, value, pcic->pc_sockets[i].pcs_flags,
22133db86aabSstevel (pcic->pc_sockets[i].pcs_flags &
22143db86aabSstevel PCS_CARD_PRESENT) ?
22153db86aabSstevel "card present" : "no card");
22163db86aabSstevel #endif
22173db86aabSstevel }
22183db86aabSstevel }
22193db86aabSstevel
22203db86aabSstevel /*
22213db86aabSstevel * pcic_intr(caddr_t, caddr_t)
22223db86aabSstevel * interrupt handler for the PCIC style adapter
22233db86aabSstevel * handles all basic interrupts and also checks
22243db86aabSstevel * for status changes and notifies the nexus if
22253db86aabSstevel * necessary
22263db86aabSstevel *
22273db86aabSstevel * On PCI bus adapters, also handles all card
22283db86aabSstevel * IO interrupts.
22293db86aabSstevel */
22303db86aabSstevel /*ARGSUSED*/
22313db86aabSstevel uint32_t
pcic_intr(caddr_t arg1,caddr_t arg2)22323db86aabSstevel pcic_intr(caddr_t arg1, caddr_t arg2)
22333db86aabSstevel {
22343db86aabSstevel pcicdev_t *pcic = (pcicdev_t *)arg1;
22353db86aabSstevel int value = 0, i, ret = DDI_INTR_UNCLAIMED;
22363db86aabSstevel uint8_t status;
22373db86aabSstevel uint_t io_ints;
22383db86aabSstevel
22393db86aabSstevel #if defined(PCIC_DEBUG)
22403db86aabSstevel pcic_err(pcic->dip, 0xf,
22413db86aabSstevel "pcic_intr: enter pc_flags=0x%x PCF_ATTACHED=0x%x"
22423db86aabSstevel " pc_numsockets=%d \n",
22433db86aabSstevel pcic->pc_flags, PCF_ATTACHED, pcic->pc_numsockets);
22443db86aabSstevel #endif
22453db86aabSstevel
22463db86aabSstevel if (!(pcic->pc_flags & PCF_ATTACHED))
22473db86aabSstevel return (DDI_INTR_UNCLAIMED);
22483db86aabSstevel
22493db86aabSstevel mutex_enter(&pcic->intr_lock);
22503db86aabSstevel
22513db86aabSstevel if (pcic->pc_flags & PCF_SUSPENDED) {
22523db86aabSstevel mutex_exit(&pcic->intr_lock);
22533db86aabSstevel return (ret);
22543db86aabSstevel }
22553db86aabSstevel
22563db86aabSstevel /*
22573db86aabSstevel * need to change to only ACK and touch the slot that
22583db86aabSstevel * actually caused the interrupt. Currently everything
22593db86aabSstevel * is acked
22603db86aabSstevel *
22613db86aabSstevel * we need to look at all known sockets to determine
22623db86aabSstevel * what might have happened, so step through the list
22633db86aabSstevel * of them
22643db86aabSstevel */
22653db86aabSstevel
22663db86aabSstevel /*
22673db86aabSstevel * Set the bitmask for IO interrupts to initially include all sockets
22683db86aabSstevel */
22693db86aabSstevel io_ints = (1 << pcic->pc_numsockets) - 1;
22703db86aabSstevel
22713db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) {
22723db86aabSstevel int card_type;
22733db86aabSstevel pcic_socket_t *sockp;
22743db86aabSstevel int value_cb = 0;
22753db86aabSstevel
22763db86aabSstevel sockp = &pcic->pc_sockets[i];
22773db86aabSstevel /* get the socket's I/O addresses */
22783db86aabSstevel
22793db86aabSstevel if (sockp->pcs_flags & PCS_WAITING) {
22803db86aabSstevel io_ints &= ~(1 << i);
22813db86aabSstevel continue;
22823db86aabSstevel }
22833db86aabSstevel
22843db86aabSstevel if (sockp->pcs_flags & PCS_CARD_IO)
22853db86aabSstevel card_type = IF_IO;
22863db86aabSstevel else
22873db86aabSstevel card_type = IF_MEMORY;
22883db86aabSstevel
22893db86aabSstevel if (pcic->pc_io_type == PCIC_IO_TYPE_YENTA)
22903db86aabSstevel value_cb = pcic_getcb(pcic, CB_STATUS_EVENT);
22913db86aabSstevel
22923db86aabSstevel value = pcic_change(pcic, i);
22933db86aabSstevel
22943db86aabSstevel if ((value != 0) || (value_cb != 0)) {
22953db86aabSstevel int x = pcic->pc_cb_arg;
22963db86aabSstevel
22973db86aabSstevel ret = DDI_INTR_CLAIMED;
22983db86aabSstevel
22993db86aabSstevel #if defined(PCIC_DEBUG)
23003db86aabSstevel pcic_err(pcic->dip, 0x9,
23013db86aabSstevel "card_type = %d, value_cb = 0x%x\n",
23023db86aabSstevel card_type,
23033db86aabSstevel value_cb ? value_cb :
23043db86aabSstevel pcic_getcb(pcic, CB_STATUS_EVENT));
23053db86aabSstevel if (pcic_debug)
23063db86aabSstevel cmn_err(CE_CONT,
23073db86aabSstevel "\tchange on socket %d (%x)\n", i,
23083db86aabSstevel value);
23093db86aabSstevel #endif
23103db86aabSstevel /* find out what happened */
23113db86aabSstevel status = pcic_getb(pcic, i, PCIC_INTERFACE_STATUS);
23123db86aabSstevel
23133db86aabSstevel /* acknowledge the interrupt */
23143db86aabSstevel if (value_cb)
23153db86aabSstevel pcic_putcb(pcic, CB_STATUS_EVENT, value_cb);
23163db86aabSstevel
23173db86aabSstevel if (value)
23183db86aabSstevel pcic_putb(pcic, i, PCIC_CARD_STATUS_CHANGE,
23193db86aabSstevel value);
23203db86aabSstevel
23213db86aabSstevel if (pcic->pc_callback == NULL) {
23223db86aabSstevel /* if not callback handler, nothing to do */
23233db86aabSstevel continue;
23243db86aabSstevel }
23253db86aabSstevel
23263db86aabSstevel /* Card Detect */
23273db86aabSstevel if (value & PCIC_CD_DETECT ||
23283db86aabSstevel value_cb & CB_PS_CCDMASK) {
23293db86aabSstevel uint8_t irq;
23303db86aabSstevel #if defined(PCIC_DEBUG)
23313db86aabSstevel if (pcic_debug)
23323db86aabSstevel cmn_err(CE_CONT,
23333db86aabSstevel "\tcd_detect: status=%x,"
23343db86aabSstevel " flags=%x\n",
23353db86aabSstevel status, sockp->pcs_flags);
23363db86aabSstevel #else
23373db86aabSstevel #ifdef lint
23383db86aabSstevel if (status == 0)
23393db86aabSstevel status++;
23403db86aabSstevel #endif
23413db86aabSstevel #endif
23423db86aabSstevel /*
23433db86aabSstevel * Turn off all interrupts for this socket here.
23443db86aabSstevel */
23453db86aabSstevel irq = pcic_getb(pcic, sockp->pcs_socket,
23463db86aabSstevel PCIC_MANAGEMENT_INT);
23473db86aabSstevel irq &= ~PCIC_CHANGE_MASK;
23483db86aabSstevel pcic_putb(pcic, sockp->pcs_socket,
23493db86aabSstevel PCIC_MANAGEMENT_INT, irq);
23503db86aabSstevel
23513db86aabSstevel pcic_putcb(pcic, CB_STATUS_MASK, 0x0);
23523db86aabSstevel
23530d282d13Srw148561 /*
23540d282d13Srw148561 * Put the socket in debouncing state so that
23550d282d13Srw148561 * the leaf driver won't receive interrupts.
23560d282d13Srw148561 * Crucial for handling surprise-removal.
23570d282d13Srw148561 */
23580d282d13Srw148561 sockp->pcs_flags |= PCS_DEBOUNCING;
23590d282d13Srw148561
23603db86aabSstevel if (!sockp->pcs_cd_softint_flg) {
23613db86aabSstevel sockp->pcs_cd_softint_flg = 1;
23623db86aabSstevel (void) ddi_intr_trigger_softint(
23633db86aabSstevel sockp->pcs_cd_softint_hdl, NULL);
23643db86aabSstevel }
23653db86aabSstevel
23663db86aabSstevel io_ints &= ~(1 << i);
23673db86aabSstevel } /* PCIC_CD_DETECT */
23683db86aabSstevel
23693db86aabSstevel /* Ready/Change Detect */
23703db86aabSstevel sockp->pcs_state ^= SBM_RDYBSY;
23713db86aabSstevel if (card_type == IF_MEMORY && value & PCIC_RD_DETECT) {
23723db86aabSstevel sockp->pcs_flags |= PCS_READY;
23733db86aabSstevel PC_CALLBACK(pcic->dip, x, PCE_CARD_READY, i);
23743db86aabSstevel }
23753db86aabSstevel
23763db86aabSstevel /* Battery Warn Detect */
23773db86aabSstevel if (card_type == IF_MEMORY &&
23783db86aabSstevel value & PCIC_BW_DETECT &&
23793db86aabSstevel !(sockp->pcs_state & SBM_BVD2)) {
23803db86aabSstevel sockp->pcs_state |= SBM_BVD2;
23813db86aabSstevel PC_CALLBACK(pcic->dip, x,
23823db86aabSstevel PCE_CARD_BATTERY_WARN, i);
23833db86aabSstevel }
23843db86aabSstevel
23853db86aabSstevel /* Battery Dead Detect */
23863db86aabSstevel if (value & PCIC_BD_DETECT) {
23873db86aabSstevel /*
23883db86aabSstevel * need to work out event if RI not enabled
23893db86aabSstevel * and card_type == IF_IO
23903db86aabSstevel */
23913db86aabSstevel if (card_type == IF_MEMORY &&
23923db86aabSstevel !(sockp->pcs_state & SBM_BVD1)) {
23933db86aabSstevel sockp->pcs_state |= SBM_BVD1;
23943db86aabSstevel PC_CALLBACK(pcic->dip, x,
23953db86aabSstevel PCE_CARD_BATTERY_DEAD,
23963db86aabSstevel i);
23973db86aabSstevel } else {
23983db86aabSstevel /*
23993db86aabSstevel * information in pin replacement
24003db86aabSstevel * register if one is available
24013db86aabSstevel */
24023db86aabSstevel PC_CALLBACK(pcic->dip, x,
24033db86aabSstevel PCE_CARD_STATUS_CHANGE,
24043db86aabSstevel i);
24053db86aabSstevel } /* IF_MEMORY */
24063db86aabSstevel } /* PCIC_BD_DETECT */
24073db86aabSstevel } /* if pcic_change */
24083db86aabSstevel /*
24093db86aabSstevel * for any controllers that we can detect whether a socket
24103db86aabSstevel * had an interrupt for the PC Card, we should sort that out
24113db86aabSstevel * here.
24123db86aabSstevel */
24133db86aabSstevel } /* for pc_numsockets */
24143db86aabSstevel
24153db86aabSstevel /*
24163db86aabSstevel * If we're on a PCI bus, we may need to cycle through each IO
24173db86aabSstevel * interrupt handler that is registered since they all
24183db86aabSstevel * share the same interrupt line.
24193db86aabSstevel */
24203db86aabSstevel
24213db86aabSstevel
24223db86aabSstevel #if defined(PCIC_DEBUG)
24233db86aabSstevel pcic_err(pcic->dip, 0xf,
24243db86aabSstevel "pcic_intr: pc_intr_mode=%d pc_type=%x io_ints=0x%x\n",
24253db86aabSstevel pcic->pc_intr_mode, pcic->pc_type, io_ints);
24263db86aabSstevel #endif
24273db86aabSstevel
24280d282d13Srw148561 if (io_ints) {
24290d282d13Srw148561 if (pcic_do_io_intr(pcic, io_ints) == DDI_INTR_CLAIMED)
24303db86aabSstevel ret = DDI_INTR_CLAIMED;
24313db86aabSstevel }
24323db86aabSstevel
24333db86aabSstevel mutex_exit(&pcic->intr_lock);
24343db86aabSstevel
24353db86aabSstevel #if defined(PCIC_DEBUG)
24363db86aabSstevel pcic_err(pcic->dip, 0xf,
24373db86aabSstevel "pcic_intr: ret=%d value=%d DDI_INTR_CLAIMED=%d\n",
24383db86aabSstevel ret, value, DDI_INTR_CLAIMED);
24393db86aabSstevel #endif
24403db86aabSstevel
24413db86aabSstevel return (ret);
24423db86aabSstevel }
24433db86aabSstevel
24443db86aabSstevel /*
24453db86aabSstevel * pcic_change()
24463db86aabSstevel * check to see if this socket had a change in state
24473db86aabSstevel * by checking the status change register
24483db86aabSstevel */
24493db86aabSstevel static int
pcic_change(pcicdev_t * pcic,int socket)24503db86aabSstevel pcic_change(pcicdev_t *pcic, int socket)
24513db86aabSstevel {
24523db86aabSstevel return (pcic_getb(pcic, socket, PCIC_CARD_STATUS_CHANGE));
24533db86aabSstevel }
24543db86aabSstevel
24553db86aabSstevel /*
24563db86aabSstevel * pcic_do_io_intr - calls client interrupt handlers
24573db86aabSstevel */
24583db86aabSstevel static int
pcic_do_io_intr(pcicdev_t * pcic,uint32_t sockets)24593db86aabSstevel pcic_do_io_intr(pcicdev_t *pcic, uint32_t sockets)
24603db86aabSstevel {
24613db86aabSstevel inthandler_t *tmp;
24623db86aabSstevel int ret = DDI_INTR_UNCLAIMED;
24633db86aabSstevel
24643db86aabSstevel #if defined(PCIC_DEBUG)
24653db86aabSstevel pcic_err(pcic->dip, 0xf,
24663db86aabSstevel "pcic_do_io_intr: pcic=%p sockets=%d irq_top=%p\n",
24673db86aabSstevel (void *)pcic, (int)sockets, (void *)pcic->irq_top);
24683db86aabSstevel #endif
24693db86aabSstevel
24703db86aabSstevel if (pcic->irq_top != NULL) {
24713db86aabSstevel tmp = pcic->irq_current;
24723db86aabSstevel
24733db86aabSstevel do {
24743db86aabSstevel int cur = pcic->irq_current->socket;
24753db86aabSstevel pcic_socket_t *sockp =
24763db86aabSstevel &pcic->pc_sockets[cur];
24773db86aabSstevel
24783db86aabSstevel #if defined(PCIC_DEBUG)
24793db86aabSstevel pcic_err(pcic->dip, 0xf,
24803db86aabSstevel "\t pcs_flags=0x%x PCS_CARD_PRESENT=0x%x\n",
24813db86aabSstevel sockp->pcs_flags, PCS_CARD_PRESENT);
24823db86aabSstevel pcic_err(pcic->dip, 0xf,
24833db86aabSstevel "\t sockets=%d cur=%d intr=%p arg1=%p "
24843db86aabSstevel "arg2=%p\n",
24853db86aabSstevel sockets, cur, (void *)pcic->irq_current->intr,
24863db86aabSstevel pcic->irq_current->arg1,
24873db86aabSstevel pcic->irq_current->arg2);
24883db86aabSstevel #endif
24890d282d13Srw148561 if ((sockp->pcs_flags & PCS_CARD_PRESENT) &&
24900d282d13Srw148561 !(sockp->pcs_flags & PCS_DEBOUNCING) &&
24910d282d13Srw148561 (sockets & (1 << cur))) {
24923db86aabSstevel
24933db86aabSstevel if ((*pcic->irq_current->intr)(pcic->irq_current->arg1,
24943db86aabSstevel pcic->irq_current->arg2) == DDI_INTR_CLAIMED)
24953db86aabSstevel ret = DDI_INTR_CLAIMED;
24963db86aabSstevel
24973db86aabSstevel #if defined(PCIC_DEBUG)
24983db86aabSstevel pcic_err(pcic->dip, 0xf,
24993db86aabSstevel "\t ret=%d DDI_INTR_CLAIMED=%d\n",
25003db86aabSstevel ret, DDI_INTR_CLAIMED);
25013db86aabSstevel #endif
25023db86aabSstevel }
25033db86aabSstevel
25043db86aabSstevel
25053db86aabSstevel if ((pcic->irq_current = pcic->irq_current->next) == NULL)
25063db86aabSstevel pcic->irq_current = pcic->irq_top;
25073db86aabSstevel
25083db86aabSstevel } while (pcic->irq_current != tmp);
25093db86aabSstevel
25103db86aabSstevel if ((pcic->irq_current = pcic->irq_current->next) == NULL)
25113db86aabSstevel pcic->irq_current = pcic->irq_top;
25123db86aabSstevel
25133db86aabSstevel } else {
25143db86aabSstevel ret = DDI_INTR_UNCLAIMED;
25153db86aabSstevel }
25163db86aabSstevel
25173db86aabSstevel #if defined(PCIC_DEBUG)
25183db86aabSstevel pcic_err(pcic->dip, 0xf,
25193db86aabSstevel "pcic_do_io_intr: exit ret=%d DDI_INTR_CLAIMED=%d\n",
25203db86aabSstevel ret, DDI_INTR_CLAIMED);
25213db86aabSstevel #endif
25223db86aabSstevel
25233db86aabSstevel return (ret);
25243db86aabSstevel
25253db86aabSstevel }
25263db86aabSstevel
25273db86aabSstevel /*
25283db86aabSstevel * pcic_inquire_adapter()
25293db86aabSstevel * SocketServices InquireAdapter function
25303db86aabSstevel * get characteristics of the physical adapter
25313db86aabSstevel */
25323db86aabSstevel /*ARGSUSED*/
25333db86aabSstevel static int
pcic_inquire_adapter(dev_info_t * dip,inquire_adapter_t * config)25343db86aabSstevel pcic_inquire_adapter(dev_info_t *dip, inquire_adapter_t *config)
25353db86aabSstevel {
25363db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
25373db86aabSstevel pcicdev_t *pcic = anp->an_private;
25383db86aabSstevel
25393db86aabSstevel config->NumSockets = pcic->pc_numsockets;
25403db86aabSstevel config->NumWindows = pcic->pc_numsockets * PCIC_NUMWINSOCK;
25413db86aabSstevel config->NumEDCs = 0;
25423db86aabSstevel config->AdpCaps = 0;
25433db86aabSstevel config->ActiveHigh = 0;
25443db86aabSstevel config->ActiveLow = PCIC_AVAIL_IRQS;
25453db86aabSstevel config->NumPower = pcic->pc_numpower;
25463db86aabSstevel config->power_entry = pcic->pc_power; /* until we resolve this */
25473db86aabSstevel #if defined(PCIC_DEBUG)
25483db86aabSstevel if (pcic_debug) {
25493db86aabSstevel cmn_err(CE_CONT, "pcic_inquire_adapter:\n");
25503db86aabSstevel cmn_err(CE_CONT, "\tNumSockets=%d\n", config->NumSockets);
25513db86aabSstevel cmn_err(CE_CONT, "\tNumWindows=%d\n", config->NumWindows);
25523db86aabSstevel }
25533db86aabSstevel #endif
25543db86aabSstevel config->ResourceFlags = 0;
25553db86aabSstevel switch (pcic->pc_intr_mode) {
25563db86aabSstevel case PCIC_INTR_MODE_PCI_1:
25573db86aabSstevel config->ResourceFlags |= RES_OWN_IRQ | RES_IRQ_NEXUS |
25583db86aabSstevel RES_IRQ_SHAREABLE;
25593db86aabSstevel break;
25603db86aabSstevel }
25613db86aabSstevel return (SUCCESS);
25623db86aabSstevel }
25633db86aabSstevel
25643db86aabSstevel /*
25653db86aabSstevel * pcic_callback()
25663db86aabSstevel * The PCMCIA nexus calls us via this function
25673db86aabSstevel * in order to set the callback function we are
25683db86aabSstevel * to call the nexus with
25693db86aabSstevel */
25703db86aabSstevel /*ARGSUSED*/
25713db86aabSstevel static int
pcic_callback(dev_info_t * dip,int (* handler)(),int arg)25723db86aabSstevel pcic_callback(dev_info_t *dip, int (*handler)(), int arg)
25733db86aabSstevel {
25743db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
25753db86aabSstevel pcicdev_t *pcic = anp->an_private;
25763db86aabSstevel
25773db86aabSstevel if (handler != NULL) {
25783db86aabSstevel pcic->pc_callback = handler;
25793db86aabSstevel pcic->pc_cb_arg = arg;
25803db86aabSstevel pcic->pc_flags |= PCF_CALLBACK;
25813db86aabSstevel } else {
25823db86aabSstevel pcic->pc_callback = NULL;
25833db86aabSstevel pcic->pc_cb_arg = 0;
25843db86aabSstevel pcic->pc_flags &= ~PCF_CALLBACK;
25853db86aabSstevel }
25863db86aabSstevel /*
25873db86aabSstevel * we're now registered with the nexus
25883db86aabSstevel * it is acceptable to do callbacks at this point.
25893db86aabSstevel * don't call back from here though since it could block
25903db86aabSstevel */
25913db86aabSstevel return (PC_SUCCESS);
25923db86aabSstevel }
25933db86aabSstevel
25943db86aabSstevel /*
25953db86aabSstevel * pcic_calc_speed (pcicdev_t *pcic, uint32_t speed)
25963db86aabSstevel * calculate the speed bits from the specified memory speed
25973db86aabSstevel * there may be more to do here
25983db86aabSstevel */
25993db86aabSstevel
26003db86aabSstevel static int
pcic_calc_speed(pcicdev_t * pcic,uint32_t speed)26013db86aabSstevel pcic_calc_speed(pcicdev_t *pcic, uint32_t speed)
26023db86aabSstevel {
26033db86aabSstevel uint32_t wspeed = 1; /* assume 1 wait state when unknown */
26043db86aabSstevel uint32_t bspeed = PCIC_ISA_DEF_SYSCLK;
26053db86aabSstevel
26063db86aabSstevel switch (pcic->pc_type) {
26073db86aabSstevel case PCIC_I82365SL:
26083db86aabSstevel case PCIC_VADEM:
26093db86aabSstevel case PCIC_VADEM_VG469:
26103db86aabSstevel default:
26113db86aabSstevel /* Intel chip wants it in waitstates */
26123db86aabSstevel wspeed = mhztons(PCIC_ISA_DEF_SYSCLK) * 3;
26133db86aabSstevel if (speed <= wspeed)
26143db86aabSstevel wspeed = 0;
26153db86aabSstevel else if (speed <= (wspeed += mhztons(bspeed)))
26163db86aabSstevel wspeed = 1;
26173db86aabSstevel else if (speed <= (wspeed += mhztons(bspeed)))
26183db86aabSstevel wspeed = 2;
26193db86aabSstevel else
26203db86aabSstevel wspeed = 3;
26213db86aabSstevel wspeed <<= 6; /* put in right bit positions */
26223db86aabSstevel break;
26233db86aabSstevel
26243db86aabSstevel case PCIC_INTEL_i82092:
26253db86aabSstevel wspeed = SYSMEM_82092_80NS;
26263db86aabSstevel if (speed > 80)
26273db86aabSstevel wspeed = SYSMEM_82092_100NS;
26283db86aabSstevel if (speed > 100)
26293db86aabSstevel wspeed = SYSMEM_82092_150NS;
26303db86aabSstevel if (speed > 150)
26313db86aabSstevel wspeed = SYSMEM_82092_200NS;
26323db86aabSstevel if (speed > 200)
26333db86aabSstevel wspeed = SYSMEM_82092_250NS;
26343db86aabSstevel if (speed > 250)
26353db86aabSstevel wspeed = SYSMEM_82092_600NS;
26363db86aabSstevel wspeed <<= 5; /* put in right bit positions */
26373db86aabSstevel break;
26383db86aabSstevel
26393db86aabSstevel } /* switch */
26403db86aabSstevel
26413db86aabSstevel return (wspeed);
26423db86aabSstevel }
26433db86aabSstevel
26443db86aabSstevel /*
26453db86aabSstevel * These values are taken from the PC Card Standard Electrical Specification.
26463db86aabSstevel * Generally the larger value is taken if 2 are possible.
26473db86aabSstevel */
26483db86aabSstevel static struct pcic_card_times {
26493db86aabSstevel uint16_t cycle; /* Speed as found in the atribute space of he card. */
26503db86aabSstevel uint16_t setup; /* Corresponding address setup time. */
26513db86aabSstevel uint16_t width; /* Corresponding width, OE or WE. */
26523db86aabSstevel uint16_t hold; /* Corresponding data or address hold time. */
26533db86aabSstevel } pcic_card_times[] = {
26543db86aabSstevel
26553db86aabSstevel /*
26563db86aabSstevel * Note: The rounded up times for 250, 200 & 150 have been increased
26573db86aabSstevel * due to problems with the 3-Com ethernet cards (pcelx) on UBIIi.
26583db86aabSstevel * See BugID 00663.
26593db86aabSstevel */
26603db86aabSstevel
26613db86aabSstevel /*
26623db86aabSstevel * Rounded up times Original times from
26633db86aabSstevel * that add up to the the PCMCIA Spec.
26643db86aabSstevel * cycle time.
26653db86aabSstevel */
26663db86aabSstevel {600, 180, 370, 140}, /* 100, 300, 70 */
26673db86aabSstevel {400, 120, 300, 90}, /* Made this one up */
26683db86aabSstevel {250, 100, 190, 70}, /* 30, 150, 30 */
26693db86aabSstevel {200, 80, 170, 70}, /* 20, 120, 30 */
26703db86aabSstevel {150, 50, 110, 40}, /* 20, 80, 20 */
26713db86aabSstevel {100, 40, 80, 40}, /* 10, 60, 15 */
26723db86aabSstevel {0, 10, 60, 15} /* 10, 60, 15 */
26733db86aabSstevel };
26743db86aabSstevel
26753db86aabSstevel /*
26763db86aabSstevel * pcic_set_cdtimers
26773db86aabSstevel * This is specific to several Cirrus Logic chips
26783db86aabSstevel */
26793db86aabSstevel static void
pcic_set_cdtimers(pcicdev_t * pcic,int socket,uint32_t speed,int tset)26803db86aabSstevel pcic_set_cdtimers(pcicdev_t *pcic, int socket, uint32_t speed, int tset)
26813db86aabSstevel {
26823db86aabSstevel int cmd, set, rec, offset, clk_pulse;
26833db86aabSstevel struct pcic_card_times *ctp;
26843db86aabSstevel
26853db86aabSstevel if ((tset == IOMEM_CLTIMER_SET_1) || (tset == SYSMEM_CLTIMER_SET_1))
26863db86aabSstevel offset = 3;
26873db86aabSstevel else
26883db86aabSstevel offset = 0;
26893db86aabSstevel
26903db86aabSstevel clk_pulse = mhztons(pcic->bus_speed);
269119397407SSherry Moore for (ctp = pcic_card_times; speed < ctp->cycle; ctp++)
269219397407SSherry Moore ;
26933db86aabSstevel
26943db86aabSstevel /*
26953db86aabSstevel * Add (clk_pulse/2) and an extra 1 to account for rounding errors.
26963db86aabSstevel */
26973db86aabSstevel set = ((ctp->setup + 10 + 1 + (clk_pulse/2))/clk_pulse) - 1;
26983db86aabSstevel if (set < 0)
26993db86aabSstevel set = 0;
27003db86aabSstevel
27013db86aabSstevel cmd = ((ctp->width + 10 + 1 + (clk_pulse/2))/clk_pulse) - 1;
27023db86aabSstevel if (cmd < 0)
27033db86aabSstevel cmd = 0;
27043db86aabSstevel
27053db86aabSstevel rec = ((ctp->hold + 10 + 1 + (clk_pulse/2))/clk_pulse) - 2;
27063db86aabSstevel if (rec < 0)
27073db86aabSstevel rec = 0;
27083db86aabSstevel
27093db86aabSstevel #if defined(PCIC_DEBUG)
27103db86aabSstevel pcic_err(pcic->dip, 8, "pcic_set_cdtimers(%d, Timer Set %d)\n"
27113db86aabSstevel "ct=%d, cp=%d, cmd=0x%x, setup=0x%x, rec=0x%x\n",
27123db86aabSstevel (unsigned)speed, offset == 3 ? 1 : 0,
27133db86aabSstevel ctp->cycle, clk_pulse, cmd, set, rec);
27143db86aabSstevel #endif
27153db86aabSstevel
27163db86aabSstevel pcic_putb(pcic, socket, PCIC_TIME_COMMAND_0 + offset, cmd);
27173db86aabSstevel pcic_putb(pcic, socket, PCIC_TIME_SETUP_0 + offset, set);
27183db86aabSstevel pcic_putb(pcic, socket, PCIC_TIME_RECOVER_0 + offset, rec);
27193db86aabSstevel }
27203db86aabSstevel
27213db86aabSstevel /*
27223db86aabSstevel * pcic_set_window
27233db86aabSstevel * essentially the same as the Socket Services specification
27243db86aabSstevel * We use socket and not adapter since they are identifiable
27253db86aabSstevel * but the rest is the same
27263db86aabSstevel *
27273db86aabSstevel * dip pcic driver's device information
27283db86aabSstevel * window parameters for the request
27293db86aabSstevel */
27303db86aabSstevel static int
pcic_set_window(dev_info_t * dip,set_window_t * window)27313db86aabSstevel pcic_set_window(dev_info_t *dip, set_window_t *window)
27323db86aabSstevel {
27333db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
27343db86aabSstevel pcicdev_t *pcic = anp->an_private;
27353db86aabSstevel int select;
27363db86aabSstevel int socket, pages, which, ret;
27373db86aabSstevel pcic_socket_t *sockp = &pcic->pc_sockets[window->socket];
27383db86aabSstevel ra_return_t res;
27393db86aabSstevel ndi_ra_request_t req;
27403db86aabSstevel uint32_t base = window->base;
27413db86aabSstevel
27423db86aabSstevel #if defined(PCIC_DEBUG)
27433db86aabSstevel if (pcic_debug) {
27443db86aabSstevel cmn_err(CE_CONT, "pcic_set_window: entered\n");
27453db86aabSstevel cmn_err(CE_CONT,
27463db86aabSstevel "\twindow=%d, socket=%d, WindowSize=%d, speed=%d\n",
27473db86aabSstevel window->window, window->socket, window->WindowSize,
27483db86aabSstevel window->speed);
27493db86aabSstevel cmn_err(CE_CONT,
27503db86aabSstevel "\tbase=%x, state=%x\n", (unsigned)window->base,
27513db86aabSstevel (unsigned)window->state);
27523db86aabSstevel }
27533db86aabSstevel #endif
27543db86aabSstevel
27553db86aabSstevel /*
27563db86aabSstevel * do some basic sanity checking on what we support
27573db86aabSstevel * we don't do paged mode
27583db86aabSstevel */
27593db86aabSstevel if (window->state & WS_PAGED) {
27603db86aabSstevel cmn_err(CE_WARN, "pcic_set_window: BAD_ATTRIBUTE\n");
27613db86aabSstevel return (BAD_ATTRIBUTE);
27623db86aabSstevel }
27633db86aabSstevel
27643db86aabSstevel /*
27653db86aabSstevel * we don't care about previous mappings.
27663db86aabSstevel * Card Services will deal with that so don't
27673db86aabSstevel * even check
27683db86aabSstevel */
27693db86aabSstevel
27703db86aabSstevel socket = window->socket;
27713db86aabSstevel
27723db86aabSstevel if (!(window->state & WS_IO)) {
27733db86aabSstevel int win, tmp;
27743db86aabSstevel pcs_memwin_t *memp;
27753db86aabSstevel #if defined(PCIC_DEBUG)
27763db86aabSstevel if (pcic_debug)
27773db86aabSstevel cmn_err(CE_CONT, "\twindow type is memory\n");
27783db86aabSstevel #endif
27793db86aabSstevel /* this is memory window mapping */
27803db86aabSstevel win = window->window % PCIC_NUMWINSOCK;
27813db86aabSstevel tmp = window->window / PCIC_NUMWINSOCK;
27823db86aabSstevel
27833db86aabSstevel /* only windows 2-6 can do memory mapping */
27843db86aabSstevel if (tmp != window->socket || win < PCIC_IOWINDOWS) {
27853db86aabSstevel cmn_err(CE_CONT,
27863db86aabSstevel "\tattempt to map to non-mem window\n");
27873db86aabSstevel return (BAD_WINDOW);
27883db86aabSstevel }
27893db86aabSstevel
27903db86aabSstevel if (window->WindowSize == 0)
27913db86aabSstevel window->WindowSize = MEM_MIN;
27923db86aabSstevel else if ((window->WindowSize & (PCIC_PAGE-1)) != 0) {
27933db86aabSstevel cmn_err(CE_WARN, "pcic_set_window: BAD_SIZE\n");
27943db86aabSstevel return (BAD_SIZE);
27953db86aabSstevel }
27963db86aabSstevel
27973db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */
27983db86aabSstevel
27993db86aabSstevel memp = &sockp->pcs_windows[win].mem;
28003db86aabSstevel memp->pcw_speed = window->speed;
28013db86aabSstevel
28023db86aabSstevel win -= PCIC_IOWINDOWS; /* put in right range */
28033db86aabSstevel
28043db86aabSstevel if (window->WindowSize != memp->pcw_len)
28053db86aabSstevel which = memp->pcw_len;
28063db86aabSstevel else
28073db86aabSstevel which = 0;
28083db86aabSstevel
28093db86aabSstevel if (window->state & WS_ENABLED) {
28103db86aabSstevel uint32_t wspeed;
28113db86aabSstevel #if defined(PCIC_DEBUG)
28123db86aabSstevel if (pcic_debug) {
28133db86aabSstevel cmn_err(CE_CONT,
28143db86aabSstevel "\tbase=%x, win=%d\n", (unsigned)base,
28153db86aabSstevel win);
28163db86aabSstevel if (which)
28173db86aabSstevel cmn_err(CE_CONT,
28183db86aabSstevel "\tneed to remap window\n");
28193db86aabSstevel }
28203db86aabSstevel #endif
28213db86aabSstevel
28223db86aabSstevel if (which && (memp->pcw_status & PCW_MAPPED)) {
28233db86aabSstevel ddi_regs_map_free(&memp->pcw_handle);
28243db86aabSstevel res.ra_addr_lo = memp->pcw_base;
28253db86aabSstevel res.ra_len = memp->pcw_len;
28268134ee03Srw148561 (void) pcmcia_free_mem(memp->res_dip, &res);
28273db86aabSstevel memp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED);
28283db86aabSstevel memp->pcw_hostmem = NULL;
28293db86aabSstevel memp->pcw_base = NULL;
28303db86aabSstevel memp->pcw_len = 0;
28313db86aabSstevel }
28323db86aabSstevel
28333db86aabSstevel which = window->WindowSize >> PAGE_SHIFT;
28343db86aabSstevel
28353db86aabSstevel if (!(memp->pcw_status & PCW_MAPPED)) {
28363db86aabSstevel ret = 0;
28373db86aabSstevel
28383db86aabSstevel memp->pcw_base = base;
28393db86aabSstevel bzero(&req, sizeof (req));
28403db86aabSstevel req.ra_len = which << PAGE_SHIFT;
28413db86aabSstevel req.ra_addr = (uint64_t)memp->pcw_base;
28423db86aabSstevel req.ra_boundbase = pcic->pc_base;
28433db86aabSstevel req.ra_boundlen = pcic->pc_bound;
28443db86aabSstevel req.ra_flags = (memp->pcw_base ?
28453db86aabSstevel NDI_RA_ALLOC_SPECIFIED : 0) |
28463db86aabSstevel NDI_RA_ALLOC_BOUNDED;
28473db86aabSstevel req.ra_align_mask =
28483db86aabSstevel (PAGESIZE - 1) | (PCIC_PAGE - 1);
28493db86aabSstevel #if defined(PCIC_DEBUG)
28503db86aabSstevel pcic_err(dip, 8,
28513db86aabSstevel "\tlen 0x%"PRIx64
28523db86aabSstevel "addr 0x%"PRIx64"bbase 0x%"PRIx64
28533db86aabSstevel " blen 0x%"PRIx64" flags 0x%x"
28543db86aabSstevel " algn 0x%"PRIx64"\n",
28553db86aabSstevel req.ra_len, req.ra_addr,
28563db86aabSstevel req.ra_boundbase,
28573db86aabSstevel req.ra_boundlen, req.ra_flags,
28583db86aabSstevel req.ra_align_mask);
28593db86aabSstevel #endif
28603db86aabSstevel
28618134ee03Srw148561 ret = pcmcia_alloc_mem(dip, &req, &res,
28628134ee03Srw148561 &memp->res_dip);
28633db86aabSstevel if (ret == DDI_FAILURE) {
28643db86aabSstevel mutex_exit(&pcic->pc_lock);
28653db86aabSstevel cmn_err(CE_WARN,
28663db86aabSstevel "\tpcmcia_alloc_mem() failed\n");
28673db86aabSstevel return (BAD_SIZE);
28683db86aabSstevel }
28693db86aabSstevel memp->pcw_base = res.ra_addr_lo;
28703db86aabSstevel base = memp->pcw_base;
28713db86aabSstevel
28723db86aabSstevel #if defined(PCIC_DEBUG)
28733db86aabSstevel if (pcic_debug)
28743db86aabSstevel cmn_err(CE_CONT,
28753db86aabSstevel "\tsetwindow: new base=%x\n",
28763db86aabSstevel (unsigned)memp->pcw_base);
28773db86aabSstevel #endif
28783db86aabSstevel memp->pcw_len = window->WindowSize;
28793db86aabSstevel
28803db86aabSstevel which = pcmcia_map_reg(pcic->dip,
28813db86aabSstevel window->child,
28823db86aabSstevel &res,
28833db86aabSstevel (uint32_t)(window->state &
28843db86aabSstevel 0xffff) |
28853db86aabSstevel (window->socket << 16),
28863db86aabSstevel (caddr_t *)&memp->pcw_hostmem,
28873db86aabSstevel &memp->pcw_handle,
28883db86aabSstevel &window->attr, NULL);
28893db86aabSstevel
28903db86aabSstevel if (which != DDI_SUCCESS) {
28913db86aabSstevel
28923db86aabSstevel cmn_err(CE_WARN, "\tpcmcia_map_reg() "
28933db86aabSstevel "failed\n");
28943db86aabSstevel
28953db86aabSstevel res.ra_addr_lo = memp->pcw_base;
28963db86aabSstevel res.ra_len = memp->pcw_len;
289719397407SSherry Moore (void) pcmcia_free_mem(memp->res_dip,
289819397407SSherry Moore &res);
28993db86aabSstevel
29003db86aabSstevel mutex_exit(&pcic->pc_lock);
29013db86aabSstevel
29023db86aabSstevel return (BAD_WINDOW);
29033db86aabSstevel }
29043db86aabSstevel memp->pcw_status |= PCW_MAPPED;
29053db86aabSstevel #if defined(PCIC_DEBUG)
29063db86aabSstevel if (pcic_debug)
29073db86aabSstevel cmn_err(CE_CONT,
29083db86aabSstevel "\tmap=%x, hostmem=%p\n",
29093db86aabSstevel which,
29103db86aabSstevel (void *)memp->pcw_hostmem);
29113db86aabSstevel #endif
29123db86aabSstevel } else {
29133db86aabSstevel base = memp->pcw_base;
29143db86aabSstevel }
29153db86aabSstevel
29163db86aabSstevel /* report the handle back to caller */
29173db86aabSstevel window->handle = memp->pcw_handle;
29183db86aabSstevel
29193db86aabSstevel #if defined(PCIC_DEBUG)
29203db86aabSstevel if (pcic_debug) {
29213db86aabSstevel cmn_err(CE_CONT,
29223db86aabSstevel "\twindow mapped to %x@%x len=%d\n",
29233db86aabSstevel (unsigned)window->base,
29243db86aabSstevel (unsigned)memp->pcw_base,
29253db86aabSstevel memp->pcw_len);
29263db86aabSstevel }
29273db86aabSstevel #endif
29283db86aabSstevel
29293db86aabSstevel /* find the register set offset */
29303db86aabSstevel select = win * PCIC_MEM_1_OFFSET;
29313db86aabSstevel #if defined(PCIC_DEBUG)
29323db86aabSstevel if (pcic_debug)
29333db86aabSstevel cmn_err(CE_CONT, "\tselect=%x\n", select);
29343db86aabSstevel #endif
29353db86aabSstevel
29363db86aabSstevel /*
29373db86aabSstevel * at this point, the register window indicator has
29383db86aabSstevel * been converted to be an offset from the first
29393db86aabSstevel * set of registers that are used for programming
29403db86aabSstevel * the window mapping and the offset used to select
29413db86aabSstevel * the correct set of registers to access the
29423db86aabSstevel * specified socket. This allows basing everything
29433db86aabSstevel * off the _0 window
29443db86aabSstevel */
29453db86aabSstevel
29463db86aabSstevel /* map the physical page base address */
29473db86aabSstevel which = (window->state & WS_16BIT) ? SYSMEM_DATA_16 : 0;
29483db86aabSstevel which |= (window->speed <= MEM_SPEED_MIN) ?
29493db86aabSstevel SYSMEM_ZERO_WAIT : 0;
29503db86aabSstevel
29513db86aabSstevel /* need to select register set */
29523db86aabSstevel select = PCIC_MEM_1_OFFSET * win;
29533db86aabSstevel
29543db86aabSstevel pcic_putb(pcic, socket,
29553db86aabSstevel PCIC_SYSMEM_0_STARTLOW + select,
29563db86aabSstevel SYSMEM_LOW(base));
29573db86aabSstevel pcic_putb(pcic, socket,
29583db86aabSstevel PCIC_SYSMEM_0_STARTHI + select,
29593db86aabSstevel SYSMEM_HIGH(base) | which);
29603db86aabSstevel
29613db86aabSstevel /*
29623db86aabSstevel * Some adapters can decode window addresses greater
29633db86aabSstevel * than 16-bits worth, so handle them here.
29643db86aabSstevel */
29653db86aabSstevel switch (pcic->pc_type) {
29663db86aabSstevel case PCIC_INTEL_i82092:
29673db86aabSstevel pcic_putb(pcic, socket,
29683db86aabSstevel PCIC_82092_CPAGE,
29693db86aabSstevel SYSMEM_EXT(base));
29703db86aabSstevel break;
29713db86aabSstevel case PCIC_CL_PD6729:
29723db86aabSstevel case PCIC_CL_PD6730:
29733db86aabSstevel clext_reg_write(pcic, socket,
29743db86aabSstevel PCIC_CLEXT_MMAP0_UA + win,
29753db86aabSstevel SYSMEM_EXT(base));
29763db86aabSstevel break;
29773db86aabSstevel case PCIC_TI_PCI1130:
29783db86aabSstevel /*
29793db86aabSstevel * Note that the TI chip has one upper byte
29803db86aabSstevel * per socket so all windows get bound to a
29813db86aabSstevel * 16MB segment. This must be detected and
29823db86aabSstevel * handled appropriately. We can detect that
29833db86aabSstevel * it is done by seeing if the pc_base has
29843db86aabSstevel * changed and changing when the register
29853db86aabSstevel * is first set. This will force the bounds
29863db86aabSstevel * to be correct.
29873db86aabSstevel */
29883db86aabSstevel if (pcic->pc_bound == 0xffffffff) {
29893db86aabSstevel pcic_putb(pcic, socket,
29903db86aabSstevel PCIC_TI_WINDOW_PAGE_PCI,
29913db86aabSstevel SYSMEM_EXT(base));
29923db86aabSstevel pcic->pc_base = SYSMEM_EXT(base) << 24;
29933db86aabSstevel pcic->pc_bound = 0x1000000;
29943db86aabSstevel }
29953db86aabSstevel break;
29963db86aabSstevel case PCIC_TI_PCI1031:
29973db86aabSstevel case PCIC_TI_PCI1131:
29983db86aabSstevel case PCIC_TI_PCI1250:
29993db86aabSstevel case PCIC_TI_PCI1225:
30003db86aabSstevel case PCIC_TI_PCI1221:
30013db86aabSstevel case PCIC_SMC_34C90:
30023db86aabSstevel case PCIC_CL_PD6832:
30033db86aabSstevel case PCIC_RICOH_RL5C466:
30043db86aabSstevel case PCIC_TI_PCI1410:
30053db86aabSstevel case PCIC_ENE_1410:
30063db86aabSstevel case PCIC_TI_PCI1510:
30073db86aabSstevel case PCIC_TI_PCI1520:
30083db86aabSstevel case PCIC_O2_OZ6912:
30093db86aabSstevel case PCIC_TI_PCI1420:
30103db86aabSstevel case PCIC_ENE_1420:
30113db86aabSstevel case PCIC_TI_VENDOR:
30123db86aabSstevel case PCIC_TOSHIBA_TOPIC100:
30133db86aabSstevel case PCIC_TOSHIBA_TOPIC95:
30143db86aabSstevel case PCIC_TOSHIBA_VENDOR:
30153db86aabSstevel case PCIC_RICOH_VENDOR:
30163db86aabSstevel case PCIC_O2MICRO_VENDOR:
30173db86aabSstevel pcic_putb(pcic, socket,
30183db86aabSstevel PCIC_YENTA_MEM_PAGE + win,
30193db86aabSstevel SYSMEM_EXT(base));
30203db86aabSstevel break;
30213db86aabSstevel default:
30223db86aabSstevel cmn_err(CE_NOTE, "pcic_set_window: unknown "
30233db86aabSstevel "cardbus vendor:0x%X\n",
30243db86aabSstevel pcic->pc_type);
30253db86aabSstevel pcic_putb(pcic, socket,
30263db86aabSstevel PCIC_YENTA_MEM_PAGE + win,
30273db86aabSstevel SYSMEM_EXT(base));
30283db86aabSstevel
30293db86aabSstevel break;
30303db86aabSstevel } /* switch */
30313db86aabSstevel
30323db86aabSstevel /*
30333db86aabSstevel * specify the length of the mapped range
30343db86aabSstevel * we convert to pages (rounding up) so that
30353db86aabSstevel * the hardware gets the right thing
30363db86aabSstevel */
30373db86aabSstevel pages = (window->WindowSize+PCIC_PAGE-1)/PCIC_PAGE;
30383db86aabSstevel
30393db86aabSstevel /*
30403db86aabSstevel * Setup this window's timing.
30413db86aabSstevel */
30423db86aabSstevel switch (pcic->pc_type) {
30433db86aabSstevel case PCIC_CL_PD6729:
30443db86aabSstevel case PCIC_CL_PD6730:
30453db86aabSstevel case PCIC_CL_PD6710:
30463db86aabSstevel case PCIC_CL_PD6722:
30473db86aabSstevel wspeed = SYSMEM_CLTIMER_SET_0;
30483db86aabSstevel pcic_set_cdtimers(pcic, socket,
30493db86aabSstevel window->speed,
30503db86aabSstevel wspeed);
30513db86aabSstevel break;
30523db86aabSstevel
30533db86aabSstevel case PCIC_INTEL_i82092:
30543db86aabSstevel default:
30553db86aabSstevel wspeed = pcic_calc_speed(pcic, window->speed);
30563db86aabSstevel break;
30573db86aabSstevel } /* switch */
30583db86aabSstevel
30593db86aabSstevel #if defined(PCIC_DEBUG)
30603db86aabSstevel if (pcic_debug)
30613db86aabSstevel cmn_err(CE_CONT,
30623db86aabSstevel "\twindow %d speed bits = %x for "
30633db86aabSstevel "%dns\n",
30643db86aabSstevel win, (unsigned)wspeed, window->speed);
30653db86aabSstevel #endif
30663db86aabSstevel
30673db86aabSstevel pcic_putb(pcic, socket, PCIC_SYSMEM_0_STOPLOW + select,
30683db86aabSstevel SYSMEM_LOW(base +
30693db86aabSstevel (pages * PCIC_PAGE)-1));
30703db86aabSstevel
30713db86aabSstevel wspeed |= SYSMEM_HIGH(base + (pages * PCIC_PAGE)-1);
30723db86aabSstevel pcic_putb(pcic, socket, PCIC_SYSMEM_0_STOPHI + select,
30733db86aabSstevel wspeed);
30743db86aabSstevel
30753db86aabSstevel /*
30763db86aabSstevel * now map the card's memory pages - we start with page
30773db86aabSstevel * 0
30783db86aabSstevel * we also default to AM -- set page might change it
30793db86aabSstevel */
30803db86aabSstevel base = memp->pcw_base;
30813db86aabSstevel pcic_putb(pcic, socket,
30823db86aabSstevel PCIC_CARDMEM_0_LOW + select,
30833db86aabSstevel CARDMEM_LOW(0 - (uint32_t)base));
30843db86aabSstevel
30853db86aabSstevel pcic_putb(pcic, socket,
30863db86aabSstevel PCIC_CARDMEM_0_HI + select,
30873db86aabSstevel CARDMEM_HIGH(0 - (uint32_t)base) |
30883db86aabSstevel CARDMEM_REG_ACTIVE);
30893db86aabSstevel
30903db86aabSstevel /*
30913db86aabSstevel * enable the window even though redundant
30923db86aabSstevel * and SetPage may do it again.
30933db86aabSstevel */
30943db86aabSstevel select = pcic_getb(pcic, socket,
30953db86aabSstevel PCIC_MAPPING_ENABLE);
30963db86aabSstevel select |= SYSMEM_WINDOW(win);
30973db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, select);
30983db86aabSstevel memp->pcw_offset = 0;
30993db86aabSstevel memp->pcw_status |= PCW_ENABLED;
31003db86aabSstevel } else {
31013db86aabSstevel /*
31023db86aabSstevel * not only do we unmap the memory, the
31033db86aabSstevel * window has been turned off.
31043db86aabSstevel */
31053db86aabSstevel if (which && memp->pcw_status & PCW_MAPPED) {
31063db86aabSstevel ddi_regs_map_free(&memp->pcw_handle);
31073db86aabSstevel res.ra_addr_lo = memp->pcw_base;
31083db86aabSstevel res.ra_len = memp->pcw_len;
31098134ee03Srw148561 (void) pcmcia_free_mem(memp->res_dip, &res);
31103db86aabSstevel memp->pcw_hostmem = NULL;
31113db86aabSstevel memp->pcw_status &= ~PCW_MAPPED;
31123db86aabSstevel }
31133db86aabSstevel
31143db86aabSstevel /* disable current mapping */
31153db86aabSstevel select = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
31163db86aabSstevel select &= ~SYSMEM_WINDOW(win);
31173db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, select);
31183db86aabSstevel memp->pcw_status &= ~PCW_ENABLED;
31193db86aabSstevel }
31203db86aabSstevel memp->pcw_len = window->WindowSize;
31213db86aabSstevel window->handle = memp->pcw_handle;
31223db86aabSstevel #if defined(PCIC_DEBUG)
31233db86aabSstevel if (pcic_debug)
31243db86aabSstevel xxdmp_all_regs(pcic, window->socket, -1);
31253db86aabSstevel #endif
31263db86aabSstevel } else {
31273db86aabSstevel /*
31283db86aabSstevel * This is a request for an IO window
31293db86aabSstevel */
31303db86aabSstevel int win, tmp;
31313db86aabSstevel pcs_iowin_t *winp;
31323db86aabSstevel /* I/O windows */
31333db86aabSstevel #if defined(PCIC_DEBUG)
31343db86aabSstevel if (pcic_debug)
31353db86aabSstevel cmn_err(CE_CONT, "\twindow type is I/O\n");
31363db86aabSstevel #endif
31373db86aabSstevel
31383db86aabSstevel /* only windows 0 and 1 can do I/O */
31393db86aabSstevel win = window->window % PCIC_NUMWINSOCK;
31403db86aabSstevel tmp = window->window / PCIC_NUMWINSOCK;
31413db86aabSstevel
31423db86aabSstevel if (win >= PCIC_IOWINDOWS || tmp != window->socket) {
31433db86aabSstevel cmn_err(CE_WARN,
31443db86aabSstevel "\twindow is out of range (%d)\n",
31453db86aabSstevel window->window);
31463db86aabSstevel return (BAD_WINDOW);
31473db86aabSstevel }
31483db86aabSstevel
31493db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */
31503db86aabSstevel
31513db86aabSstevel winp = &sockp->pcs_windows[win].io;
31523db86aabSstevel winp->pcw_speed = window->speed;
31533db86aabSstevel if (window->WindowSize != 1 && window->WindowSize & 1) {
31543db86aabSstevel /* we don't want an odd-size window */
31553db86aabSstevel window->WindowSize++;
31563db86aabSstevel }
31573db86aabSstevel winp->pcw_len = window->WindowSize;
31583db86aabSstevel
31593db86aabSstevel if (window->state & WS_ENABLED) {
31603db86aabSstevel if (winp->pcw_status & PCW_MAPPED) {
31613db86aabSstevel ddi_regs_map_free(&winp->pcw_handle);
31623db86aabSstevel res.ra_addr_lo = winp->pcw_base;
31633db86aabSstevel res.ra_len = winp->pcw_len;
31648134ee03Srw148561 (void) pcmcia_free_io(winp->res_dip, &res);
31653db86aabSstevel winp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED);
31663db86aabSstevel }
31673db86aabSstevel
31683db86aabSstevel /*
31693db86aabSstevel * if the I/O address wasn't allocated, allocate
31703db86aabSstevel * it now. If it was allocated, it better
31713db86aabSstevel * be free to use.
31723db86aabSstevel * The winp->pcw_offset value is set and used
31733db86aabSstevel * later on if the particular adapter
31743db86aabSstevel * that we're running on has the ability
31753db86aabSstevel * to translate IO accesses to the card
31763db86aabSstevel * (such as some adapters in the Cirrus
31773db86aabSstevel * Logic family).
31783db86aabSstevel */
31793db86aabSstevel winp->pcw_offset = 0;
31803db86aabSstevel
31813db86aabSstevel /*
31823db86aabSstevel * Setup the request parameters for the
31833db86aabSstevel * requested base and length. If
31843db86aabSstevel * we're on an adapter that has
31853db86aabSstevel * IO window offset registers, then
31863db86aabSstevel * we don't need a specific base
31873db86aabSstevel * address, just a length, and then
31883db86aabSstevel * we'll cause the correct IO address
31893db86aabSstevel * to be generated on the socket by
31903db86aabSstevel * setting up the IO window offset
31913db86aabSstevel * registers.
31923db86aabSstevel * For adapters that support this capability, we
31933db86aabSstevel * always use the IO window offset registers,
31943db86aabSstevel * even if the passed base/length would be in
31953db86aabSstevel * range.
31963db86aabSstevel */
31973db86aabSstevel base = window->base;
31983db86aabSstevel bzero(&req, sizeof (req));
31993db86aabSstevel req.ra_len = window->WindowSize;
32003db86aabSstevel
32013db86aabSstevel req.ra_addr = (uint64_t)
32023db86aabSstevel ((pcic->pc_flags & PCF_IO_REMAP) ? 0 : base);
32033db86aabSstevel req.ra_flags = (req.ra_addr) ?
32043db86aabSstevel NDI_RA_ALLOC_SPECIFIED : 0;
32053db86aabSstevel
32063db86aabSstevel req.ra_flags |= NDI_RA_ALIGN_SIZE;
32073db86aabSstevel /* need to rethink this */
32083db86aabSstevel req.ra_boundbase = pcic->pc_iobase;
32093db86aabSstevel req.ra_boundlen = pcic->pc_iobound;
32103db86aabSstevel req.ra_flags |= NDI_RA_ALLOC_BOUNDED;
32113db86aabSstevel
32123db86aabSstevel #if defined(PCIC_DEBUG)
32133db86aabSstevel pcic_err(dip, 8,
32143db86aabSstevel "\tlen 0x%"PRIx64" addr 0x%"PRIx64
32153db86aabSstevel "bbase 0x%"PRIx64
32163db86aabSstevel "blen 0x%"PRIx64" flags 0x%x algn 0x%"
32173db86aabSstevel PRIx64"\n",
32183db86aabSstevel req.ra_len, (uint64_t)req.ra_addr,
32193db86aabSstevel req.ra_boundbase,
32203db86aabSstevel req.ra_boundlen, req.ra_flags,
32213db86aabSstevel req.ra_align_mask);
32223db86aabSstevel #endif
32233db86aabSstevel
32243db86aabSstevel /*
32253db86aabSstevel * Try to allocate the space. If we fail this,
32263db86aabSstevel * return the appropriate error depending
32273db86aabSstevel * on whether the caller specified a
32283db86aabSstevel * specific base address or not.
32293db86aabSstevel */
32308134ee03Srw148561 if (pcmcia_alloc_io(dip, &req, &res,
32318134ee03Srw148561 &winp->res_dip) == DDI_FAILURE) {
32323db86aabSstevel winp->pcw_status &= ~PCW_ENABLED;
32333db86aabSstevel mutex_exit(&pcic->pc_lock);
32343db86aabSstevel cmn_err(CE_WARN, "Failed to alloc I/O:\n"
32353db86aabSstevel "\tlen 0x%" PRIx64 " addr 0x%" PRIx64
32363db86aabSstevel "bbase 0x%" PRIx64
32373db86aabSstevel "blen 0x%" PRIx64 "flags 0x%x"
32383db86aabSstevel "algn 0x%" PRIx64 "\n",
32393db86aabSstevel req.ra_len, req.ra_addr,
32403db86aabSstevel req.ra_boundbase,
32413db86aabSstevel req.ra_boundlen, req.ra_flags,
32423db86aabSstevel req.ra_align_mask);
32433db86aabSstevel
32443db86aabSstevel return (base?BAD_BASE:BAD_SIZE);
32453db86aabSstevel } /* pcmcia_alloc_io */
32463db86aabSstevel
32473db86aabSstevel /*
32483db86aabSstevel * Don't change the original base. Either we use
32493db86aabSstevel * the offset registers below (PCF_IO_REMAP is set)
32503db86aabSstevel * or it was allocated correctly anyway.
32513db86aabSstevel */
32523db86aabSstevel winp->pcw_base = res.ra_addr_lo;
32533db86aabSstevel
32543db86aabSstevel #if defined(PCIC_DEBUG)
32553db86aabSstevel pcic_err(dip, 8,
32563db86aabSstevel "\tsetwindow: new base=%x orig base 0x%x\n",
32573db86aabSstevel (unsigned)winp->pcw_base, base);
32583db86aabSstevel #endif
32593db86aabSstevel
32603db86aabSstevel if ((which = pcmcia_map_reg(pcic->dip,
32613db86aabSstevel window->child,
32623db86aabSstevel &res,
32633db86aabSstevel (uint32_t)(window->state &
32643db86aabSstevel 0xffff) |
32653db86aabSstevel (window->socket << 16),
32663db86aabSstevel (caddr_t *)&winp->pcw_hostmem,
32673db86aabSstevel &winp->pcw_handle,
32683db86aabSstevel &window->attr,
32693db86aabSstevel base)) != DDI_SUCCESS) {
32703db86aabSstevel
32713db86aabSstevel cmn_err(CE_WARN, "pcmcia_map_reg()"
32723db86aabSstevel "failed\n");
32733db86aabSstevel
32743db86aabSstevel res.ra_addr_lo = winp->pcw_base;
32753db86aabSstevel res.ra_len = winp->pcw_len;
327619397407SSherry Moore (void) pcmcia_free_io(winp->res_dip,
327719397407SSherry Moore &res);
32783db86aabSstevel
32793db86aabSstevel mutex_exit(&pcic->pc_lock);
32803db86aabSstevel return (BAD_WINDOW);
32813db86aabSstevel }
32823db86aabSstevel
32833db86aabSstevel window->handle = winp->pcw_handle;
32843db86aabSstevel winp->pcw_status |= PCW_MAPPED;
32853db86aabSstevel
32863db86aabSstevel /* find the register set offset */
32873db86aabSstevel select = win * PCIC_IO_OFFSET;
32883db86aabSstevel
32893db86aabSstevel #if defined(PCIC_DEBUG)
32903db86aabSstevel if (pcic_debug) {
32913db86aabSstevel cmn_err(CE_CONT,
32923db86aabSstevel "\tenable: window=%d, select=%x, "
32933db86aabSstevel "base=%x, handle=%p\n",
32943db86aabSstevel win, select,
32953db86aabSstevel (unsigned)window->base,
32963db86aabSstevel (void *)window->handle);
32973db86aabSstevel }
32983db86aabSstevel #endif
32993db86aabSstevel /*
33003db86aabSstevel * at this point, the register window indicator has
33013db86aabSstevel * been converted to be an offset from the first
33023db86aabSstevel * set of registers that are used for programming
33033db86aabSstevel * the window mapping and the offset used to select
33043db86aabSstevel * the correct set of registers to access the
33053db86aabSstevel * specified socket. This allows basing everything
33063db86aabSstevel * off the _0 window
33073db86aabSstevel */
33083db86aabSstevel
33093db86aabSstevel /* map the I/O base in */
33103db86aabSstevel pcic_putb(pcic, socket,
33113db86aabSstevel PCIC_IO_ADDR_0_STARTLOW + select,
33123db86aabSstevel LOW_BYTE((uint32_t)winp->pcw_base));
33133db86aabSstevel pcic_putb(pcic, socket,
33143db86aabSstevel PCIC_IO_ADDR_0_STARTHI + select,
33153db86aabSstevel HIGH_BYTE((uint32_t)winp->pcw_base));
33163db86aabSstevel
33173db86aabSstevel pcic_putb(pcic, socket,
33183db86aabSstevel PCIC_IO_ADDR_0_STOPLOW + select,
33193db86aabSstevel LOW_BYTE((uint32_t)winp->pcw_base +
33203db86aabSstevel window->WindowSize - 1));
33213db86aabSstevel pcic_putb(pcic, socket,
33223db86aabSstevel PCIC_IO_ADDR_0_STOPHI + select,
33233db86aabSstevel HIGH_BYTE((uint32_t)winp->pcw_base +
33243db86aabSstevel window->WindowSize - 1));
33253db86aabSstevel
33263db86aabSstevel /*
33273db86aabSstevel * We've got the requested IO space, now see if we
33283db86aabSstevel * need to adjust the IO window offset registers
33293db86aabSstevel * so that the correct IO address is generated
33303db86aabSstevel * at the socket. If this window doesn't have
33313db86aabSstevel * this capability, then we're all done setting
33323db86aabSstevel * up the IO resources.
33333db86aabSstevel */
33343db86aabSstevel if (pcic->pc_flags & PCF_IO_REMAP) {
33353db86aabSstevel
33363db86aabSstevel
33373db86aabSstevel /*
33383db86aabSstevel * Note that only 16 bits are used to program
33393db86aabSstevel * the registers but leave 32 bits on pcw_offset
33403db86aabSstevel * so that we can generate the original base
33413db86aabSstevel * in get_window()
33423db86aabSstevel */
33433db86aabSstevel winp->pcw_offset = (base - winp->pcw_base);
33443db86aabSstevel
33453db86aabSstevel pcic_putb(pcic, socket,
33463db86aabSstevel PCIC_IO_OFFSET_LOW +
33473db86aabSstevel (win * PCIC_IO_OFFSET_OFFSET),
33483db86aabSstevel winp->pcw_offset & 0x0ff);
33493db86aabSstevel pcic_putb(pcic, socket,
33503db86aabSstevel PCIC_IO_OFFSET_HI +
33513db86aabSstevel (win * PCIC_IO_OFFSET_OFFSET),
33523db86aabSstevel (winp->pcw_offset >> 8) & 0x0ff);
33533db86aabSstevel
33543db86aabSstevel } /* PCF_IO_REMAP */
33553db86aabSstevel
33563db86aabSstevel /* now get the other details (size, etc) right */
33573db86aabSstevel
33583db86aabSstevel /*
33593db86aabSstevel * Set the data size control bits here. Most of the
33603db86aabSstevel * adapters will ignore IOMEM_16BIT when
33613db86aabSstevel * IOMEM_IOCS16 is set, except for the Intel
33623db86aabSstevel * 82092, which only pays attention to the
33633db86aabSstevel * IOMEM_16BIT bit. Sigh... Intel can't even
33643db86aabSstevel * make a proper clone of their own chip.
33653db86aabSstevel * The 82092 also apparently can't set the timing
33663db86aabSstevel * of I/O windows.
33673db86aabSstevel */
33683db86aabSstevel which = (window->state & WS_16BIT) ?
33693db86aabSstevel (IOMEM_16BIT | IOMEM_IOCS16) : 0;
33703db86aabSstevel
33713db86aabSstevel switch (pcic->pc_type) {
33723db86aabSstevel case PCIC_CL_PD6729:
33733db86aabSstevel case PCIC_CL_PD6730:
33743db86aabSstevel case PCIC_CL_PD6710:
33753db86aabSstevel case PCIC_CL_PD6722:
33763db86aabSstevel case PCIC_CL_PD6832:
33773db86aabSstevel /*
33783db86aabSstevel * Select Timer Set 1 - this will take
33793db86aabSstevel * effect when the PCIC_IO_CONTROL
33803db86aabSstevel * register is written to later on;
33813db86aabSstevel * the call to pcic_set_cdtimers
33823db86aabSstevel * just sets up the timer itself.
33833db86aabSstevel */
33843db86aabSstevel which |= IOMEM_CLTIMER_SET_1;
33853db86aabSstevel pcic_set_cdtimers(pcic, socket,
33863db86aabSstevel window->speed,
33873db86aabSstevel IOMEM_CLTIMER_SET_1);
33883db86aabSstevel which |= IOMEM_IOCS16;
33893db86aabSstevel break;
33903db86aabSstevel case PCIC_TI_PCI1031:
33913db86aabSstevel
33923db86aabSstevel if (window->state & WS_16BIT)
33933db86aabSstevel which |= IOMEM_WAIT16;
33943db86aabSstevel
33953db86aabSstevel break;
33963db86aabSstevel case PCIC_TI_PCI1130:
33973db86aabSstevel
33983db86aabSstevel if (window->state & WS_16BIT)
33993db86aabSstevel which |= IOMEM_WAIT16;
34003db86aabSstevel
34013db86aabSstevel break;
34023db86aabSstevel case PCIC_INTEL_i82092:
34033db86aabSstevel break;
34043db86aabSstevel default:
34053db86aabSstevel if (window->speed >
34063db86aabSstevel mhztons(pcic->bus_speed) * 3)
34073db86aabSstevel which |= IOMEM_WAIT16;
34083db86aabSstevel #ifdef notdef
34093db86aabSstevel if (window->speed <
34103db86aabSstevel mhztons(pcic->bus_speed) * 6)
34113db86aabSstevel which |= IOMEM_ZERO_WAIT;
34123db86aabSstevel #endif
34133db86aabSstevel break;
34143db86aabSstevel } /* switch (pc_type) */
34153db86aabSstevel
34163db86aabSstevel /*
34173db86aabSstevel * Setup the data width and timing
34183db86aabSstevel */
34193db86aabSstevel select = pcic_getb(pcic, socket, PCIC_IO_CONTROL);
34203db86aabSstevel select &= ~(PCIC_IO_WIN_MASK << (win * 4));
34213db86aabSstevel select |= IOMEM_SETWIN(win, which);
34223db86aabSstevel pcic_putb(pcic, socket, PCIC_IO_CONTROL, select);
34233db86aabSstevel
34243db86aabSstevel /*
34253db86aabSstevel * Enable the IO window
34263db86aabSstevel */
34273db86aabSstevel select = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
34283db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE,
34293db86aabSstevel select | IOMEM_WINDOW(win));
34303db86aabSstevel
34313db86aabSstevel winp->pcw_status |= PCW_ENABLED;
34323db86aabSstevel
34333db86aabSstevel #if defined(PCIC_DEBUG)
34343db86aabSstevel if (pcic_debug) {
34353db86aabSstevel cmn_err(CE_CONT,
34363db86aabSstevel "\twhich = %x, select = %x (%x)\n",
34373db86aabSstevel which, select,
34383db86aabSstevel IOMEM_SETWIN(win, which));
34393db86aabSstevel xxdmp_all_regs(pcic, window->socket * 0x40, 24);
34403db86aabSstevel }
34413db86aabSstevel #endif
34423db86aabSstevel } else {
34433db86aabSstevel /*
34443db86aabSstevel * not only do we unmap the IO space, the
34453db86aabSstevel * window has been turned off.
34463db86aabSstevel */
34473db86aabSstevel if (winp->pcw_status & PCW_MAPPED) {
34483db86aabSstevel ddi_regs_map_free(&winp->pcw_handle);
34493db86aabSstevel res.ra_addr_lo = winp->pcw_base;
34503db86aabSstevel res.ra_len = winp->pcw_len;
34518134ee03Srw148561 (void) pcmcia_free_io(winp->res_dip, &res);
34523db86aabSstevel winp->pcw_status &= ~PCW_MAPPED;
34533db86aabSstevel }
34543db86aabSstevel
34553db86aabSstevel /* disable current mapping */
34563db86aabSstevel select = pcic_getb(pcic, socket,
34573db86aabSstevel PCIC_MAPPING_ENABLE);
34583db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE,
34593db86aabSstevel select &= ~IOMEM_WINDOW(win));
34603db86aabSstevel winp->pcw_status &= ~PCW_ENABLED;
34613db86aabSstevel
34623db86aabSstevel winp->pcw_base = 0;
34633db86aabSstevel winp->pcw_len = 0;
34643db86aabSstevel winp->pcw_offset = 0;
34653db86aabSstevel window->base = 0;
34663db86aabSstevel /* now make sure we don't accidentally re-enable */
34673db86aabSstevel /* find the register set offset */
34683db86aabSstevel select = win * PCIC_IO_OFFSET;
34693db86aabSstevel pcic_putb(pcic, socket,
34703db86aabSstevel PCIC_IO_ADDR_0_STARTLOW + select, 0);
34713db86aabSstevel pcic_putb(pcic, socket,
34723db86aabSstevel PCIC_IO_ADDR_0_STARTHI + select, 0);
34733db86aabSstevel pcic_putb(pcic, socket,
34743db86aabSstevel PCIC_IO_ADDR_0_STOPLOW + select, 0);
34753db86aabSstevel pcic_putb(pcic, socket,
34763db86aabSstevel PCIC_IO_ADDR_0_STOPHI + select, 0);
34773db86aabSstevel }
34783db86aabSstevel }
34793db86aabSstevel mutex_exit(&pcic->pc_lock);
34803db86aabSstevel
34813db86aabSstevel return (SUCCESS);
34823db86aabSstevel }
34833db86aabSstevel
34843db86aabSstevel /*
34853db86aabSstevel * pcic_card_state()
34863db86aabSstevel * compute the instantaneous Card State information
34873db86aabSstevel */
34883db86aabSstevel static int
pcic_card_state(pcicdev_t * pcic,pcic_socket_t * sockp)34893db86aabSstevel pcic_card_state(pcicdev_t *pcic, pcic_socket_t *sockp)
34903db86aabSstevel {
34913db86aabSstevel int value, result;
34923db86aabSstevel #if defined(PCIC_DEBUG)
34933db86aabSstevel int orig_value;
34943db86aabSstevel #endif
34953db86aabSstevel
34963db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */
34973db86aabSstevel
34983db86aabSstevel value = pcic_getb(pcic, sockp->pcs_socket, PCIC_INTERFACE_STATUS);
34993db86aabSstevel
35003db86aabSstevel #if defined(PCIC_DEBUG)
35013db86aabSstevel orig_value = value;
35023db86aabSstevel if (pcic_debug >= 8)
35033db86aabSstevel cmn_err(CE_CONT, "pcic_card_state(%p) if status = %b for %d\n",
35043db86aabSstevel (void *)sockp,
35053db86aabSstevel value,
35063db86aabSstevel "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI",
35073db86aabSstevel sockp->pcs_socket);
35083db86aabSstevel #endif
35093db86aabSstevel /*
35103db86aabSstevel * Lie to socket services if we are not ready.
35113db86aabSstevel * This is when we are starting up or during debounce timeouts
35123db86aabSstevel * or if the card is a cardbus card.
35133db86aabSstevel */
35143db86aabSstevel if (!(sockp->pcs_flags & (PCS_STARTING|PCS_CARD_ISCARDBUS)) &&
35153db86aabSstevel !sockp->pcs_debounce_id &&
35163db86aabSstevel (value & PCIC_ISTAT_CD_MASK) == PCIC_CD_PRESENT_OK) {
35173db86aabSstevel result = SBM_CD;
35183db86aabSstevel
35193db86aabSstevel if (value & PCIC_WRITE_PROTECT || !(value & PCIC_POWER_ON))
35203db86aabSstevel result |= SBM_WP;
35213db86aabSstevel if (value & PCIC_POWER_ON) {
35223db86aabSstevel if (value & PCIC_READY)
35233db86aabSstevel result |= SBM_RDYBSY;
35243db86aabSstevel value = (~value) & (PCIC_BVD1 | PCIC_BVD2);
35253db86aabSstevel if (value & PCIC_BVD1)
35263db86aabSstevel result |= SBM_BVD1;
35273db86aabSstevel if (value & PCIC_BVD2)
35283db86aabSstevel result |= SBM_BVD2;
35293db86aabSstevel }
35303db86aabSstevel } else
35313db86aabSstevel result = 0;
35323db86aabSstevel
35333db86aabSstevel mutex_exit(&pcic->pc_lock);
35343db86aabSstevel
35353db86aabSstevel #if defined(PCIC_DEBUG)
35363db86aabSstevel pcic_err(pcic->dip, 8,
35373db86aabSstevel "pcic_card_state(%p) if status = %b for %d (rval=0x%x)\n",
35383db86aabSstevel (void *) sockp, orig_value,
35393db86aabSstevel "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI",
35403db86aabSstevel sockp->pcs_socket, result);
35413db86aabSstevel #endif
35423db86aabSstevel
35433db86aabSstevel return (result);
35443db86aabSstevel }
35453db86aabSstevel
35463db86aabSstevel /*
35473db86aabSstevel * pcic_set_page()
35483db86aabSstevel * SocketServices SetPage function
35493db86aabSstevel * set the page of PC Card memory that should be in the mapped
35503db86aabSstevel * window
35513db86aabSstevel */
35523db86aabSstevel /*ARGSUSED*/
35533db86aabSstevel static int
pcic_set_page(dev_info_t * dip,set_page_t * page)35543db86aabSstevel pcic_set_page(dev_info_t *dip, set_page_t *page)
35553db86aabSstevel {
35563db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
35573db86aabSstevel pcicdev_t *pcic = anp->an_private;
35583db86aabSstevel int select;
35593db86aabSstevel int which, socket, window;
35603db86aabSstevel uint32_t base;
35613db86aabSstevel pcs_memwin_t *memp;
35623db86aabSstevel
35633db86aabSstevel /* get real socket/window numbers */
35643db86aabSstevel window = page->window % PCIC_NUMWINSOCK;
35653db86aabSstevel socket = page->window / PCIC_NUMWINSOCK;
35663db86aabSstevel
35673db86aabSstevel #if defined(PCIC_DEBUG)
35683db86aabSstevel if (pcic_debug) {
35693db86aabSstevel cmn_err(CE_CONT,
35703db86aabSstevel "pcic_set_page: window=%d, socket=%d, page=%d\n",
35713db86aabSstevel window, socket, page->page);
35723db86aabSstevel }
35733db86aabSstevel #endif
35743db86aabSstevel /* only windows 2-6 work on memory */
35753db86aabSstevel if (window < PCIC_IOWINDOWS)
35763db86aabSstevel return (BAD_WINDOW);
35773db86aabSstevel
35783db86aabSstevel /* only one page supported (but any size) */
35793db86aabSstevel if (page->page != 0)
35803db86aabSstevel return (BAD_PAGE);
35813db86aabSstevel
35823db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */
35833db86aabSstevel
35843db86aabSstevel memp = &pcic->pc_sockets[socket].pcs_windows[window].mem;
35853db86aabSstevel window -= PCIC_IOWINDOWS;
35863db86aabSstevel
35873db86aabSstevel #if defined(PCIC_DEBUG)
35883db86aabSstevel if (pcic_debug)
35893db86aabSstevel cmn_err(CE_CONT, "\tpcw_base=%x, pcw_hostmem=%p, pcw_len=%x\n",
35903db86aabSstevel (uint32_t)memp->pcw_base,
35913db86aabSstevel (void *)memp->pcw_hostmem, memp->pcw_len);
35923db86aabSstevel #endif
35933db86aabSstevel
35943db86aabSstevel /* window must be enabled */
35953db86aabSstevel if (!(memp->pcw_status & PCW_ENABLED))
35963db86aabSstevel return (BAD_ATTRIBUTE);
35973db86aabSstevel
35983db86aabSstevel /* find the register set offset */
35993db86aabSstevel select = window * PCIC_MEM_1_OFFSET;
36003db86aabSstevel #if defined(PCIC_DEBUG)
36013db86aabSstevel if (pcic_debug)
36023db86aabSstevel cmn_err(CE_CONT, "\tselect=%x\n", select);
36033db86aabSstevel #endif
36043db86aabSstevel
36053db86aabSstevel /*
36063db86aabSstevel * now map the card's memory pages - we start with page 0
36073db86aabSstevel */
36083db86aabSstevel
36093db86aabSstevel which = 0; /* assume simple case */
36103db86aabSstevel if (page->state & PS_ATTRIBUTE) {
36113db86aabSstevel which |= CARDMEM_REG_ACTIVE;
36123db86aabSstevel memp->pcw_status |= PCW_ATTRIBUTE;
36133db86aabSstevel } else {
36143db86aabSstevel memp->pcw_status &= ~PCW_ATTRIBUTE;
36153db86aabSstevel }
36163db86aabSstevel
36173db86aabSstevel /*
36183db86aabSstevel * if caller says Write Protect, enforce it.
36193db86aabSstevel */
36203db86aabSstevel if (page->state & PS_WP) {
36213db86aabSstevel which |= CARDMEM_WRITE_PROTECT;
36223db86aabSstevel memp->pcw_status |= PCW_WP;
36233db86aabSstevel } else {
36243db86aabSstevel memp->pcw_status &= ~PCW_WP;
36253db86aabSstevel }
36263db86aabSstevel #if defined(PCIC_DEBUG)
36273db86aabSstevel if (pcic_debug) {
36283db86aabSstevel cmn_err(CE_CONT, "\tmemory type = %s\n",
36293db86aabSstevel (which & CARDMEM_REG_ACTIVE) ? "attribute" : "common");
36303db86aabSstevel if (which & CARDMEM_WRITE_PROTECT)
36313db86aabSstevel cmn_err(CE_CONT, "\twrite protect\n");
36323db86aabSstevel cmn_err(CE_CONT, "\tpage offset=%x pcw_base=%x (%x)\n",
36333db86aabSstevel (unsigned)page->offset,
36343db86aabSstevel (unsigned)memp->pcw_base,
36353db86aabSstevel (int)page->offset - (int)memp->pcw_base & 0xffffff);
36363db86aabSstevel }
36373db86aabSstevel #endif
36383db86aabSstevel /* address computation based on 64MB range and not larger */
36393db86aabSstevel base = (uint32_t)memp->pcw_base & 0x3ffffff;
36403db86aabSstevel pcic_putb(pcic, socket, PCIC_CARDMEM_0_LOW + select,
36413db86aabSstevel CARDMEM_LOW((int)page->offset - (int)base));
36423db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_CARDMEM_0_LOW + select);
36433db86aabSstevel pcic_putb(pcic, socket, PCIC_CARDMEM_0_HI + select,
36443db86aabSstevel CARDMEM_HIGH((int)page->offset - base) | which);
36453db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_CARDMEM_0_HI + select);
36463db86aabSstevel
36473db86aabSstevel /*
36483db86aabSstevel * while not really necessary, this just makes sure
36493db86aabSstevel * nothing turned the window off behind our backs
36503db86aabSstevel */
36513db86aabSstevel which = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
36523db86aabSstevel which |= SYSMEM_WINDOW(window);
36533db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, which);
36543db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
36553db86aabSstevel
36563db86aabSstevel memp->pcw_offset = (off_t)page->offset;
36573db86aabSstevel
36583db86aabSstevel #if defined(PCIC_DEBUG)
36593db86aabSstevel if (pcic_debug) {
36603db86aabSstevel cmn_err(CE_CONT, "\tbase=%p, *base=%x\n",
36613db86aabSstevel (void *)memp->pcw_hostmem,
36623db86aabSstevel (uint32_t)*memp->pcw_hostmem);
36633db86aabSstevel
36643db86aabSstevel xxdmp_all_regs(pcic, socket, -1);
36653db86aabSstevel
36663db86aabSstevel cmn_err(CE_CONT, "\tbase=%p, *base=%x\n",
36673db86aabSstevel (void *)memp->pcw_hostmem,
36683db86aabSstevel (uint32_t)*memp->pcw_hostmem);
36693db86aabSstevel }
36703db86aabSstevel #endif
36713db86aabSstevel
36723db86aabSstevel if (which & PCW_ATTRIBUTE)
36733db86aabSstevel pcic_mswait(pcic, socket, 2);
36743db86aabSstevel
36753db86aabSstevel mutex_exit(&pcic->pc_lock);
36763db86aabSstevel
36773db86aabSstevel return (SUCCESS);
36783db86aabSstevel }
36793db86aabSstevel
36803db86aabSstevel /*
36813db86aabSstevel * pcic_set_vcc_level()
36823db86aabSstevel *
36833db86aabSstevel * set voltage based on adapter information
36843db86aabSstevel *
36853db86aabSstevel * this routine implements a limited solution for support of 3.3v cards.
36863db86aabSstevel * the general solution, which would fully support the pcmcia spec
36873db86aabSstevel * as far as allowing client drivers to request which voltage levels
36883db86aabSstevel * to be set, requires more framework support and driver changes - ess
36893db86aabSstevel */
36903db86aabSstevel static int
pcic_set_vcc_level(pcicdev_t * pcic,set_socket_t * socket)36913db86aabSstevel pcic_set_vcc_level(pcicdev_t *pcic, set_socket_t *socket)
36923db86aabSstevel {
36933db86aabSstevel uint32_t socket_present_state;
36943db86aabSstevel
36953db86aabSstevel #if defined(PCIC_DEBUG)
36963db86aabSstevel if (pcic_debug) {
36973db86aabSstevel cmn_err(CE_CONT,
36983db86aabSstevel "pcic_set_vcc_level(pcic=%p, VccLevel=%d)\n",
36993db86aabSstevel (void *)pcic, socket->VccLevel);
37003db86aabSstevel }
37013db86aabSstevel #endif
37023db86aabSstevel
37033db86aabSstevel /*
37043db86aabSstevel * check VccLevel
37053db86aabSstevel * if this is zero, power is being turned off
37063db86aabSstevel * if it is non-zero, power is being turned on.
37073db86aabSstevel */
37083db86aabSstevel if (socket->VccLevel == 0) {
37093db86aabSstevel return (0);
37103db86aabSstevel }
37113db86aabSstevel
37123db86aabSstevel /*
37133db86aabSstevel * range checking for sanity's sake
37143db86aabSstevel */
37153db86aabSstevel if (socket->VccLevel >= pcic->pc_numpower) {
37163db86aabSstevel return (BAD_VCC);
37173db86aabSstevel }
37183db86aabSstevel
37193db86aabSstevel switch (pcic->pc_io_type) {
37203db86aabSstevel /*
37213db86aabSstevel * Yenta-compliant adapters have vcc info in the extended registers
37223db86aabSstevel * Other adapters can be added as needed, but the 'default' case
37233db86aabSstevel * has been left as it was previously so as not to break existing
37243db86aabSstevel * adapters.
37253db86aabSstevel */
37263db86aabSstevel case PCIC_IO_TYPE_YENTA:
37273db86aabSstevel /*
37283db86aabSstevel * Here we ignore the VccLevel passed in and read the
37293db86aabSstevel * card type from the adapter socket present state register
37303db86aabSstevel */
37313db86aabSstevel socket_present_state =
37323db86aabSstevel ddi_get32(pcic->handle, (uint32_t *)(pcic->ioaddr +
37333db86aabSstevel PCIC_PRESENT_STATE_REG));
37343db86aabSstevel #if defined(PCIC_DEBUG)
37353db86aabSstevel if (pcic_debug) {
37363db86aabSstevel cmn_err(CE_CONT,
37373db86aabSstevel "socket present state = 0x%x\n",
37383db86aabSstevel socket_present_state);
37393db86aabSstevel }
37403db86aabSstevel #endif
37413db86aabSstevel switch (socket_present_state & PCIC_VCC_MASK) {
37423db86aabSstevel case PCIC_VCC_3VCARD:
37433db86aabSstevel /* fall through */
37443db86aabSstevel case PCIC_VCC_3VCARD|PCIC_VCC_5VCARD:
37453db86aabSstevel socket->VccLevel = PCIC_VCC_3VLEVEL;
37463db86aabSstevel return
37473db86aabSstevel (POWER_3VCARD_ENABLE|POWER_OUTPUT_ENABLE);
37483db86aabSstevel case PCIC_VCC_5VCARD:
37493db86aabSstevel socket->VccLevel = PCIC_VCC_5VLEVEL;
37503db86aabSstevel return
37513db86aabSstevel (POWER_CARD_ENABLE|POWER_OUTPUT_ENABLE);
37523db86aabSstevel default:
37533db86aabSstevel /*
37543db86aabSstevel * if no card is present, this can be the
37553db86aabSstevel * case of a client making a SetSocket call
37563db86aabSstevel * after card removal. In this case we return
37573db86aabSstevel * the current power level
37583db86aabSstevel */
37593db86aabSstevel return ((unsigned)ddi_get8(pcic->handle,
37603db86aabSstevel pcic->ioaddr + CB_R2_OFFSET +
37613db86aabSstevel PCIC_POWER_CONTROL));
37623db86aabSstevel }
37633db86aabSstevel
37643db86aabSstevel default:
37653db86aabSstevel
37663db86aabSstevel switch (socket->VccLevel) {
37673db86aabSstevel case PCIC_VCC_3VLEVEL:
37683db86aabSstevel return (BAD_VCC);
37693db86aabSstevel case PCIC_VCC_5VLEVEL:
37703db86aabSstevel /* enable Vcc */
37713db86aabSstevel return (POWER_CARD_ENABLE|POWER_OUTPUT_ENABLE);
37723db86aabSstevel default:
37733db86aabSstevel return (BAD_VCC);
37743db86aabSstevel }
37753db86aabSstevel }
37763db86aabSstevel }
37773db86aabSstevel
37783db86aabSstevel
37793db86aabSstevel /*
37803db86aabSstevel * pcic_set_socket()
37813db86aabSstevel * Socket Services SetSocket call
37823db86aabSstevel * sets basic socket configuration
37833db86aabSstevel */
37843db86aabSstevel static int
pcic_set_socket(dev_info_t * dip,set_socket_t * socket)37853db86aabSstevel pcic_set_socket(dev_info_t *dip, set_socket_t *socket)
37863db86aabSstevel {
37873db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
37883db86aabSstevel pcicdev_t *pcic = anp->an_private;
37893db86aabSstevel pcic_socket_t *sockp = &pcic->pc_sockets[socket->socket];
37903db86aabSstevel int irq, interrupt, mirq;
37913db86aabSstevel int powerlevel = 0;
37923db86aabSstevel int ind, value, orig_pwrctl;
37933db86aabSstevel
37943db86aabSstevel #if defined(PCIC_DEBUG)
37953db86aabSstevel if (pcic_debug) {
37963db86aabSstevel cmn_err(CE_CONT,
37973db86aabSstevel "pcic_set_socket(dip=%p, socket=%d)"
37983db86aabSstevel " Vcc=%d Vpp1=%d Vpp2=%d\n", (void *)dip,
37993db86aabSstevel socket->socket, socket->VccLevel, socket->Vpp1Level,
38003db86aabSstevel socket->Vpp2Level);
38013db86aabSstevel }
38023db86aabSstevel #endif
38033db86aabSstevel /*
38043db86aabSstevel * check VccLevel, etc. before setting mutex
38053db86aabSstevel * if this is zero, power is being turned off
38063db86aabSstevel * if it is non-zero, power is being turned on.
38073db86aabSstevel * the default case is to assume Vcc only.
38083db86aabSstevel */
38093db86aabSstevel
38103db86aabSstevel /* this appears to be very implementation specific */
38113db86aabSstevel
38123db86aabSstevel if (socket->Vpp1Level != socket->Vpp2Level)
38133db86aabSstevel return (BAD_VPP);
38143db86aabSstevel
38153db86aabSstevel if (socket->VccLevel == 0 || !(sockp->pcs_flags & PCS_CARD_PRESENT)) {
38163db86aabSstevel powerlevel = 0;
38173db86aabSstevel sockp->pcs_vcc = 0;
38183db86aabSstevel sockp->pcs_vpp1 = 0;
38193db86aabSstevel sockp->pcs_vpp2 = 0;
38203db86aabSstevel } else {
38213db86aabSstevel #if defined(PCIC_DEBUG)
38223db86aabSstevel pcic_err(dip, 9, "\tVcc=%d Vpp1Level=%d, Vpp2Level=%d\n",
38233db86aabSstevel socket->VccLevel, socket->Vpp1Level, socket->Vpp2Level);
38243db86aabSstevel #endif
38253db86aabSstevel /* valid Vcc power level? */
38263db86aabSstevel if (socket->VccLevel >= pcic->pc_numpower)
38273db86aabSstevel return (BAD_VCC);
38283db86aabSstevel
38293db86aabSstevel switch (pcic_power[socket->VccLevel].PowerLevel) {
38303db86aabSstevel case 33: /* 3.3V */
38313db86aabSstevel case 60: /* for bad CIS in Option GPRS card */
38323db86aabSstevel if (!(pcic->pc_flags & PCF_33VCAP)) {
38333db86aabSstevel cmn_err(CE_WARN,
38343db86aabSstevel "%s%d: Bad Request for 3.3V "
38353db86aabSstevel "(Controller incapable)\n",
38363db86aabSstevel ddi_get_name(pcic->dip),
38373db86aabSstevel ddi_get_instance(pcic->dip));
38383db86aabSstevel return (BAD_VCC);
38393db86aabSstevel }
38403db86aabSstevel /* FALLTHROUGH */
38413db86aabSstevel case 50: /* 5V */
38423db86aabSstevel if ((pcic->pc_io_type == PCIC_IO_TYPE_YENTA) &&
38433db86aabSstevel pcic_getcb(pcic, CB_PRESENT_STATE) &
38443db86aabSstevel CB_PS_33VCARD) {
38453db86aabSstevel /*
38463db86aabSstevel * This is actually a 3.3V card.
38473db86aabSstevel * Solaris Card Services
38483db86aabSstevel * doesn't understand 3.3V
38493db86aabSstevel * so we cheat and change
38503db86aabSstevel * the setting to the one appropriate to 3.3V.
38513db86aabSstevel * Note that this is the entry number
38523db86aabSstevel * in the pcic_power[] array.
38533db86aabSstevel */
38543db86aabSstevel sockp->pcs_vcc = PCIC_VCC_3VLEVEL;
38553db86aabSstevel } else
38563db86aabSstevel sockp->pcs_vcc = socket->VccLevel;
38573db86aabSstevel break;
38583db86aabSstevel default:
38593db86aabSstevel return (BAD_VCC);
38603db86aabSstevel }
38613db86aabSstevel
38623db86aabSstevel /* enable Vcc */
38633db86aabSstevel powerlevel = POWER_CARD_ENABLE;
38643db86aabSstevel
38653db86aabSstevel #if defined(PCIC_DEBUG)
38663db86aabSstevel if (pcic_debug) {
38673db86aabSstevel cmn_err(CE_CONT, "\tVcc=%d powerlevel=%x\n",
38683db86aabSstevel socket->VccLevel, powerlevel);
38693db86aabSstevel }
38703db86aabSstevel #endif
38713db86aabSstevel ind = 0; /* default index to 0 power */
38723db86aabSstevel if ((int)socket->Vpp1Level >= 0 &&
38733db86aabSstevel socket->Vpp1Level < pcic->pc_numpower) {
38743db86aabSstevel if (!(pcic_power[socket->Vpp1Level].ValidSignals
38753db86aabSstevel & VPP1)) {
38763db86aabSstevel return (BAD_VPP);
38773db86aabSstevel }
38783db86aabSstevel ind = pcic_power[socket->Vpp1Level].PowerLevel/10;
38793db86aabSstevel powerlevel |= pcic_vpp_levels[ind];
38803db86aabSstevel sockp->pcs_vpp1 = socket->Vpp1Level;
38813db86aabSstevel }
38823db86aabSstevel if ((int)socket->Vpp2Level >= 0 &&
38833db86aabSstevel socket->Vpp2Level < pcic->pc_numpower) {
38843db86aabSstevel if (!(pcic_power[socket->Vpp2Level].ValidSignals
38853db86aabSstevel & VPP2)) {
38863db86aabSstevel return (BAD_VPP);
38873db86aabSstevel }
38883db86aabSstevel ind = pcic_power[socket->Vpp2Level].PowerLevel/10;
38893db86aabSstevel powerlevel |= (pcic_vpp_levels[ind] << 2);
38903db86aabSstevel sockp->pcs_vpp2 = socket->Vpp2Level;
38913db86aabSstevel }
38923db86aabSstevel
38933db86aabSstevel if (pcic->pc_flags & PCF_VPPX) {
38943db86aabSstevel /*
38953db86aabSstevel * this adapter doesn't allow separate Vpp1/Vpp2
38963db86aabSstevel * if one is turned on, both are turned on and only
38973db86aabSstevel * the Vpp1 bits should be set
38983db86aabSstevel */
38993db86aabSstevel if (sockp->pcs_vpp2 != sockp->pcs_vpp1) {
39003db86aabSstevel /* must be the same if one not zero */
39013db86aabSstevel if (sockp->pcs_vpp1 != 0 &&
39023db86aabSstevel sockp->pcs_vpp2 != 0) {
39033db86aabSstevel cmn_err(CE_WARN,
39043db86aabSstevel "%s%d: Bad Power Request "
39053db86aabSstevel "(Vpp1/2 not the same)\n",
39063db86aabSstevel ddi_get_name(pcic->dip),
39073db86aabSstevel ddi_get_instance(pcic->dip));
39083db86aabSstevel return (BAD_VPP);
39093db86aabSstevel }
39103db86aabSstevel }
39113db86aabSstevel powerlevel &= ~(3<<2);
39123db86aabSstevel }
39133db86aabSstevel
39143db86aabSstevel #if defined(PCIC_DEBUG)
39153db86aabSstevel if (pcic_debug) {
39163db86aabSstevel cmn_err(CE_CONT, "\tpowerlevel=%x, ind=%x\n",
39173db86aabSstevel powerlevel, ind);
39183db86aabSstevel }
39193db86aabSstevel #endif
39203db86aabSstevel }
39213db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */
39223db86aabSstevel
39233db86aabSstevel /* turn socket->IREQRouting off while programming */
39243db86aabSstevel interrupt = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT);
39253db86aabSstevel interrupt &= ~PCIC_INTR_MASK;
39263db86aabSstevel if (pcic->pc_flags & PCF_USE_SMI)
39273db86aabSstevel interrupt |= PCIC_INTR_ENABLE;
39283db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, interrupt);
39293db86aabSstevel
39303db86aabSstevel switch (pcic->pc_type) {
39313db86aabSstevel case PCIC_INTEL_i82092:
39323db86aabSstevel pcic_82092_smiirq_ctl(pcic, socket->socket, PCIC_82092_CTL_IRQ,
39333db86aabSstevel PCIC_82092_INT_DISABLE);
39343db86aabSstevel break;
39353db86aabSstevel default:
39363db86aabSstevel break;
39373db86aabSstevel } /* switch */
39383db86aabSstevel
39393db86aabSstevel /* the SCIntMask specifies events to detect */
39403db86aabSstevel mirq = pcic_getb(pcic, socket->socket, PCIC_MANAGEMENT_INT);
39413db86aabSstevel
39423db86aabSstevel #if defined(PCIC_DEBUG)
39433db86aabSstevel if (pcic_debug)
39443db86aabSstevel cmn_err(CE_CONT,
39453db86aabSstevel "\tSCIntMask=%x, interrupt=%x, mirq=%x\n",
39463db86aabSstevel socket->SCIntMask, interrupt, mirq);
39473db86aabSstevel #endif
39483db86aabSstevel mirq &= ~(PCIC_BD_DETECT|PCIC_BW_DETECT|PCIC_RD_DETECT);
39493db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MANAGEMENT_INT,
39503db86aabSstevel mirq & ~PCIC_CHANGE_MASK);
39513db86aabSstevel
39523db86aabSstevel /* save the mask we want to use */
39533db86aabSstevel sockp->pcs_intmask = socket->SCIntMask;
39543db86aabSstevel
39553db86aabSstevel /*
39563db86aabSstevel * Until there is a card present it's not worth enabling
39573db86aabSstevel * any interrupts except "Card detect". This is done
39583db86aabSstevel * elsewhere in the driver so don't change things if
39593db86aabSstevel * there is no card!
39603db86aabSstevel */
39613db86aabSstevel if (sockp->pcs_flags & PCS_CARD_PRESENT) {
39623db86aabSstevel
39633db86aabSstevel /* now update the hardware to reflect events desired */
39643db86aabSstevel if (sockp->pcs_intmask & SBM_BVD1 || socket->IFType == IF_IO)
39653db86aabSstevel mirq |= PCIC_BD_DETECT;
39663db86aabSstevel
39673db86aabSstevel if (sockp->pcs_intmask & SBM_BVD2)
39683db86aabSstevel mirq |= PCIC_BW_DETECT;
39693db86aabSstevel
39703db86aabSstevel if (sockp->pcs_intmask & SBM_RDYBSY)
39713db86aabSstevel mirq |= PCIC_RD_DETECT;
39723db86aabSstevel
39733db86aabSstevel if (sockp->pcs_intmask & SBM_CD)
39743db86aabSstevel mirq |= PCIC_CD_DETECT;
39753db86aabSstevel }
39763db86aabSstevel
39773db86aabSstevel if (sockp->pcs_flags & PCS_READY) {
39783db86aabSstevel /*
39793db86aabSstevel * card just came ready.
39803db86aabSstevel * make sure enough time elapses
39813db86aabSstevel * before touching it.
39823db86aabSstevel */
39833db86aabSstevel sockp->pcs_flags &= ~PCS_READY;
39843db86aabSstevel pcic_mswait(pcic, socket->socket, 10);
39853db86aabSstevel }
39863db86aabSstevel
39873db86aabSstevel #if defined(PCIC_DEBUG)
39883db86aabSstevel if (pcic_debug) {
39893db86aabSstevel cmn_err(CE_CONT, "\tstatus change set to %x\n", mirq);
39903db86aabSstevel }
39913db86aabSstevel #endif
39923db86aabSstevel
39933db86aabSstevel switch (pcic->pc_type) {
39943db86aabSstevel case PCIC_I82365SL:
39953db86aabSstevel case PCIC_VADEM:
39963db86aabSstevel case PCIC_VADEM_VG469:
39973db86aabSstevel /*
39983db86aabSstevel * The Intel version has different options. This is a
39993db86aabSstevel * special case of GPI which might be used for eject
40003db86aabSstevel */
40013db86aabSstevel
40023db86aabSstevel irq = pcic_getb(pcic, socket->socket, PCIC_CARD_DETECT);
40033db86aabSstevel if (sockp->pcs_intmask & (SBM_EJECT|SBM_INSERT) &&
40043db86aabSstevel pcic->pc_flags & PCF_GPI_EJECT) {
40053db86aabSstevel irq |= PCIC_GPI_ENABLE;
40063db86aabSstevel } else {
40073db86aabSstevel irq &= ~PCIC_GPI_ENABLE;
40083db86aabSstevel }
40093db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_CARD_DETECT, irq);
40103db86aabSstevel break;
40113db86aabSstevel case PCIC_CL_PD6710:
40123db86aabSstevel case PCIC_CL_PD6722:
40133db86aabSstevel if (socket->IFType == IF_IO) {
40143db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_2, 0x0);
40153db86aabSstevel value = pcic_getb(pcic, socket->socket,
40163db86aabSstevel PCIC_MISC_CTL_1);
40173db86aabSstevel if (pcic->pc_flags & PCF_AUDIO)
40183db86aabSstevel value |= PCIC_MC_SPEAKER_ENB;
40193db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1,
40203db86aabSstevel value);
40213db86aabSstevel } else {
40223db86aabSstevel value = pcic_getb(pcic, socket->socket,
40233db86aabSstevel PCIC_MISC_CTL_1);
40243db86aabSstevel value &= ~PCIC_MC_SPEAKER_ENB;
40253db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1,
40263db86aabSstevel value);
40273db86aabSstevel }
40283db86aabSstevel break;
40293db86aabSstevel case PCIC_CL_PD6729:
40303db86aabSstevel case PCIC_CL_PD6730:
40313db86aabSstevel case PCIC_CL_PD6832:
40323db86aabSstevel value = pcic_getb(pcic, socket->socket, PCIC_MISC_CTL_1);
40333db86aabSstevel if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) {
40343db86aabSstevel value |= PCIC_MC_SPEAKER_ENB;
40353db86aabSstevel } else {
40363db86aabSstevel value &= ~PCIC_MC_SPEAKER_ENB;
40373db86aabSstevel }
40383db86aabSstevel
40393db86aabSstevel if (pcic_power[sockp->pcs_vcc].PowerLevel == 33)
40403db86aabSstevel value |= PCIC_MC_3VCC;
40413db86aabSstevel else
40423db86aabSstevel value &= ~PCIC_MC_3VCC;
40433db86aabSstevel
40443db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1, value);
40453db86aabSstevel break;
40463db86aabSstevel
40473db86aabSstevel case PCIC_O2_OZ6912:
40483db86aabSstevel value = pcic_getcb(pcic, CB_MISCCTRL);
40493db86aabSstevel if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO))
40503db86aabSstevel value |= (1<<25);
40513db86aabSstevel else
40523db86aabSstevel value &= ~(1<<25);
40533db86aabSstevel pcic_putcb(pcic, CB_MISCCTRL, value);
40543db86aabSstevel if (pcic_power[sockp->pcs_vcc].PowerLevel == 33)
40553db86aabSstevel powerlevel |= 0x08;
40563db86aabSstevel break;
40573db86aabSstevel
40583db86aabSstevel case PCIC_TI_PCI1250:
40593db86aabSstevel case PCIC_TI_PCI1221:
40603db86aabSstevel case PCIC_TI_PCI1225:
40613db86aabSstevel case PCIC_TI_PCI1410:
40623db86aabSstevel case PCIC_ENE_1410:
40633db86aabSstevel case PCIC_TI_PCI1510:
40643db86aabSstevel case PCIC_TI_PCI1520:
40653db86aabSstevel case PCIC_TI_PCI1420:
40663db86aabSstevel case PCIC_ENE_1420:
40673db86aabSstevel value = ddi_get8(pcic->cfg_handle,
40683db86aabSstevel pcic->cfgaddr + PCIC_CRDCTL_REG);
40693db86aabSstevel if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) {
40703db86aabSstevel value |= PCIC_CRDCTL_SPKR_ENBL;
40713db86aabSstevel } else {
40723db86aabSstevel value &= ~PCIC_CRDCTL_SPKR_ENBL;
40733db86aabSstevel }
40743db86aabSstevel ddi_put8(pcic->cfg_handle,
40753db86aabSstevel pcic->cfgaddr + PCIC_CRDCTL_REG, value);
40763db86aabSstevel if (pcic_power[sockp->pcs_vcc].PowerLevel == 33)
40773db86aabSstevel powerlevel |= 0x08;
40783db86aabSstevel break;
40793db86aabSstevel }
40803db86aabSstevel
40813db86aabSstevel /*
40823db86aabSstevel * ctlind processing -- we can ignore this
40833db86aabSstevel * there aren't any outputs on the chip for this and
40843db86aabSstevel * the GUI will display what it thinks is correct
40853db86aabSstevel */
40863db86aabSstevel
40873db86aabSstevel /*
40883db86aabSstevel * If outputs are enabled and the power is going off
40893db86aabSstevel * turn off outputs first.
40903db86aabSstevel */
40913db86aabSstevel
40923db86aabSstevel /* power setup -- if necessary */
40933db86aabSstevel orig_pwrctl = pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL);
40943db86aabSstevel if ((orig_pwrctl & POWER_OUTPUT_ENABLE) && sockp->pcs_vcc == 0) {
40953db86aabSstevel orig_pwrctl &= ~POWER_OUTPUT_ENABLE;
40963db86aabSstevel pcic_putb(pcic, socket->socket,
40973db86aabSstevel PCIC_POWER_CONTROL, orig_pwrctl);
40983db86aabSstevel (void) pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL);
40993db86aabSstevel }
41003db86aabSstevel
41013db86aabSstevel if (pcic->pc_flags & PCF_CBPWRCTL) {
41023db86aabSstevel value = pcic_cbus_powerctl(pcic, socket->socket);
41033db86aabSstevel powerlevel = 0;
41043db86aabSstevel } else
41053db86aabSstevel value = pcic_exca_powerctl(pcic, socket->socket, powerlevel);
41063db86aabSstevel
41073db86aabSstevel if (value != SUCCESS) {
41083db86aabSstevel mutex_exit(&pcic->pc_lock);
41093db86aabSstevel return (value);
41103db86aabSstevel }
41113db86aabSstevel
41123db86aabSstevel /*
41133db86aabSstevel * If outputs were disabled and the power is going on
41143db86aabSstevel * turn on outputs afterwards.
41153db86aabSstevel */
41163db86aabSstevel if (!(orig_pwrctl & POWER_OUTPUT_ENABLE) && sockp->pcs_vcc != 0) {
41173db86aabSstevel orig_pwrctl = pcic_getb(pcic, socket->socket,
41183db86aabSstevel PCIC_POWER_CONTROL);
41193db86aabSstevel orig_pwrctl |= POWER_OUTPUT_ENABLE;
41203db86aabSstevel pcic_putb(pcic, socket->socket,
41213db86aabSstevel PCIC_POWER_CONTROL, orig_pwrctl);
41223db86aabSstevel (void) pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL);
41233db86aabSstevel }
41243db86aabSstevel
41253db86aabSstevel /*
41263db86aabSstevel * Once we have done the power stuff can re-enable management
41273db86aabSstevel * interrupts.
41283db86aabSstevel */
41293db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MANAGEMENT_INT, mirq);
41303db86aabSstevel
41313db86aabSstevel #if defined(PCIC_DEBUG)
41323db86aabSstevel pcic_err(dip, 8, "\tmanagement int set to %x pwrctl to 0x%x "
41333db86aabSstevel "cbctl 0x%x\n",
41343db86aabSstevel mirq, pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL),
41353db86aabSstevel pcic_getcb(pcic, CB_CONTROL));
41363db86aabSstevel #endif
41373db86aabSstevel
41383db86aabSstevel /* irq processing */
41393db86aabSstevel if (socket->IFType == IF_IO) {
41403db86aabSstevel /* IRQ only for I/O */
41413db86aabSstevel irq = socket->IREQRouting & PCIC_INTR_MASK;
41423db86aabSstevel value = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT);
41433db86aabSstevel value &= ~PCIC_INTR_MASK;
41443db86aabSstevel
41453db86aabSstevel /* to enable I/O operation */
41463db86aabSstevel value |= PCIC_IO_CARD | PCIC_RESET;
41473db86aabSstevel sockp->pcs_flags |= PCS_CARD_IO;
41483db86aabSstevel if (irq != sockp->pcs_irq) {
41493db86aabSstevel if (sockp->pcs_irq != 0)
41503db86aabSstevel cmn_err(CE_CONT,
41513db86aabSstevel "SetSocket: IRQ mismatch %x != %x!\n",
41523db86aabSstevel irq, sockp->pcs_irq);
41533db86aabSstevel else
41543db86aabSstevel sockp->pcs_irq = irq;
41553db86aabSstevel }
41563db86aabSstevel irq = sockp->pcs_irq;
41573db86aabSstevel
41583db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, value);
41593db86aabSstevel if (socket->IREQRouting & IRQ_ENABLE) {
41603db86aabSstevel pcic_enable_io_intr(pcic, socket->socket, irq);
41613db86aabSstevel sockp->pcs_flags |= PCS_IRQ_ENABLED;
41623db86aabSstevel } else {
41633db86aabSstevel pcic_disable_io_intr(pcic, socket->socket);
41643db86aabSstevel sockp->pcs_flags &= ~PCS_IRQ_ENABLED;
41653db86aabSstevel }
41663db86aabSstevel #if defined(PCIC_DEBUG)
41673db86aabSstevel if (pcic_debug) {
41683db86aabSstevel cmn_err(CE_CONT,
41693db86aabSstevel "\tsocket type is I/O and irq %x is %s\n", irq,
41703db86aabSstevel (socket->IREQRouting & IRQ_ENABLE) ?
41713db86aabSstevel "enabled" : "not enabled");
41723db86aabSstevel xxdmp_all_regs(pcic, socket->socket, 20);
41733db86aabSstevel }
41743db86aabSstevel #endif
41753db86aabSstevel } else {
41763db86aabSstevel /* make sure I/O mode is off */
41773db86aabSstevel
41783db86aabSstevel sockp->pcs_irq = 0;
41793db86aabSstevel
41803db86aabSstevel value = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT);
41813db86aabSstevel value &= ~PCIC_IO_CARD;
41823db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, value);
41833db86aabSstevel pcic_disable_io_intr(pcic, socket->socket);
41843db86aabSstevel sockp->pcs_flags &= ~(PCS_CARD_IO|PCS_IRQ_ENABLED);
41853db86aabSstevel }
41863db86aabSstevel
41873db86aabSstevel sockp->pcs_state &= ~socket->State;
41883db86aabSstevel
41893db86aabSstevel mutex_exit(&pcic->pc_lock);
41903db86aabSstevel return (SUCCESS);
41913db86aabSstevel }
41923db86aabSstevel
41933db86aabSstevel /*
41943db86aabSstevel * pcic_inquire_socket()
41953db86aabSstevel * SocketServices InquireSocket function
41963db86aabSstevel * returns basic characteristics of the socket
41973db86aabSstevel */
41983db86aabSstevel /*ARGSUSED*/
41993db86aabSstevel static int
pcic_inquire_socket(dev_info_t * dip,inquire_socket_t * socket)42003db86aabSstevel pcic_inquire_socket(dev_info_t *dip, inquire_socket_t *socket)
42013db86aabSstevel {
42023db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
42033db86aabSstevel pcicdev_t *pcic = anp->an_private;
42043db86aabSstevel int value;
42053db86aabSstevel
42063db86aabSstevel socket->SCIntCaps = PCIC_DEFAULT_INT_CAPS;
42073db86aabSstevel socket->SCRptCaps = PCIC_DEFAULT_RPT_CAPS;
42083db86aabSstevel socket->CtlIndCaps = PCIC_DEFAULT_CTL_CAPS;
42093db86aabSstevel value = pcic->pc_sockets[socket->socket].pcs_flags;
42103db86aabSstevel socket->SocketCaps = (value & PCS_SOCKET_IO) ? IF_IO : IF_MEMORY;
42113db86aabSstevel socket->ActiveHigh = 0;
42123db86aabSstevel /* these are the usable IRQs */
42133db86aabSstevel socket->ActiveLow = 0xfff0;
42143db86aabSstevel return (SUCCESS);
42153db86aabSstevel }
42163db86aabSstevel
42173db86aabSstevel /*
42183db86aabSstevel * pcic_inquire_window()
42193db86aabSstevel * SocketServices InquireWindow function
42203db86aabSstevel * returns detailed characteristics of the window
42213db86aabSstevel * this is where windows get tied to sockets
42223db86aabSstevel */
42233db86aabSstevel /*ARGSUSED*/
42243db86aabSstevel static int
pcic_inquire_window(dev_info_t * dip,inquire_window_t * window)42253db86aabSstevel pcic_inquire_window(dev_info_t *dip, inquire_window_t *window)
42263db86aabSstevel {
42273db86aabSstevel int type, socket;
42283db86aabSstevel
42293db86aabSstevel type = window->window % PCIC_NUMWINSOCK;
42303db86aabSstevel socket = window->window / PCIC_NUMWINSOCK;
42313db86aabSstevel
42323db86aabSstevel #if defined(PCIC_DEBUG)
42333db86aabSstevel if (pcic_debug >= 8)
42343db86aabSstevel cmn_err(CE_CONT,
42353db86aabSstevel "pcic_inquire_window: window = %d/%d socket=%d\n",
42363db86aabSstevel window->window, type, socket);
42373db86aabSstevel #endif
42383db86aabSstevel if (type < PCIC_IOWINDOWS) {
42393db86aabSstevel window->WndCaps = WC_IO|WC_WAIT;
42403db86aabSstevel type = IF_IO;
42413db86aabSstevel } else {
42423db86aabSstevel window->WndCaps = WC_COMMON|WC_ATTRIBUTE|WC_WAIT;
42433db86aabSstevel type = IF_MEMORY;
42443db86aabSstevel }
42453db86aabSstevel
42463db86aabSstevel /* initialize the socket map - one socket per window */
42473db86aabSstevel PR_ZERO(window->Sockets);
42483db86aabSstevel PR_SET(window->Sockets, socket);
42493db86aabSstevel
42503db86aabSstevel if (type == IF_IO) {
42513db86aabSstevel iowin_char_t *io;
42523db86aabSstevel io = &window->iowin_char;
42533db86aabSstevel io->IOWndCaps = WC_BASE|WC_SIZE|WC_WENABLE|WC_8BIT|
42543db86aabSstevel WC_16BIT;
42553db86aabSstevel io->FirstByte = (baseaddr_t)IOMEM_FIRST;
42563db86aabSstevel io->LastByte = (baseaddr_t)IOMEM_LAST;
42573db86aabSstevel io->MinSize = IOMEM_MIN;
42583db86aabSstevel io->MaxSize = IOMEM_MAX;
42593db86aabSstevel io->ReqGran = IOMEM_GRAN;
42603db86aabSstevel io->AddrLines = IOMEM_DECODE;
42613db86aabSstevel io->EISASlot = 0;
42623db86aabSstevel } else {
42633db86aabSstevel mem_win_char_t *mem;
42643db86aabSstevel mem = &window->mem_win_char;
42653db86aabSstevel mem->MemWndCaps = WC_BASE|WC_SIZE|WC_WENABLE|WC_8BIT|
42663db86aabSstevel WC_16BIT|WC_WP;
42673db86aabSstevel
42683db86aabSstevel mem->FirstByte = (baseaddr_t)MEM_FIRST;
42693db86aabSstevel mem->LastByte = (baseaddr_t)MEM_LAST;
42703db86aabSstevel
42713db86aabSstevel mem->MinSize = MEM_MIN;
42723db86aabSstevel mem->MaxSize = MEM_MAX;
42733db86aabSstevel mem->ReqGran = PCIC_PAGE;
42743db86aabSstevel mem->ReqBase = 0;
42753db86aabSstevel mem->ReqOffset = PCIC_PAGE;
42763db86aabSstevel mem->Slowest = MEM_SPEED_MAX;
42773db86aabSstevel mem->Fastest = MEM_SPEED_MIN;
42783db86aabSstevel }
42793db86aabSstevel return (SUCCESS);
42803db86aabSstevel }
42813db86aabSstevel
42823db86aabSstevel /*
42833db86aabSstevel * pcic_get_adapter()
42843db86aabSstevel * SocketServices GetAdapter function
42853db86aabSstevel * this is nearly a no-op.
42863db86aabSstevel */
42873db86aabSstevel /*ARGSUSED*/
42883db86aabSstevel static int
pcic_get_adapter(dev_info_t * dip,get_adapter_t * adapt)42893db86aabSstevel pcic_get_adapter(dev_info_t *dip, get_adapter_t *adapt)
42903db86aabSstevel {
42913db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
42923db86aabSstevel pcicdev_t *pcic = anp->an_private;
42933db86aabSstevel
42943db86aabSstevel if (pcic->pc_flags & PCF_INTRENAB)
42953db86aabSstevel adapt->SCRouting = IRQ_ENABLE;
42963db86aabSstevel adapt->state = 0;
42973db86aabSstevel return (SUCCESS);
42983db86aabSstevel }
42993db86aabSstevel
43003db86aabSstevel /*
43013db86aabSstevel * pcic_get_page()
43023db86aabSstevel * SocketServices GetPage function
43033db86aabSstevel * returns info about the window
43043db86aabSstevel */
43053db86aabSstevel /*ARGSUSED*/
43063db86aabSstevel static int
pcic_get_page(dev_info_t * dip,get_page_t * page)43073db86aabSstevel pcic_get_page(dev_info_t *dip, get_page_t *page)
43083db86aabSstevel {
43093db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
43103db86aabSstevel pcicdev_t *pcic = anp->an_private;
43113db86aabSstevel int socket, window;
43123db86aabSstevel pcs_memwin_t *winp;
43133db86aabSstevel
43143db86aabSstevel socket = page->window / PCIC_NUMWINSOCK;
43153db86aabSstevel window = page->window % PCIC_NUMWINSOCK;
43163db86aabSstevel
43173db86aabSstevel /* I/O windows are the first two */
43183db86aabSstevel if (window < PCIC_IOWINDOWS || socket >= pcic->pc_numsockets) {
43193db86aabSstevel return (BAD_WINDOW);
43203db86aabSstevel }
43213db86aabSstevel
43223db86aabSstevel winp = &pcic->pc_sockets[socket].pcs_windows[window].mem;
43233db86aabSstevel
43243db86aabSstevel if (page->page != 0)
43253db86aabSstevel return (BAD_PAGE);
43263db86aabSstevel
43273db86aabSstevel page->state = 0;
43283db86aabSstevel if (winp->pcw_status & PCW_ENABLED)
43293db86aabSstevel page->state |= PS_ENABLED;
43303db86aabSstevel if (winp->pcw_status & PCW_ATTRIBUTE)
43313db86aabSstevel page->state |= PS_ATTRIBUTE;
43323db86aabSstevel if (winp->pcw_status & PCW_WP)
43333db86aabSstevel page->state |= PS_WP;
43343db86aabSstevel
43353db86aabSstevel page->offset = (off_t)winp->pcw_offset;
43363db86aabSstevel
43373db86aabSstevel return (SUCCESS);
43383db86aabSstevel }
43393db86aabSstevel
43403db86aabSstevel /*
43413db86aabSstevel * pcic_get_socket()
43423db86aabSstevel * SocketServices GetSocket
43433db86aabSstevel * returns information about the current socket setting
43443db86aabSstevel */
43453db86aabSstevel /*ARGSUSED*/
43463db86aabSstevel static int
pcic_get_socket(dev_info_t * dip,get_socket_t * socket)43473db86aabSstevel pcic_get_socket(dev_info_t *dip, get_socket_t *socket)
43483db86aabSstevel {
43493db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
43503db86aabSstevel pcicdev_t *pcic = anp->an_private;
43513db86aabSstevel int socknum, irq_enabled;
43523db86aabSstevel pcic_socket_t *sockp;
43533db86aabSstevel
43543db86aabSstevel socknum = socket->socket;
43553db86aabSstevel sockp = &pcic->pc_sockets[socknum];
43563db86aabSstevel
43573db86aabSstevel socket->SCIntMask = sockp->pcs_intmask;
43583db86aabSstevel sockp->pcs_state = pcic_card_state(pcic, sockp);
43593db86aabSstevel
43603db86aabSstevel socket->state = sockp->pcs_state;
43613db86aabSstevel if (socket->state & SBM_CD) {
43623db86aabSstevel socket->VccLevel = sockp->pcs_vcc;
43633db86aabSstevel socket->Vpp1Level = sockp->pcs_vpp1;
43643db86aabSstevel socket->Vpp2Level = sockp->pcs_vpp2;
43653db86aabSstevel irq_enabled = (sockp->pcs_flags & PCS_IRQ_ENABLED) ?
43663db86aabSstevel IRQ_ENABLE : 0;
43673db86aabSstevel socket->IRQRouting = sockp->pcs_irq | irq_enabled;
43683db86aabSstevel socket->IFType = (sockp->pcs_flags & PCS_CARD_IO) ?
43693db86aabSstevel IF_IO : IF_MEMORY;
43703db86aabSstevel } else {
43713db86aabSstevel socket->VccLevel = 0;
43723db86aabSstevel socket->Vpp1Level = 0;
43733db86aabSstevel socket->Vpp2Level = 0;
43743db86aabSstevel socket->IRQRouting = 0;
43753db86aabSstevel socket->IFType = IF_MEMORY;
43763db86aabSstevel }
43773db86aabSstevel socket->CtlInd = 0; /* no indicators */
43783db86aabSstevel
43793db86aabSstevel return (SUCCESS);
43803db86aabSstevel }
43813db86aabSstevel
43823db86aabSstevel /*
43833db86aabSstevel * pcic_get_status()
43843db86aabSstevel * SocketServices GetStatus
43853db86aabSstevel * returns status information about the PC Card in
43863db86aabSstevel * the selected socket
43873db86aabSstevel */
43883db86aabSstevel /*ARGSUSED*/
43893db86aabSstevel static int
pcic_get_status(dev_info_t * dip,get_ss_status_t * status)43903db86aabSstevel pcic_get_status(dev_info_t *dip, get_ss_status_t *status)
43913db86aabSstevel {
43923db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
43933db86aabSstevel pcicdev_t *pcic = anp->an_private;
43943db86aabSstevel int socknum, irq_enabled;
43953db86aabSstevel pcic_socket_t *sockp;
43963db86aabSstevel
43973db86aabSstevel socknum = status->socket;
43983db86aabSstevel sockp = &pcic->pc_sockets[socknum];
43993db86aabSstevel
44003db86aabSstevel status->CardState = pcic_card_state(pcic, sockp);
44013db86aabSstevel status->SocketState = sockp->pcs_state;
44023db86aabSstevel status->CtlInd = 0; /* no indicators */
44033db86aabSstevel
44043db86aabSstevel if (sockp->pcs_flags & PCS_CARD_PRESENT)
44053db86aabSstevel status->SocketState |= SBM_CD;
44063db86aabSstevel if (status->CardState & SBM_CD) {
44073db86aabSstevel irq_enabled = (sockp->pcs_flags & PCS_CARD_ENABLED) ?
44083db86aabSstevel IRQ_ENABLE : 0;
44093db86aabSstevel status->IRQRouting = sockp->pcs_irq | irq_enabled;
44103db86aabSstevel status->IFType = (sockp->pcs_flags & PCS_CARD_IO) ?
44113db86aabSstevel IF_IO : IF_MEMORY;
44123db86aabSstevel } else {
44133db86aabSstevel status->IRQRouting = 0;
44143db86aabSstevel status->IFType = IF_MEMORY;
44153db86aabSstevel }
44163db86aabSstevel
44173db86aabSstevel #if defined(PCIC_DEBUG)
44183db86aabSstevel if (pcic_debug >= 8)
44193db86aabSstevel cmn_err(CE_CONT, "pcic_get_status: socket=%d, CardState=%x,"
44203db86aabSstevel "SocketState=%x\n",
44213db86aabSstevel socknum, status->CardState, status->SocketState);
44223db86aabSstevel #endif
44233db86aabSstevel switch (pcic->pc_type) {
44243db86aabSstevel uint32_t present_state;
44253db86aabSstevel case PCIC_TI_PCI1410:
44263db86aabSstevel case PCIC_TI_PCI1520:
44273db86aabSstevel case PCIC_TI_PCI1420:
44283db86aabSstevel case PCIC_ENE_1420:
44293db86aabSstevel case PCIC_TOSHIBA_TOPIC100:
44303db86aabSstevel case PCIC_TOSHIBA_TOPIC95:
44313db86aabSstevel case PCIC_TOSHIBA_VENDOR:
44323db86aabSstevel case PCIC_O2MICRO_VENDOR:
44333db86aabSstevel case PCIC_TI_VENDOR:
44343db86aabSstevel case PCIC_RICOH_VENDOR:
44353db86aabSstevel present_state = pcic_getcb(pcic, CB_PRESENT_STATE);
44363db86aabSstevel if (present_state & PCIC_CB_CARD)
44373db86aabSstevel status->IFType = IF_CARDBUS;
44383db86aabSstevel #if defined(PCIC_DEBUG)
44393db86aabSstevel if (pcic_debug >= 8)
444019397407SSherry Moore cmn_err(CE_CONT,
444119397407SSherry Moore "pcic_get_status: present_state=0x%x\n",
44423db86aabSstevel present_state);
44433db86aabSstevel #endif
44443db86aabSstevel break;
44453db86aabSstevel default:
44463db86aabSstevel break;
44473db86aabSstevel }
44483db86aabSstevel
44493db86aabSstevel return (SUCCESS);
44503db86aabSstevel }
44513db86aabSstevel
44523db86aabSstevel /*
44533db86aabSstevel * pcic_get_window()
44543db86aabSstevel * SocketServices GetWindow function
44553db86aabSstevel * returns state information about the specified window
44563db86aabSstevel */
44573db86aabSstevel /*ARGSUSED*/
44583db86aabSstevel static int
pcic_get_window(dev_info_t * dip,get_window_t * window)44593db86aabSstevel pcic_get_window(dev_info_t *dip, get_window_t *window)
44603db86aabSstevel {
44613db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
44623db86aabSstevel pcicdev_t *pcic = anp->an_private;
44633db86aabSstevel int socket, win;
44643db86aabSstevel pcic_socket_t *sockp;
44653db86aabSstevel pcs_memwin_t *winp;
44663db86aabSstevel
44673db86aabSstevel socket = window->window / PCIC_NUMWINSOCK;
44683db86aabSstevel win = window->window % PCIC_NUMWINSOCK;
44693db86aabSstevel #if defined(PCIC_DEBUG)
44703db86aabSstevel if (pcic_debug) {
44713db86aabSstevel cmn_err(CE_CONT, "pcic_get_window(socket=%d, window=%d)\n",
44723db86aabSstevel socket, win);
44733db86aabSstevel }
44743db86aabSstevel #endif
44753db86aabSstevel
44763db86aabSstevel if (socket > pcic->pc_numsockets)
44773db86aabSstevel return (BAD_WINDOW);
44783db86aabSstevel
44793db86aabSstevel sockp = &pcic->pc_sockets[socket];
44803db86aabSstevel winp = &sockp->pcs_windows[win].mem;
44813db86aabSstevel
44823db86aabSstevel window->socket = socket;
44833db86aabSstevel window->size = winp->pcw_len;
44843db86aabSstevel window->speed = winp->pcw_speed;
44853db86aabSstevel window->handle = (ddi_acc_handle_t)winp->pcw_handle;
44863db86aabSstevel window->base = (uint32_t)winp->pcw_base + winp->pcw_offset;
44873db86aabSstevel
44883db86aabSstevel if (win >= PCIC_IOWINDOWS) {
44893db86aabSstevel window->state = 0;
44903db86aabSstevel } else {
44913db86aabSstevel window->state = WS_IO;
44923db86aabSstevel }
44933db86aabSstevel if (winp->pcw_status & PCW_ENABLED)
44943db86aabSstevel window->state |= WS_ENABLED;
44953db86aabSstevel
44963db86aabSstevel if (winp->pcw_status & PCS_CARD_16BIT)
44973db86aabSstevel window->state |= WS_16BIT;
44983db86aabSstevel #if defined(PCIC_DEBUG)
44993db86aabSstevel if (pcic_debug)
45003db86aabSstevel cmn_err(CE_CONT, "\tsize=%d, speed=%d, base=%p, state=%x\n",
45013db86aabSstevel window->size, (unsigned)window->speed,
45023db86aabSstevel (void *)window->handle, window->state);
45033db86aabSstevel #endif
45043db86aabSstevel
45053db86aabSstevel return (SUCCESS);
45063db86aabSstevel }
45073db86aabSstevel
45083db86aabSstevel /*
45093db86aabSstevel * pcic_ll_reset
45103db86aabSstevel * low level reset
45113db86aabSstevel * separated out so it can be called when already locked
45123db86aabSstevel *
45133db86aabSstevel * There are two variables that control the RESET timing:
45143db86aabSstevel * pcic_prereset_time - time in mS before asserting RESET
45153db86aabSstevel * pcic_reset_time - time in mS to assert RESET
45163db86aabSstevel *
45173db86aabSstevel */
45183db86aabSstevel int pcic_prereset_time = 1;
45193db86aabSstevel int pcic_reset_time = 10;
45203db86aabSstevel int pcic_postreset_time = 20;
45213db86aabSstevel int pcic_vpp_is_vcc_during_reset = 0;
45223db86aabSstevel
45233db86aabSstevel static int
pcic_ll_reset(pcicdev_t * pcic,int socket)45243db86aabSstevel pcic_ll_reset(pcicdev_t *pcic, int socket)
45253db86aabSstevel {
45263db86aabSstevel int windowbits, iobits;
45273db86aabSstevel uint32_t pwr;
45283db86aabSstevel
45293db86aabSstevel /* save windows that were on */
45303db86aabSstevel windowbits = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
45313db86aabSstevel if (pcic_reset_time == 0)
45323db86aabSstevel return (windowbits);
45333db86aabSstevel /* turn all windows off */
45343db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, 0);
45353db86aabSstevel
45363db86aabSstevel #if defined(PCIC_DEBUG)
45373db86aabSstevel pcic_err(pcic->dip, 6,
45383db86aabSstevel "pcic_ll_reset(socket %d) powerlevel=%x cbctl 0x%x cbps 0x%x\n",
45393db86aabSstevel socket, pcic_getb(pcic, socket, PCIC_POWER_CONTROL),
45403db86aabSstevel pcic_getcb(pcic, CB_CONTROL),
45413db86aabSstevel pcic_getcb(pcic, CB_PRESENT_STATE));
45423db86aabSstevel #endif
45433db86aabSstevel
45443db86aabSstevel if (pcic_vpp_is_vcc_during_reset) {
45453db86aabSstevel
45463db86aabSstevel /*
45473db86aabSstevel * Set VPP to VCC for the duration of the reset - for aironet
45483db86aabSstevel * card.
45493db86aabSstevel */
45503db86aabSstevel if (pcic->pc_flags & PCF_CBPWRCTL) {
45513db86aabSstevel pwr = pcic_getcb(pcic, CB_CONTROL);
45523db86aabSstevel pcic_putcb(pcic, CB_CONTROL, (pwr&~CB_C_VPPMASK)|CB_C_VPPVCC);
45533db86aabSstevel (void) pcic_getcb(pcic, CB_CONTROL);
45543db86aabSstevel } else {
45553db86aabSstevel pwr = pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
45563db86aabSstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL,
45573db86aabSstevel pwr | 1);
45583db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
45593db86aabSstevel }
45603db86aabSstevel }
45613db86aabSstevel
45623db86aabSstevel if (pcic_prereset_time > 0) {
45633db86aabSstevel pcic_err(pcic->dip, 8, "pcic_ll_reset pre_wait %d mS\n",
45643db86aabSstevel pcic_prereset_time);
45653db86aabSstevel pcic_mswait(pcic, socket, pcic_prereset_time);
45663db86aabSstevel }
45673db86aabSstevel
45683db86aabSstevel /* turn interrupts off and start a reset */
45693db86aabSstevel pcic_err(pcic->dip, 8,
45703db86aabSstevel "pcic_ll_reset turn interrupts off and start a reset\n");
45713db86aabSstevel iobits = pcic_getb(pcic, socket, PCIC_INTERRUPT);
45723db86aabSstevel iobits &= ~(PCIC_INTR_MASK | PCIC_RESET);
45733db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits);
45743db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_INTERRUPT);
45753db86aabSstevel
45763db86aabSstevel switch (pcic->pc_type) {
45773db86aabSstevel case PCIC_INTEL_i82092:
45783db86aabSstevel pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ,
45793db86aabSstevel PCIC_82092_INT_DISABLE);
45803db86aabSstevel break;
45813db86aabSstevel default:
45823db86aabSstevel break;
45833db86aabSstevel } /* switch */
45843db86aabSstevel
45853db86aabSstevel pcic->pc_sockets[socket].pcs_state = 0;
45863db86aabSstevel
45873db86aabSstevel if (pcic_reset_time > 0) {
45883db86aabSstevel pcic_err(pcic->dip, 8, "pcic_ll_reset reset_wait %d mS\n",
45893db86aabSstevel pcic_reset_time);
45903db86aabSstevel pcic_mswait(pcic, socket, pcic_reset_time);
45913db86aabSstevel }
45923db86aabSstevel
45933db86aabSstevel pcic_err(pcic->dip, 8, "pcic_ll_reset take it out of reset now\n");
45943db86aabSstevel
45953db86aabSstevel /* take it out of RESET now */
45963db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, PCIC_RESET | iobits);
45973db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_INTERRUPT);
45983db86aabSstevel
45993db86aabSstevel /*
46003db86aabSstevel * can't access the card for 20ms, but we really don't
46013db86aabSstevel * want to sit around that long. The pcic is still usable.
46023db86aabSstevel * memory accesses must wait for RDY to come up.
46033db86aabSstevel */
46043db86aabSstevel if (pcic_postreset_time > 0) {
46053db86aabSstevel pcic_err(pcic->dip, 8, "pcic_ll_reset post_wait %d mS\n",
46063db86aabSstevel pcic_postreset_time);
46073db86aabSstevel pcic_mswait(pcic, socket, pcic_postreset_time);
46083db86aabSstevel }
46093db86aabSstevel
46103db86aabSstevel if (pcic_vpp_is_vcc_during_reset > 1) {
46113db86aabSstevel
46123db86aabSstevel /*
46133db86aabSstevel * Return VPP power to whatever it was before.
46143db86aabSstevel */
46153db86aabSstevel if (pcic->pc_flags & PCF_CBPWRCTL) {
46163db86aabSstevel pcic_putcb(pcic, CB_CONTROL, pwr);
46173db86aabSstevel (void) pcic_getcb(pcic, CB_CONTROL);
46183db86aabSstevel } else {
46193db86aabSstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, pwr);
46203db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
46213db86aabSstevel }
46223db86aabSstevel }
46233db86aabSstevel
46243db86aabSstevel pcic_err(pcic->dip, 7, "pcic_ll_reset returning 0x%x\n", windowbits);
46253db86aabSstevel
46263db86aabSstevel return (windowbits);
46273db86aabSstevel }
46283db86aabSstevel
46293db86aabSstevel /*
46303db86aabSstevel * pcic_reset_socket()
46313db86aabSstevel * SocketServices ResetSocket function
46323db86aabSstevel * puts the PC Card in the socket into the RESET state
46333db86aabSstevel * and then takes it out after the the cycle time
46343db86aabSstevel * The socket is back to initial state when done
46353db86aabSstevel */
46363db86aabSstevel static int
pcic_reset_socket(dev_info_t * dip,int socket,int mode)46373db86aabSstevel pcic_reset_socket(dev_info_t *dip, int socket, int mode)
46383db86aabSstevel {
46393db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
46403db86aabSstevel pcicdev_t *pcic = anp->an_private;
46413db86aabSstevel int value;
46423db86aabSstevel int i, mint;
46433db86aabSstevel pcic_socket_t *sockp;
46443db86aabSstevel
46453db86aabSstevel #if defined(PCIC_DEBUG)
46463db86aabSstevel if (pcic_debug >= 8)
46473db86aabSstevel cmn_err(CE_CONT, "pcic_reset_socket(%p, %d, %d/%s)\n",
46483db86aabSstevel (void *)dip, socket, mode,
46493db86aabSstevel mode == RESET_MODE_FULL ? "full" : "partial");
46503db86aabSstevel #endif
46513db86aabSstevel
46523db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */
46533db86aabSstevel
46543db86aabSstevel /* Turn off management interupts. */
46553db86aabSstevel mint = pcic_getb(pcic, socket, PCIC_MANAGEMENT_INT);
46563db86aabSstevel pcic_putb(pcic, socket, PCIC_MANAGEMENT_INT, mint & ~PCIC_CHANGE_MASK);
46573db86aabSstevel
46583db86aabSstevel sockp = &pcic->pc_sockets[socket];
46593db86aabSstevel
46603db86aabSstevel value = pcic_ll_reset(pcic, socket);
46613db86aabSstevel if (mode == RESET_MODE_FULL) {
46623db86aabSstevel /* disable and unmap all mapped windows */
46633db86aabSstevel for (i = 0; i < PCIC_NUMWINSOCK; i++) {
46643db86aabSstevel if (i < PCIC_IOWINDOWS) {
46653db86aabSstevel if (sockp->pcs_windows[i].io.pcw_status &
46663db86aabSstevel PCW_MAPPED) {
46673db86aabSstevel pcs_iowin_t *io;
46683db86aabSstevel io = &sockp->pcs_windows[i].io;
46693db86aabSstevel io->pcw_status &= ~PCW_ENABLED;
46703db86aabSstevel }
46713db86aabSstevel } else {
46723db86aabSstevel if (sockp->pcs_windows[i].mem.pcw_status &
46733db86aabSstevel PCW_MAPPED) {
46743db86aabSstevel pcs_memwin_t *mem;
46753db86aabSstevel mem = &sockp->pcs_windows[i].mem;
46763db86aabSstevel mem->pcw_status &= ~PCW_ENABLED;
46773db86aabSstevel }
46783db86aabSstevel }
46793db86aabSstevel }
46803db86aabSstevel } else {
46813db86aabSstevel /* turn windows back on */
46823db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, value);
46833db86aabSstevel /* wait the rest of the time here */
46843db86aabSstevel pcic_mswait(pcic, socket, 10);
46853db86aabSstevel }
46863db86aabSstevel pcic_putb(pcic, socket, PCIC_MANAGEMENT_INT, mint);
46873db86aabSstevel mutex_exit(&pcic->pc_lock);
46883db86aabSstevel return (SUCCESS);
46893db86aabSstevel }
46903db86aabSstevel
46913db86aabSstevel /*
46923db86aabSstevel * pcic_set_interrupt()
46933db86aabSstevel * SocketServices SetInterrupt function
46943db86aabSstevel */
46953db86aabSstevel static int
pcic_set_interrupt(dev_info_t * dip,set_irq_handler_t * handler)46963db86aabSstevel pcic_set_interrupt(dev_info_t *dip, set_irq_handler_t *handler)
46973db86aabSstevel {
46983db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
46993db86aabSstevel pcicdev_t *pcic = anp->an_private;
47003db86aabSstevel int value = DDI_SUCCESS;
47013db86aabSstevel inthandler_t *intr;
47023db86aabSstevel
47033db86aabSstevel #if defined(PCIC_DEBUG)
47043db86aabSstevel if (pcic_debug) {
47053db86aabSstevel cmn_err(CE_CONT,
47063db86aabSstevel "pcic_set_interrupt: entered pc_intr_mode=0x%x\n",
47073db86aabSstevel pcic->pc_intr_mode);
47083db86aabSstevel cmn_err(CE_CONT,
47093db86aabSstevel "\t irq_top=%p handler=%p handler_id=%x\n",
47103db86aabSstevel (void *)pcic->irq_top, (void *)handler->handler,
47113db86aabSstevel handler->handler_id);
47123db86aabSstevel }
47133db86aabSstevel #endif
47143db86aabSstevel
47153db86aabSstevel /*
47163db86aabSstevel * If we're on a PCI bus, we route all IO IRQs through a single
47173db86aabSstevel * PCI interrupt (typically INT A#) so we don't have to do
47183db86aabSstevel * much other than add the caller to general interrupt handler
47193db86aabSstevel * and set some state.
47203db86aabSstevel */
47213db86aabSstevel
47223db86aabSstevel intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP);
47233db86aabSstevel if (intr == NULL)
47243db86aabSstevel return (NO_RESOURCE);
47253db86aabSstevel
47263db86aabSstevel switch (pcic->pc_intr_mode) {
47273db86aabSstevel case PCIC_INTR_MODE_PCI_1:
47283db86aabSstevel /*
47293db86aabSstevel * We only allow above-lock-level IO IRQ handlers
47303db86aabSstevel * in the PCI bus case.
47313db86aabSstevel */
47323db86aabSstevel
47333db86aabSstevel mutex_enter(&pcic->intr_lock);
47343db86aabSstevel
47353db86aabSstevel if (pcic->irq_top == NULL) {
47363db86aabSstevel pcic->irq_top = intr;
47373db86aabSstevel pcic->irq_current = pcic->irq_top;
47383db86aabSstevel } else {
47393db86aabSstevel while (pcic->irq_current->next != NULL)
47403db86aabSstevel pcic->irq_current = pcic->irq_current->next;
47413db86aabSstevel pcic->irq_current->next = intr;
47423db86aabSstevel pcic->irq_current = pcic->irq_current->next;
47433db86aabSstevel }
47443db86aabSstevel
47453db86aabSstevel pcic->irq_current->intr =
47463db86aabSstevel (ddi_intr_handler_t *)handler->handler;
47473db86aabSstevel pcic->irq_current->handler_id = handler->handler_id;
47483db86aabSstevel pcic->irq_current->arg1 = handler->arg1;
47493db86aabSstevel pcic->irq_current->arg2 = handler->arg2;
47503db86aabSstevel pcic->irq_current->socket = handler->socket;
47513db86aabSstevel
47523db86aabSstevel mutex_exit(&pcic->intr_lock);
47533db86aabSstevel
47543db86aabSstevel handler->iblk_cookie = &pcic->pc_pri;
47553db86aabSstevel handler->idev_cookie = &pcic->pc_dcookie;
47563db86aabSstevel break;
47573db86aabSstevel
47583db86aabSstevel default:
47593db86aabSstevel intr->intr = (ddi_intr_handler_t *)handler->handler;
47603db86aabSstevel intr->handler_id = handler->handler_id;
47613db86aabSstevel intr->arg1 = handler->arg1;
47623db86aabSstevel intr->arg2 = handler->arg2;
47633db86aabSstevel intr->socket = handler->socket;
47643db86aabSstevel intr->irq = handler->irq;
47653db86aabSstevel
47663db86aabSstevel /*
47673db86aabSstevel * need to revisit this to see if interrupts can be
47683db86aabSstevel * shared someday. Note that IRQ is set in the common
47693db86aabSstevel * code.
47703db86aabSstevel */
47713db86aabSstevel mutex_enter(&pcic->pc_lock);
47723db86aabSstevel if (pcic->pc_handlers == NULL) {
47733db86aabSstevel pcic->pc_handlers = intr;
47743db86aabSstevel intr->next = intr->prev = intr;
47753db86aabSstevel } else {
47763db86aabSstevel insque(intr, pcic->pc_handlers);
47773db86aabSstevel }
47783db86aabSstevel mutex_exit(&pcic->pc_lock);
47793db86aabSstevel
47803db86aabSstevel break;
47813db86aabSstevel }
47823db86aabSstevel
47833db86aabSstevel /*
47843db86aabSstevel * need to fill in cookies in event of multiple high priority
47853db86aabSstevel * interrupt handlers on same IRQ
47863db86aabSstevel */
47873db86aabSstevel
47883db86aabSstevel #if defined(PCIC_DEBUG)
47893db86aabSstevel if (pcic_debug) {
47903db86aabSstevel cmn_err(CE_CONT,
47913db86aabSstevel "pcic_set_interrupt: exit irq_top=%p value=%d\n",
47923db86aabSstevel (void *)pcic->irq_top, value);
47933db86aabSstevel }
47943db86aabSstevel #endif
47953db86aabSstevel
47963db86aabSstevel if (value == DDI_SUCCESS) {
47973db86aabSstevel return (SUCCESS);
47983db86aabSstevel } else {
47993db86aabSstevel return (BAD_IRQ);
48003db86aabSstevel }
48013db86aabSstevel }
48023db86aabSstevel
48033db86aabSstevel /*
48043db86aabSstevel * pcic_clear_interrupt()
48053db86aabSstevel * SocketServices ClearInterrupt function
48063db86aabSstevel *
48073db86aabSstevel * Interrupts for PCIC are complicated by the fact that we must
48083db86aabSstevel * follow several different models for interrupts.
48093db86aabSstevel * ISA: there is an interrupt per adapter and per socket and
48103db86aabSstevel * they can't be shared.
48113db86aabSstevel * PCI: some adapters have one PCI interrupt available while others
48123db86aabSstevel * have up to 4. Solaris may or may not allow us to use more
48133db86aabSstevel * than 1 so we essentially share them all at this point.
48143db86aabSstevel * Hybrid: PCI bridge but interrupts wired to host interrupt controller.
48153db86aabSstevel * This is like ISA but we have to fudge and create an intrspec
48163db86aabSstevel * that PCI's parent understands and bypass the PCI nexus.
48173db86aabSstevel * multifunction: this requires sharing the interrupts on a per-socket
48183db86aabSstevel * basis.
48193db86aabSstevel */
48203db86aabSstevel static int
pcic_clear_interrupt(dev_info_t * dip,clear_irq_handler_t * handler)48213db86aabSstevel pcic_clear_interrupt(dev_info_t *dip, clear_irq_handler_t *handler)
48223db86aabSstevel {
48233db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
48243db86aabSstevel pcicdev_t *pcic = anp->an_private;
48253db86aabSstevel inthandler_t *intr, *prev, *current;
48263db86aabSstevel int i;
48273db86aabSstevel
48283db86aabSstevel /*
48293db86aabSstevel * If we're on a PCI bus, we route all IO IRQs through a single
48303db86aabSstevel * PCI interrupt (typically INT A#) so we don't have to do
48313db86aabSstevel * much other than remove the caller from the general
48323db86aabSstevel * interrupt handler callout list.
48333db86aabSstevel */
48343db86aabSstevel
48353db86aabSstevel #if defined(PCIC_DEBUG)
48363db86aabSstevel if (pcic_debug) {
48373db86aabSstevel cmn_err(CE_CONT,
48383db86aabSstevel "pcic_clear_interrupt: entered pc_intr_mode=0x%x\n",
48393db86aabSstevel pcic->pc_intr_mode);
48403db86aabSstevel cmn_err(CE_CONT,
48413db86aabSstevel "\t irq_top=%p handler=%p handler_id=%x\n",
48423db86aabSstevel (void *)pcic->irq_top, (void *)handler->handler,
48433db86aabSstevel handler->handler_id);
48443db86aabSstevel }
48453db86aabSstevel #endif
48463db86aabSstevel
48473db86aabSstevel switch (pcic->pc_intr_mode) {
48483db86aabSstevel case PCIC_INTR_MODE_PCI_1:
48493db86aabSstevel
48503db86aabSstevel mutex_enter(&pcic->intr_lock);
48513db86aabSstevel if (pcic->irq_top == NULL) {
48523db86aabSstevel mutex_exit(&pcic->intr_lock);
48533db86aabSstevel return (BAD_IRQ);
48543db86aabSstevel }
48553db86aabSstevel
48563db86aabSstevel intr = NULL;
48573db86aabSstevel pcic->irq_current = pcic->irq_top;
48583db86aabSstevel
48593db86aabSstevel while ((pcic->irq_current != NULL) &&
48603db86aabSstevel (pcic->irq_current->handler_id !=
48613db86aabSstevel handler->handler_id)) {
48623db86aabSstevel intr = pcic->irq_current;
48633db86aabSstevel pcic->irq_current = pcic->irq_current->next;
48643db86aabSstevel }
48653db86aabSstevel
48663db86aabSstevel if (pcic->irq_current == NULL) {
48673db86aabSstevel mutex_exit(&pcic->intr_lock);
48683db86aabSstevel return (BAD_IRQ);
48693db86aabSstevel }
48703db86aabSstevel
48713db86aabSstevel if (intr != NULL) {
48723db86aabSstevel intr->next = pcic->irq_current->next;
48733db86aabSstevel } else {
48743db86aabSstevel pcic->irq_top = pcic->irq_current->next;
48753db86aabSstevel }
48763db86aabSstevel
48773db86aabSstevel current = pcic->irq_current;
48783db86aabSstevel pcic->irq_current = pcic->irq_top;
48793db86aabSstevel mutex_exit(&pcic->intr_lock);
48803db86aabSstevel kmem_free(current, sizeof (inthandler_t));
48813db86aabSstevel
48823db86aabSstevel break;
48833db86aabSstevel
48843db86aabSstevel default:
48853db86aabSstevel
48863db86aabSstevel mutex_enter(&pcic->pc_lock);
48873db86aabSstevel intr = pcic_handlers;
48883db86aabSstevel prev = (inthandler_t *)&pcic_handlers;
48893db86aabSstevel
48903db86aabSstevel while (intr != NULL) {
48913db86aabSstevel if (intr->handler_id == handler->handler_id) {
48923db86aabSstevel i = intr->irq & PCIC_INTR_MASK;
48933db86aabSstevel if (--pcic_irq_map[i].count == 0) {
48943db86aabSstevel /* multi-handler form */
48953db86aabSstevel (void) ddi_intr_disable(pcic->pc_intr_htblp[i]);
48963db86aabSstevel (void) ddi_intr_remove_handler(
48973db86aabSstevel pcic->pc_intr_htblp[i]);
48983db86aabSstevel (void) ddi_intr_free(pcic->pc_intr_htblp[i]);
48993db86aabSstevel (void) pcmcia_return_intr(pcic->dip, i);
49003db86aabSstevel #if defined(PCIC_DEBUG)
49013db86aabSstevel if (pcic_debug) {
49023db86aabSstevel cmn_err(CE_CONT,
49033db86aabSstevel "removing interrupt %d at %s "
49043db86aabSstevel "priority\n", i, "high");
49053db86aabSstevel cmn_err(CE_CONT,
49063db86aabSstevel "ddi_remove_intr(%p, %x, %p)\n",
49073db86aabSstevel (void *)dip,
49083db86aabSstevel 0,
49093db86aabSstevel (void *)intr->iblk_cookie);
49103db86aabSstevel }
49113db86aabSstevel #endif
49123db86aabSstevel }
49133db86aabSstevel prev->next = intr->next;
49143db86aabSstevel kmem_free(intr, sizeof (inthandler_t));
49153db86aabSstevel intr = prev->next;
49163db86aabSstevel } else {
49173db86aabSstevel prev = intr;
49183db86aabSstevel intr = intr->next;
49193db86aabSstevel } /* if (handler_id) */
49203db86aabSstevel } /* while */
49213db86aabSstevel
49223db86aabSstevel mutex_exit(&pcic->pc_lock);
49233db86aabSstevel }
49243db86aabSstevel
49253db86aabSstevel #if defined(PCIC_DEBUG)
49263db86aabSstevel if (pcic_debug) {
49273db86aabSstevel cmn_err(CE_CONT,
49283db86aabSstevel "pcic_clear_interrupt: exit irq_top=%p\n",
49293db86aabSstevel (void *)pcic->irq_top);
49303db86aabSstevel }
49313db86aabSstevel #endif
49323db86aabSstevel
49333db86aabSstevel
49343db86aabSstevel return (SUCCESS);
49353db86aabSstevel }
49363db86aabSstevel
49373db86aabSstevel struct intel_regs {
49383db86aabSstevel char *name;
49393db86aabSstevel int off;
49403db86aabSstevel char *fmt;
49413db86aabSstevel } iregs[] = {
49423db86aabSstevel {"ident ", 0},
49433db86aabSstevel {"if-status ", 1, "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI"},
49443db86aabSstevel {"power ", 2, "\020\1Vpp1c0\2Vpp1c1\3Vpp2c0\4Vpp2c1\5PE\6AUTO"
49453db86aabSstevel "\7DRD\10OE"},
49463db86aabSstevel {"cardstatus", 4, "\020\1BD\2BW\3RC\4CD\5GPI\6R1\7R2\010R3"},
49473db86aabSstevel {"enable ", 6, "\020\1MW0\2MW1\3MW2\4MW3\5MW4\6MEM16\7IO0\10IO1"},
49483db86aabSstevel {"cd-gcr ", 0x16, "\020\1MDI16\2CRE\3GPIE\4GPIT\5CDR\6S/W"},
49493db86aabSstevel {"GCR ", 0x1e, "\020\1PD\2LEVEL\3WCSC\4PLS14"},
49503db86aabSstevel {"int-gcr ", 3, "\020\5INTR\6IO\7~RST\10RI"},
49513db86aabSstevel {"management", 5, "\020\1BDE\2BWE\3RE\4CDE"},
49523db86aabSstevel {"volt-sense", 0x1f, "\020\1A_VS1\2A_VS2\3B_VS1\4B_VS2"},
49533db86aabSstevel {"volt-sel ", 0x2f, "\020\5EXTCONF\6BUSSELECT\7MIXEDV\10ISAV"},
49543db86aabSstevel {"VG ext A ", 0x3c, "\20\3IVS\4CABLE\5CSTEP\6TEST\7RIO"},
49553db86aabSstevel {"io-ctrl ", 7, "\020\1DS0\2IOCS0\3ZWS0\4WS0\5DS1\6IOS1\7ZWS1\10WS1"},
49563db86aabSstevel {"io0-slow ", 8},
49573db86aabSstevel {"io0-shi ", 9},
49583db86aabSstevel {"io0-elow ", 0xa},
49593db86aabSstevel {"io0-ehi ", 0xb},
49603db86aabSstevel {"io1-slow ", 0xc},
49613db86aabSstevel {"io1-shi ", 0xd},
49623db86aabSstevel {"io1-elow ", 0xe},
49633db86aabSstevel {"io1-ehi ", 0xf},
49643db86aabSstevel {"mem0-slow ", 0x10},
49653db86aabSstevel {"mem0-shi ", 0x11, "\020\7ZW\10DS"},
49663db86aabSstevel {"mem0-elow ", 0x12},
49673db86aabSstevel {"mem0-ehi ", 0x13, "\020\7WS0\10WS1"},
49683db86aabSstevel {"card0-low ", 0x14},
49693db86aabSstevel {"card0-hi ", 0x15, "\020\7AM\10WP"},
49703db86aabSstevel {"mem1-slow ", 0x18},
49713db86aabSstevel {"mem1-shi ", 0x19, "\020\7ZW\10DS"},
49723db86aabSstevel {"mem1-elow ", 0x1a},
49733db86aabSstevel {"mem1-ehi ", 0x1b, "\020\7WS0\10WS1"},
49743db86aabSstevel {"card1-low ", 0x1c},
49753db86aabSstevel {"card1-hi ", 0x1d, "\020\7AM\10WP"},
49763db86aabSstevel {"mem2-slow ", 0x20},
49773db86aabSstevel {"mem2-shi ", 0x21, "\020\7ZW\10DS"},
49783db86aabSstevel {"mem2-elow ", 0x22},
49793db86aabSstevel {"mem2-ehi ", 0x23, "\020\7WS0\10WS1"},
49803db86aabSstevel {"card2-low ", 0x24},
49813db86aabSstevel {"card2-hi ", 0x25, "\020\7AM\10WP"},
49823db86aabSstevel {"mem3-slow ", 0x28},
49833db86aabSstevel {"mem3-shi ", 0x29, "\020\7ZW\10DS"},
49843db86aabSstevel {"mem3-elow ", 0x2a},
49853db86aabSstevel {"mem3-ehi ", 0x2b, "\020\7WS0\10WS1"},
49863db86aabSstevel {"card3-low ", 0x2c},
49873db86aabSstevel {"card3-hi ", 0x2d, "\020\7AM\10WP"},
49883db86aabSstevel
49893db86aabSstevel {"mem4-slow ", 0x30},
49903db86aabSstevel {"mem4-shi ", 0x31, "\020\7ZW\10DS"},
49913db86aabSstevel {"mem4-elow ", 0x32},
49923db86aabSstevel {"mem4-ehi ", 0x33, "\020\7WS0\10WS1"},
49933db86aabSstevel {"card4-low ", 0x34},
49943db86aabSstevel {"card4-hi ", 0x35, "\020\7AM\10WP"},
49953db86aabSstevel {"mpage0 ", 0x40},
49963db86aabSstevel {"mpage1 ", 0x41},
49973db86aabSstevel {"mpage2 ", 0x42},
49983db86aabSstevel {"mpage3 ", 0x43},
49993db86aabSstevel {"mpage4 ", 0x44},
50003db86aabSstevel {NULL},
50013db86aabSstevel };
50023db86aabSstevel
50033db86aabSstevel static struct intel_regs cregs[] = {
50043db86aabSstevel {"misc-ctl1 ", 0x16, "\20\2VCC3\3PMI\4PSI\5SPKR\10INPACK"},
50053db86aabSstevel {"fifo ", 0x17, "\20\6DIOP\7DMEMP\10EMPTY"},
50063db86aabSstevel {"misc-ctl2 ", 0x1e, "\20\1XCLK\2LOW\3SUSP\4CORE5V\5TCD\10RIOUT"},
50073db86aabSstevel {"chip-info ", 0x1f, "\20\6DUAL"},
50083db86aabSstevel {"IO-offlow0", 0x36},
50093db86aabSstevel {"IO-offhi0 ", 0x37},
50103db86aabSstevel {"IO-offlow1", 0x38},
50113db86aabSstevel {"IO-offhi1 ", 0x39},
50123db86aabSstevel NULL,
50133db86aabSstevel };
50143db86aabSstevel
50153db86aabSstevel static struct intel_regs cxregs[] = {
50163db86aabSstevel {"ext-ctl-1 ", 0x03,
50173db86aabSstevel "\20\1VCCLCK\2AUTOCLR\3LED\4INVIRQC\5INVIRQM\6PUC"},
50183db86aabSstevel {"misc-ctl3 ", 0x25, "\20\5HWSUSP"},
50193db86aabSstevel {"mem0-up ", 0x05},
50203db86aabSstevel {"mem1-up ", 0x06},
50213db86aabSstevel {"mem2-up ", 0x07},
50223db86aabSstevel {"mem3-up ", 0x08},
50233db86aabSstevel {"mem4-up ", 0x09},
50243db86aabSstevel {NULL}
50253db86aabSstevel };
50263db86aabSstevel
50273db86aabSstevel void
xxdmp_cl_regs(pcicdev_t * pcic,int socket,uint32_t len)50283db86aabSstevel xxdmp_cl_regs(pcicdev_t *pcic, int socket, uint32_t len)
50293db86aabSstevel {
50303db86aabSstevel int i, value, j;
50313db86aabSstevel char buff[256];
50323db86aabSstevel char *fmt;
50333db86aabSstevel
50343db86aabSstevel cmn_err(CE_CONT, "--------- Cirrus Logic Registers --------\n");
50353db86aabSstevel for (buff[0] = '\0', i = 0; cregs[i].name != NULL && len-- != 0; i++) {
50363db86aabSstevel int sval;
50373db86aabSstevel if (cregs[i].off == PCIC_MISC_CTL_2)
50383db86aabSstevel sval = 0;
50393db86aabSstevel else
50403db86aabSstevel sval = socket;
50413db86aabSstevel value = pcic_getb(pcic, sval, cregs[i].off);
50423db86aabSstevel if (i & 1) {
50433db86aabSstevel if (cregs[i].fmt)
50443db86aabSstevel fmt = "%s\t%s\t%b\n";
50453db86aabSstevel else
50463db86aabSstevel fmt = "%s\t%s\t%x\n";
50473db86aabSstevel cmn_err(CE_CONT, fmt, buff,
50483db86aabSstevel cregs[i].name, value, cregs[i].fmt);
50493db86aabSstevel buff[0] = '\0';
50503db86aabSstevel } else {
50513db86aabSstevel if (cregs[i].fmt)
50523db86aabSstevel fmt = "\t%s\t%b";
50533db86aabSstevel else
50543db86aabSstevel fmt = "\t%s\t%x";
50553db86aabSstevel (void) sprintf(buff, fmt,
50563db86aabSstevel cregs[i].name, value, cregs[i].fmt);
50573db86aabSstevel for (j = strlen(buff); j < 40; j++)
50583db86aabSstevel buff[j] = ' ';
50593db86aabSstevel buff[40] = '\0';
50603db86aabSstevel }
50613db86aabSstevel }
50623db86aabSstevel cmn_err(CE_CONT, "%s\n", buff);
50633db86aabSstevel
50643db86aabSstevel i = pcic_getb(pcic, socket, PCIC_TIME_SETUP_0);
50653db86aabSstevel j = pcic_getb(pcic, socket, PCIC_TIME_SETUP_1);
50663db86aabSstevel cmn_err(CE_CONT, "\tsetup-tim0\t%x\tsetup-tim1\t%x\n", i, j);
50673db86aabSstevel
50683db86aabSstevel i = pcic_getb(pcic, socket, PCIC_TIME_COMMAND_0);
50693db86aabSstevel j = pcic_getb(pcic, socket, PCIC_TIME_COMMAND_1);
50703db86aabSstevel cmn_err(CE_CONT, "\tcmd-tim0 \t%x\tcmd-tim1 \t%x\n", i, j);
50713db86aabSstevel
50723db86aabSstevel i = pcic_getb(pcic, socket, PCIC_TIME_RECOVER_0);
50733db86aabSstevel j = pcic_getb(pcic, socket, PCIC_TIME_RECOVER_1);
50743db86aabSstevel cmn_err(CE_CONT, "\trcvr-tim0 \t%x\trcvr-tim1 \t%x\n", i, j);
50753db86aabSstevel
50763db86aabSstevel cmn_err(CE_CONT, "--------- Extended Registers --------\n");
50773db86aabSstevel
50783db86aabSstevel for (buff[0] = '\0', i = 0; cxregs[i].name != NULL && len-- != 0; i++) {
50793db86aabSstevel value = clext_reg_read(pcic, socket, cxregs[i].off);
50803db86aabSstevel if (i & 1) {
50813db86aabSstevel if (cxregs[i].fmt)
50823db86aabSstevel fmt = "%s\t%s\t%b\n";
50833db86aabSstevel else
50843db86aabSstevel fmt = "%s\t%s\t%x\n";
50853db86aabSstevel cmn_err(CE_CONT, fmt, buff,
50863db86aabSstevel cxregs[i].name, value, cxregs[i].fmt);
50873db86aabSstevel buff[0] = '\0';
50883db86aabSstevel } else {
50893db86aabSstevel if (cxregs[i].fmt)
50903db86aabSstevel fmt = "\t%s\t%b";
50913db86aabSstevel else
50923db86aabSstevel fmt = "\t%s\t%x";
50933db86aabSstevel (void) sprintf(buff, fmt,
50943db86aabSstevel cxregs[i].name, value, cxregs[i].fmt);
50953db86aabSstevel for (j = strlen(buff); j < 40; j++)
50963db86aabSstevel buff[j] = ' ';
50973db86aabSstevel buff[40] = '\0';
50983db86aabSstevel }
50993db86aabSstevel }
51003db86aabSstevel }
51013db86aabSstevel
51023db86aabSstevel #if defined(PCIC_DEBUG)
51033db86aabSstevel static void
xxdmp_all_regs(pcicdev_t * pcic,int socket,uint32_t len)51043db86aabSstevel xxdmp_all_regs(pcicdev_t *pcic, int socket, uint32_t len)
51053db86aabSstevel {
51063db86aabSstevel int i, value, j;
51073db86aabSstevel char buff[256];
51083db86aabSstevel char *fmt;
51093db86aabSstevel
51103db86aabSstevel #if defined(PCIC_DEBUG)
51113db86aabSstevel if (pcic_debug < 2)
51123db86aabSstevel return;
51133db86aabSstevel #endif
51143db86aabSstevel cmn_err(CE_CONT,
51153db86aabSstevel "----------- PCIC Registers for socket %d---------\n",
51163db86aabSstevel socket);
51173db86aabSstevel cmn_err(CE_CONT,
51183db86aabSstevel "\tname value name value\n");
51193db86aabSstevel
51203db86aabSstevel for (buff[0] = '\0', i = 0; iregs[i].name != NULL && len-- != 0; i++) {
51213db86aabSstevel value = pcic_getb(pcic, socket, iregs[i].off);
51223db86aabSstevel if (i & 1) {
51233db86aabSstevel if (iregs[i].fmt)
51243db86aabSstevel fmt = "%s\t%s\t%b\n";
51253db86aabSstevel else
51263db86aabSstevel fmt = "%s\t%s\t%x\n";
51273db86aabSstevel cmn_err(CE_CONT, fmt, buff,
51283db86aabSstevel iregs[i].name, value, iregs[i].fmt);
51293db86aabSstevel buff[0] = '\0';
51303db86aabSstevel } else {
51313db86aabSstevel if (iregs[i].fmt)
51323db86aabSstevel fmt = "\t%s\t%b";
51333db86aabSstevel else
51343db86aabSstevel fmt = "\t%s\t%x";
51353db86aabSstevel (void) sprintf(buff, fmt,
51363db86aabSstevel iregs[i].name, value, iregs[i].fmt);
51373db86aabSstevel for (j = strlen(buff); j < 40; j++)
51383db86aabSstevel buff[j] = ' ';
51393db86aabSstevel buff[40] = '\0';
51403db86aabSstevel }
51413db86aabSstevel }
51423db86aabSstevel switch (pcic->pc_type) {
51433db86aabSstevel case PCIC_CL_PD6710:
51443db86aabSstevel case PCIC_CL_PD6722:
51453db86aabSstevel case PCIC_CL_PD6729:
51463db86aabSstevel case PCIC_CL_PD6832:
51473db86aabSstevel (void) xxdmp_cl_regs(pcic, socket, 0xFFFF);
51483db86aabSstevel break;
51493db86aabSstevel }
51503db86aabSstevel cmn_err(CE_CONT, "%s\n", buff);
51513db86aabSstevel }
51523db86aabSstevel #endif
51533db86aabSstevel
51543db86aabSstevel /*
51553db86aabSstevel * pcic_mswait(ms)
51563db86aabSstevel * sleep ms milliseconds
51573db86aabSstevel * call drv_usecwait once for each ms
51583db86aabSstevel */
51593db86aabSstevel static void
pcic_mswait(pcicdev_t * pcic,int socket,int ms)51603db86aabSstevel pcic_mswait(pcicdev_t *pcic, int socket, int ms)
51613db86aabSstevel {
51623db86aabSstevel if (ms) {
51633db86aabSstevel pcic->pc_sockets[socket].pcs_flags |= PCS_WAITING;
51643db86aabSstevel pcic_mutex_exit(&pcic->pc_lock);
51653db86aabSstevel delay(drv_usectohz(ms*1000));
51663db86aabSstevel pcic_mutex_enter(&pcic->pc_lock);
51673db86aabSstevel pcic->pc_sockets[socket].pcs_flags &= ~PCS_WAITING;
51683db86aabSstevel }
51693db86aabSstevel }
51703db86aabSstevel
51713db86aabSstevel /*
51723db86aabSstevel * pcic_check_ready(pcic, index, off)
51733db86aabSstevel * Wait for card to come ready
51743db86aabSstevel * We only wait if the card is NOT in RESET
51753db86aabSstevel * and power is on.
51763db86aabSstevel */
51773db86aabSstevel static boolean_t
pcic_check_ready(pcicdev_t * pcic,int socket)51783db86aabSstevel pcic_check_ready(pcicdev_t *pcic, int socket)
51793db86aabSstevel {
51803db86aabSstevel int ifstate, intstate;
51813db86aabSstevel
51823db86aabSstevel intstate = pcic_getb(pcic, socket, PCIC_INTERRUPT);
51833db86aabSstevel ifstate = pcic_getb(pcic, socket, PCIC_INTERFACE_STATUS);
51843db86aabSstevel
51853db86aabSstevel if ((intstate & PCIC_RESET) &&
51863db86aabSstevel ((ifstate & (PCIC_READY|PCIC_POWER_ON|PCIC_ISTAT_CD_MASK)) ==
51873db86aabSstevel (PCIC_READY|PCIC_POWER_ON|PCIC_CD_PRESENT_OK)))
51883db86aabSstevel return (B_TRUE);
51893db86aabSstevel
51903db86aabSstevel #ifdef PCIC_DEBUG
51913db86aabSstevel pcic_err(NULL, 5, "pcic_check_read: Card not ready, intstate = 0x%x, "
51923db86aabSstevel "ifstate = 0x%x\n", intstate, ifstate);
51933db86aabSstevel if (pcic_debug) {
51943db86aabSstevel pcic_debug += 4;
51953db86aabSstevel xxdmp_all_regs(pcic, socket, -1);
51963db86aabSstevel pcic_debug -= 4;
51973db86aabSstevel }
51983db86aabSstevel #endif
51993db86aabSstevel return (B_FALSE);
52003db86aabSstevel }
52013db86aabSstevel
52023db86aabSstevel /*
52033db86aabSstevel * Cirrus Logic extended register read/write routines
52043db86aabSstevel */
52053db86aabSstevel static int
clext_reg_read(pcicdev_t * pcic,int sn,uchar_t ext_reg)52063db86aabSstevel clext_reg_read(pcicdev_t *pcic, int sn, uchar_t ext_reg)
52073db86aabSstevel {
52083db86aabSstevel int val;
52093db86aabSstevel
52103db86aabSstevel switch (pcic->pc_io_type) {
52113db86aabSstevel case PCIC_IO_TYPE_YENTA:
52123db86aabSstevel val = ddi_get8(pcic->handle,
52133db86aabSstevel pcic->ioaddr + CB_CLEXT_OFFSET + ext_reg);
52143db86aabSstevel break;
52153db86aabSstevel default:
52163db86aabSstevel pcic_putb(pcic, sn, PCIC_CL_EXINDEX, ext_reg);
52173db86aabSstevel val = pcic_getb(pcic, sn, PCIC_CL_EXINDEX + 1);
52183db86aabSstevel break;
52193db86aabSstevel }
52203db86aabSstevel
52213db86aabSstevel return (val);
52223db86aabSstevel }
52233db86aabSstevel
52243db86aabSstevel static void
clext_reg_write(pcicdev_t * pcic,int sn,uchar_t ext_reg,uchar_t value)52253db86aabSstevel clext_reg_write(pcicdev_t *pcic, int sn, uchar_t ext_reg, uchar_t value)
52263db86aabSstevel {
52273db86aabSstevel switch (pcic->pc_io_type) {
52283db86aabSstevel case PCIC_IO_TYPE_YENTA:
52293db86aabSstevel ddi_put8(pcic->handle,
52303db86aabSstevel pcic->ioaddr + CB_CLEXT_OFFSET + ext_reg, value);
52313db86aabSstevel break;
52323db86aabSstevel default:
52333db86aabSstevel pcic_putb(pcic, sn, PCIC_CL_EXINDEX, ext_reg);
52343db86aabSstevel pcic_putb(pcic, sn, PCIC_CL_EXINDEX + 1, value);
52353db86aabSstevel break;
52363db86aabSstevel }
52373db86aabSstevel }
52383db86aabSstevel
52393db86aabSstevel /*
52403db86aabSstevel * Misc PCI functions
52413db86aabSstevel */
52423db86aabSstevel static void
pcic_iomem_pci_ctl(ddi_acc_handle_t handle,uchar_t * cfgaddr,unsigned flags)52433db86aabSstevel pcic_iomem_pci_ctl(ddi_acc_handle_t handle, uchar_t *cfgaddr, unsigned flags)
52443db86aabSstevel {
52453db86aabSstevel unsigned cmd;
52463db86aabSstevel
52473db86aabSstevel if (flags & (PCIC_ENABLE_IO | PCIC_ENABLE_MEM)) {
52483db86aabSstevel cmd = ddi_get16(handle, (ushort_t *)(cfgaddr + 4));
52493db86aabSstevel if ((cmd & (PCI_COMM_IO|PCI_COMM_MAE)) ==
52503db86aabSstevel (PCI_COMM_IO|PCI_COMM_MAE))
52513db86aabSstevel return;
52523db86aabSstevel
52533db86aabSstevel if (flags & PCIC_ENABLE_IO)
52543db86aabSstevel cmd |= PCI_COMM_IO;
52553db86aabSstevel
52563db86aabSstevel if (flags & PCIC_ENABLE_MEM)
52573db86aabSstevel cmd |= PCI_COMM_MAE;
52583db86aabSstevel
52593db86aabSstevel ddi_put16(handle, (ushort_t *)(cfgaddr + 4), cmd);
52603db86aabSstevel } /* if (PCIC_ENABLE_IO | PCIC_ENABLE_MEM) */
52613db86aabSstevel }
52623db86aabSstevel
52633db86aabSstevel /*
52643db86aabSstevel * pcic_find_pci_type - Find and return PCI-PCMCIA adapter type
52653db86aabSstevel */
52663db86aabSstevel static int
pcic_find_pci_type(pcicdev_t * pcic)52673db86aabSstevel pcic_find_pci_type(pcicdev_t *pcic)
52683db86aabSstevel {
52693db86aabSstevel uint32_t vend, device;
52703db86aabSstevel
52713db86aabSstevel vend = ddi_getprop(DDI_DEV_T_ANY, pcic->dip,
52723db86aabSstevel DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
52733db86aabSstevel "vendor-id", -1);
52743db86aabSstevel device = ddi_getprop(DDI_DEV_T_ANY, pcic->dip,
52753db86aabSstevel DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
52763db86aabSstevel "device-id", -1);
52773db86aabSstevel
52783db86aabSstevel device = PCI_ID(vend, device);
52793db86aabSstevel pcic->pc_type = device;
52803db86aabSstevel pcic->pc_chipname = "PCI:unknown";
52813db86aabSstevel
52823db86aabSstevel switch (device) {
52833db86aabSstevel case PCIC_INTEL_i82092:
52843db86aabSstevel pcic->pc_chipname = PCIC_TYPE_i82092;
52853db86aabSstevel break;
52863db86aabSstevel case PCIC_CL_PD6729:
52873db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6729;
52883db86aabSstevel /*
52893db86aabSstevel * Some 6730's incorrectly identify themselves
52903db86aabSstevel * as a 6729, so we need to do some more tests
52913db86aabSstevel * here to see if the device that's claiming
52923db86aabSstevel * to be a 6729 is really a 6730.
52933db86aabSstevel */
52943db86aabSstevel if ((clext_reg_read(pcic, 0, PCIC_CLEXT_MISC_CTL_3) &
52953db86aabSstevel PCIC_CLEXT_MISC_CTL_3_REV_MASK) ==
52963db86aabSstevel 0) {
52973db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6730;
52983db86aabSstevel pcic->pc_type = PCIC_CL_PD6730;
52993db86aabSstevel }
53003db86aabSstevel break;
53013db86aabSstevel case PCIC_CL_PD6730:
53023db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6730;
53033db86aabSstevel break;
53043db86aabSstevel case PCIC_CL_PD6832:
53053db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6832;
53063db86aabSstevel break;
53073db86aabSstevel case PCIC_SMC_34C90:
53083db86aabSstevel pcic->pc_chipname = PCIC_TYPE_34C90;
53093db86aabSstevel break;
53103db86aabSstevel case PCIC_TOSHIBA_TOPIC95:
53113db86aabSstevel pcic->pc_chipname = PCIC_TYPE_TOPIC95;
53123db86aabSstevel break;
53133db86aabSstevel case PCIC_TOSHIBA_TOPIC100:
53143db86aabSstevel pcic->pc_chipname = PCIC_TYPE_TOPIC100;
53153db86aabSstevel break;
53163db86aabSstevel case PCIC_TI_PCI1031:
53173db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1031;
53183db86aabSstevel break;
53193db86aabSstevel case PCIC_TI_PCI1130:
53203db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1130;
53213db86aabSstevel break;
53223db86aabSstevel case PCIC_TI_PCI1131:
53233db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1131;
53243db86aabSstevel break;
53253db86aabSstevel case PCIC_TI_PCI1250:
53263db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1250;
53273db86aabSstevel break;
53283db86aabSstevel case PCIC_TI_PCI1225:
53293db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1225;
53303db86aabSstevel break;
53313db86aabSstevel case PCIC_TI_PCI1410:
53323db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1410;
53333db86aabSstevel break;
53343db86aabSstevel case PCIC_TI_PCI1510:
53353db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1510;
53363db86aabSstevel break;
53373db86aabSstevel case PCIC_TI_PCI1520:
53383db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1520;
53393db86aabSstevel break;
53403db86aabSstevel case PCIC_TI_PCI1221:
53413db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1221;
53423db86aabSstevel break;
53433db86aabSstevel case PCIC_TI_PCI1050:
53443db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1050;
53453db86aabSstevel break;
53463db86aabSstevel case PCIC_ENE_1410:
53473db86aabSstevel pcic->pc_chipname = PCIC_TYPE_1410;
53483db86aabSstevel break;
53493db86aabSstevel case PCIC_O2_OZ6912:
53503db86aabSstevel pcic->pc_chipname = PCIC_TYPE_OZ6912;
53513db86aabSstevel break;
53523db86aabSstevel case PCIC_RICOH_RL5C466:
53533db86aabSstevel pcic->pc_chipname = PCIC_TYPE_RL5C466;
53543db86aabSstevel break;
53553db86aabSstevel case PCIC_TI_PCI1420:
53563db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1420;
53573db86aabSstevel break;
53583db86aabSstevel case PCIC_ENE_1420:
53593db86aabSstevel pcic->pc_chipname = PCIC_TYPE_1420;
53603db86aabSstevel break;
53613db86aabSstevel default:
53623db86aabSstevel switch (PCI_ID(vend, (uint32_t)0)) {
53633db86aabSstevel case PCIC_TOSHIBA_VENDOR:
53643db86aabSstevel pcic->pc_chipname = PCIC_TYPE_TOSHIBA;
53653db86aabSstevel pcic->pc_type = PCIC_TOSHIBA_VENDOR;
53663db86aabSstevel break;
53673db86aabSstevel case PCIC_TI_VENDOR:
53683db86aabSstevel pcic->pc_chipname = PCIC_TYPE_TI;
53693db86aabSstevel pcic->pc_type = PCIC_TI_VENDOR;
53703db86aabSstevel break;
53713db86aabSstevel case PCIC_O2MICRO_VENDOR:
53723db86aabSstevel pcic->pc_chipname = PCIC_TYPE_O2MICRO;
53733db86aabSstevel pcic->pc_type = PCIC_O2MICRO_VENDOR;
53743db86aabSstevel break;
53753db86aabSstevel case PCIC_RICOH_VENDOR:
53763db86aabSstevel pcic->pc_chipname = PCIC_TYPE_RICOH;
53773db86aabSstevel pcic->pc_type = PCIC_RICOH_VENDOR;
53783db86aabSstevel break;
53793db86aabSstevel default:
53803db86aabSstevel if (!(pcic->pc_flags & PCF_CARDBUS))
53813db86aabSstevel return (DDI_FAILURE);
53823db86aabSstevel pcic->pc_chipname = PCIC_TYPE_YENTA;
53833db86aabSstevel break;
53843db86aabSstevel }
53853db86aabSstevel }
53863db86aabSstevel return (DDI_SUCCESS);
53873db86aabSstevel }
53883db86aabSstevel
53893db86aabSstevel static void
pcic_82092_smiirq_ctl(pcicdev_t * pcic,int socket,int intr,int state)53903db86aabSstevel pcic_82092_smiirq_ctl(pcicdev_t *pcic, int socket, int intr, int state)
53913db86aabSstevel {
53923db86aabSstevel uchar_t ppirr = ddi_get8(pcic->cfg_handle,
53933db86aabSstevel pcic->cfgaddr + PCIC_82092_PPIRR);
53943db86aabSstevel uchar_t val;
53953db86aabSstevel
53963db86aabSstevel if (intr == PCIC_82092_CTL_SMI) {
53973db86aabSstevel val = PCIC_82092_SMI_CTL(socket,
53983db86aabSstevel PCIC_82092_INT_DISABLE);
53993db86aabSstevel ppirr &= ~val;
54003db86aabSstevel val = PCIC_82092_SMI_CTL(socket, state);
54013db86aabSstevel ppirr |= val;
54023db86aabSstevel } else {
54033db86aabSstevel val = PCIC_82092_IRQ_CTL(socket,
54043db86aabSstevel PCIC_82092_INT_DISABLE);
54053db86aabSstevel ppirr &= ~val;
54063db86aabSstevel val = PCIC_82092_IRQ_CTL(socket, state);
54073db86aabSstevel ppirr |= val;
54083db86aabSstevel }
54093db86aabSstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_82092_PPIRR,
54103db86aabSstevel ppirr);
54113db86aabSstevel }
54123db86aabSstevel
54133db86aabSstevel static uint_t
pcic_cd_softint(caddr_t arg1,caddr_t arg2)54143db86aabSstevel pcic_cd_softint(caddr_t arg1, caddr_t arg2)
54153db86aabSstevel {
54163db86aabSstevel pcic_socket_t *sockp = (pcic_socket_t *)arg1;
54173db86aabSstevel uint_t rc = DDI_INTR_UNCLAIMED;
54183db86aabSstevel
54193db86aabSstevel _NOTE(ARGUNUSED(arg2))
54203db86aabSstevel
54213db86aabSstevel mutex_enter(&sockp->pcs_pcic->pc_lock);
54223db86aabSstevel if (sockp->pcs_cd_softint_flg) {
54233db86aabSstevel uint8_t status;
54243db86aabSstevel sockp->pcs_cd_softint_flg = 0;
54253db86aabSstevel rc = DDI_INTR_CLAIMED;
54263db86aabSstevel status = pcic_getb(sockp->pcs_pcic, sockp->pcs_socket,
54273db86aabSstevel PCIC_INTERFACE_STATUS);
54283db86aabSstevel pcic_handle_cd_change(sockp->pcs_pcic, sockp, status);
54293db86aabSstevel }
54303db86aabSstevel mutex_exit(&sockp->pcs_pcic->pc_lock);
54313db86aabSstevel return (rc);
54323db86aabSstevel }
54333db86aabSstevel
54343db86aabSstevel int pcic_debounce_cnt = PCIC_REM_DEBOUNCE_CNT;
54353db86aabSstevel int pcic_debounce_intr_time = PCIC_REM_DEBOUNCE_TIME;
54363db86aabSstevel int pcic_debounce_cnt_ok = PCIC_DEBOUNCE_OK_CNT;
54373db86aabSstevel
54383db86aabSstevel #ifdef CARDBUS
54393db86aabSstevel static uint32_t pcic_cbps_on = 0;
54403db86aabSstevel static uint32_t pcic_cbps_off = CB_PS_NOTACARD | CB_PS_CCDMASK |
54413db86aabSstevel CB_PS_XVCARD | CB_PS_YVCARD;
54423db86aabSstevel #else
54433db86aabSstevel static uint32_t pcic_cbps_on = CB_PS_16BITCARD;
54443db86aabSstevel static uint32_t pcic_cbps_off = CB_PS_NOTACARD | CB_PS_CCDMASK |
54453db86aabSstevel CB_PS_CBCARD |
54463db86aabSstevel CB_PS_XVCARD | CB_PS_YVCARD;
54473db86aabSstevel #endif
54483db86aabSstevel static void
pcic_handle_cd_change(pcicdev_t * pcic,pcic_socket_t * sockp,uint8_t status)54493db86aabSstevel pcic_handle_cd_change(pcicdev_t *pcic, pcic_socket_t *sockp, uint8_t status)
54503db86aabSstevel {
54513db86aabSstevel boolean_t do_debounce = B_FALSE;
54523db86aabSstevel int debounce_time = drv_usectohz(pcic_debounce_time);
54533db86aabSstevel uint8_t irq;
54543db86aabSstevel timeout_id_t debounce;
54553db86aabSstevel
54563db86aabSstevel /*
54573db86aabSstevel * Always reset debounce but may need to check original state later.
54583db86aabSstevel */
54593db86aabSstevel debounce = sockp->pcs_debounce_id;
54603db86aabSstevel sockp->pcs_debounce_id = 0;
54613db86aabSstevel
54623db86aabSstevel /*
54633db86aabSstevel * Check to see whether a card is present or not. There are
54643db86aabSstevel * only two states that we are concerned with - the state
54653db86aabSstevel * where both CD pins are asserted, which means that the
54663db86aabSstevel * card is fully seated, and the state where neither CD
54673db86aabSstevel * pin is asserted, which means that the card is not
54683db86aabSstevel * present.
54693db86aabSstevel * The CD signals are generally very noisy and cause a lot of
54703db86aabSstevel * contact bounce as the card is being inserted and
54713db86aabSstevel * removed, so we need to do some software debouncing.
54723db86aabSstevel */
54733db86aabSstevel
54743db86aabSstevel #ifdef PCIC_DEBUG
54753db86aabSstevel pcic_err(pcic->dip, 6,
54763db86aabSstevel "pcic%d handle_cd_change: socket %d card status 0x%x"
54773db86aabSstevel " deb 0x%p\n", ddi_get_instance(pcic->dip),
54783db86aabSstevel sockp->pcs_socket, status, debounce);
54793db86aabSstevel #endif
54803db86aabSstevel switch (status & PCIC_ISTAT_CD_MASK) {
54813db86aabSstevel case PCIC_CD_PRESENT_OK:
54823db86aabSstevel sockp->pcs_flags &= ~(PCS_CARD_REMOVED|PCS_CARD_CBREM);
54833db86aabSstevel if (!(sockp->pcs_flags & PCS_CARD_PRESENT)) {
54843db86aabSstevel uint32_t cbps;
54853db86aabSstevel #ifdef PCIC_DEBUG
54863db86aabSstevel pcic_err(pcic->dip, 8, "New card (0x%x)\n", sockp->pcs_flags);
54873db86aabSstevel #endif
54883db86aabSstevel cbps = pcic_getcb(pcic, CB_PRESENT_STATE);
54893db86aabSstevel #ifdef PCIC_DEBUG
54903db86aabSstevel pcic_err(pcic->dip, 8, "CBus PS (0x%x)\n", cbps);
54913db86aabSstevel #endif
54923db86aabSstevel /*
54933db86aabSstevel * Check the CB bits are sane.
54943db86aabSstevel */
54953db86aabSstevel if ((cbps & pcic_cbps_on) != pcic_cbps_on ||
54963db86aabSstevel cbps & pcic_cbps_off) {
54973db86aabSstevel cmn_err(CE_WARN,
54983db86aabSstevel "%s%d: Odd Cardbus Present State 0x%x\n",
54993db86aabSstevel ddi_get_name(pcic->dip),
55003db86aabSstevel ddi_get_instance(pcic->dip),
55013db86aabSstevel cbps);
55023db86aabSstevel pcic_putcb(pcic, CB_EVENT_FORCE, CB_EF_CVTEST);
55033db86aabSstevel debounce = 0;
55043db86aabSstevel debounce_time = drv_usectohz(1000000);
55053db86aabSstevel }
55063db86aabSstevel if (debounce) {
55073db86aabSstevel sockp->pcs_flags |= PCS_CARD_PRESENT;
55083db86aabSstevel if (pcic_do_insertion) {
55093db86aabSstevel
55103db86aabSstevel cbps = pcic_getcb(pcic, CB_PRESENT_STATE);
55113db86aabSstevel
55123db86aabSstevel if (cbps & CB_PS_16BITCARD) {
551319397407SSherry Moore pcic_err(pcic->dip,
551419397407SSherry Moore 8, "16 bit card inserted\n");
55153db86aabSstevel sockp->pcs_flags |= PCS_CARD_IS16BIT;
55163db86aabSstevel /* calls pcm_adapter_callback() */
55173db86aabSstevel if (pcic->pc_callback) {
55183db86aabSstevel
551919397407SSherry Moore (void) ddi_prop_update_string(
552019397407SSherry Moore DDI_DEV_T_NONE,
55213db86aabSstevel pcic->dip, PCM_DEVICETYPE,
55223db86aabSstevel "pccard");
552319397407SSherry Moore PC_CALLBACK(pcic->dip,
552419397407SSherry Moore pcic->pc_cb_arg,
55253db86aabSstevel PCE_CARD_INSERT,
55263db86aabSstevel sockp->pcs_socket);
55273db86aabSstevel }
55283db86aabSstevel } else if (cbps & CB_PS_CBCARD) {
552919397407SSherry Moore pcic_err(pcic->dip,
553019397407SSherry Moore 8, "32 bit card inserted\n");
55313db86aabSstevel
55323db86aabSstevel if (pcic->pc_flags & PCF_CARDBUS) {
553319397407SSherry Moore sockp->pcs_flags |=
553419397407SSherry Moore PCS_CARD_ISCARDBUS;
55353db86aabSstevel #ifdef CARDBUS
553619397407SSherry Moore if (!pcic_load_cardbus(pcic,
553719397407SSherry Moore sockp)) {
553819397407SSherry Moore pcic_unload_cardbus(
553919397407SSherry Moore pcic, sockp);
55403db86aabSstevel }
55413db86aabSstevel
55423db86aabSstevel #else
55433db86aabSstevel cmn_err(CE_NOTE,
554419397407SSherry Moore "32 bit Cardbus not"
554519397407SSherry Moore " supported in"
55463db86aabSstevel " this device driver\n");
55473db86aabSstevel #endif
55483db86aabSstevel } else {
55493db86aabSstevel /*
55503db86aabSstevel * Ignore the card
55513db86aabSstevel */
55523db86aabSstevel cmn_err(CE_NOTE,
555319397407SSherry Moore "32 bit Cardbus not"
555419397407SSherry Moore " supported on this"
55553db86aabSstevel " device\n");
55563db86aabSstevel }
55573db86aabSstevel } else {
55583db86aabSstevel cmn_err(CE_NOTE,
555919397407SSherry Moore "Unsupported PCMCIA card"
556019397407SSherry Moore " inserted\n");
55613db86aabSstevel }
55623db86aabSstevel }
55633db86aabSstevel } else {
55643db86aabSstevel do_debounce = B_TRUE;
55653db86aabSstevel }
55663db86aabSstevel } else {
55673db86aabSstevel /*
55683db86aabSstevel * It is possible to come through here if the system
55693db86aabSstevel * starts up with cards already inserted. Do nothing
55703db86aabSstevel * and don't worry about it.
55713db86aabSstevel */
55723db86aabSstevel #ifdef PCIC_DEBUG
55733db86aabSstevel pcic_err(pcic->dip, 5,
55743db86aabSstevel "pcic%d: Odd card insertion indication on socket %d\n",
55753db86aabSstevel ddi_get_instance(pcic->dip),
55763db86aabSstevel sockp->pcs_socket);
55773db86aabSstevel #endif
55783db86aabSstevel }
55793db86aabSstevel break;
55803db86aabSstevel
55813db86aabSstevel default:
55823db86aabSstevel if (!(sockp->pcs_flags & PCS_CARD_PRESENT)) {
55833db86aabSstevel /*
55843db86aabSstevel * Someone has started to insert a card so delay a while.
55853db86aabSstevel */
55863db86aabSstevel do_debounce = B_TRUE;
55873db86aabSstevel break;
55883db86aabSstevel }
55893db86aabSstevel /*
55903db86aabSstevel * Otherwise this is basically the same as not present
55913db86aabSstevel * so fall through.
55923db86aabSstevel */
55933db86aabSstevel
55943db86aabSstevel /* FALLTHRU */
55953db86aabSstevel case 0:
55963db86aabSstevel if (sockp->pcs_flags & PCS_CARD_PRESENT) {
55973db86aabSstevel if (pcic->pc_flags & PCF_CBPWRCTL) {
55983db86aabSstevel pcic_putcb(pcic, CB_CONTROL, 0);
55993db86aabSstevel } else {
560019397407SSherry Moore pcic_putb(pcic, sockp->pcs_socket,
560119397407SSherry Moore PCIC_POWER_CONTROL, 0);
56023db86aabSstevel (void) pcic_getb(pcic, sockp->pcs_socket,
56033db86aabSstevel PCIC_POWER_CONTROL);
56043db86aabSstevel }
56053db86aabSstevel #ifdef PCIC_DEBUG
56063db86aabSstevel pcic_err(pcic->dip, 8, "Card removed\n");
56073db86aabSstevel #endif
56083db86aabSstevel sockp->pcs_flags &= ~PCS_CARD_PRESENT;
56093db86aabSstevel
56103db86aabSstevel if (sockp->pcs_flags & PCS_CARD_IS16BIT) {
56113db86aabSstevel sockp->pcs_flags &= ~PCS_CARD_IS16BIT;
56123db86aabSstevel if (pcic_do_removal && pcic->pc_callback) {
56133db86aabSstevel PC_CALLBACK(pcic->dip, pcic->pc_cb_arg,
56143db86aabSstevel PCE_CARD_REMOVAL, sockp->pcs_socket);
56153db86aabSstevel }
56163db86aabSstevel }
56173db86aabSstevel if (sockp->pcs_flags & PCS_CARD_ISCARDBUS) {
56183db86aabSstevel sockp->pcs_flags &= ~PCS_CARD_ISCARDBUS;
56193db86aabSstevel sockp->pcs_flags |= PCS_CARD_CBREM;
56203db86aabSstevel }
56213db86aabSstevel sockp->pcs_flags |= PCS_CARD_REMOVED;
56223db86aabSstevel
56233db86aabSstevel do_debounce = B_TRUE;
56243db86aabSstevel }
56253db86aabSstevel if (debounce && (sockp->pcs_flags & PCS_CARD_REMOVED)) {
56263db86aabSstevel if (sockp->pcs_flags & PCS_CARD_CBREM) {
56273db86aabSstevel /*
56283db86aabSstevel * Ensure that we do the unloading in the
56293db86aabSstevel * debounce handler, that way we're not doing
56303db86aabSstevel * nasty things in an interrupt handler. e.g.
56313db86aabSstevel * a USB device will wait for data which will
56323db86aabSstevel * obviously never come because we've
56333db86aabSstevel * unplugged the device, but the wait will
56343db86aabSstevel * wait forever because no interrupts can
56353db86aabSstevel * come in...
56363db86aabSstevel */
56373db86aabSstevel #ifdef CARDBUS
56383db86aabSstevel pcic_unload_cardbus(pcic, sockp);
56393db86aabSstevel /* pcic_dump_all(pcic); */
56403db86aabSstevel #endif
56413db86aabSstevel sockp->pcs_flags &= ~PCS_CARD_CBREM;
56423db86aabSstevel }
56433db86aabSstevel sockp->pcs_flags &= ~PCS_CARD_REMOVED;
56443db86aabSstevel }
56453db86aabSstevel break;
56463db86aabSstevel } /* switch */
56473db86aabSstevel
56483db86aabSstevel if (do_debounce) {
56493db86aabSstevel /*
56503db86aabSstevel * Delay doing
56513db86aabSstevel * anything for a while so that things can settle
56523db86aabSstevel * down a little. Interrupts are already disabled.
56533db86aabSstevel * Reset the state and we'll reevaluate the
56543db86aabSstevel * whole kit 'n kaboodle when the timeout fires
56553db86aabSstevel */
56563db86aabSstevel #ifdef PCIC_DEBUG
56573db86aabSstevel pcic_err(pcic->dip, 8, "Queueing up debounce timeout for "
56583db86aabSstevel "socket %d.%d\n",
56593db86aabSstevel ddi_get_instance(pcic->dip),
56603db86aabSstevel sockp->pcs_socket);
56613db86aabSstevel #endif
566219397407SSherry Moore sockp->pcs_debounce_id =
566319397407SSherry Moore pcic_add_debqueue(sockp, debounce_time);
56643db86aabSstevel
56653db86aabSstevel /*
56663db86aabSstevel * We bug out here without re-enabling interrupts. They will
56673db86aabSstevel * be re-enabled when the debounce timeout swings through
56683db86aabSstevel * here.
56693db86aabSstevel */
56703db86aabSstevel return;
56713db86aabSstevel }
56723db86aabSstevel
56733db86aabSstevel /*
56743db86aabSstevel * Turn on Card detect interrupts. Other interrupts will be
56753db86aabSstevel * enabled during set_socket calls.
56763db86aabSstevel *
56773db86aabSstevel * Note that set_socket only changes interrupt settings when there
56783db86aabSstevel * is a card present.
56793db86aabSstevel */
56803db86aabSstevel irq = pcic_getb(pcic, sockp->pcs_socket, PCIC_MANAGEMENT_INT);
56813db86aabSstevel irq |= PCIC_CD_DETECT;
56823db86aabSstevel pcic_putb(pcic, sockp->pcs_socket, PCIC_MANAGEMENT_INT, irq);
56830e995c33Srw148561 pcic_putcb(pcic, CB_STATUS_MASK, CB_SE_CCDMASK);
56843db86aabSstevel
56850d282d13Srw148561 /* Out from debouncing state */
56860d282d13Srw148561 sockp->pcs_flags &= ~PCS_DEBOUNCING;
56870d282d13Srw148561
56883db86aabSstevel pcic_err(pcic->dip, 7, "Leaving pcic_handle_cd_change\n");
56893db86aabSstevel }
56903db86aabSstevel
56913db86aabSstevel /*
56923db86aabSstevel * pcic_getb()
56933db86aabSstevel * get an I/O byte based on the yardware decode method
56943db86aabSstevel */
56953db86aabSstevel static uint8_t
pcic_getb(pcicdev_t * pcic,int socket,int reg)56963db86aabSstevel pcic_getb(pcicdev_t *pcic, int socket, int reg)
56973db86aabSstevel {
56983db86aabSstevel int work;
56993db86aabSstevel
57003db86aabSstevel #if defined(PCIC_DEBUG)
57013db86aabSstevel if (pcic_debug == 0x7fff) {
57023db86aabSstevel cmn_err(CE_CONT, "pcic_getb0: pcic=%p socket=%d reg=%d\n",
57033db86aabSstevel (void *)pcic, socket, reg);
57043db86aabSstevel cmn_err(CE_CONT, "pcic_getb1: type=%d handle=%p ioaddr=%p \n",
57053db86aabSstevel pcic->pc_io_type, (void *)pcic->handle,
57063db86aabSstevel (void *)pcic->ioaddr);
57073db86aabSstevel }
57083db86aabSstevel #endif
57093db86aabSstevel
57103db86aabSstevel switch (pcic->pc_io_type) {
57113db86aabSstevel case PCIC_IO_TYPE_YENTA:
57123db86aabSstevel return (ddi_get8(pcic->handle,
57133db86aabSstevel pcic->ioaddr + CB_R2_OFFSET + reg));
57143db86aabSstevel default:
57153db86aabSstevel work = (socket * PCIC_SOCKET_1) | reg;
57163db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr, work);
57173db86aabSstevel return (ddi_get8(pcic->handle, pcic->ioaddr + 1));
57183db86aabSstevel }
57193db86aabSstevel }
57203db86aabSstevel
57213db86aabSstevel static void
pcic_putb(pcicdev_t * pcic,int socket,int reg,int8_t value)57223db86aabSstevel pcic_putb(pcicdev_t *pcic, int socket, int reg, int8_t value)
57233db86aabSstevel {
57243db86aabSstevel int work;
57253db86aabSstevel
57263db86aabSstevel #if defined(PCIC_DEBUG)
57273db86aabSstevel if (pcic_debug == 0x7fff) {
57283db86aabSstevel cmn_err(CE_CONT,
57293db86aabSstevel "pcic_putb0: pcic=%p socket=%d reg=%d value=%x \n",
57303db86aabSstevel (void *)pcic, socket, reg, value);
57313db86aabSstevel cmn_err(CE_CONT,
57323db86aabSstevel "pcic_putb1: type=%d handle=%p ioaddr=%p \n",
57333db86aabSstevel pcic->pc_io_type, (void *)pcic->handle,
57343db86aabSstevel (void *)pcic->ioaddr);
57353db86aabSstevel }
57363db86aabSstevel #endif
57373db86aabSstevel
57383db86aabSstevel
57393db86aabSstevel switch (pcic->pc_io_type) {
57403db86aabSstevel case PCIC_IO_TYPE_YENTA:
57413db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr + CB_R2_OFFSET + reg,
57423db86aabSstevel value);
57433db86aabSstevel break;
57443db86aabSstevel default:
57453db86aabSstevel work = (socket * PCIC_SOCKET_1) | reg;
57463db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr, work);
57473db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr + 1, value);
57483db86aabSstevel break;
57493db86aabSstevel }
57503db86aabSstevel }
57513db86aabSstevel
57523db86aabSstevel /*
57533db86aabSstevel * chip identification functions
57543db86aabSstevel */
57553db86aabSstevel
57563db86aabSstevel /*
57573db86aabSstevel * chip identification: Cirrus Logic PD6710/6720/6722
57583db86aabSstevel */
57593db86aabSstevel static int
pcic_ci_cirrus(pcicdev_t * pcic)57603db86aabSstevel pcic_ci_cirrus(pcicdev_t *pcic)
57613db86aabSstevel {
57623db86aabSstevel int value1, value2;
57633db86aabSstevel
57643db86aabSstevel /* Init the CL id mode */
57653db86aabSstevel value1 = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
57663db86aabSstevel pcic_putb(pcic, 0, PCIC_CHIP_INFO, 0);
57673db86aabSstevel value1 = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
57683db86aabSstevel value2 = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
57693db86aabSstevel
57703db86aabSstevel if ((value1 & PCIC_CI_ID) == PCIC_CI_ID &&
57713db86aabSstevel (value2 & PCIC_CI_ID) == 0) {
57723db86aabSstevel /* chip is a Cirrus Logic and not Intel */
57733db86aabSstevel pcic->pc_type = PCIC_CL_PD6710;
57743db86aabSstevel if (value1 & PCIC_CI_SLOTS)
57753db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6720;
57763db86aabSstevel else
57773db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6710;
57783db86aabSstevel /* now fine tune things just in case a 6722 */
57793db86aabSstevel value1 = clext_reg_read(pcic, 0, PCIC_CLEXT_DMASK_0);
57803db86aabSstevel if (value1 == 0) {
57813db86aabSstevel clext_reg_write(pcic, 0, PCIC_CLEXT_SCRATCH, 0x55);
57823db86aabSstevel value1 = clext_reg_read(pcic, 0, PCIC_CLEXT_SCRATCH);
57833db86aabSstevel if (value1 == 0x55) {
57843db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6722;
57853db86aabSstevel pcic->pc_type = PCIC_CL_PD6722;
57863db86aabSstevel clext_reg_write(pcic, 0, PCIC_CLEXT_SCRATCH, 0);
57873db86aabSstevel }
57883db86aabSstevel }
57893db86aabSstevel return (1);
57903db86aabSstevel }
57913db86aabSstevel return (0);
57923db86aabSstevel }
57933db86aabSstevel
57943db86aabSstevel /*
57953db86aabSstevel * chip identification: Vadem (VG365/465/468/469)
57963db86aabSstevel */
57973db86aabSstevel
57983db86aabSstevel static void
pcic_vadem_enable(pcicdev_t * pcic)57993db86aabSstevel pcic_vadem_enable(pcicdev_t *pcic)
58003db86aabSstevel {
58013db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr, PCIC_VADEM_P1);
58023db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr, PCIC_VADEM_P2);
58033db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr, pcic->pc_lastreg);
58043db86aabSstevel }
58053db86aabSstevel
58063db86aabSstevel static int
pcic_ci_vadem(pcicdev_t * pcic)58073db86aabSstevel pcic_ci_vadem(pcicdev_t *pcic)
58083db86aabSstevel {
58093db86aabSstevel int value;
58103db86aabSstevel
58113db86aabSstevel pcic_vadem_enable(pcic);
58123db86aabSstevel value = pcic_getb(pcic, 0, PCIC_CHIP_REVISION);
58133db86aabSstevel pcic_putb(pcic, 0, PCIC_CHIP_REVISION, 0xFF);
58143db86aabSstevel if (pcic_getb(pcic, 0, PCIC_CHIP_REVISION) ==
58153db86aabSstevel (value | PCIC_VADEM_D3) ||
58163db86aabSstevel (pcic_getb(pcic, 0, PCIC_CHIP_REVISION) & PCIC_REV_MASK) ==
58173db86aabSstevel PCIC_VADEM_469) {
58183db86aabSstevel int vadem, new;
58193db86aabSstevel pcic_vadem_enable(pcic);
58203db86aabSstevel vadem = pcic_getb(pcic, 0, PCIC_VG_DMA) &
58213db86aabSstevel ~(PCIC_V_UNLOCK | PCIC_V_VADEMREV);
58223db86aabSstevel new = vadem | (PCIC_V_VADEMREV|PCIC_V_UNLOCK);
58233db86aabSstevel pcic_putb(pcic, 0, PCIC_VG_DMA, new);
58243db86aabSstevel value = pcic_getb(pcic, 0, PCIC_CHIP_REVISION);
58253db86aabSstevel
58263db86aabSstevel /* want to lock but leave mouse or other on */
58273db86aabSstevel pcic_putb(pcic, 0, PCIC_VG_DMA, vadem);
58283db86aabSstevel switch (value & PCIC_REV_MASK) {
58293db86aabSstevel case PCIC_VADEM_365:
58303db86aabSstevel pcic->pc_chipname = PCIC_VG_365;
58313db86aabSstevel pcic->pc_type = PCIC_VADEM;
58323db86aabSstevel break;
58333db86aabSstevel case PCIC_VADEM_465:
58343db86aabSstevel pcic->pc_chipname = PCIC_VG_465;
58353db86aabSstevel pcic->pc_type = PCIC_VADEM;
58363db86aabSstevel pcic->pc_flags |= PCF_1SOCKET;
58373db86aabSstevel break;
58383db86aabSstevel case PCIC_VADEM_468:
58393db86aabSstevel pcic->pc_chipname = PCIC_VG_468;
58403db86aabSstevel pcic->pc_type = PCIC_VADEM;
58413db86aabSstevel break;
58423db86aabSstevel case PCIC_VADEM_469:
58433db86aabSstevel pcic->pc_chipname = PCIC_VG_469;
58443db86aabSstevel pcic->pc_type = PCIC_VADEM_VG469;
58453db86aabSstevel break;
58463db86aabSstevel }
58473db86aabSstevel return (1);
58483db86aabSstevel }
58493db86aabSstevel return (0);
58503db86aabSstevel }
58513db86aabSstevel
58523db86aabSstevel /*
58533db86aabSstevel * chip identification: Ricoh
58543db86aabSstevel */
58553db86aabSstevel static int
pcic_ci_ricoh(pcicdev_t * pcic)58563db86aabSstevel pcic_ci_ricoh(pcicdev_t *pcic)
58573db86aabSstevel {
58583db86aabSstevel int value;
58593db86aabSstevel
58603db86aabSstevel value = pcic_getb(pcic, 0, PCIC_RF_CHIP_IDENT);
58613db86aabSstevel switch (value) {
58623db86aabSstevel case PCIC_RF_296:
58633db86aabSstevel pcic->pc_type = PCIC_RICOH;
58643db86aabSstevel pcic->pc_chipname = PCIC_TYPE_RF5C296;
58653db86aabSstevel return (1);
58663db86aabSstevel case PCIC_RF_396:
58673db86aabSstevel pcic->pc_type = PCIC_RICOH;
58683db86aabSstevel pcic->pc_chipname = PCIC_TYPE_RF5C396;
58693db86aabSstevel return (1);
58703db86aabSstevel }
58713db86aabSstevel return (0);
58723db86aabSstevel }
58733db86aabSstevel
58743db86aabSstevel
58753db86aabSstevel /*
58763db86aabSstevel * set up available address spaces in busra
58773db86aabSstevel */
58783db86aabSstevel static void
pcic_init_assigned(dev_info_t * dip)58793db86aabSstevel pcic_init_assigned(dev_info_t *dip)
58803db86aabSstevel {
58813db86aabSstevel pcm_regs_t *pcic_avail_p;
58823db86aabSstevel pci_regspec_t *pci_avail_p, *regs;
58833db86aabSstevel int len, entries, rlen;
58843db86aabSstevel dev_info_t *pdip;
58853db86aabSstevel
58863db86aabSstevel if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
58873db86aabSstevel "available", (caddr_t)&pcic_avail_p, &len) == DDI_PROP_SUCCESS) {
58883db86aabSstevel /*
58893db86aabSstevel * found "available" property at the cardbus/pcmcia node
58903db86aabSstevel * need to translate address space entries from pcmcia
58913db86aabSstevel * format to pci format
58923db86aabSstevel */
58933db86aabSstevel entries = len / sizeof (pcm_regs_t);
58943db86aabSstevel pci_avail_p = kmem_alloc(sizeof (pci_regspec_t) * entries,
58953db86aabSstevel KM_SLEEP);
58963db86aabSstevel if (pcic_apply_avail_ranges(dip, pcic_avail_p, pci_avail_p,
58973db86aabSstevel entries) == DDI_SUCCESS)
58983db86aabSstevel (void) pci_resource_setup_avail(dip, pci_avail_p,
58993db86aabSstevel entries);
59003db86aabSstevel kmem_free(pcic_avail_p, len);
59013db86aabSstevel kmem_free(pci_avail_p, entries * sizeof (pci_regspec_t));
59023db86aabSstevel return;
59033db86aabSstevel }
59043db86aabSstevel
59053db86aabSstevel /*
59063db86aabSstevel * "legacy" platforms will have "available" property in pci node
59073db86aabSstevel */
59083db86aabSstevel for (pdip = ddi_get_parent(dip); pdip; pdip = ddi_get_parent(pdip)) {
59093db86aabSstevel if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
59103db86aabSstevel "available", (caddr_t)&pci_avail_p, &len) ==
59113db86aabSstevel DDI_PROP_SUCCESS) {
59123db86aabSstevel /* (void) pci_resource_setup(pdip); */
59133db86aabSstevel kmem_free(pci_avail_p, len);
59143db86aabSstevel break;
59153db86aabSstevel }
59163db86aabSstevel }
59173db86aabSstevel
59183db86aabSstevel if (pdip == NULL) {
59193db86aabSstevel int len;
59203db86aabSstevel char bus_type[16] = "(unknown)";
59213db86aabSstevel dev_info_t *par;
59223db86aabSstevel
59233db86aabSstevel cmn_err(CE_CONT,
59243db86aabSstevel "?pcic_init_assigned: no available property for pcmcia\n");
59253db86aabSstevel
59263db86aabSstevel /*
59273db86aabSstevel * This code is taken from pci_resource_setup() but does
59283db86aabSstevel * not attempt to use the "available" property to populate
59293db86aabSstevel * the ndi maps that are created.
59303db86aabSstevel * The fact that we will actually
59313db86aabSstevel * free some resource below (that was allocated by OBP)
59323db86aabSstevel * should be enough to be going on with.
59333db86aabSstevel */
59343db86aabSstevel for (par = dip; par != NULL; par = ddi_get_parent(par)) {
59353db86aabSstevel len = sizeof (bus_type);
59363db86aabSstevel
59373db86aabSstevel if ((ddi_prop_op(DDI_DEV_T_ANY, par,
59383db86aabSstevel PROP_LEN_AND_VAL_BUF,
59393db86aabSstevel DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
59403db86aabSstevel "device_type",
59413db86aabSstevel (caddr_t)&bus_type, &len) == DDI_SUCCESS) &&
59428134ee03Srw148561 (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0 ||
59438134ee03Srw148561 strcmp(bus_type, DEVI_PCIEX_NEXNAME) == 0))
59443db86aabSstevel break;
59453db86aabSstevel }
59463db86aabSstevel if (par != NULL &&
59473db86aabSstevel (ndi_ra_map_setup(par, NDI_RA_TYPE_MEM) != NDI_SUCCESS ||
59483db86aabSstevel ndi_ra_map_setup(par, NDI_RA_TYPE_IO) != NDI_SUCCESS))
59493db86aabSstevel par = NULL;
59503db86aabSstevel } else {
59513db86aabSstevel #ifdef CARDBUS
59523db86aabSstevel cardbus_bus_range_t *bus_range;
59533db86aabSstevel int k;
59543db86aabSstevel
59553db86aabSstevel if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "bus-range",
59563db86aabSstevel (caddr_t)&bus_range, &k) == DDI_PROP_SUCCESS) {
59573db86aabSstevel if (bus_range->lo != bus_range->hi)
59583db86aabSstevel pcic_err(pdip, 9, "allowable bus range is "
59593db86aabSstevel "%u->%u\n", bus_range->lo, bus_range->hi);
59603db86aabSstevel else {
59613db86aabSstevel pcic_err(pdip, 0,
59623db86aabSstevel "!No spare PCI bus numbers, range is "
59633db86aabSstevel "%u->%u, cardbus isn't usable\n",
59643db86aabSstevel bus_range->lo, bus_range->hi);
59653db86aabSstevel }
59663db86aabSstevel kmem_free(bus_range, k);
59673db86aabSstevel } else
59683db86aabSstevel pcic_err(pdip, 0, "!No bus-range property seems to "
59693db86aabSstevel "have been set up\n");
59703db86aabSstevel #endif
59713db86aabSstevel /*
59723db86aabSstevel * Have a valid parent with the "available" property
59733db86aabSstevel */
59743db86aabSstevel (void) pci_resource_setup(pdip);
59753db86aabSstevel }
59763db86aabSstevel
59773db86aabSstevel if ((strcmp(ddi_get_name(dip), "pcma") == 0) &&
59783db86aabSstevel ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
59793db86aabSstevel "assigned-addresses",
59803db86aabSstevel (caddr_t)®s, &rlen) == DDI_SUCCESS) {
59813db86aabSstevel ra_return_t ra;
59823db86aabSstevel
59833db86aabSstevel /*
59843db86aabSstevel * On the UltraBook IIi the ranges are assigned under
59853db86aabSstevel * openboot. If we don't free them here the first I/O
59863db86aabSstevel * space that can be used is up above 0x10000 which
59873db86aabSstevel * doesn't work for this driver due to restrictions
59883db86aabSstevel * on the PCI I/O addresses the controllers can cope with.
59893db86aabSstevel * They are never going to be used by anything else
59903db86aabSstevel * so free them up to the general pool. AG.
59913db86aabSstevel */
59923db86aabSstevel pcic_err(dip, 1, "Free assigned addresses\n");
59933db86aabSstevel
59943db86aabSstevel if ((PCI_REG_ADDR_G(regs[0].pci_phys_hi) ==
59953db86aabSstevel PCI_REG_ADDR_G(PCI_ADDR_MEM32)) &&
59963db86aabSstevel regs[0].pci_size_low == 0x1000000) {
59973db86aabSstevel ra.ra_addr_lo = regs[0].pci_phys_low;
59983db86aabSstevel ra.ra_len = regs[0].pci_size_low;
59993db86aabSstevel (void) pcmcia_free_mem(dip, &ra);
60003db86aabSstevel }
60013db86aabSstevel if ((PCI_REG_ADDR_G(regs[1].pci_phys_hi) ==
60023db86aabSstevel PCI_REG_ADDR_G(PCI_ADDR_IO)) &&
60033db86aabSstevel (regs[1].pci_size_low == 0x8000 ||
60043db86aabSstevel regs[1].pci_size_low == 0x4000)) /* UB-IIi || UB-I */
60053db86aabSstevel {
60063db86aabSstevel ra.ra_addr_lo = regs[1].pci_phys_low;
60073db86aabSstevel ra.ra_len = regs[1].pci_size_low;
60083db86aabSstevel (void) pcmcia_free_io(dip, &ra);
60093db86aabSstevel }
60103db86aabSstevel kmem_free((caddr_t)regs, rlen);
60113db86aabSstevel }
60123db86aabSstevel }
60133db86aabSstevel
60143db86aabSstevel /*
60153db86aabSstevel * translate "available" from pcmcia format to pci format
60163db86aabSstevel */
60173db86aabSstevel static int
pcic_apply_avail_ranges(dev_info_t * dip,pcm_regs_t * pcic_p,pci_regspec_t * pci_p,int entries)60183db86aabSstevel pcic_apply_avail_ranges(dev_info_t *dip, pcm_regs_t *pcic_p,
60193db86aabSstevel pci_regspec_t *pci_p, int entries)
60203db86aabSstevel {
60213db86aabSstevel int i, range_len, range_entries;
60223db86aabSstevel pcic_ranges_t *pcic_range_p;
60233db86aabSstevel
60243db86aabSstevel if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
60253db86aabSstevel (caddr_t)&pcic_range_p, &range_len) != DDI_PROP_SUCCESS) {
60263db86aabSstevel cmn_err(CE_CONT, "?pcic_apply_avail_ranges: "
60273db86aabSstevel "no ranges property for pcmcia\n");
60283db86aabSstevel return (DDI_FAILURE);
60293db86aabSstevel }
60303db86aabSstevel
60313db86aabSstevel range_entries = range_len / sizeof (pcic_ranges_t);
60323db86aabSstevel
60333db86aabSstevel /* for each "available" entry to be translated */
60343db86aabSstevel for (i = 0; i < entries; i++, pcic_p++, pci_p++) {
60353db86aabSstevel int j;
60363db86aabSstevel pcic_ranges_t *range_p = pcic_range_p;
60373db86aabSstevel pci_p->pci_phys_hi = -1u; /* default invalid value */
60383db86aabSstevel
60393db86aabSstevel /* for each "ranges" entry to be searched */
60403db86aabSstevel for (j = 0; j < range_entries; j++, range_p++) {
60413db86aabSstevel uint64_t range_end = range_p->pcic_range_caddrlo +
60423db86aabSstevel range_p->pcic_range_size;
60433db86aabSstevel uint64_t avail_end = pcic_p->phys_lo + pcic_p->phys_len;
60443db86aabSstevel
60453db86aabSstevel if ((range_p->pcic_range_caddrhi != pcic_p->phys_hi) ||
60463db86aabSstevel (range_p->pcic_range_caddrlo > pcic_p->phys_lo) ||
60473db86aabSstevel (range_end < avail_end))
60483db86aabSstevel continue;
60493db86aabSstevel
60503db86aabSstevel pci_p->pci_phys_hi = range_p->pcic_range_paddrhi;
60513db86aabSstevel pci_p->pci_phys_mid = range_p->pcic_range_paddrmid;
60523db86aabSstevel pci_p->pci_phys_low = range_p->pcic_range_paddrlo
60533db86aabSstevel + (pcic_p->phys_lo - range_p->pcic_range_caddrlo);
60543db86aabSstevel pci_p->pci_size_hi = 0;
60553db86aabSstevel pci_p->pci_size_low = pcic_p->phys_len;
60563db86aabSstevel }
60573db86aabSstevel }
60583db86aabSstevel kmem_free(pcic_range_p, range_len);
60593db86aabSstevel return (DDI_SUCCESS);
60603db86aabSstevel }
60613db86aabSstevel
60623db86aabSstevel static int
pcic_open(dev_t * dev,int flag,int otyp,cred_t * cred)60633db86aabSstevel pcic_open(dev_t *dev, int flag, int otyp, cred_t *cred)
60643db86aabSstevel {
60653db86aabSstevel #ifdef CARDBUS
60663db86aabSstevel if (cardbus_is_cb_minor(*dev))
60673db86aabSstevel return (cardbus_open(dev, flag, otyp, cred));
60683db86aabSstevel #endif
60693db86aabSstevel return (EINVAL);
60703db86aabSstevel }
60713db86aabSstevel
60723db86aabSstevel static int
pcic_close(dev_t dev,int flag,int otyp,cred_t * cred)60733db86aabSstevel pcic_close(dev_t dev, int flag, int otyp, cred_t *cred)
60743db86aabSstevel {
60753db86aabSstevel #ifdef CARDBUS
60763db86aabSstevel if (cardbus_is_cb_minor(dev))
60773db86aabSstevel return (cardbus_close(dev, flag, otyp, cred));
60783db86aabSstevel #endif
60793db86aabSstevel return (EINVAL);
60803db86aabSstevel }
60813db86aabSstevel
60823db86aabSstevel static int
pcic_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred,int * rval)60833db86aabSstevel pcic_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred,
60843db86aabSstevel int *rval)
60853db86aabSstevel {
60863db86aabSstevel #ifdef CARDBUS
60873db86aabSstevel if (cardbus_is_cb_minor(dev))
60883db86aabSstevel return (cardbus_ioctl(dev, cmd, arg, mode, cred, rval));
60893db86aabSstevel #endif
60903db86aabSstevel return (EINVAL);
60913db86aabSstevel }
60923db86aabSstevel
60933db86aabSstevel
60943db86aabSstevel static boolean_t
pcic_load_cardbus(pcicdev_t * pcic,const pcic_socket_t * sockp)60953db86aabSstevel pcic_load_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp)
60963db86aabSstevel {
60973db86aabSstevel uint32_t present_state;
60983db86aabSstevel dev_info_t *dip = pcic->dip;
60993db86aabSstevel set_socket_t s;
61003db86aabSstevel get_socket_t g;
61013db86aabSstevel boolean_t retval;
61023db86aabSstevel unsigned vccLevel;
61033db86aabSstevel
61043db86aabSstevel pcic_err(dip, 8, "entering pcic_load_cardbus\n");
61053db86aabSstevel
61063db86aabSstevel pcic_mutex_exit(&pcic->pc_lock);
61073db86aabSstevel
61083db86aabSstevel bzero(&s, sizeof (set_socket_t));
61093db86aabSstevel s.socket = sockp->pcs_socket;
61103db86aabSstevel s.SCIntMask = SBM_CD|SBM_RDYBSY;
61113db86aabSstevel s.IFType = IF_CARDBUS;
61123db86aabSstevel s.State = (unsigned)~0;
61133db86aabSstevel
61143db86aabSstevel present_state = pcic_getcb(pcic, CB_PRESENT_STATE);
61153db86aabSstevel if (present_state & PCIC_VCC_3VCARD)
61163db86aabSstevel s.VccLevel = PCIC_VCC_3VLEVEL;
61173db86aabSstevel else if (present_state & PCIC_VCC_5VCARD)
61183db86aabSstevel s.VccLevel = PCIC_VCC_5VLEVEL;
61193db86aabSstevel else {
61203db86aabSstevel cmn_err(CE_CONT,
61213db86aabSstevel "pcic_load_cardbus: unsupported card voltage\n");
61223db86aabSstevel goto failure;
61233db86aabSstevel }
61243db86aabSstevel vccLevel = s.VccLevel;
61253db86aabSstevel s.Vpp1Level = s.Vpp2Level = 0;
61263db86aabSstevel
61273db86aabSstevel if (pcic_set_socket(dip, &s) != SUCCESS)
61283db86aabSstevel goto failure;
61293db86aabSstevel
61303db86aabSstevel if (pcic_reset_socket(dip, sockp->pcs_socket,
61313db86aabSstevel RESET_MODE_CARD_ONLY) != SUCCESS)
61323db86aabSstevel goto failure;
61333db86aabSstevel
61343db86aabSstevel bzero(&g, sizeof (get_socket_t));
61353db86aabSstevel g.socket = sockp->pcs_socket;
61363db86aabSstevel if (pcic_get_socket(dip, &g) != SUCCESS)
61373db86aabSstevel goto failure;
61383db86aabSstevel
61393db86aabSstevel bzero(&s, sizeof (set_socket_t));
61403db86aabSstevel s.socket = sockp->pcs_socket;
61413db86aabSstevel s.SCIntMask = SBM_CD;
61423db86aabSstevel s.IREQRouting = g.IRQRouting;
61433db86aabSstevel s.IFType = g.IFType;
61443db86aabSstevel s.CtlInd = g.CtlInd;
61453db86aabSstevel s.State = (unsigned)~0;
61463db86aabSstevel s.VccLevel = vccLevel;
61473db86aabSstevel s.Vpp1Level = s.Vpp2Level = 0;
61483db86aabSstevel
614911c2b4c0Srw148561 retval = pcic_set_socket(dip, &s);
615011c2b4c0Srw148561 pcmcia_cb_resumed(s.socket);
615111c2b4c0Srw148561 if (retval != SUCCESS)
61523db86aabSstevel goto failure;
61533db86aabSstevel
61543db86aabSstevel retval = cardbus_load_cardbus(dip, sockp->pcs_socket, pcic->pc_base);
61553db86aabSstevel goto exit;
61563db86aabSstevel
61573db86aabSstevel failure:
61583db86aabSstevel retval = B_FALSE;
61593db86aabSstevel
61603db86aabSstevel exit:
61613db86aabSstevel pcic_mutex_enter(&pcic->pc_lock);
61623db86aabSstevel pcic_err(dip, 8, "exit pcic_load_cardbus (%s)\n",
61633db86aabSstevel retval ? "success" : "failure");
61643db86aabSstevel return (retval);
61653db86aabSstevel }
61663db86aabSstevel
61673db86aabSstevel static void
pcic_unload_cardbus(pcicdev_t * pcic,const pcic_socket_t * sockp)61683db86aabSstevel pcic_unload_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp)
61693db86aabSstevel {
61703db86aabSstevel dev_info_t *dip = pcic->dip;
61713db86aabSstevel set_socket_t s;
61723db86aabSstevel
61733db86aabSstevel pcic_mutex_exit(&pcic->pc_lock);
61743db86aabSstevel
61753db86aabSstevel cardbus_unload_cardbus(dip);
61763db86aabSstevel
61773db86aabSstevel bzero(&s, sizeof (set_socket_t));
61783db86aabSstevel s.socket = sockp->pcs_socket;
61793db86aabSstevel s.SCIntMask = SBM_CD|SBM_RDYBSY;
61803db86aabSstevel s.IREQRouting = 0;
61813db86aabSstevel s.IFType = IF_MEMORY;
61823db86aabSstevel s.CtlInd = 0;
61833db86aabSstevel s.State = 0;
61843db86aabSstevel s.VccLevel = s.Vpp1Level = s.Vpp2Level = 0;
61853db86aabSstevel
61863db86aabSstevel (void) pcic_set_socket(dip, &s);
61873db86aabSstevel
61883db86aabSstevel pcic_mutex_enter(&pcic->pc_lock);
61893db86aabSstevel }
61903db86aabSstevel
61913db86aabSstevel static uint32_t
pcic_getcb(pcicdev_t * pcic,int reg)61923db86aabSstevel pcic_getcb(pcicdev_t *pcic, int reg)
61933db86aabSstevel {
61943db86aabSstevel ASSERT(pcic->pc_io_type == PCIC_IO_TYPE_YENTA);
61953db86aabSstevel
61963db86aabSstevel return (ddi_get32(pcic->handle,
61973db86aabSstevel (uint32_t *)(pcic->ioaddr + CB_CB_OFFSET + reg)));
61983db86aabSstevel }
61993db86aabSstevel
62003db86aabSstevel static void
pcic_putcb(pcicdev_t * pcic,int reg,uint32_t value)62013db86aabSstevel pcic_putcb(pcicdev_t *pcic, int reg, uint32_t value)
62023db86aabSstevel {
62033db86aabSstevel ASSERT(pcic->pc_io_type == PCIC_IO_TYPE_YENTA);
62043db86aabSstevel
62053db86aabSstevel ddi_put32(pcic->handle,
62063db86aabSstevel (uint32_t *)(pcic->ioaddr + CB_CB_OFFSET + reg), value);
62073db86aabSstevel }
62083db86aabSstevel
62093db86aabSstevel static void
pcic_enable_io_intr(pcicdev_t * pcic,int socket,int irq)62103db86aabSstevel pcic_enable_io_intr(pcicdev_t *pcic, int socket, int irq)
62113db86aabSstevel {
62123db86aabSstevel uint8_t value;
62133db86aabSstevel uint16_t brdgctl;
62143db86aabSstevel
62153db86aabSstevel value = pcic_getb(pcic, socket, PCIC_INTERRUPT) & ~PCIC_INTR_MASK;
62163db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, value | irq);
62173db86aabSstevel
62183db86aabSstevel switch (pcic->pc_type) {
62193db86aabSstevel case PCIC_INTEL_i82092:
62203db86aabSstevel pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ,
62213db86aabSstevel PCIC_82092_INT_ENABLE);
62223db86aabSstevel break;
62233db86aabSstevel case PCIC_O2_OZ6912:
62243db86aabSstevel value = pcic_getb(pcic, 0, PCIC_CENTDMA);
62253db86aabSstevel value |= 0x8;
62263db86aabSstevel pcic_putb(pcic, 0, PCIC_CENTDMA, value);
62273db86aabSstevel break;
62283db86aabSstevel case PCIC_CL_PD6832:
62293db86aabSstevel case PCIC_TI_PCI1250:
62303db86aabSstevel case PCIC_TI_PCI1221:
62313db86aabSstevel case PCIC_TI_PCI1225:
62323db86aabSstevel case PCIC_TI_PCI1410:
62333db86aabSstevel case PCIC_ENE_1410:
62343db86aabSstevel case PCIC_TI_PCI1510:
62353db86aabSstevel case PCIC_TI_PCI1520:
62363db86aabSstevel case PCIC_TI_PCI1420:
62373db86aabSstevel case PCIC_ENE_1420:
62383db86aabSstevel /* route card functional interrupts to PCI interrupts */
62393db86aabSstevel brdgctl = ddi_get16(pcic->cfg_handle,
62403db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
62413db86aabSstevel pcic_err(NULL, 1,
62423db86aabSstevel "pcic_enable_io_intr brdgctl(0x%x) was: 0x%x\n",
62433db86aabSstevel PCI_CBUS_BRIDGE_CTRL, brdgctl);
62443db86aabSstevel brdgctl &= ~PCIC_BRDGCTL_INTR_MASK;
62453db86aabSstevel ddi_put16(pcic->cfg_handle,
62463db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL),
62473db86aabSstevel brdgctl);
62483db86aabSstevel /* Flush the write */
62493db86aabSstevel (void) ddi_get16(pcic->cfg_handle,
62503db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
62513db86aabSstevel break;
62523db86aabSstevel default:
62533db86aabSstevel break;
62543db86aabSstevel }
62553db86aabSstevel }
62563db86aabSstevel
62573db86aabSstevel static void
pcic_disable_io_intr(pcicdev_t * pcic,int socket)62583db86aabSstevel pcic_disable_io_intr(pcicdev_t *pcic, int socket)
62593db86aabSstevel {
62603db86aabSstevel uint8_t value;
62613db86aabSstevel uint16_t brdgctl;
62623db86aabSstevel
62633db86aabSstevel value = pcic_getb(pcic, socket, PCIC_INTERRUPT) & ~PCIC_INTR_MASK;
62643db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, value);
62653db86aabSstevel
62663db86aabSstevel switch (pcic->pc_type) {
62673db86aabSstevel case PCIC_INTEL_i82092:
62683db86aabSstevel pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ,
62693db86aabSstevel PCIC_82092_INT_DISABLE);
62703db86aabSstevel break;
62713db86aabSstevel case PCIC_O2_OZ6912:
62723db86aabSstevel value = pcic_getb(pcic, 0, PCIC_CENTDMA);
62733db86aabSstevel value &= ~0x8;
62743db86aabSstevel pcic_putb(pcic, 0, PCIC_CENTDMA, value);
62753db86aabSstevel /* Flush the write */
62763db86aabSstevel (void) pcic_getb(pcic, 0, PCIC_CENTDMA);
62773db86aabSstevel break;
62783db86aabSstevel case PCIC_CL_PD6832:
62793db86aabSstevel case PCIC_TI_PCI1250:
62803db86aabSstevel case PCIC_TI_PCI1221:
62813db86aabSstevel case PCIC_TI_PCI1225:
62823db86aabSstevel case PCIC_TI_PCI1410:
62833db86aabSstevel case PCIC_ENE_1410:
62843db86aabSstevel case PCIC_TI_PCI1510:
62853db86aabSstevel case PCIC_TI_PCI1520:
62863db86aabSstevel case PCIC_TI_PCI1420:
62873db86aabSstevel case PCIC_ENE_1420:
62883db86aabSstevel /*
62893db86aabSstevel * This maps I/O interrupts to ExCA which
62903db86aabSstevel * have been turned off by the write to
62913db86aabSstevel * PCIC_INTERRUPT above. It would appear to
62923db86aabSstevel * be the only way to actually turn I/O Ints off
62933db86aabSstevel * while retaining CS Ints.
62943db86aabSstevel */
62953db86aabSstevel brdgctl = ddi_get16(pcic->cfg_handle,
62963db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
62973db86aabSstevel pcic_err(NULL, 1,
62983db86aabSstevel "pcic_disable_io_intr brdgctl(0x%x) was: 0x%x\n",
62993db86aabSstevel PCI_CBUS_BRIDGE_CTRL, brdgctl);
63003db86aabSstevel brdgctl |= PCIC_BRDGCTL_INTR_MASK;
63013db86aabSstevel ddi_put16(pcic->cfg_handle,
63023db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL),
63033db86aabSstevel brdgctl);
63043db86aabSstevel /* Flush the write */
63053db86aabSstevel (void) ddi_get16(pcic->cfg_handle,
63063db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
63073db86aabSstevel break;
63083db86aabSstevel default:
63093db86aabSstevel break;
63103db86aabSstevel }
63113db86aabSstevel }
63123db86aabSstevel
63133db86aabSstevel static void
pcic_cb_enable_intr(dev_info_t * dip)63143db86aabSstevel pcic_cb_enable_intr(dev_info_t *dip)
63153db86aabSstevel {
63163db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
63173db86aabSstevel pcicdev_t *pcic = anp->an_private;
63183db86aabSstevel
63193db86aabSstevel mutex_enter(&pcic->pc_lock);
63203db86aabSstevel pcic_enable_io_intr(pcic, 0, pcic->pc_sockets[0].pcs_irq);
63213db86aabSstevel mutex_exit(&pcic->pc_lock);
63223db86aabSstevel }
63233db86aabSstevel
63243db86aabSstevel static void
pcic_cb_disable_intr(dev_info_t * dip)63253db86aabSstevel pcic_cb_disable_intr(dev_info_t *dip)
63263db86aabSstevel {
63273db86aabSstevel anp_t *anp = ddi_get_driver_private(dip);
63283db86aabSstevel pcicdev_t *pcic = anp->an_private;
63293db86aabSstevel
63303db86aabSstevel mutex_enter(&pcic->pc_lock);
63313db86aabSstevel pcic_disable_io_intr(pcic, 0);
63323db86aabSstevel mutex_exit(&pcic->pc_lock);
63333db86aabSstevel }
63343db86aabSstevel
63353db86aabSstevel static int
log_pci_cfg_err(ushort_t e,int bridge_secondary)63363db86aabSstevel log_pci_cfg_err(ushort_t e, int bridge_secondary)
63373db86aabSstevel {
63383db86aabSstevel int nerr = 0;
63393db86aabSstevel if (e & PCI_STAT_PERROR) {
63403db86aabSstevel nerr++;
63413db86aabSstevel cmn_err(CE_CONT, "detected parity error.\n");
63423db86aabSstevel }
63433db86aabSstevel if (e & PCI_STAT_S_SYSERR) {
63443db86aabSstevel nerr++;
63453db86aabSstevel if (bridge_secondary)
63463db86aabSstevel cmn_err(CE_CONT, "received system error.\n");
63473db86aabSstevel else
63483db86aabSstevel cmn_err(CE_CONT, "signalled system error.\n");
63493db86aabSstevel }
63503db86aabSstevel if (e & PCI_STAT_R_MAST_AB) {
63513db86aabSstevel nerr++;
63523db86aabSstevel cmn_err(CE_CONT, "received master abort.\n");
63533db86aabSstevel }
63543db86aabSstevel if (e & PCI_STAT_R_TARG_AB)
63553db86aabSstevel cmn_err(CE_CONT, "received target abort.\n");
63563db86aabSstevel if (e & PCI_STAT_S_TARG_AB)
63573db86aabSstevel cmn_err(CE_CONT, "signalled target abort\n");
63583db86aabSstevel if (e & PCI_STAT_S_PERROR) {
63593db86aabSstevel nerr++;
63603db86aabSstevel cmn_err(CE_CONT, "signalled parity error\n");
63613db86aabSstevel }
63623db86aabSstevel return (nerr);
63633db86aabSstevel }
63643db86aabSstevel
63653db86aabSstevel #if defined(__sparc)
63663db86aabSstevel static int
pcic_fault(enum pci_fault_ops op,void * arg)63673db86aabSstevel pcic_fault(enum pci_fault_ops op, void *arg)
63683db86aabSstevel {
63693db86aabSstevel pcicdev_t *pcic = (pcicdev_t *)arg;
63703db86aabSstevel ushort_t pci_cfg_stat =
63713db86aabSstevel pci_config_get16(pcic->cfg_handle, PCI_CONF_STAT);
63723db86aabSstevel ushort_t pci_cfg_sec_stat =
63733db86aabSstevel pci_config_get16(pcic->cfg_handle, 0x16);
63743db86aabSstevel char nm[24];
63753db86aabSstevel int nerr = 0;
63763db86aabSstevel
63773db86aabSstevel cardbus_dump_pci_config(pcic->dip);
63783db86aabSstevel
63793db86aabSstevel switch (op) {
63803db86aabSstevel case FAULT_LOG:
63813db86aabSstevel (void) sprintf(nm, "%s-%d", ddi_driver_name(pcic->dip),
63823db86aabSstevel ddi_get_instance(pcic->dip));
63833db86aabSstevel
63843db86aabSstevel cmn_err(CE_WARN, "%s: PCIC fault log start:\n", nm);
63853db86aabSstevel cmn_err(CE_WARN, "%s: primary err (%x):\n", nm, pci_cfg_stat);
63863db86aabSstevel nerr += log_pci_cfg_err(pci_cfg_stat, 0);
63873db86aabSstevel cmn_err(CE_WARN, "%s: sec err (%x):\n", nm, pci_cfg_sec_stat);
63883db86aabSstevel nerr += log_pci_cfg_err(pci_cfg_sec_stat, 1);
63893db86aabSstevel cmn_err(CE_CONT, "%s: PCI fault log end.\n", nm);
63903db86aabSstevel return (nerr);
63913db86aabSstevel case FAULT_POKEFINI:
63923db86aabSstevel case FAULT_RESET:
63933db86aabSstevel pci_config_put16(pcic->cfg_handle,
63943db86aabSstevel PCI_CONF_STAT, pci_cfg_stat);
63953db86aabSstevel pci_config_put16(pcic->cfg_handle, 0x16, pci_cfg_sec_stat);
63963db86aabSstevel break;
63973db86aabSstevel case FAULT_POKEFLT:
63983db86aabSstevel if (!(pci_cfg_stat & PCI_STAT_S_SYSERR))
63993db86aabSstevel return (1);
64003db86aabSstevel if (!(pci_cfg_sec_stat & PCI_STAT_R_MAST_AB))
64013db86aabSstevel return (1);
64023db86aabSstevel break;
64033db86aabSstevel default:
64043db86aabSstevel break;
64053db86aabSstevel }
64063db86aabSstevel return (DDI_SUCCESS);
64073db86aabSstevel }
64083db86aabSstevel #endif
64093db86aabSstevel
64103db86aabSstevel static void
pcic_do_resume(pcicdev_t * pcic)641111c2b4c0Srw148561 pcic_do_resume(pcicdev_t *pcic)
64123db86aabSstevel {
641311c2b4c0Srw148561 int i, interrupt;
641411c2b4c0Srw148561 uint8_t cfg;
64153db86aabSstevel
64163db86aabSstevel
64173db86aabSstevel #if defined(PCIC_DEBUG)
641811c2b4c0Srw148561 pcic_err(NULL, 6, "pcic_do_resume(): entered\n");
64193db86aabSstevel #endif
64203db86aabSstevel
64213db86aabSstevel pcic_mutex_enter(&pcic->pc_lock); /* protect the registers */
64223db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) {
64233db86aabSstevel /* Enable interrupts on PCI if needs be */
64243db86aabSstevel interrupt = pcic_getb(pcic, i, PCIC_INTERRUPT);
64253db86aabSstevel if (pcic->pc_flags & PCF_USE_SMI)
64263db86aabSstevel interrupt |= PCIC_INTR_ENABLE;
64273db86aabSstevel pcic_putb(pcic, i, PCIC_INTERRUPT,
64283db86aabSstevel PCIC_RESET | interrupt);
64293db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id =
64303db86aabSstevel pcic_add_debqueue(&pcic->pc_sockets[i],
64313db86aabSstevel drv_usectohz(pcic_debounce_time));
64323db86aabSstevel }
64333db86aabSstevel pcic_mutex_exit(&pcic->pc_lock); /* protect the registers */
64343db86aabSstevel if (pcic_do_pcmcia_sr)
64353db86aabSstevel (void) pcmcia_wait_insert(pcic->dip);
643611c2b4c0Srw148561 /*
643711c2b4c0Srw148561 * The CardBus controller may be in RESET state after the
643811c2b4c0Srw148561 * system is resumed from sleeping. The RESET bit is in
643911c2b4c0Srw148561 * the Bridge Control register. This is true for all(TI,
644011c2b4c0Srw148561 * Toshiba ToPIC95/97, RICOH, and O2Micro) CardBus
644111c2b4c0Srw148561 * controllers. Need to clear the RESET bit explicitly.
644211c2b4c0Srw148561 */
644311c2b4c0Srw148561 cfg = ddi_get8(pcic->cfg_handle,
644411c2b4c0Srw148561 pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
644511c2b4c0Srw148561 if (cfg & (1<<6)) {
644611c2b4c0Srw148561 cfg &= ~(1<<6);
644711c2b4c0Srw148561 ddi_put8(pcic->cfg_handle,
644811c2b4c0Srw148561 pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
644911c2b4c0Srw148561 cfg);
645011c2b4c0Srw148561 cfg = ddi_get8(pcic->cfg_handle,
645111c2b4c0Srw148561 pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
645211c2b4c0Srw148561 if (cfg & (1<<6)) {
645319397407SSherry Moore pcic_err(pcic->dip, 1,
645419397407SSherry Moore "Failed to take pcic out of reset");
64553db86aabSstevel }
64563db86aabSstevel }
64573db86aabSstevel
645811c2b4c0Srw148561 }
645911c2b4c0Srw148561
64603db86aabSstevel static void
pcic_debounce(pcic_socket_t * pcs)64613db86aabSstevel pcic_debounce(pcic_socket_t *pcs)
64623db86aabSstevel {
64633db86aabSstevel uint8_t status, stschng;
64643db86aabSstevel
64653db86aabSstevel pcic_mutex_enter(&pcs->pcs_pcic->pc_lock);
64663db86aabSstevel pcs->pcs_flags &= ~PCS_STARTING;
64673db86aabSstevel stschng = pcic_getb(pcs->pcs_pcic, pcs->pcs_socket,
64683db86aabSstevel PCIC_CARD_STATUS_CHANGE);
64693db86aabSstevel status = pcic_getb(pcs->pcs_pcic, pcs->pcs_socket,
64703db86aabSstevel PCIC_INTERFACE_STATUS);
64713db86aabSstevel #ifdef PCIC_DEBUG
64723db86aabSstevel pcic_err(pcs->pcs_pcic->dip, 8,
64733db86aabSstevel "pcic_debounce(0x%p, dip=0x%p) socket %d st 0x%x "
64743db86aabSstevel "chg 0x%x flg 0x%x\n",
64753db86aabSstevel (void *)pcs, (void *) pcs->pcs_pcic->dip, pcs->pcs_socket,
64763db86aabSstevel status, stschng, pcs->pcs_flags);
64773db86aabSstevel #endif
64783db86aabSstevel
64793db86aabSstevel pcic_putb(pcs->pcs_pcic, pcs->pcs_socket, PCIC_CARD_STATUS_CHANGE,
64803db86aabSstevel PCIC_CD_DETECT);
64813db86aabSstevel pcic_handle_cd_change(pcs->pcs_pcic, pcs, status);
64823db86aabSstevel pcic_mutex_exit(&pcs->pcs_pcic->pc_lock);
64833db86aabSstevel }
64843db86aabSstevel
64853db86aabSstevel static void
pcic_deb_thread()64863db86aabSstevel pcic_deb_thread()
64873db86aabSstevel {
64883db86aabSstevel callb_cpr_t cprinfo;
64893db86aabSstevel struct debounce *debp;
64903db86aabSstevel clock_t lastt;
64913db86aabSstevel
64923db86aabSstevel CALLB_CPR_INIT(&cprinfo, &pcic_deb_mtx,
64933db86aabSstevel callb_generic_cpr, "pcic debounce thread");
64943db86aabSstevel mutex_enter(&pcic_deb_mtx);
64953db86aabSstevel while (pcic_deb_threadid) {
64963db86aabSstevel while (pcic_deb_queue) {
64973db86aabSstevel #ifdef PCIC_DEBUG
64983db86aabSstevel pcic_dump_debqueue("Thread");
64993db86aabSstevel #endif
65003db86aabSstevel debp = pcic_deb_queue;
65013db86aabSstevel (void) drv_getparm(LBOLT, &lastt);
65023db86aabSstevel if (lastt >= debp->expire) {
65033db86aabSstevel pcic_deb_queue = debp->next;
65043db86aabSstevel mutex_exit(&pcic_deb_mtx);
65053db86aabSstevel pcic_debounce(debp->pcs);
65063db86aabSstevel mutex_enter(&pcic_deb_mtx);
65073db86aabSstevel kmem_free(debp, sizeof (*debp));
65083db86aabSstevel } else {
65093db86aabSstevel (void) cv_timedwait(&pcic_deb_cv,
65103db86aabSstevel &pcic_deb_mtx, debp->expire);
65113db86aabSstevel }
65123db86aabSstevel }
65133db86aabSstevel CALLB_CPR_SAFE_BEGIN(&cprinfo);
65143db86aabSstevel cv_wait(&pcic_deb_cv, &pcic_deb_mtx);
65153db86aabSstevel CALLB_CPR_SAFE_END(&cprinfo, &pcic_deb_mtx);
65163db86aabSstevel }
65173db86aabSstevel pcic_deb_threadid = (kthread_t *)1;
65183db86aabSstevel cv_signal(&pcic_deb_cv);
65193db86aabSstevel CALLB_CPR_EXIT(&cprinfo); /* Also exits the mutex */
65203db86aabSstevel thread_exit();
65213db86aabSstevel }
65223db86aabSstevel
65233db86aabSstevel static void *
pcic_add_debqueue(pcic_socket_t * pcs,int clocks)65243db86aabSstevel pcic_add_debqueue(pcic_socket_t *pcs, int clocks)
65253db86aabSstevel {
65263db86aabSstevel clock_t lbolt;
65273db86aabSstevel struct debounce *dbp, **dbpp = &pcic_deb_queue;
65283db86aabSstevel
65293db86aabSstevel (void) drv_getparm(LBOLT, &lbolt);
65308134ee03Srw148561 dbp = kmem_alloc(sizeof (struct debounce), KM_SLEEP);
65313db86aabSstevel
65323db86aabSstevel dbp->expire = lbolt + clocks;
65333db86aabSstevel dbp->pcs = pcs;
65343db86aabSstevel mutex_enter(&pcic_deb_mtx);
65353db86aabSstevel while (*dbpp) {
65363db86aabSstevel if (dbp->expire > (*dbpp)->expire)
65373db86aabSstevel dbpp = &((*dbpp)->next);
65383db86aabSstevel else
65393db86aabSstevel break;
65403db86aabSstevel }
65413db86aabSstevel dbp->next = *dbpp;
65423db86aabSstevel *dbpp = dbp;
65433db86aabSstevel #ifdef PCIC_DEBUG
65443db86aabSstevel pcic_dump_debqueue("Add");
65453db86aabSstevel #endif
65463db86aabSstevel cv_signal(&pcic_deb_cv);
65473db86aabSstevel mutex_exit(&pcic_deb_mtx);
65483db86aabSstevel return (dbp);
65493db86aabSstevel }
65503db86aabSstevel
65513db86aabSstevel static void
pcic_rm_debqueue(void * id)65523db86aabSstevel pcic_rm_debqueue(void *id)
65533db86aabSstevel {
65543db86aabSstevel struct debounce *dbp, **dbpp = &pcic_deb_queue;
65553db86aabSstevel
65563db86aabSstevel dbp = (struct debounce *)id;
65573db86aabSstevel mutex_enter(&pcic_deb_mtx);
65583db86aabSstevel while (*dbpp) {
65593db86aabSstevel if (*dbpp == dbp) {
65603db86aabSstevel *dbpp = dbp->next;
65613db86aabSstevel kmem_free(dbp, sizeof (*dbp));
65623db86aabSstevel #ifdef PCIC_DEBUG
65633db86aabSstevel pcic_dump_debqueue("Remove");
65643db86aabSstevel #endif
65653db86aabSstevel cv_signal(&pcic_deb_cv);
65663db86aabSstevel mutex_exit(&pcic_deb_mtx);
65673db86aabSstevel return;
65683db86aabSstevel }
65693db86aabSstevel dbpp = &((*dbpp)->next);
65703db86aabSstevel }
65713db86aabSstevel pcic_err(NULL, 6, "pcic: Failed to find debounce id 0x%p\n", id);
65723db86aabSstevel mutex_exit(&pcic_deb_mtx);
65733db86aabSstevel }
65743db86aabSstevel
65753db86aabSstevel
65763db86aabSstevel static int pcic_powerdelay = 0;
65773db86aabSstevel
65783db86aabSstevel static int
pcic_exca_powerctl(pcicdev_t * pcic,int socket,int powerlevel)65793db86aabSstevel pcic_exca_powerctl(pcicdev_t *pcic, int socket, int powerlevel)
65803db86aabSstevel {
65813db86aabSstevel int ind, value, orig_pwrctl;
65823db86aabSstevel
65833db86aabSstevel /* power setup -- if necessary */
65843db86aabSstevel orig_pwrctl = pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
65853db86aabSstevel
65863db86aabSstevel #if defined(PCIC_DEBUG)
65873db86aabSstevel pcic_err(pcic->dip, 6,
65883db86aabSstevel "pcic_exca_powerctl(socket %d) powerlevel=%x orig 0x%x\n",
65893db86aabSstevel socket, powerlevel, orig_pwrctl);
65903db86aabSstevel #endif
65913db86aabSstevel /* Preserve the PCIC_OUTPUT_ENABLE (control lines output enable) bit. */
65923db86aabSstevel powerlevel = (powerlevel & ~POWER_OUTPUT_ENABLE) |
65933db86aabSstevel (orig_pwrctl & POWER_OUTPUT_ENABLE);
65943db86aabSstevel if (powerlevel != orig_pwrctl) {
65953db86aabSstevel if (powerlevel & ~POWER_OUTPUT_ENABLE) {
65963db86aabSstevel int ifs;
65973db86aabSstevel /*
65983db86aabSstevel * set power to socket
65993db86aabSstevel * note that the powerlevel was calculated earlier
66003db86aabSstevel */
66013db86aabSstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel);
66023db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
66033db86aabSstevel
66043db86aabSstevel /*
66053db86aabSstevel * this second write to the power control register
66063db86aabSstevel * is needed to resolve a problem on
66073db86aabSstevel * the IBM ThinkPad 750
66083db86aabSstevel * where the first write doesn't latch.
66093db86aabSstevel * The second write appears to always work and
66103db86aabSstevel * doesn't hurt the operation of other chips
66113db86aabSstevel * so we can just use it -- this is good since we can't
66123db86aabSstevel * determine what chip the 750 actually uses
66133db86aabSstevel * (I suspect an early Ricoh).
66143db86aabSstevel */
66153db86aabSstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel);
66163db86aabSstevel
66173db86aabSstevel value = pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
66183db86aabSstevel pcic_mswait(pcic, socket, pcic_powerdelay);
66193db86aabSstevel #if defined(PCIC_DEBUG)
66203db86aabSstevel pcic_err(pcic->dip, 8,
66213db86aabSstevel "\tpowerlevel reg = %x (ifs %x)\n",
66223db86aabSstevel value, pcic_getb(pcic, socket,
66233db86aabSstevel PCIC_INTERFACE_STATUS));
66243db86aabSstevel pcic_err(pcic->dip, 8,
66253db86aabSstevel "CBus regs: PS 0x%x, Control 0x%x\n",
66263db86aabSstevel pcic_getcb(pcic, CB_PRESENT_STATE),
66273db86aabSstevel pcic_getcb(pcic, CB_CONTROL));
66283db86aabSstevel #endif
66293db86aabSstevel /*
66303db86aabSstevel * since power was touched, make sure it says it
66313db86aabSstevel * is on. This lets it become stable.
66323db86aabSstevel */
66333db86aabSstevel for (ind = 0; ind < 20; ind++) {
66343db86aabSstevel ifs = pcic_getb(pcic, socket,
66353db86aabSstevel PCIC_INTERFACE_STATUS);
66363db86aabSstevel if (ifs & PCIC_POWER_ON)
66373db86aabSstevel break;
66383db86aabSstevel else {
66393db86aabSstevel pcic_putb(pcic, socket,
66403db86aabSstevel PCIC_POWER_CONTROL, 0);
66413db86aabSstevel (void) pcic_getb(pcic, socket,
66423db86aabSstevel PCIC_POWER_CONTROL);
66433db86aabSstevel pcic_mswait(pcic, socket, 40);
66443db86aabSstevel if (ind == 10) {
66453db86aabSstevel pcic_putcb(pcic, CB_EVENT_FORCE,
66463db86aabSstevel CB_EF_CVTEST);
66473db86aabSstevel pcic_mswait(pcic, socket, 100);
66483db86aabSstevel }
66493db86aabSstevel pcic_putb(pcic, socket,
66503db86aabSstevel PCIC_POWER_CONTROL,
66513db86aabSstevel powerlevel & ~POWER_OUTPUT_ENABLE);
66523db86aabSstevel (void) pcic_getb(pcic, socket,
66533db86aabSstevel PCIC_POWER_CONTROL);
66543db86aabSstevel pcic_mswait(pcic, socket,
66553db86aabSstevel pcic_powerdelay);
66563db86aabSstevel pcic_putb(pcic, socket,
66573db86aabSstevel PCIC_POWER_CONTROL, powerlevel);
66583db86aabSstevel (void) pcic_getb(pcic, socket,
66593db86aabSstevel PCIC_POWER_CONTROL);
66603db86aabSstevel pcic_mswait(pcic, socket,
66613db86aabSstevel pcic_powerdelay);
66623db86aabSstevel }
66633db86aabSstevel }
66643db86aabSstevel
66653db86aabSstevel if (!(ifs & PCIC_POWER_ON)) {
66663db86aabSstevel cmn_err(CE_WARN,
66673db86aabSstevel "pcic socket %d: Power didn't get turned"
66683db86aabSstevel "on!\nif status 0x%x pwrc 0x%x(x%x) "
66693db86aabSstevel "misc1 0x%x igc 0x%x ind %d\n",
66703db86aabSstevel socket, ifs,
66713db86aabSstevel pcic_getb(pcic, socket, PCIC_POWER_CONTROL),
66723db86aabSstevel orig_pwrctl,
66733db86aabSstevel pcic_getb(pcic, socket, PCIC_MISC_CTL_1),
66743db86aabSstevel pcic_getb(pcic, socket, PCIC_INTERRUPT),
66753db86aabSstevel ind);
66763db86aabSstevel return (BAD_VCC);
66773db86aabSstevel }
66783db86aabSstevel #if defined(PCIC_DEBUG)
66793db86aabSstevel pcic_err(pcic->dip, 8,
66803db86aabSstevel "\tind = %d, if status %x pwrc 0x%x "
66813db86aabSstevel "misc1 0x%x igc 0x%x\n",
66823db86aabSstevel ind, ifs,
66833db86aabSstevel pcic_getb(pcic, socket, PCIC_POWER_CONTROL),
66843db86aabSstevel pcic_getb(pcic, socket, PCIC_MISC_CTL_1),
66853db86aabSstevel pcic_getb(pcic, socket, PCIC_INTERRUPT));
66863db86aabSstevel #endif
66873db86aabSstevel } else {
66883db86aabSstevel /* explicitly turned off the power */
66893db86aabSstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel);
66903db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
66913db86aabSstevel }
66923db86aabSstevel }
66933db86aabSstevel return (SUCCESS);
66943db86aabSstevel }
66953db86aabSstevel
66963db86aabSstevel static int pcic_cbdoreset_during_poweron = 1;
66973db86aabSstevel static int
pcic_cbus_powerctl(pcicdev_t * pcic,int socket)66983db86aabSstevel pcic_cbus_powerctl(pcicdev_t *pcic, int socket)
66993db86aabSstevel {
67003db86aabSstevel uint32_t cbctl = 0, orig_cbctl, cbstev, cbps;
67013db86aabSstevel int ind, iobits;
67023db86aabSstevel pcic_socket_t *sockp = &pcic->pc_sockets[socket];
67033db86aabSstevel
67043db86aabSstevel pcic_putcb(pcic, CB_STATUS_EVENT, CB_SE_POWER_CYCLE);
67053db86aabSstevel
67063db86aabSstevel ind = pcic_power[sockp->pcs_vpp1].PowerLevel/10;
67073db86aabSstevel cbctl |= pcic_cbv_levels[ind];
67083db86aabSstevel
67093db86aabSstevel ind = pcic_power[sockp->pcs_vcc].PowerLevel/10;
67103db86aabSstevel cbctl |= (pcic_cbv_levels[ind]<<4);
67113db86aabSstevel
67123db86aabSstevel orig_cbctl = pcic_getcb(pcic, CB_CONTROL);
67133db86aabSstevel
67143db86aabSstevel #if defined(PCIC_DEBUG)
67153db86aabSstevel pcic_err(pcic->dip, 6,
67163db86aabSstevel "pcic_cbus_powerctl(socket %d) vcc %d vpp1 %d "
67173db86aabSstevel "cbctl 0x%x->0x%x\n",
67183db86aabSstevel socket, sockp->pcs_vcc, sockp->pcs_vpp1, orig_cbctl, cbctl);
67193db86aabSstevel #endif
67203db86aabSstevel if (cbctl != orig_cbctl) {
67213db86aabSstevel if (pcic_cbdoreset_during_poweron &&
67223db86aabSstevel (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) {
67233db86aabSstevel iobits = pcic_getb(pcic, socket, PCIC_INTERRUPT);
672419397407SSherry Moore pcic_putb(pcic, socket, PCIC_INTERRUPT,
672519397407SSherry Moore iobits & ~PCIC_RESET);
67263db86aabSstevel }
67273db86aabSstevel pcic_putcb(pcic, CB_CONTROL, cbctl);
67283db86aabSstevel
67293db86aabSstevel if ((cbctl & CB_C_VCCMASK) == (orig_cbctl & CB_C_VCCMASK)) {
67303db86aabSstevel pcic_mswait(pcic, socket, pcic_powerdelay);
67313db86aabSstevel return (SUCCESS);
67323db86aabSstevel }
67333db86aabSstevel for (ind = 0; ind < 20; ind++) {
67343db86aabSstevel cbstev = pcic_getcb(pcic, CB_STATUS_EVENT);
67353db86aabSstevel
67363db86aabSstevel if (cbstev & CB_SE_POWER_CYCLE) {
67373db86aabSstevel
67383db86aabSstevel /*
67393db86aabSstevel * delay 400 ms: though the standard defines that the Vcc
67403db86aabSstevel * set-up time is 20 ms, some PC-Card bridge requires longer
67413db86aabSstevel * duration.
67423db86aabSstevel * Note: We should check the status AFTER the delay to give time
67433db86aabSstevel * for things to stabilize.
67443db86aabSstevel */
67453db86aabSstevel pcic_mswait(pcic, socket, 400);
67463db86aabSstevel
67473db86aabSstevel cbps = pcic_getcb(pcic, CB_PRESENT_STATE);
67483db86aabSstevel if (cbctl && !(cbps & CB_PS_POWER_CYCLE)) {
67493db86aabSstevel /* break; */
67503db86aabSstevel cmn_err(CE_WARN, "cbus_powerctl: power off??\n");
67513db86aabSstevel }
67523db86aabSstevel if (cbctl & CB_PS_BADVCC) {
67533db86aabSstevel cmn_err(CE_WARN, "cbus_powerctl: bad power request\n");
67543db86aabSstevel break;
67553db86aabSstevel }
67563db86aabSstevel
67573db86aabSstevel #if defined(PCIC_DEBUG)
67583db86aabSstevel pcic_err(pcic->dip, 8,
67593db86aabSstevel "cbstev = 0x%x cbps = 0x%x cbctl 0x%x(0x%x)",
67603db86aabSstevel cbstev, pcic_getcb(pcic, CB_PRESENT_STATE),
67613db86aabSstevel cbctl, orig_cbctl);
67623db86aabSstevel #endif
67633db86aabSstevel if (pcic_cbdoreset_during_poweron &&
67643db86aabSstevel (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) {
67653db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits);
67663db86aabSstevel }
67673db86aabSstevel return (SUCCESS);
67683db86aabSstevel }
67693db86aabSstevel pcic_mswait(pcic, socket, 40);
67703db86aabSstevel }
67713db86aabSstevel if (pcic_cbdoreset_during_poweron &&
67723db86aabSstevel (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) {
67733db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits);
67743db86aabSstevel }
67753db86aabSstevel cmn_err(CE_WARN,
67763db86aabSstevel "pcic socket %d: Power didn't get turned on/off!\n"
67773db86aabSstevel "cbstev = 0x%x cbps = 0x%x cbctl 0x%x(0x%x) "
67783db86aabSstevel "vcc %d vpp1 %d", socket, cbstev,
67793db86aabSstevel pcic_getcb(pcic, CB_PRESENT_STATE),
67803db86aabSstevel cbctl, orig_cbctl, sockp->pcs_vcc, sockp->pcs_vpp1);
67813db86aabSstevel return (BAD_VCC);
67823db86aabSstevel }
67833db86aabSstevel return (SUCCESS);
67843db86aabSstevel }
67853db86aabSstevel
67863db86aabSstevel static int pcic_do_pprintf = 0;
67873db86aabSstevel
67883db86aabSstevel static void
pcic_dump_debqueue(char * msg)67893db86aabSstevel pcic_dump_debqueue(char *msg)
67903db86aabSstevel {
67913db86aabSstevel struct debounce *debp = pcic_deb_queue;
67923db86aabSstevel clock_t lbolt;
67933db86aabSstevel
67943db86aabSstevel (void) drv_getparm(LBOLT, &lbolt);
67953db86aabSstevel pcic_err(NULL, 6, debp ? "pcic debounce list (%s) lbolt 0x%x:\n" :
67963db86aabSstevel "pcic debounce_list (%s) EMPTY lbolt 0x%x\n", msg, lbolt);
67973db86aabSstevel while (debp) {
67983db86aabSstevel pcic_err(NULL, 6, "%p: exp 0x%x next 0x%p id 0x%p\n",
67993db86aabSstevel (void *) debp, (int)debp->expire, (void *) debp->next,
68003db86aabSstevel debp->pcs->pcs_debounce_id);
68013db86aabSstevel debp = debp->next;
68023db86aabSstevel }
68033db86aabSstevel }
68043db86aabSstevel
68053db86aabSstevel
68063db86aabSstevel /* PRINTFLIKE3 */
68073db86aabSstevel static void
pcic_err(dev_info_t * dip,int level,const char * fmt,...)68083db86aabSstevel pcic_err(dev_info_t *dip, int level, const char *fmt, ...)
68093db86aabSstevel {
68103db86aabSstevel if (pcic_debug && (level <= pcic_debug)) {
68113db86aabSstevel va_list adx;
68123db86aabSstevel int instance;
68133db86aabSstevel char buf[256];
68143db86aabSstevel const char *name;
68153db86aabSstevel #if !defined(PCIC_DEBUG)
68163db86aabSstevel int ce;
68173db86aabSstevel char qmark = 0;
68183db86aabSstevel
68193db86aabSstevel if (level <= 3)
68203db86aabSstevel ce = CE_WARN;
68213db86aabSstevel else
68223db86aabSstevel ce = CE_CONT;
68233db86aabSstevel if (level == 4)
68243db86aabSstevel qmark = 1;
68253db86aabSstevel #endif
68263db86aabSstevel
68273db86aabSstevel if (dip) {
68283db86aabSstevel instance = ddi_get_instance(dip);
68293db86aabSstevel /* name = ddi_binding_name(dip); */
68303db86aabSstevel name = ddi_driver_name(dip);
68313db86aabSstevel } else {
68323db86aabSstevel instance = 0;
68333db86aabSstevel name = "";
68343db86aabSstevel }
68353db86aabSstevel
68363db86aabSstevel va_start(adx, fmt);
68373db86aabSstevel (void) vsprintf(buf, fmt, adx);
68383db86aabSstevel va_end(adx);
68393db86aabSstevel
68403db86aabSstevel #if defined(PCIC_DEBUG)
68413db86aabSstevel if (pcic_do_pprintf) {
68423db86aabSstevel if (dip) {
68433db86aabSstevel if (instance >= 0)
68443db86aabSstevel prom_printf("%s(%d),0x%p: %s", name,
6845903a11ebSrh87107 instance, (void *)dip, buf);
68463db86aabSstevel else
68473db86aabSstevel prom_printf("%s,0x%p: %s",
6848903a11ebSrh87107 name, (void *)dip, buf);
68493db86aabSstevel } else
68503db86aabSstevel prom_printf(buf);
68513db86aabSstevel } else {
68523db86aabSstevel if (dip) {
68533db86aabSstevel if (instance >= 0)
68543db86aabSstevel cmn_err(CE_CONT, "%s(%d),0x%p: %s",
68553db86aabSstevel name, instance, (void *) dip, buf);
68563db86aabSstevel else
68573db86aabSstevel cmn_err(CE_CONT, "%s,0x%p: %s",
68583db86aabSstevel name, (void *) dip, buf);
68593db86aabSstevel } else
68603db86aabSstevel cmn_err(CE_CONT, buf);
68613db86aabSstevel }
68623db86aabSstevel #else
68633db86aabSstevel if (dip)
68643db86aabSstevel cmn_err(ce, qmark ? "?%s%d: %s" : "%s%d: %s", name,
68653db86aabSstevel instance, buf);
68663db86aabSstevel else
68673db86aabSstevel cmn_err(ce, qmark ? "?%s" : buf, buf);
68683db86aabSstevel #endif
68693db86aabSstevel }
68703db86aabSstevel }
6871