17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*19397407SSherry Moore * Common Development and Distribution License (the "License"). 6*19397407SSherry Moore * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*19397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <sys/types.h> 287c478bd9Sstevel@tonic-gate #include <sys/conf.h> 297c478bd9Sstevel@tonic-gate #include <sys/open.h> 307c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 317c478bd9Sstevel@tonic-gate #include <sys/promif.h> 327c478bd9Sstevel@tonic-gate #include <sys/stat.h> 337c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 347c478bd9Sstevel@tonic-gate #include <sys/jbusppm.h> 357c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 367c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate /* 397c478bd9Sstevel@tonic-gate * JBus Power Management Driver 407c478bd9Sstevel@tonic-gate * 417c478bd9Sstevel@tonic-gate * jbusppm driver initiates the JBus clock speed change 427c478bd9Sstevel@tonic-gate * as part of the protocol to adjust the clock speed on 437c478bd9Sstevel@tonic-gate * all JBus resident devices. 447c478bd9Sstevel@tonic-gate * 457c478bd9Sstevel@tonic-gate * jbusppm driver is loaded because of the explicit dependency 467c478bd9Sstevel@tonic-gate * defined in PPM driver. 477c478bd9Sstevel@tonic-gate */ 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate /* 507c478bd9Sstevel@tonic-gate * Configuration Function prototypes and data structures 517c478bd9Sstevel@tonic-gate */ 527c478bd9Sstevel@tonic-gate static int jbppm_attach(dev_info_t *, ddi_attach_cmd_t); 537c478bd9Sstevel@tonic-gate static int jbppm_detach(dev_info_t *, ddi_detach_cmd_t); 547c478bd9Sstevel@tonic-gate static int jbppm_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 557c478bd9Sstevel@tonic-gate static int jbppm_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p); 567c478bd9Sstevel@tonic-gate static int jbppm_close(dev_t dev, int flag, int otyp, cred_t *cred_p); 577c478bd9Sstevel@tonic-gate static int jbppm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate /* 607c478bd9Sstevel@tonic-gate * Configuration data structures 617c478bd9Sstevel@tonic-gate */ 627c478bd9Sstevel@tonic-gate static struct cb_ops jbppm_cbops = { 637c478bd9Sstevel@tonic-gate jbppm_open, /* open */ 647c478bd9Sstevel@tonic-gate jbppm_close, /* close */ 657c478bd9Sstevel@tonic-gate nodev, /* strategy */ 667c478bd9Sstevel@tonic-gate nodev, /* print */ 677c478bd9Sstevel@tonic-gate nodev, /* dump */ 687c478bd9Sstevel@tonic-gate nodev, /* read */ 697c478bd9Sstevel@tonic-gate nodev, /* write */ 707c478bd9Sstevel@tonic-gate jbppm_ioctl, /* ioctl */ 717c478bd9Sstevel@tonic-gate nodev, /* devmap */ 727c478bd9Sstevel@tonic-gate nodev, /* mmap */ 737c478bd9Sstevel@tonic-gate nodev, /* segmap */ 747c478bd9Sstevel@tonic-gate nochpoll, /* chpoll */ 757c478bd9Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 767c478bd9Sstevel@tonic-gate NULL, /* stream */ 777c478bd9Sstevel@tonic-gate D_MP | D_NEW, /* flag */ 787c478bd9Sstevel@tonic-gate CB_REV, /* rev */ 797c478bd9Sstevel@tonic-gate nodev, /* aread */ 807c478bd9Sstevel@tonic-gate nodev, /* awrite */ 817c478bd9Sstevel@tonic-gate }; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate static struct dev_ops jbppm_ops = { 847c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 857c478bd9Sstevel@tonic-gate 0, /* refcnt */ 867c478bd9Sstevel@tonic-gate jbppm_getinfo, /* getinfo */ 877c478bd9Sstevel@tonic-gate nulldev, /* identify */ 887c478bd9Sstevel@tonic-gate nulldev, /* probe */ 897c478bd9Sstevel@tonic-gate jbppm_attach, /* attach */ 907c478bd9Sstevel@tonic-gate jbppm_detach, /* detach */ 917c478bd9Sstevel@tonic-gate nodev, /* reset */ 927c478bd9Sstevel@tonic-gate &jbppm_cbops, /* cb_ops */ 937c478bd9Sstevel@tonic-gate NULL, /* bus_ops */ 94*19397407SSherry Moore NULL, /* power */ 95*19397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */ 967c478bd9Sstevel@tonic-gate }; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 1017c478bd9Sstevel@tonic-gate &mod_driverops, 102*19397407SSherry Moore "JBus ppm driver", 1037c478bd9Sstevel@tonic-gate &jbppm_ops, 1047c478bd9Sstevel@tonic-gate }; 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1077c478bd9Sstevel@tonic-gate MODREV_1, 1087c478bd9Sstevel@tonic-gate &modldrv, 1097c478bd9Sstevel@tonic-gate NULL 1107c478bd9Sstevel@tonic-gate }; 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate /* 1137c478bd9Sstevel@tonic-gate * Local functions 1147c478bd9Sstevel@tonic-gate */ 1157c478bd9Sstevel@tonic-gate static void jbppm_next_speed(dev_info_t *, uint_t); 1167c478bd9Sstevel@tonic-gate static int jbppm_start_next(dev_info_t *, int); 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate /* 1197c478bd9Sstevel@tonic-gate * Driver global variables 1207c478bd9Sstevel@tonic-gate * 1217c478bd9Sstevel@tonic-gate * jbppm_lock synchronize the access of lyr handle to each jbppm 1227c478bd9Sstevel@tonic-gate * minor device, therefore write to tomatillo device is 1237c478bd9Sstevel@tonic-gate * sequentialized. Lyr protocol requires pairing up lyr open 1247c478bd9Sstevel@tonic-gate * and close, so only a single reference is allowed per minor node. 1257c478bd9Sstevel@tonic-gate */ 1267c478bd9Sstevel@tonic-gate static void *jbppm_statep; 1277c478bd9Sstevel@tonic-gate static kmutex_t jbppm_lock; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate /* 1307c478bd9Sstevel@tonic-gate * bit masks to scale the IO bridge clock in sync with and only with 1317c478bd9Sstevel@tonic-gate * scaling CPU clock. 1327c478bd9Sstevel@tonic-gate * 1337c478bd9Sstevel@tonic-gate * The array index indicates power level (from lowest to highest). 1347c478bd9Sstevel@tonic-gate */ 1357c478bd9Sstevel@tonic-gate static const uint64_t jbus_clock_masks[] = { 1367c478bd9Sstevel@tonic-gate JBUS_ESTAR_CNTL_32, 1377c478bd9Sstevel@tonic-gate JBUS_ESTAR_CNTL_2, 1387c478bd9Sstevel@tonic-gate JBUS_ESTAR_CNTL_1 1397c478bd9Sstevel@tonic-gate }; 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate int 1427c478bd9Sstevel@tonic-gate _init(void) 1437c478bd9Sstevel@tonic-gate { 1447c478bd9Sstevel@tonic-gate int error; 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate if ((error = ddi_soft_state_init(&jbppm_statep, 1477c478bd9Sstevel@tonic-gate sizeof (jbppm_unit), 0)) != DDI_SUCCESS) { 1487c478bd9Sstevel@tonic-gate return (error); 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate mutex_init(&jbppm_lock, NULL, MUTEX_DRIVER, NULL); 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate if ((error = mod_install(&modlinkage)) != DDI_SUCCESS) { 1547c478bd9Sstevel@tonic-gate mutex_destroy(&jbppm_lock); 1557c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&jbppm_statep); 1567c478bd9Sstevel@tonic-gate return (error); 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate return (error); 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate int 1637c478bd9Sstevel@tonic-gate _fini(void) 1647c478bd9Sstevel@tonic-gate { 1657c478bd9Sstevel@tonic-gate int error; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate if ((error = mod_remove(&modlinkage)) == DDI_SUCCESS) { 1687c478bd9Sstevel@tonic-gate mutex_destroy(&jbppm_lock); 1697c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&jbppm_statep); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate return (error); 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate int 1777c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1787c478bd9Sstevel@tonic-gate { 1797c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate /* 1857c478bd9Sstevel@tonic-gate * Driver attach(9e) entry point 1867c478bd9Sstevel@tonic-gate */ 1877c478bd9Sstevel@tonic-gate static int 1887c478bd9Sstevel@tonic-gate jbppm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1897c478bd9Sstevel@tonic-gate { 1907c478bd9Sstevel@tonic-gate char *str = "jbppm_attach"; 1917c478bd9Sstevel@tonic-gate int instance; 1927c478bd9Sstevel@tonic-gate jbppm_unit *unitp; 1937c478bd9Sstevel@tonic-gate uint64_t data64; 1947c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 1957c478bd9Sstevel@tonic-gate int rv = DDI_SUCCESS; 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate switch (cmd) { 1987c478bd9Sstevel@tonic-gate case DDI_ATTACH: 1997c478bd9Sstevel@tonic-gate break; 2007c478bd9Sstevel@tonic-gate case DDI_RESUME: 2017c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2027c478bd9Sstevel@tonic-gate default: 2037c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: cmd %d unsupported.\n", str, cmd); 2047c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 2087c478bd9Sstevel@tonic-gate rv = ddi_soft_state_zalloc(jbppm_statep, instance); 2097c478bd9Sstevel@tonic-gate if (rv != DDI_SUCCESS) { 2107c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: failed alloc for dev(%s@%s)", 2117c478bd9Sstevel@tonic-gate str, ddi_binding_name(dip), 2127c478bd9Sstevel@tonic-gate ddi_get_name_addr(dip) ? ddi_get_name_addr(dip) : " "); 2137c478bd9Sstevel@tonic-gate return (rv); 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate if ((unitp = ddi_get_soft_state(jbppm_statep, instance)) == NULL) { 2177c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 2187c478bd9Sstevel@tonic-gate goto doerrs; 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate /* 2227c478bd9Sstevel@tonic-gate * Export "ddi-kernel-ioctl" property - prepared to support 2237c478bd9Sstevel@tonic-gate * kernel ioctls (driver layering). 2247c478bd9Sstevel@tonic-gate */ 2257c478bd9Sstevel@tonic-gate rv = ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 2267c478bd9Sstevel@tonic-gate DDI_KERNEL_IOCTL, NULL, 0); 2277c478bd9Sstevel@tonic-gate if (rv != DDI_PROP_SUCCESS) 2287c478bd9Sstevel@tonic-gate goto doerrs; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 2317c478bd9Sstevel@tonic-gate unitp->dip = dip; 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 2347c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 2357c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate rv = ddi_regs_map_setup(dip, 0, (caddr_t *)&unitp->devid_csr, 0, 8, 2387c478bd9Sstevel@tonic-gate &attr, &unitp->devid_hndl); 2397c478bd9Sstevel@tonic-gate if (rv != DDI_SUCCESS) 2407c478bd9Sstevel@tonic-gate goto doerrs; 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate rv = ddi_regs_map_setup(dip, 1, (caddr_t *)&unitp->estar_csr, 0, 16, 2437c478bd9Sstevel@tonic-gate &attr, &unitp->estar_hndl); 2447c478bd9Sstevel@tonic-gate if (rv != DDI_SUCCESS) 2457c478bd9Sstevel@tonic-gate goto doerrs; 2467c478bd9Sstevel@tonic-gate unitp->j_chng_csr = (uint64_t *)((caddr_t)unitp->estar_csr + 2477c478bd9Sstevel@tonic-gate J_CHNG_INITIATION_OFFSET); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate data64 = ddi_get64(unitp->devid_hndl, (uint64_t *)unitp->devid_csr); 2507c478bd9Sstevel@tonic-gate unitp->is_master = (data64 & MASTER_IOBRIDGE_BIT) ? 1 : 0; 2517c478bd9Sstevel@tonic-gate unitp->lyropen = 0; 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate /* 2547c478bd9Sstevel@tonic-gate * create minor node for kernel_ioctl calls 2557c478bd9Sstevel@tonic-gate */ 2567c478bd9Sstevel@tonic-gate rv = ddi_create_minor_node(dip, "jbus-ppm", S_IFCHR, instance, 0, 0); 2577c478bd9Sstevel@tonic-gate if (rv != DDI_SUCCESS) 2587c478bd9Sstevel@tonic-gate goto doerrs; 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate return (rv); 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate doerrs: 2637c478bd9Sstevel@tonic-gate if (unitp->devid_hndl != NULL) 2647c478bd9Sstevel@tonic-gate ddi_regs_map_free(&unitp->devid_hndl); 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate if (unitp->estar_csr != NULL) 2677c478bd9Sstevel@tonic-gate ddi_regs_map_free(&unitp->estar_hndl); 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS | 2707c478bd9Sstevel@tonic-gate DDI_PROP_NOTPROM, DDI_KERNEL_IOCTL)) 2717c478bd9Sstevel@tonic-gate ddi_prop_remove_all(dip); 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate ddi_soft_state_free(jbppm_statep, instance); 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate return (rv); 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate /* 2807c478bd9Sstevel@tonic-gate * Driver getinfo(9e) entry routine 2817c478bd9Sstevel@tonic-gate */ 2827c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2837c478bd9Sstevel@tonic-gate static int 2847c478bd9Sstevel@tonic-gate jbppm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 2857c478bd9Sstevel@tonic-gate { 2867c478bd9Sstevel@tonic-gate jbppm_unit *unitp; 2877c478bd9Sstevel@tonic-gate int instance; 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate switch (cmd) { 2907c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 2917c478bd9Sstevel@tonic-gate instance = getminor((dev_t)arg); 2927c478bd9Sstevel@tonic-gate unitp = ddi_get_soft_state(jbppm_statep, instance); 2937c478bd9Sstevel@tonic-gate if (unitp == NULL) { 2947c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate *result = (void *) unitp->dip; 2977c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 3007c478bd9Sstevel@tonic-gate instance = getminor((dev_t)arg); 3017c478bd9Sstevel@tonic-gate *result = (void *)(uintptr_t)instance; 3027c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate default: 3057c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* 3117c478bd9Sstevel@tonic-gate * detach(9e) 3127c478bd9Sstevel@tonic-gate */ 3137c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3147c478bd9Sstevel@tonic-gate static int 3157c478bd9Sstevel@tonic-gate jbppm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3167c478bd9Sstevel@tonic-gate { 3177c478bd9Sstevel@tonic-gate char *str = "jbppm_detach"; 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate switch (cmd) { 3207c478bd9Sstevel@tonic-gate case DDI_DETACH: 3217c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3227c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 3237c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3247c478bd9Sstevel@tonic-gate default: 3257c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s: cmd %d unsupported", str, cmd); 3267c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3327c478bd9Sstevel@tonic-gate static int 3337c478bd9Sstevel@tonic-gate jbppm_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p) 3347c478bd9Sstevel@tonic-gate { 3357c478bd9Sstevel@tonic-gate jbppm_unit *unitp; 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate /* not intended to allow sysadmin level root process to open it */ 3387c478bd9Sstevel@tonic-gate if (drv_priv(cred_p) != DDI_SUCCESS) 3397c478bd9Sstevel@tonic-gate return (EPERM); 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate if ((unitp = ddi_get_soft_state( 3427c478bd9Sstevel@tonic-gate jbppm_statep, getminor(*dev_p))) == NULL) { 3437c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "jbppm_open: failed to get soft state!"); 3447c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate mutex_enter(&jbppm_lock); 3487c478bd9Sstevel@tonic-gate if (unitp->lyropen != 0) { 3497c478bd9Sstevel@tonic-gate mutex_exit(&jbppm_lock); 3507c478bd9Sstevel@tonic-gate return (EBUSY); 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate unitp->lyropen++; 3537c478bd9Sstevel@tonic-gate mutex_exit(&jbppm_lock); 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3607c478bd9Sstevel@tonic-gate static int 3617c478bd9Sstevel@tonic-gate jbppm_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 3627c478bd9Sstevel@tonic-gate { 3637c478bd9Sstevel@tonic-gate jbppm_unit *unitp; 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate if ((unitp = 3667c478bd9Sstevel@tonic-gate ddi_get_soft_state(jbppm_statep, getminor(dev))) == NULL) 3677c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate mutex_enter(&jbppm_lock); 3707c478bd9Sstevel@tonic-gate unitp->lyropen = 0; 3717c478bd9Sstevel@tonic-gate mutex_exit(&jbppm_lock); 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate #define JBPPMIOC ('j' << 8) 3787c478bd9Sstevel@tonic-gate #define JBPPMIOC_ISMASTER (JBPPMIOC | 1) /* no 'arg' */ 3797c478bd9Sstevel@tonic-gate #define JBPPMIOC_NEXT (JBPPMIOC | 2) /* 'arg': next speed level */ 3807c478bd9Sstevel@tonic-gate #define JBPPMIOC_GO (JBPPMIOC | 3) /* 'arg': jbus chng_delay */ 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate /* ARGSUSED3 */ 3837c478bd9Sstevel@tonic-gate static int 3847c478bd9Sstevel@tonic-gate jbppm_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, 3857c478bd9Sstevel@tonic-gate cred_t *cred_p, int *rval_p) 3867c478bd9Sstevel@tonic-gate { 3877c478bd9Sstevel@tonic-gate jbppm_unit *unitp; 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate if (drv_priv(cred_p) != 0) 3907c478bd9Sstevel@tonic-gate return (EPERM); 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate if ((unitp = 3937c478bd9Sstevel@tonic-gate ddi_get_soft_state(jbppm_statep, getminor(dev))) == NULL) 3947c478bd9Sstevel@tonic-gate return (EIO); 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate switch (cmd) { 3977c478bd9Sstevel@tonic-gate case JBPPMIOC_ISMASTER: 3987c478bd9Sstevel@tonic-gate if (unitp->is_master) 3997c478bd9Sstevel@tonic-gate return (0); 4007c478bd9Sstevel@tonic-gate else 4017c478bd9Sstevel@tonic-gate return (-1); 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate case JBPPMIOC_NEXT: 4047c478bd9Sstevel@tonic-gate jbppm_next_speed(unitp->dip, (uint_t)arg); 4057c478bd9Sstevel@tonic-gate return (0); 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate case JBPPMIOC_GO: 4087c478bd9Sstevel@tonic-gate if (!unitp->is_master) 4097c478bd9Sstevel@tonic-gate return (EINVAL); 4107c478bd9Sstevel@tonic-gate return (jbppm_start_next(unitp->dip, (int)arg)); 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate default: 4137c478bd9Sstevel@tonic-gate return (ENOTTY); 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate /* 4197c478bd9Sstevel@tonic-gate * jbppm_next_speed - program a new speed into IO bridge device prior to 4207c478bd9Sstevel@tonic-gate * actual speed transition. 4217c478bd9Sstevel@tonic-gate */ 4227c478bd9Sstevel@tonic-gate static void 4237c478bd9Sstevel@tonic-gate jbppm_next_speed(dev_info_t *dip, uint_t lvl_index) 4247c478bd9Sstevel@tonic-gate { 4257c478bd9Sstevel@tonic-gate volatile uint64_t data64; 4267c478bd9Sstevel@tonic-gate static jbppm_unit *unitp; 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate unitp = ddi_get_soft_state(jbppm_statep, ddi_get_instance(dip)); 4297c478bd9Sstevel@tonic-gate ASSERT(unitp); 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate mutex_enter(&jbppm_lock); 4327c478bd9Sstevel@tonic-gate data64 = ddi_get64(unitp->estar_hndl, unitp->estar_csr); 4337c478bd9Sstevel@tonic-gate data64 &= ~JBUS_ESTAR_CNTL_MASK; 4347c478bd9Sstevel@tonic-gate data64 |= jbus_clock_masks[lvl_index]; 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate ddi_put64(unitp->estar_hndl, (uint64_t *)unitp->estar_csr, data64); 4377c478bd9Sstevel@tonic-gate data64 = ddi_get64(unitp->estar_hndl, unitp->estar_csr); 4387c478bd9Sstevel@tonic-gate mutex_exit(&jbppm_lock); 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate /* 4437c478bd9Sstevel@tonic-gate * jbppm_start_next - Initiate JBus speed change on all JBus devices. 4447c478bd9Sstevel@tonic-gate * chng_delay indicates after master deassert j_chng signal the number of 4457c478bd9Sstevel@tonic-gate * jbus clock delay before all jbus device start to transit to the new 4467c478bd9Sstevel@tonic-gate * speed. 4477c478bd9Sstevel@tonic-gate * Trigger sequence: 4487c478bd9Sstevel@tonic-gate * wait while j_chng[1:0] == 10 4497c478bd9Sstevel@tonic-gate * write 00 to j_chng 4507c478bd9Sstevel@tonic-gate * trigger by writing 10 to j_chng[1:0] 4517c478bd9Sstevel@tonic-gate * wait while j_chng[1:0] == 10 4527c478bd9Sstevel@tonic-gate * write 00 to j_chng[1:0] 4537c478bd9Sstevel@tonic-gate * Note: this sequence is not the same as Enchilada spec described, chiefly 4547c478bd9Sstevel@tonic-gate * because else where (e.g. flush E$ code) may have speed change code. If sw 4557c478bd9Sstevel@tonic-gate * wait upon j_chng[1:0] == 11 in both places, we'll have problem. That spec 4567c478bd9Sstevel@tonic-gate * requires wait on 11 to ensure that trigger has completed. An alternative 4577c478bd9Sstevel@tonic-gate * way to ensure that is to check and wait upon 10. J_chng[1:0] stays as 10 4587c478bd9Sstevel@tonic-gate * for only a short period of time that is under HW control, unlike 11 signals 4597c478bd9Sstevel@tonic-gate * which has to be cleared by sw. 4607c478bd9Sstevel@tonic-gate */ 4617c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4627c478bd9Sstevel@tonic-gate static int 4637c478bd9Sstevel@tonic-gate jbppm_start_next(dev_info_t *dip, int chng_delay) 4647c478bd9Sstevel@tonic-gate { 4657c478bd9Sstevel@tonic-gate volatile uint64_t data64; 4667c478bd9Sstevel@tonic-gate static jbppm_unit *unitp; 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate unitp = ddi_get_soft_state(jbppm_statep, ddi_get_instance(dip)); 4697c478bd9Sstevel@tonic-gate ASSERT(unitp && unitp->is_master); 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate mutex_enter(&jbppm_lock); 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate /* wait while trigger is incomplete */ 4747c478bd9Sstevel@tonic-gate do { 4757c478bd9Sstevel@tonic-gate data64 = ddi_get64(unitp->estar_hndl, unitp->j_chng_csr); 4767c478bd9Sstevel@tonic-gate } while ((J_CHNG_INITIATION_MASK & data64) == J_CHNG_START); 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate /* clear(reset) */ 4797c478bd9Sstevel@tonic-gate data64 &= ~J_CHNG_INITIATION_MASK; 4807c478bd9Sstevel@tonic-gate ddi_put64(unitp->estar_hndl, (uint64_t *)unitp->j_chng_csr, data64); 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate /* trigger */ 4837c478bd9Sstevel@tonic-gate data64 &= ~J_CHNG_DELAY_MASK; 4847c478bd9Sstevel@tonic-gate data64 |= (J_CHNG_START | chng_delay); 4857c478bd9Sstevel@tonic-gate ddi_put64(unitp->estar_hndl, (uint64_t *)unitp->j_chng_csr, data64); 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate /* wait while trigger is incomplete */ 4887c478bd9Sstevel@tonic-gate do { 4897c478bd9Sstevel@tonic-gate data64 = ddi_get64(unitp->estar_hndl, unitp->j_chng_csr); 4907c478bd9Sstevel@tonic-gate } while ((J_CHNG_INITIATION_MASK & data64) == J_CHNG_START); 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate /* clear(reset) */ 4937c478bd9Sstevel@tonic-gate data64 &= ~J_CHNG_INITIATION_MASK; 4947c478bd9Sstevel@tonic-gate ddi_put64(unitp->estar_hndl, (uint64_t *)unitp->j_chng_csr, data64); 4957c478bd9Sstevel@tonic-gate (void) ddi_get64(unitp->estar_hndl, unitp->j_chng_csr); 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate mutex_exit(&jbppm_lock); 4987c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4997c478bd9Sstevel@tonic-gate } 500