1*67ca7330SBjoern A. Zeeb /*- 2*67ca7330SBjoern A. Zeeb * Copyright (c) 2017 Ilya Bakulin. All rights reserved. 3*67ca7330SBjoern A. Zeeb * Copyright (c) 2018-2019 The FreeBSD Foundation 4*67ca7330SBjoern A. Zeeb * 5*67ca7330SBjoern A. Zeeb * Portions of this software were developed by Björn Zeeb 6*67ca7330SBjoern A. Zeeb * under sponsorship from the FreeBSD Foundation. 7*67ca7330SBjoern A. Zeeb * 8*67ca7330SBjoern A. Zeeb * Redistribution and use in source and binary forms, with or without 9*67ca7330SBjoern A. Zeeb * modification, are permitted provided that the following conditions 10*67ca7330SBjoern A. Zeeb * are met: 11*67ca7330SBjoern A. Zeeb * 1. Redistributions of source code must retain the above copyright 12*67ca7330SBjoern A. Zeeb * notice, this list of conditions and the following disclaimer. 13*67ca7330SBjoern A. Zeeb * 2. Redistributions in binary form must reproduce the above copyright 14*67ca7330SBjoern A. Zeeb * notice, this list of conditions and the following disclaimer in the 15*67ca7330SBjoern A. Zeeb * documentation and/or other materials provided with the distribution. 16*67ca7330SBjoern A. Zeeb * 17*67ca7330SBjoern A. Zeeb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18*67ca7330SBjoern A. Zeeb * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19*67ca7330SBjoern A. Zeeb * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20*67ca7330SBjoern A. Zeeb * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21*67ca7330SBjoern A. Zeeb * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22*67ca7330SBjoern A. Zeeb * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23*67ca7330SBjoern A. Zeeb * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24*67ca7330SBjoern A. Zeeb * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25*67ca7330SBjoern A. Zeeb * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26*67ca7330SBjoern A. Zeeb * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27*67ca7330SBjoern A. Zeeb * 28*67ca7330SBjoern A. Zeeb * 29*67ca7330SBjoern A. Zeeb * Portions of this software may have been developed with reference to 30*67ca7330SBjoern A. Zeeb * the SD Simplified Specification. The following disclaimer may apply: 31*67ca7330SBjoern A. Zeeb * 32*67ca7330SBjoern A. Zeeb * The following conditions apply to the release of the simplified 33*67ca7330SBjoern A. Zeeb * specification ("Simplified Specification") by the SD Card Association and 34*67ca7330SBjoern A. Zeeb * the SD Group. The Simplified Specification is a subset of the complete SD 35*67ca7330SBjoern A. Zeeb * Specification which is owned by the SD Card Association and the SD 36*67ca7330SBjoern A. Zeeb * Group. This Simplified Specification is provided on a non-confidential 37*67ca7330SBjoern A. Zeeb * basis subject to the disclaimers below. Any implementation of the 38*67ca7330SBjoern A. Zeeb * Simplified Specification may require a license from the SD Card 39*67ca7330SBjoern A. Zeeb * Association, SD Group, SD-3C LLC or other third parties. 40*67ca7330SBjoern A. Zeeb * 41*67ca7330SBjoern A. Zeeb * Disclaimers: 42*67ca7330SBjoern A. Zeeb * 43*67ca7330SBjoern A. Zeeb * The information contained in the Simplified Specification is presented only 44*67ca7330SBjoern A. Zeeb * as a standard specification for SD Cards and SD Host/Ancillary products and 45*67ca7330SBjoern A. Zeeb * is provided "AS-IS" without any representations or warranties of any 46*67ca7330SBjoern A. Zeeb * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD 47*67ca7330SBjoern A. Zeeb * Card Association for any damages, any infringements of patents or other 48*67ca7330SBjoern A. Zeeb * right of the SD Group, SD-3C LLC, the SD Card Association or any third 49*67ca7330SBjoern A. Zeeb * parties, which may result from its use. No license is granted by 50*67ca7330SBjoern A. Zeeb * implication, estoppel or otherwise under any patent or other rights of the 51*67ca7330SBjoern A. Zeeb * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing 52*67ca7330SBjoern A. Zeeb * herein shall be construed as an obligation by the SD Group, the SD-3C LLC 53*67ca7330SBjoern A. Zeeb * or the SD Card Association to disclose or distribute any technical 54*67ca7330SBjoern A. Zeeb * information, know-how or other confidential information to any third party. 55*67ca7330SBjoern A. Zeeb */ 56*67ca7330SBjoern A. Zeeb /* 57*67ca7330SBjoern A. Zeeb * Implements the (kernel specific) SDIO parts. 58*67ca7330SBjoern A. Zeeb * This will hide all cam(4) functionality from the SDIO driver implementations 59*67ca7330SBjoern A. Zeeb * which will just be newbus/device(9) and hence look like any other driver for, 60*67ca7330SBjoern A. Zeeb * e.g., PCI. 61*67ca7330SBjoern A. Zeeb * The sdiob(4) parts effetively "translate" between the two worlds "bridging" 62*67ca7330SBjoern A. Zeeb * messages from MMCCAM to newbus and back. 63*67ca7330SBjoern A. Zeeb */ 64*67ca7330SBjoern A. Zeeb 65*67ca7330SBjoern A. Zeeb #include <sys/cdefs.h> 66*67ca7330SBjoern A. Zeeb __FBSDID("$FreeBSD$"); 67*67ca7330SBjoern A. Zeeb 68*67ca7330SBjoern A. Zeeb #include "opt_cam.h" 69*67ca7330SBjoern A. Zeeb 70*67ca7330SBjoern A. Zeeb #include <sys/param.h> 71*67ca7330SBjoern A. Zeeb #include <sys/systm.h> 72*67ca7330SBjoern A. Zeeb #include <sys/types.h> 73*67ca7330SBjoern A. Zeeb #include <sys/kernel.h> 74*67ca7330SBjoern A. Zeeb #include <sys/bus.h> 75*67ca7330SBjoern A. Zeeb #include <sys/endian.h> 76*67ca7330SBjoern A. Zeeb #include <sys/lock.h> 77*67ca7330SBjoern A. Zeeb #include <sys/malloc.h> 78*67ca7330SBjoern A. Zeeb #include <sys/module.h> 79*67ca7330SBjoern A. Zeeb #include <sys/mutex.h> 80*67ca7330SBjoern A. Zeeb 81*67ca7330SBjoern A. Zeeb #include <cam/cam.h> 82*67ca7330SBjoern A. Zeeb #include <cam/cam_ccb.h> 83*67ca7330SBjoern A. Zeeb #include <cam/cam_queue.h> 84*67ca7330SBjoern A. Zeeb #include <cam/cam_periph.h> 85*67ca7330SBjoern A. Zeeb #include <cam/cam_xpt.h> 86*67ca7330SBjoern A. Zeeb #include <cam/cam_xpt_periph.h> 87*67ca7330SBjoern A. Zeeb #include <cam/cam_xpt_internal.h> /* for cam_path */ 88*67ca7330SBjoern A. Zeeb #include <cam/cam_debug.h> 89*67ca7330SBjoern A. Zeeb 90*67ca7330SBjoern A. Zeeb #include <dev/mmc/mmcreg.h> 91*67ca7330SBjoern A. Zeeb 92*67ca7330SBjoern A. Zeeb #include <dev/sdio/sdiob.h> 93*67ca7330SBjoern A. Zeeb #include <dev/sdio/sdio_subr.h> 94*67ca7330SBjoern A. Zeeb 95*67ca7330SBjoern A. Zeeb #include "sdio_if.h" 96*67ca7330SBjoern A. Zeeb 97*67ca7330SBjoern A. Zeeb #ifdef DEBUG 98*67ca7330SBjoern A. Zeeb #define DPRINTF(...) printf(__VA_ARGS__) 99*67ca7330SBjoern A. Zeeb #define DPRINTFDEV(_dev, ...) device_printf((_dev), __VA_ARGS__) 100*67ca7330SBjoern A. Zeeb #else 101*67ca7330SBjoern A. Zeeb #define DPRINTF(...) 102*67ca7330SBjoern A. Zeeb #define DPRINTFDEV(_dev, ...) 103*67ca7330SBjoern A. Zeeb #endif 104*67ca7330SBjoern A. Zeeb 105*67ca7330SBjoern A. Zeeb struct sdiob_softc { 106*67ca7330SBjoern A. Zeeb uint32_t sdio_state; 107*67ca7330SBjoern A. Zeeb #define SDIO_STATE_DEAD 0x0001 108*67ca7330SBjoern A. Zeeb #define SDIO_STATE_INITIALIZING 0x0002 109*67ca7330SBjoern A. Zeeb #define SDIO_STATE_READY 0x0004 110*67ca7330SBjoern A. Zeeb uint32_t nb_state; 111*67ca7330SBjoern A. Zeeb #define NB_STATE_DEAD 0x0001 112*67ca7330SBjoern A. Zeeb #define NB_STATE_SIM_ADDED 0x0002 113*67ca7330SBjoern A. Zeeb #define NB_STATE_READY 0x0004 114*67ca7330SBjoern A. Zeeb 115*67ca7330SBjoern A. Zeeb /* CAM side (including sim_dev). */ 116*67ca7330SBjoern A. Zeeb struct card_info cardinfo; 117*67ca7330SBjoern A. Zeeb struct cam_periph *periph; 118*67ca7330SBjoern A. Zeeb union ccb *ccb; 119*67ca7330SBjoern A. Zeeb struct task discover_task; 120*67ca7330SBjoern A. Zeeb 121*67ca7330SBjoern A. Zeeb /* Newbus side. */ 122*67ca7330SBjoern A. Zeeb device_t dev; /* Ourselves. */ 123*67ca7330SBjoern A. Zeeb device_t child[8]; 124*67ca7330SBjoern A. Zeeb }; 125*67ca7330SBjoern A. Zeeb 126*67ca7330SBjoern A. Zeeb /* -------------------------------------------------------------------------- */ 127*67ca7330SBjoern A. Zeeb /* 128*67ca7330SBjoern A. Zeeb * SDIO CMD52 and CM53 implementations along with wrapper functions for 129*67ca7330SBjoern A. Zeeb * read/write and a CAM periph helper function. 130*67ca7330SBjoern A. Zeeb * These are the backend implementations of the sdio_if.m framework talking 131*67ca7330SBjoern A. Zeeb * through CAM to sdhci. 132*67ca7330SBjoern A. Zeeb * Note: these functions are also called during early discovery stage when 133*67ca7330SBjoern A. Zeeb * we are not a device(9) yet. Hence they cannot always use device_printf() 134*67ca7330SBjoern A. Zeeb * to log errors and have to call CAM_DEBUG() during these early stages. 135*67ca7330SBjoern A. Zeeb */ 136*67ca7330SBjoern A. Zeeb 137*67ca7330SBjoern A. Zeeb static int 138*67ca7330SBjoern A. Zeeb sdioerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 139*67ca7330SBjoern A. Zeeb { 140*67ca7330SBjoern A. Zeeb 141*67ca7330SBjoern A. Zeeb return (cam_periph_error(ccb, cam_flags, sense_flags)); 142*67ca7330SBjoern A. Zeeb } 143*67ca7330SBjoern A. Zeeb 144*67ca7330SBjoern A. Zeeb /* CMD52: direct byte access. */ 145*67ca7330SBjoern A. Zeeb static int 146*67ca7330SBjoern A. Zeeb sdiob_rw_direct_sc(struct sdiob_softc *sc, uint8_t fn, uint32_t addr, bool wr, 147*67ca7330SBjoern A. Zeeb uint8_t *val) 148*67ca7330SBjoern A. Zeeb { 149*67ca7330SBjoern A. Zeeb uint32_t arg, flags; 150*67ca7330SBjoern A. Zeeb int error; 151*67ca7330SBjoern A. Zeeb 152*67ca7330SBjoern A. Zeeb KASSERT((val != NULL), ("%s val passed as NULL\n", __func__)); 153*67ca7330SBjoern A. Zeeb 154*67ca7330SBjoern A. Zeeb if (sc->ccb == NULL) 155*67ca7330SBjoern A. Zeeb sc->ccb = xpt_alloc_ccb(); 156*67ca7330SBjoern A. Zeeb else 157*67ca7330SBjoern A. Zeeb memset(sc->ccb, 0, sizeof(*sc->ccb)); 158*67ca7330SBjoern A. Zeeb xpt_setup_ccb(&sc->ccb->ccb_h, sc->periph->path, CAM_PRIORITY_NONE); 159*67ca7330SBjoern A. Zeeb CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_TRACE, 160*67ca7330SBjoern A. Zeeb ("%s(fn=%d, addr=%#02x, wr=%d, *val=%#02x)\n", __func__, 161*67ca7330SBjoern A. Zeeb fn, addr, wr, *val)); 162*67ca7330SBjoern A. Zeeb 163*67ca7330SBjoern A. Zeeb flags = MMC_RSP_R5 | MMC_CMD_AC; 164*67ca7330SBjoern A. Zeeb arg = SD_IO_RW_FUNC(fn) | SD_IO_RW_ADR(addr); 165*67ca7330SBjoern A. Zeeb if (wr) 166*67ca7330SBjoern A. Zeeb arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*val); 167*67ca7330SBjoern A. Zeeb 168*67ca7330SBjoern A. Zeeb cam_fill_mmcio(&sc->ccb->mmcio, 169*67ca7330SBjoern A. Zeeb /*retries*/ 0, 170*67ca7330SBjoern A. Zeeb /*cbfcnp*/ NULL, 171*67ca7330SBjoern A. Zeeb /*flags*/ CAM_DIR_NONE, 172*67ca7330SBjoern A. Zeeb /*mmc_opcode*/ SD_IO_RW_DIRECT, 173*67ca7330SBjoern A. Zeeb /*mmc_arg*/ arg, 174*67ca7330SBjoern A. Zeeb /*mmc_flags*/ flags, 175*67ca7330SBjoern A. Zeeb /*mmc_data*/ 0, 176*67ca7330SBjoern A. Zeeb /*timeout*/ sc->cardinfo.f[fn].timeout); 177*67ca7330SBjoern A. Zeeb error = cam_periph_runccb(sc->ccb, sdioerror, CAM_FLAG_NONE, 0, NULL); 178*67ca7330SBjoern A. Zeeb if (error != 0) { 179*67ca7330SBjoern A. Zeeb if (sc->dev != NULL) 180*67ca7330SBjoern A. Zeeb device_printf(sc->dev, 181*67ca7330SBjoern A. Zeeb "%s: Failed to %s address %#10x error=%d\n", 182*67ca7330SBjoern A. Zeeb __func__, (wr) ? "write" : "read", addr, error); 183*67ca7330SBjoern A. Zeeb else 184*67ca7330SBjoern A. Zeeb CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_INFO, 185*67ca7330SBjoern A. Zeeb ("%s: Failed to %s address: %#10x error=%d\n", 186*67ca7330SBjoern A. Zeeb __func__, (wr) ? "write" : "read", addr, error)); 187*67ca7330SBjoern A. Zeeb return (error); 188*67ca7330SBjoern A. Zeeb } 189*67ca7330SBjoern A. Zeeb 190*67ca7330SBjoern A. Zeeb /* TODO: Add handling of MMC errors */ 191*67ca7330SBjoern A. Zeeb /* ccb->mmcio.cmd.error ? */ 192*67ca7330SBjoern A. Zeeb if (wr == false) 193*67ca7330SBjoern A. Zeeb *val = sc->ccb->mmcio.cmd.resp[0] & 0xff; 194*67ca7330SBjoern A. Zeeb 195*67ca7330SBjoern A. Zeeb return (0); 196*67ca7330SBjoern A. Zeeb } 197*67ca7330SBjoern A. Zeeb 198*67ca7330SBjoern A. Zeeb static int 199*67ca7330SBjoern A. Zeeb sdio_rw_direct(device_t dev, uint8_t fn, uint32_t addr, bool wr, 200*67ca7330SBjoern A. Zeeb uint8_t *val) 201*67ca7330SBjoern A. Zeeb { 202*67ca7330SBjoern A. Zeeb struct sdiob_softc *sc; 203*67ca7330SBjoern A. Zeeb int error; 204*67ca7330SBjoern A. Zeeb 205*67ca7330SBjoern A. Zeeb sc = device_get_softc(dev); 206*67ca7330SBjoern A. Zeeb cam_periph_lock(sc->periph); 207*67ca7330SBjoern A. Zeeb error = sdiob_rw_direct_sc(sc, fn, addr, wr, val); 208*67ca7330SBjoern A. Zeeb cam_periph_unlock(sc->periph); 209*67ca7330SBjoern A. Zeeb return (error); 210*67ca7330SBjoern A. Zeeb } 211*67ca7330SBjoern A. Zeeb 212*67ca7330SBjoern A. Zeeb static int 213*67ca7330SBjoern A. Zeeb sdiob_read_direct(device_t dev, uint8_t fn, uint32_t addr, uint8_t *val) 214*67ca7330SBjoern A. Zeeb { 215*67ca7330SBjoern A. Zeeb int error; 216*67ca7330SBjoern A. Zeeb uint8_t v; 217*67ca7330SBjoern A. Zeeb 218*67ca7330SBjoern A. Zeeb error = sdio_rw_direct(dev, fn, addr, false, &v); 219*67ca7330SBjoern A. Zeeb /* Be polite and do not touch the value on read error. */ 220*67ca7330SBjoern A. Zeeb if (error == 0 && val != NULL) 221*67ca7330SBjoern A. Zeeb *val = v; 222*67ca7330SBjoern A. Zeeb return (error); 223*67ca7330SBjoern A. Zeeb } 224*67ca7330SBjoern A. Zeeb 225*67ca7330SBjoern A. Zeeb static int 226*67ca7330SBjoern A. Zeeb sdiob_write_direct(device_t dev, uint8_t fn, uint32_t addr, uint8_t val) 227*67ca7330SBjoern A. Zeeb { 228*67ca7330SBjoern A. Zeeb 229*67ca7330SBjoern A. Zeeb return (sdio_rw_direct(dev, fn, addr, true, &val)); 230*67ca7330SBjoern A. Zeeb } 231*67ca7330SBjoern A. Zeeb 232*67ca7330SBjoern A. Zeeb /* 233*67ca7330SBjoern A. Zeeb * CMD53: IO_RW_EXTENDED, read and write multiple I/O registers. 234*67ca7330SBjoern A. Zeeb * Increment false gets FIFO mode (single register address). 235*67ca7330SBjoern A. Zeeb */ 236*67ca7330SBjoern A. Zeeb /* 237*67ca7330SBjoern A. Zeeb * A b_count of 0 means byte mode, b_count > 0 gets block mode. 238*67ca7330SBjoern A. Zeeb * A b_count of >= 512 would mean infinitive block transfer, which would become 239*67ca7330SBjoern A. Zeeb * b_count = 0, is not yet supported. 240*67ca7330SBjoern A. Zeeb * For b_count == 0, blksz is the len of bytes, otherwise it is the amount of 241*67ca7330SBjoern A. Zeeb * full sized blocks (you must not round the blocks up and leave the last one 242*67ca7330SBjoern A. Zeeb * partial!) 243*67ca7330SBjoern A. Zeeb * For byte mode, the maximum of blksz is the functions cur_blksize. 244*67ca7330SBjoern A. Zeeb * This function should ever only be called by sdio_rw_extended_sc()! 245*67ca7330SBjoern A. Zeeb */ 246*67ca7330SBjoern A. Zeeb static int 247*67ca7330SBjoern A. Zeeb sdiob_rw_extended_cam(struct sdiob_softc *sc, uint8_t fn, uint32_t addr, 248*67ca7330SBjoern A. Zeeb bool wr, uint8_t *buffer, bool incaddr, uint32_t b_count, uint16_t blksz) 249*67ca7330SBjoern A. Zeeb { 250*67ca7330SBjoern A. Zeeb struct mmc_data mmcd; 251*67ca7330SBjoern A. Zeeb uint32_t arg, cam_flags, flags, len; 252*67ca7330SBjoern A. Zeeb int error; 253*67ca7330SBjoern A. Zeeb 254*67ca7330SBjoern A. Zeeb if (sc->ccb == NULL) 255*67ca7330SBjoern A. Zeeb sc->ccb = xpt_alloc_ccb(); 256*67ca7330SBjoern A. Zeeb else 257*67ca7330SBjoern A. Zeeb memset(sc->ccb, 0, sizeof(*sc->ccb)); 258*67ca7330SBjoern A. Zeeb xpt_setup_ccb(&sc->ccb->ccb_h, sc->periph->path, CAM_PRIORITY_NONE); 259*67ca7330SBjoern A. Zeeb CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_TRACE, 260*67ca7330SBjoern A. Zeeb ("%s(fn=%d addr=%#0x wr=%d b_count=%u blksz=%u buf=%p incr=%d)\n", 261*67ca7330SBjoern A. Zeeb __func__, fn, addr, wr, b_count, blksz, buffer, incaddr)); 262*67ca7330SBjoern A. Zeeb 263*67ca7330SBjoern A. Zeeb KASSERT((b_count <= 511), ("%s: infinitive block transfer not yet " 264*67ca7330SBjoern A. Zeeb "supported: b_count %u blksz %u, sc %p, fn %u, addr %#10x, %s, " 265*67ca7330SBjoern A. Zeeb "buffer %p, %s\n", __func__, b_count, blksz, sc, fn, addr, 266*67ca7330SBjoern A. Zeeb wr ? "wr" : "rd", buffer, incaddr ? "incaddr" : "fifo")); 267*67ca7330SBjoern A. Zeeb /* Blksz needs to be within bounds for both byte and block mode! */ 268*67ca7330SBjoern A. Zeeb KASSERT((blksz <= sc->cardinfo.f[fn].cur_blksize), ("%s: blksz " 269*67ca7330SBjoern A. Zeeb "%u > bur_blksize %u, sc %p, fn %u, addr %#10x, %s, " 270*67ca7330SBjoern A. Zeeb "buffer %p, %s, b_count %u\n", __func__, blksz, 271*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].cur_blksize, sc, fn, addr, 272*67ca7330SBjoern A. Zeeb wr ? "wr" : "rd", buffer, incaddr ? "incaddr" : "fifo", 273*67ca7330SBjoern A. Zeeb b_count)); 274*67ca7330SBjoern A. Zeeb if (b_count == 0) { 275*67ca7330SBjoern A. Zeeb /* Byte mode */ 276*67ca7330SBjoern A. Zeeb len = blksz; 277*67ca7330SBjoern A. Zeeb if (blksz == 512) 278*67ca7330SBjoern A. Zeeb blksz = 0; 279*67ca7330SBjoern A. Zeeb arg = SD_IOE_RW_LEN(blksz); 280*67ca7330SBjoern A. Zeeb } else { 281*67ca7330SBjoern A. Zeeb /* Block mode. */ 282*67ca7330SBjoern A. Zeeb #ifdef __notyet__ 283*67ca7330SBjoern A. Zeeb if (b_count > 511) { 284*67ca7330SBjoern A. Zeeb /* Infinitive block transfer. */ 285*67ca7330SBjoern A. Zeeb b_count = 0; 286*67ca7330SBjoern A. Zeeb } 287*67ca7330SBjoern A. Zeeb #endif 288*67ca7330SBjoern A. Zeeb len = b_count * blksz; 289*67ca7330SBjoern A. Zeeb arg = SD_IOE_RW_BLK | SD_IOE_RW_LEN(b_count); 290*67ca7330SBjoern A. Zeeb } 291*67ca7330SBjoern A. Zeeb 292*67ca7330SBjoern A. Zeeb flags = MMC_RSP_R5 | MMC_CMD_ADTC; 293*67ca7330SBjoern A. Zeeb arg |= SD_IOE_RW_FUNC(fn) | SD_IOE_RW_ADR(addr); 294*67ca7330SBjoern A. Zeeb if (incaddr) 295*67ca7330SBjoern A. Zeeb arg |= SD_IOE_RW_INCR; 296*67ca7330SBjoern A. Zeeb 297*67ca7330SBjoern A. Zeeb memset(&mmcd, 0, sizeof(mmcd)); 298*67ca7330SBjoern A. Zeeb mmcd.data = buffer; 299*67ca7330SBjoern A. Zeeb mmcd.len = len; 300*67ca7330SBjoern A. Zeeb if (arg & SD_IOE_RW_BLK) { 301*67ca7330SBjoern A. Zeeb /* XXX both should be known from elsewhere, aren't they? */ 302*67ca7330SBjoern A. Zeeb mmcd.block_size = blksz; 303*67ca7330SBjoern A. Zeeb mmcd.block_count = b_count; 304*67ca7330SBjoern A. Zeeb } 305*67ca7330SBjoern A. Zeeb 306*67ca7330SBjoern A. Zeeb if (wr) { 307*67ca7330SBjoern A. Zeeb arg |= SD_IOE_RW_WR; 308*67ca7330SBjoern A. Zeeb cam_flags = CAM_DIR_OUT; 309*67ca7330SBjoern A. Zeeb mmcd.flags = MMC_DATA_WRITE; 310*67ca7330SBjoern A. Zeeb } else { 311*67ca7330SBjoern A. Zeeb cam_flags = CAM_DIR_IN; 312*67ca7330SBjoern A. Zeeb mmcd.flags = MMC_DATA_READ; 313*67ca7330SBjoern A. Zeeb } 314*67ca7330SBjoern A. Zeeb #ifdef __notyet__ 315*67ca7330SBjoern A. Zeeb if (b_count == 0) { 316*67ca7330SBjoern A. Zeeb /* XXX-BZ TODO FIXME. Cancel I/O: CCCR -> ASx */ 317*67ca7330SBjoern A. Zeeb /* Stop cmd. */ 318*67ca7330SBjoern A. Zeeb } 319*67ca7330SBjoern A. Zeeb #endif 320*67ca7330SBjoern A. Zeeb cam_fill_mmcio(&sc->ccb->mmcio, 321*67ca7330SBjoern A. Zeeb /*retries*/ 0, 322*67ca7330SBjoern A. Zeeb /*cbfcnp*/ NULL, 323*67ca7330SBjoern A. Zeeb /*flags*/ cam_flags, 324*67ca7330SBjoern A. Zeeb /*mmc_opcode*/ SD_IO_RW_EXTENDED, 325*67ca7330SBjoern A. Zeeb /*mmc_arg*/ arg, 326*67ca7330SBjoern A. Zeeb /*mmc_flags*/ flags, 327*67ca7330SBjoern A. Zeeb /*mmc_data*/ &mmcd, 328*67ca7330SBjoern A. Zeeb /*timeout*/ sc->cardinfo.f[fn].timeout); 329*67ca7330SBjoern A. Zeeb if (arg & SD_IOE_RW_BLK) { 330*67ca7330SBjoern A. Zeeb mmcd.flags |= MMC_DATA_BLOCK_SIZE; 331*67ca7330SBjoern A. Zeeb if (b_count != 1) 332*67ca7330SBjoern A. Zeeb sc->ccb->mmcio.cmd.data->flags |= MMC_DATA_MULTI; 333*67ca7330SBjoern A. Zeeb } 334*67ca7330SBjoern A. Zeeb 335*67ca7330SBjoern A. Zeeb /* Execute. */ 336*67ca7330SBjoern A. Zeeb error = cam_periph_runccb(sc->ccb, sdioerror, CAM_FLAG_NONE, 0, NULL); 337*67ca7330SBjoern A. Zeeb if (error != 0) { 338*67ca7330SBjoern A. Zeeb if (sc->dev != NULL) 339*67ca7330SBjoern A. Zeeb device_printf(sc->dev, 340*67ca7330SBjoern A. Zeeb "%s: Failed to %s address %#10x buffer %p size %u " 341*67ca7330SBjoern A. Zeeb "%s b_count %u blksz %u error=%d\n", 342*67ca7330SBjoern A. Zeeb __func__, (wr) ? "write to" : "read from", addr, 343*67ca7330SBjoern A. Zeeb buffer, len, (incaddr) ? "incr" : "fifo", 344*67ca7330SBjoern A. Zeeb b_count, blksz, error); 345*67ca7330SBjoern A. Zeeb else 346*67ca7330SBjoern A. Zeeb CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_INFO, 347*67ca7330SBjoern A. Zeeb ("%s: Failed to %s address %#10x buffer %p size %u " 348*67ca7330SBjoern A. Zeeb "%s b_count %u blksz %u error=%d\n", 349*67ca7330SBjoern A. Zeeb __func__, (wr) ? "write to" : "read from", addr, 350*67ca7330SBjoern A. Zeeb buffer, len, (incaddr) ? "incr" : "fifo", 351*67ca7330SBjoern A. Zeeb b_count, blksz, error)); 352*67ca7330SBjoern A. Zeeb return (error); 353*67ca7330SBjoern A. Zeeb } 354*67ca7330SBjoern A. Zeeb 355*67ca7330SBjoern A. Zeeb /* TODO: Add handling of MMC errors */ 356*67ca7330SBjoern A. Zeeb /* ccb->mmcio.cmd.error ? */ 357*67ca7330SBjoern A. Zeeb error = sc->ccb->mmcio.cmd.resp[0] & 0xff; 358*67ca7330SBjoern A. Zeeb if (error != 0) { 359*67ca7330SBjoern A. Zeeb if (sc->dev != NULL) 360*67ca7330SBjoern A. Zeeb device_printf(sc->dev, 361*67ca7330SBjoern A. Zeeb "%s: Failed to %s address %#10x buffer %p size %u " 362*67ca7330SBjoern A. Zeeb "%s b_count %u blksz %u mmcio resp error=%d\n", 363*67ca7330SBjoern A. Zeeb __func__, (wr) ? "write to" : "read from", addr, 364*67ca7330SBjoern A. Zeeb buffer, len, (incaddr) ? "incr" : "fifo", 365*67ca7330SBjoern A. Zeeb b_count, blksz, error); 366*67ca7330SBjoern A. Zeeb else 367*67ca7330SBjoern A. Zeeb CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_INFO, 368*67ca7330SBjoern A. Zeeb ("%s: Failed to %s address %#10x buffer %p size %u " 369*67ca7330SBjoern A. Zeeb "%s b_count %u blksz %u mmcio resp error=%d\n", 370*67ca7330SBjoern A. Zeeb __func__, (wr) ? "write to" : "read from", addr, 371*67ca7330SBjoern A. Zeeb buffer, len, (incaddr) ? "incr" : "fifo", 372*67ca7330SBjoern A. Zeeb b_count, blksz, error)); 373*67ca7330SBjoern A. Zeeb } 374*67ca7330SBjoern A. Zeeb return (error); 375*67ca7330SBjoern A. Zeeb } 376*67ca7330SBjoern A. Zeeb 377*67ca7330SBjoern A. Zeeb static int 378*67ca7330SBjoern A. Zeeb sdiob_rw_extended_sc(struct sdiob_softc *sc, uint8_t fn, uint32_t addr, 379*67ca7330SBjoern A. Zeeb bool wr, uint32_t size, uint8_t *buffer, bool incaddr) 380*67ca7330SBjoern A. Zeeb { 381*67ca7330SBjoern A. Zeeb int error; 382*67ca7330SBjoern A. Zeeb uint32_t len; 383*67ca7330SBjoern A. Zeeb uint32_t b_count; 384*67ca7330SBjoern A. Zeeb 385*67ca7330SBjoern A. Zeeb /* 386*67ca7330SBjoern A. Zeeb * If block mode is supported and we have at least 4 bytes to write and 387*67ca7330SBjoern A. Zeeb * the size is at least one block, then start doing blk transfers. 388*67ca7330SBjoern A. Zeeb */ 389*67ca7330SBjoern A. Zeeb while (sc->cardinfo.support_multiblk && 390*67ca7330SBjoern A. Zeeb size > 4 && size >= sc->cardinfo.f[fn].cur_blksize) { 391*67ca7330SBjoern A. Zeeb 392*67ca7330SBjoern A. Zeeb b_count = size / sc->cardinfo.f[fn].cur_blksize; 393*67ca7330SBjoern A. Zeeb KASSERT(b_count >= 1, ("%s: block count too small %u size %u " 394*67ca7330SBjoern A. Zeeb "cur_blksize %u\n", __func__, b_count, size, 395*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].cur_blksize)); 396*67ca7330SBjoern A. Zeeb 397*67ca7330SBjoern A. Zeeb #ifdef __notyet__ 398*67ca7330SBjoern A. Zeeb /* XXX support inifinite transfer with b_count = 0. */ 399*67ca7330SBjoern A. Zeeb #else 400*67ca7330SBjoern A. Zeeb if (b_count > 511) 401*67ca7330SBjoern A. Zeeb b_count = 511; 402*67ca7330SBjoern A. Zeeb #endif 403*67ca7330SBjoern A. Zeeb len = b_count * sc->cardinfo.f[fn].cur_blksize; 404*67ca7330SBjoern A. Zeeb error = sdiob_rw_extended_cam(sc, fn, addr, wr, buffer, incaddr, 405*67ca7330SBjoern A. Zeeb b_count, sc->cardinfo.f[fn].cur_blksize); 406*67ca7330SBjoern A. Zeeb if (error != 0) 407*67ca7330SBjoern A. Zeeb return (error); 408*67ca7330SBjoern A. Zeeb 409*67ca7330SBjoern A. Zeeb size -= len; 410*67ca7330SBjoern A. Zeeb buffer += len; 411*67ca7330SBjoern A. Zeeb if (incaddr) 412*67ca7330SBjoern A. Zeeb addr += len; 413*67ca7330SBjoern A. Zeeb } 414*67ca7330SBjoern A. Zeeb 415*67ca7330SBjoern A. Zeeb while (size > 0) { 416*67ca7330SBjoern A. Zeeb len = MIN(size, sc->cardinfo.f[fn].cur_blksize); 417*67ca7330SBjoern A. Zeeb 418*67ca7330SBjoern A. Zeeb error = sdiob_rw_extended_cam(sc, fn, addr, wr, buffer, incaddr, 419*67ca7330SBjoern A. Zeeb 0, len); 420*67ca7330SBjoern A. Zeeb if (error != 0) 421*67ca7330SBjoern A. Zeeb return (error); 422*67ca7330SBjoern A. Zeeb 423*67ca7330SBjoern A. Zeeb /* Prepare for next iteration. */ 424*67ca7330SBjoern A. Zeeb size -= len; 425*67ca7330SBjoern A. Zeeb buffer += len; 426*67ca7330SBjoern A. Zeeb if (incaddr) 427*67ca7330SBjoern A. Zeeb addr += len; 428*67ca7330SBjoern A. Zeeb } 429*67ca7330SBjoern A. Zeeb 430*67ca7330SBjoern A. Zeeb return (0); 431*67ca7330SBjoern A. Zeeb } 432*67ca7330SBjoern A. Zeeb 433*67ca7330SBjoern A. Zeeb static int 434*67ca7330SBjoern A. Zeeb sdiob_rw_extended(device_t dev, uint8_t fn, uint32_t addr, bool wr, 435*67ca7330SBjoern A. Zeeb uint32_t size, uint8_t *buffer, bool incaddr) 436*67ca7330SBjoern A. Zeeb { 437*67ca7330SBjoern A. Zeeb struct sdiob_softc *sc; 438*67ca7330SBjoern A. Zeeb int error; 439*67ca7330SBjoern A. Zeeb 440*67ca7330SBjoern A. Zeeb sc = device_get_softc(dev); 441*67ca7330SBjoern A. Zeeb cam_periph_lock(sc->periph); 442*67ca7330SBjoern A. Zeeb error = sdiob_rw_extended_sc(sc, fn, addr, wr, size, buffer, incaddr); 443*67ca7330SBjoern A. Zeeb cam_periph_unlock(sc->periph); 444*67ca7330SBjoern A. Zeeb return (error); 445*67ca7330SBjoern A. Zeeb } 446*67ca7330SBjoern A. Zeeb 447*67ca7330SBjoern A. Zeeb static int 448*67ca7330SBjoern A. Zeeb sdiob_read_extended(device_t dev, uint8_t fn, uint32_t addr, uint32_t size, 449*67ca7330SBjoern A. Zeeb uint8_t *buffer, bool incaddr) 450*67ca7330SBjoern A. Zeeb { 451*67ca7330SBjoern A. Zeeb 452*67ca7330SBjoern A. Zeeb return (sdiob_rw_extended(dev, fn, addr, false, size, buffer, incaddr)); 453*67ca7330SBjoern A. Zeeb } 454*67ca7330SBjoern A. Zeeb 455*67ca7330SBjoern A. Zeeb static int 456*67ca7330SBjoern A. Zeeb sdiob_write_extended(device_t dev, uint8_t fn, uint32_t addr, uint32_t size, 457*67ca7330SBjoern A. Zeeb uint8_t *buffer, bool incaddr) 458*67ca7330SBjoern A. Zeeb { 459*67ca7330SBjoern A. Zeeb 460*67ca7330SBjoern A. Zeeb return (sdiob_rw_extended(dev, fn, addr, true, size, buffer, incaddr)); 461*67ca7330SBjoern A. Zeeb } 462*67ca7330SBjoern A. Zeeb 463*67ca7330SBjoern A. Zeeb /* -------------------------------------------------------------------------- */ 464*67ca7330SBjoern A. Zeeb /* Bus interface, ivars handling. */ 465*67ca7330SBjoern A. Zeeb 466*67ca7330SBjoern A. Zeeb static int 467*67ca7330SBjoern A. Zeeb sdiob_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 468*67ca7330SBjoern A. Zeeb { 469*67ca7330SBjoern A. Zeeb struct sdiob_softc *sc; 470*67ca7330SBjoern A. Zeeb struct sdio_func *f; 471*67ca7330SBjoern A. Zeeb 472*67ca7330SBjoern A. Zeeb f = device_get_ivars(child); 473*67ca7330SBjoern A. Zeeb KASSERT(f != NULL, ("%s: dev %p child %p which %d, child ivars NULL\n", 474*67ca7330SBjoern A. Zeeb __func__, dev, child, which)); 475*67ca7330SBjoern A. Zeeb 476*67ca7330SBjoern A. Zeeb switch (which) { 477*67ca7330SBjoern A. Zeeb case SDIOB_IVAR_SUPPORT_MULTIBLK: 478*67ca7330SBjoern A. Zeeb sc = device_get_softc(dev); 479*67ca7330SBjoern A. Zeeb KASSERT(sc != NULL, ("%s: dev %p child %p which %d, sc NULL\n", 480*67ca7330SBjoern A. Zeeb __func__, dev, child, which)); 481*67ca7330SBjoern A. Zeeb *result = sc->cardinfo.support_multiblk; 482*67ca7330SBjoern A. Zeeb break; 483*67ca7330SBjoern A. Zeeb case SDIOB_IVAR_FUNCTION: 484*67ca7330SBjoern A. Zeeb *result = (uintptr_t)f; 485*67ca7330SBjoern A. Zeeb break; 486*67ca7330SBjoern A. Zeeb case SDIOB_IVAR_FUNCNUM: 487*67ca7330SBjoern A. Zeeb *result = f->fn; 488*67ca7330SBjoern A. Zeeb break; 489*67ca7330SBjoern A. Zeeb case SDIOB_IVAR_CLASS: 490*67ca7330SBjoern A. Zeeb *result = f->class; 491*67ca7330SBjoern A. Zeeb break; 492*67ca7330SBjoern A. Zeeb case SDIOB_IVAR_VENDOR: 493*67ca7330SBjoern A. Zeeb *result = f->vendor; 494*67ca7330SBjoern A. Zeeb break; 495*67ca7330SBjoern A. Zeeb case SDIOB_IVAR_DEVICE: 496*67ca7330SBjoern A. Zeeb *result = f->device; 497*67ca7330SBjoern A. Zeeb break; 498*67ca7330SBjoern A. Zeeb case SDIOB_IVAR_DRVDATA: 499*67ca7330SBjoern A. Zeeb *result = f->drvdata; 500*67ca7330SBjoern A. Zeeb break; 501*67ca7330SBjoern A. Zeeb default: 502*67ca7330SBjoern A. Zeeb return (ENOENT); 503*67ca7330SBjoern A. Zeeb } 504*67ca7330SBjoern A. Zeeb return (0); 505*67ca7330SBjoern A. Zeeb } 506*67ca7330SBjoern A. Zeeb 507*67ca7330SBjoern A. Zeeb static int 508*67ca7330SBjoern A. Zeeb sdiob_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 509*67ca7330SBjoern A. Zeeb { 510*67ca7330SBjoern A. Zeeb struct sdio_func *f; 511*67ca7330SBjoern A. Zeeb 512*67ca7330SBjoern A. Zeeb f = device_get_ivars(child); 513*67ca7330SBjoern A. Zeeb KASSERT(f != NULL, ("%s: dev %p child %p which %d, child ivars NULL\n", 514*67ca7330SBjoern A. Zeeb __func__, dev, child, which)); 515*67ca7330SBjoern A. Zeeb 516*67ca7330SBjoern A. Zeeb switch (which) { 517*67ca7330SBjoern A. Zeeb case SDIOB_IVAR_SUPPORT_MULTIBLK: 518*67ca7330SBjoern A. Zeeb case SDIOB_IVAR_FUNCTION: 519*67ca7330SBjoern A. Zeeb case SDIOB_IVAR_FUNCNUM: 520*67ca7330SBjoern A. Zeeb case SDIOB_IVAR_CLASS: 521*67ca7330SBjoern A. Zeeb case SDIOB_IVAR_VENDOR: 522*67ca7330SBjoern A. Zeeb case SDIOB_IVAR_DEVICE: 523*67ca7330SBjoern A. Zeeb return (EINVAL); /* Disallowed. */ 524*67ca7330SBjoern A. Zeeb case SDIOB_IVAR_DRVDATA: 525*67ca7330SBjoern A. Zeeb f->drvdata = value; 526*67ca7330SBjoern A. Zeeb break; 527*67ca7330SBjoern A. Zeeb default: 528*67ca7330SBjoern A. Zeeb return (ENOENT); 529*67ca7330SBjoern A. Zeeb } 530*67ca7330SBjoern A. Zeeb 531*67ca7330SBjoern A. Zeeb return (0); 532*67ca7330SBjoern A. Zeeb } 533*67ca7330SBjoern A. Zeeb 534*67ca7330SBjoern A. Zeeb 535*67ca7330SBjoern A. Zeeb /* -------------------------------------------------------------------------- */ 536*67ca7330SBjoern A. Zeeb /* 537*67ca7330SBjoern A. Zeeb * Newbus functions for ourselves to probe/attach/detach and become a proper 538*67ca7330SBjoern A. Zeeb * device(9). Attach will also probe for child devices (another driver 539*67ca7330SBjoern A. Zeeb * implementing SDIO). 540*67ca7330SBjoern A. Zeeb */ 541*67ca7330SBjoern A. Zeeb 542*67ca7330SBjoern A. Zeeb static int 543*67ca7330SBjoern A. Zeeb sdiob_probe(device_t dev) 544*67ca7330SBjoern A. Zeeb { 545*67ca7330SBjoern A. Zeeb 546*67ca7330SBjoern A. Zeeb device_set_desc(dev, "SDIO CAM-Newbus bridge"); 547*67ca7330SBjoern A. Zeeb return (BUS_PROBE_DEFAULT); 548*67ca7330SBjoern A. Zeeb } 549*67ca7330SBjoern A. Zeeb 550*67ca7330SBjoern A. Zeeb static int 551*67ca7330SBjoern A. Zeeb sdiob_attach(device_t dev) 552*67ca7330SBjoern A. Zeeb { 553*67ca7330SBjoern A. Zeeb struct sdiob_softc *sc; 554*67ca7330SBjoern A. Zeeb int error, i; 555*67ca7330SBjoern A. Zeeb 556*67ca7330SBjoern A. Zeeb sc = device_get_softc(dev); 557*67ca7330SBjoern A. Zeeb if (sc == NULL) 558*67ca7330SBjoern A. Zeeb return (ENXIO); 559*67ca7330SBjoern A. Zeeb 560*67ca7330SBjoern A. Zeeb /* 561*67ca7330SBjoern A. Zeeb * Now that we are a dev, create one child device per function, 562*67ca7330SBjoern A. Zeeb * initialize the backpointer, so we can pass them around and 563*67ca7330SBjoern A. Zeeb * call CAM operations on the parent, and also set the function 564*67ca7330SBjoern A. Zeeb * itself as ivars, so that we can query/update them. 565*67ca7330SBjoern A. Zeeb * Do this before any child gets a chance to attach. 566*67ca7330SBjoern A. Zeeb */ 567*67ca7330SBjoern A. Zeeb for (i = 0; i < sc->cardinfo.num_funcs; i++) { 568*67ca7330SBjoern A. Zeeb 569*67ca7330SBjoern A. Zeeb sc->child[i] = device_add_child(dev, NULL, -1); 570*67ca7330SBjoern A. Zeeb if (sc->child[i] == NULL) { 571*67ca7330SBjoern A. Zeeb device_printf(dev, "%s: failed to add child\n", __func__); 572*67ca7330SBjoern A. Zeeb return (ENXIO); 573*67ca7330SBjoern A. Zeeb } 574*67ca7330SBjoern A. Zeeb sc->cardinfo.f[i].dev = sc->child[i]; 575*67ca7330SBjoern A. Zeeb 576*67ca7330SBjoern A. Zeeb /* Set the function as ivar to the child device. */ 577*67ca7330SBjoern A. Zeeb device_set_ivars(sc->child[i], &sc->cardinfo.f[i]); 578*67ca7330SBjoern A. Zeeb } 579*67ca7330SBjoern A. Zeeb 580*67ca7330SBjoern A. Zeeb /* 581*67ca7330SBjoern A. Zeeb * No one will ever attach to F0; we do the above to have a "device" 582*67ca7330SBjoern A. Zeeb * to talk to in a general way in the code. 583*67ca7330SBjoern A. Zeeb * Also do the probe/attach in a 2nd loop, so that all devices are 584*67ca7330SBjoern A. Zeeb * present as we do have drivers consuming more than one device/func 585*67ca7330SBjoern A. Zeeb * and might play "tricks" in order to do that assuming devices and 586*67ca7330SBjoern A. Zeeb * ivars are available for all. 587*67ca7330SBjoern A. Zeeb */ 588*67ca7330SBjoern A. Zeeb for (i = 1; i < sc->cardinfo.num_funcs; i++) { 589*67ca7330SBjoern A. Zeeb error = device_probe_and_attach(sc->child[i]); 590*67ca7330SBjoern A. Zeeb if (error != 0 && bootverbose) 591*67ca7330SBjoern A. Zeeb device_printf(dev, "%s: device_probe_and_attach(%p %s) " 592*67ca7330SBjoern A. Zeeb "failed %d for function %d, no child yet\n", 593*67ca7330SBjoern A. Zeeb __func__, 594*67ca7330SBjoern A. Zeeb sc->child, device_get_nameunit(sc->child[i]), 595*67ca7330SBjoern A. Zeeb error, i); 596*67ca7330SBjoern A. Zeeb } 597*67ca7330SBjoern A. Zeeb 598*67ca7330SBjoern A. Zeeb sc->nb_state = NB_STATE_READY; 599*67ca7330SBjoern A. Zeeb 600*67ca7330SBjoern A. Zeeb cam_periph_lock(sc->periph); 601*67ca7330SBjoern A. Zeeb xpt_announce_periph(sc->periph, NULL); 602*67ca7330SBjoern A. Zeeb cam_periph_unlock(sc->periph); 603*67ca7330SBjoern A. Zeeb 604*67ca7330SBjoern A. Zeeb return (0); 605*67ca7330SBjoern A. Zeeb } 606*67ca7330SBjoern A. Zeeb 607*67ca7330SBjoern A. Zeeb static int 608*67ca7330SBjoern A. Zeeb sdiob_detach(device_t dev) 609*67ca7330SBjoern A. Zeeb { 610*67ca7330SBjoern A. Zeeb 611*67ca7330SBjoern A. Zeeb /* XXX TODO? */ 612*67ca7330SBjoern A. Zeeb return (EOPNOTSUPP); 613*67ca7330SBjoern A. Zeeb } 614*67ca7330SBjoern A. Zeeb 615*67ca7330SBjoern A. Zeeb 616*67ca7330SBjoern A. Zeeb /* -------------------------------------------------------------------------- */ 617*67ca7330SBjoern A. Zeeb /* 618*67ca7330SBjoern A. Zeeb * driver(9) and device(9) "control plane". 619*67ca7330SBjoern A. Zeeb * This is what we use when we are making ourselves a device(9) in order to 620*67ca7330SBjoern A. Zeeb * provide a newbus interface again, as well as the implementation of the 621*67ca7330SBjoern A. Zeeb * SDIO interface. 622*67ca7330SBjoern A. Zeeb */ 623*67ca7330SBjoern A. Zeeb 624*67ca7330SBjoern A. Zeeb static device_method_t sdiob_methods[] = { 625*67ca7330SBjoern A. Zeeb 626*67ca7330SBjoern A. Zeeb /* Device interface. */ 627*67ca7330SBjoern A. Zeeb DEVMETHOD(device_probe, sdiob_probe), 628*67ca7330SBjoern A. Zeeb DEVMETHOD(device_attach, sdiob_attach), 629*67ca7330SBjoern A. Zeeb DEVMETHOD(device_detach, sdiob_detach), 630*67ca7330SBjoern A. Zeeb 631*67ca7330SBjoern A. Zeeb /* Bus interface. */ 632*67ca7330SBjoern A. Zeeb DEVMETHOD(bus_add_child, bus_generic_add_child), 633*67ca7330SBjoern A. Zeeb DEVMETHOD(bus_driver_added, bus_generic_driver_added), 634*67ca7330SBjoern A. Zeeb DEVMETHOD(bus_read_ivar, sdiob_read_ivar), 635*67ca7330SBjoern A. Zeeb DEVMETHOD(bus_write_ivar, sdiob_write_ivar), 636*67ca7330SBjoern A. Zeeb 637*67ca7330SBjoern A. Zeeb /* SDIO interface. */ 638*67ca7330SBjoern A. Zeeb DEVMETHOD(sdio_read_direct, sdiob_read_direct), 639*67ca7330SBjoern A. Zeeb DEVMETHOD(sdio_write_direct, sdiob_write_direct), 640*67ca7330SBjoern A. Zeeb DEVMETHOD(sdio_read_extended, sdiob_read_extended), 641*67ca7330SBjoern A. Zeeb DEVMETHOD(sdio_write_extended, sdiob_write_extended), 642*67ca7330SBjoern A. Zeeb 643*67ca7330SBjoern A. Zeeb DEVMETHOD_END 644*67ca7330SBjoern A. Zeeb }; 645*67ca7330SBjoern A. Zeeb 646*67ca7330SBjoern A. Zeeb static devclass_t sdiob_devclass; 647*67ca7330SBjoern A. Zeeb static driver_t sdiob_driver = { 648*67ca7330SBjoern A. Zeeb SDIOB_NAME_S, 649*67ca7330SBjoern A. Zeeb sdiob_methods, 650*67ca7330SBjoern A. Zeeb 0 651*67ca7330SBjoern A. Zeeb }; 652*67ca7330SBjoern A. Zeeb 653*67ca7330SBjoern A. Zeeb 654*67ca7330SBjoern A. Zeeb /* -------------------------------------------------------------------------- */ 655*67ca7330SBjoern A. Zeeb /* 656*67ca7330SBjoern A. Zeeb * CIS related. 657*67ca7330SBjoern A. Zeeb * Read card and function information and populate the cardinfo structure. 658*67ca7330SBjoern A. Zeeb */ 659*67ca7330SBjoern A. Zeeb 660*67ca7330SBjoern A. Zeeb static int 661*67ca7330SBjoern A. Zeeb sdio_read_direct_sc(struct sdiob_softc *sc, uint8_t fn, uint32_t addr, 662*67ca7330SBjoern A. Zeeb uint8_t *val) 663*67ca7330SBjoern A. Zeeb { 664*67ca7330SBjoern A. Zeeb int error; 665*67ca7330SBjoern A. Zeeb uint8_t v; 666*67ca7330SBjoern A. Zeeb 667*67ca7330SBjoern A. Zeeb error = sdiob_rw_direct_sc(sc, fn, addr, false, &v); 668*67ca7330SBjoern A. Zeeb if (error == 0 && val != NULL) 669*67ca7330SBjoern A. Zeeb *val = v; 670*67ca7330SBjoern A. Zeeb return (error); 671*67ca7330SBjoern A. Zeeb } 672*67ca7330SBjoern A. Zeeb 673*67ca7330SBjoern A. Zeeb static int 674*67ca7330SBjoern A. Zeeb sdio_func_read_cis(struct sdiob_softc *sc, uint8_t fn, uint32_t cis_addr) 675*67ca7330SBjoern A. Zeeb { 676*67ca7330SBjoern A. Zeeb char cis1_info_buf[256]; 677*67ca7330SBjoern A. Zeeb char *cis1_info[4]; 678*67ca7330SBjoern A. Zeeb int start, i, count, ret; 679*67ca7330SBjoern A. Zeeb uint32_t addr; 680*67ca7330SBjoern A. Zeeb uint8_t ch, tuple_id, tuple_len, tuple_count, v; 681*67ca7330SBjoern A. Zeeb 682*67ca7330SBjoern A. Zeeb /* If we encounter any read errors, abort and return. */ 683*67ca7330SBjoern A. Zeeb #define ERR_OUT(ret) \ 684*67ca7330SBjoern A. Zeeb if (ret != 0) \ 685*67ca7330SBjoern A. Zeeb goto err; 686*67ca7330SBjoern A. Zeeb ret = 0; 687*67ca7330SBjoern A. Zeeb /* Use to prevent infinite loop in case of parse errors. */ 688*67ca7330SBjoern A. Zeeb tuple_count = 0; 689*67ca7330SBjoern A. Zeeb memset(cis1_info_buf, 0, 256); 690*67ca7330SBjoern A. Zeeb do { 691*67ca7330SBjoern A. Zeeb addr = cis_addr; 692*67ca7330SBjoern A. Zeeb ret = sdio_read_direct_sc(sc, 0, addr++, &tuple_id); 693*67ca7330SBjoern A. Zeeb ERR_OUT(ret); 694*67ca7330SBjoern A. Zeeb if (tuple_id == SD_IO_CISTPL_END) 695*67ca7330SBjoern A. Zeeb break; 696*67ca7330SBjoern A. Zeeb if (tuple_id == 0) { 697*67ca7330SBjoern A. Zeeb cis_addr++; 698*67ca7330SBjoern A. Zeeb continue; 699*67ca7330SBjoern A. Zeeb } 700*67ca7330SBjoern A. Zeeb ret = sdio_read_direct_sc(sc, 0, addr++, &tuple_len); 701*67ca7330SBjoern A. Zeeb ERR_OUT(ret); 702*67ca7330SBjoern A. Zeeb if (tuple_len == 0) { 703*67ca7330SBjoern A. Zeeb CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_PERIPH, 704*67ca7330SBjoern A. Zeeb ("%s: parse error: 0-length tuple %#02x\n", 705*67ca7330SBjoern A. Zeeb __func__, tuple_id)); 706*67ca7330SBjoern A. Zeeb return (EIO); 707*67ca7330SBjoern A. Zeeb } 708*67ca7330SBjoern A. Zeeb 709*67ca7330SBjoern A. Zeeb switch (tuple_id) { 710*67ca7330SBjoern A. Zeeb case SD_IO_CISTPL_VERS_1: 711*67ca7330SBjoern A. Zeeb addr += 2; 712*67ca7330SBjoern A. Zeeb for (count = 0, start = 0, i = 0; 713*67ca7330SBjoern A. Zeeb (count < 4) && ((i + 4) < 256); i++) { 714*67ca7330SBjoern A. Zeeb ret = sdio_read_direct_sc(sc, 0, addr + i, &ch); 715*67ca7330SBjoern A. Zeeb ERR_OUT(ret); 716*67ca7330SBjoern A. Zeeb DPRINTF("%s: count=%d, start=%d, i=%d, got " 717*67ca7330SBjoern A. Zeeb "(%#02x)\n", __func__, count, start, i, ch); 718*67ca7330SBjoern A. Zeeb if (ch == 0xff) 719*67ca7330SBjoern A. Zeeb break; 720*67ca7330SBjoern A. Zeeb cis1_info_buf[i] = ch; 721*67ca7330SBjoern A. Zeeb if (ch == 0) { 722*67ca7330SBjoern A. Zeeb cis1_info[count] = 723*67ca7330SBjoern A. Zeeb cis1_info_buf + start; 724*67ca7330SBjoern A. Zeeb start = i + 1; 725*67ca7330SBjoern A. Zeeb count++; 726*67ca7330SBjoern A. Zeeb } 727*67ca7330SBjoern A. Zeeb } 728*67ca7330SBjoern A. Zeeb DPRINTF("Card info: "); 729*67ca7330SBjoern A. Zeeb for (i=0; i < 4; i++) 730*67ca7330SBjoern A. Zeeb if (cis1_info[i]) 731*67ca7330SBjoern A. Zeeb DPRINTF(" %s", cis1_info[i]); 732*67ca7330SBjoern A. Zeeb DPRINTF("\n"); 733*67ca7330SBjoern A. Zeeb break; 734*67ca7330SBjoern A. Zeeb case SD_IO_CISTPL_MANFID: 735*67ca7330SBjoern A. Zeeb /* TPLMID_MANF */ 736*67ca7330SBjoern A. Zeeb ret = sdio_read_direct_sc(sc, 0, addr++, &v); 737*67ca7330SBjoern A. Zeeb ERR_OUT(ret); 738*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].vendor = v; 739*67ca7330SBjoern A. Zeeb ret = sdio_read_direct_sc(sc, 0, addr++, &v); 740*67ca7330SBjoern A. Zeeb ERR_OUT(ret); 741*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].vendor |= (v << 8); 742*67ca7330SBjoern A. Zeeb /* TPLMID_CARD */ 743*67ca7330SBjoern A. Zeeb ret = sdio_read_direct_sc(sc, 0, addr++, &v); 744*67ca7330SBjoern A. Zeeb ERR_OUT(ret); 745*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].device = v; 746*67ca7330SBjoern A. Zeeb ret = sdio_read_direct_sc(sc, 0, addr, &v); 747*67ca7330SBjoern A. Zeeb ERR_OUT(ret); 748*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].device |= (v << 8); 749*67ca7330SBjoern A. Zeeb break; 750*67ca7330SBjoern A. Zeeb case SD_IO_CISTPL_FUNCID: 751*67ca7330SBjoern A. Zeeb /* Not sure if we need to parse it? */ 752*67ca7330SBjoern A. Zeeb break; 753*67ca7330SBjoern A. Zeeb case SD_IO_CISTPL_FUNCE: 754*67ca7330SBjoern A. Zeeb if (tuple_len < 4) { 755*67ca7330SBjoern A. Zeeb printf("%s: FUNCE is too short: %d\n", 756*67ca7330SBjoern A. Zeeb __func__, tuple_len); 757*67ca7330SBjoern A. Zeeb break; 758*67ca7330SBjoern A. Zeeb } 759*67ca7330SBjoern A. Zeeb /* TPLFE_TYPE (Extended Data) */ 760*67ca7330SBjoern A. Zeeb ret = sdio_read_direct_sc(sc, 0, addr++, &v); 761*67ca7330SBjoern A. Zeeb ERR_OUT(ret); 762*67ca7330SBjoern A. Zeeb if (fn == 0) { 763*67ca7330SBjoern A. Zeeb if (v != 0x00) 764*67ca7330SBjoern A. Zeeb break; 765*67ca7330SBjoern A. Zeeb } else { 766*67ca7330SBjoern A. Zeeb if (v != 0x01) 767*67ca7330SBjoern A. Zeeb break; 768*67ca7330SBjoern A. Zeeb addr += 0x0b; 769*67ca7330SBjoern A. Zeeb } 770*67ca7330SBjoern A. Zeeb ret = sdio_read_direct_sc(sc, 0, addr, &v); 771*67ca7330SBjoern A. Zeeb ERR_OUT(ret); 772*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].max_blksize = v; 773*67ca7330SBjoern A. Zeeb ret = sdio_read_direct_sc(sc, 0, addr+1, &v); 774*67ca7330SBjoern A. Zeeb ERR_OUT(ret); 775*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].max_blksize |= (v << 8); 776*67ca7330SBjoern A. Zeeb break; 777*67ca7330SBjoern A. Zeeb default: 778*67ca7330SBjoern A. Zeeb CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_PERIPH, 779*67ca7330SBjoern A. Zeeb ("%s: Skipping fn %d tuple %d ID %#02x " 780*67ca7330SBjoern A. Zeeb "len %#02x\n", __func__, fn, tuple_count, 781*67ca7330SBjoern A. Zeeb tuple_id, tuple_len)); 782*67ca7330SBjoern A. Zeeb } 783*67ca7330SBjoern A. Zeeb if (tuple_len == 0xff) { 784*67ca7330SBjoern A. Zeeb /* Also marks the end of a tuple chain (E1 16.2) */ 785*67ca7330SBjoern A. Zeeb /* The tuple is valid, hence this going at the end. */ 786*67ca7330SBjoern A. Zeeb break; 787*67ca7330SBjoern A. Zeeb } 788*67ca7330SBjoern A. Zeeb cis_addr += 2 + tuple_len; 789*67ca7330SBjoern A. Zeeb tuple_count++; 790*67ca7330SBjoern A. Zeeb } while (tuple_count < 20); 791*67ca7330SBjoern A. Zeeb err: 792*67ca7330SBjoern A. Zeeb #undef ERR_OUT 793*67ca7330SBjoern A. Zeeb return (ret); 794*67ca7330SBjoern A. Zeeb } 795*67ca7330SBjoern A. Zeeb 796*67ca7330SBjoern A. Zeeb static int 797*67ca7330SBjoern A. Zeeb sdio_get_common_cis_addr(struct sdiob_softc *sc, uint32_t *addr) 798*67ca7330SBjoern A. Zeeb { 799*67ca7330SBjoern A. Zeeb int error; 800*67ca7330SBjoern A. Zeeb uint32_t a; 801*67ca7330SBjoern A. Zeeb uint8_t val; 802*67ca7330SBjoern A. Zeeb 803*67ca7330SBjoern A. Zeeb error = sdio_read_direct_sc(sc, 0, SD_IO_CCCR_CISPTR + 0, &val); 804*67ca7330SBjoern A. Zeeb if (error != 0) 805*67ca7330SBjoern A. Zeeb goto err; 806*67ca7330SBjoern A. Zeeb a = val; 807*67ca7330SBjoern A. Zeeb error = sdio_read_direct_sc(sc, 0, SD_IO_CCCR_CISPTR + 1, &val); 808*67ca7330SBjoern A. Zeeb if (error != 0) 809*67ca7330SBjoern A. Zeeb goto err; 810*67ca7330SBjoern A. Zeeb a |= (val << 8); 811*67ca7330SBjoern A. Zeeb error = sdio_read_direct_sc(sc, 0, SD_IO_CCCR_CISPTR + 2, &val); 812*67ca7330SBjoern A. Zeeb if (error != 0) 813*67ca7330SBjoern A. Zeeb goto err; 814*67ca7330SBjoern A. Zeeb a |= (val << 16); 815*67ca7330SBjoern A. Zeeb 816*67ca7330SBjoern A. Zeeb if (a < SD_IO_CIS_START || a > SD_IO_CIS_START + SD_IO_CIS_SIZE) { 817*67ca7330SBjoern A. Zeeb err: 818*67ca7330SBjoern A. Zeeb CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_PERIPH, 819*67ca7330SBjoern A. Zeeb ("%s: bad CIS address: %#04x, error %d\n", __func__, a, 820*67ca7330SBjoern A. Zeeb error)); 821*67ca7330SBjoern A. Zeeb } else if (error == 0 && addr != NULL) 822*67ca7330SBjoern A. Zeeb *addr = a; 823*67ca7330SBjoern A. Zeeb 824*67ca7330SBjoern A. Zeeb return (error); 825*67ca7330SBjoern A. Zeeb } 826*67ca7330SBjoern A. Zeeb 827*67ca7330SBjoern A. Zeeb static int 828*67ca7330SBjoern A. Zeeb sdiob_get_card_info(struct sdiob_softc *sc) 829*67ca7330SBjoern A. Zeeb { 830*67ca7330SBjoern A. Zeeb struct mmc_params *mmcp; 831*67ca7330SBjoern A. Zeeb uint32_t cis_addr, fbr_addr; 832*67ca7330SBjoern A. Zeeb int fn, error; 833*67ca7330SBjoern A. Zeeb uint8_t fn_max, val; 834*67ca7330SBjoern A. Zeeb 835*67ca7330SBjoern A. Zeeb error = sdio_get_common_cis_addr(sc, &cis_addr); 836*67ca7330SBjoern A. Zeeb if (error != 0) 837*67ca7330SBjoern A. Zeeb return (-1); 838*67ca7330SBjoern A. Zeeb 839*67ca7330SBjoern A. Zeeb memset(&sc->cardinfo, 0, sizeof(sc->cardinfo)); 840*67ca7330SBjoern A. Zeeb 841*67ca7330SBjoern A. Zeeb /* F0 must always be present. */ 842*67ca7330SBjoern A. Zeeb fn = 0; 843*67ca7330SBjoern A. Zeeb error = sdio_func_read_cis(sc, fn, cis_addr); 844*67ca7330SBjoern A. Zeeb if (error != 0) 845*67ca7330SBjoern A. Zeeb return (error); 846*67ca7330SBjoern A. Zeeb sc->cardinfo.num_funcs++; 847*67ca7330SBjoern A. Zeeb /* Read CCCR Card Capability. */ 848*67ca7330SBjoern A. Zeeb error = sdio_read_direct_sc(sc, 0, SD_IO_CCCR_CARDCAP, &val); 849*67ca7330SBjoern A. Zeeb if (error != 0) 850*67ca7330SBjoern A. Zeeb return (error); 851*67ca7330SBjoern A. Zeeb sc->cardinfo.support_multiblk = (val & CCCR_CC_SMB) ? true : false; 852*67ca7330SBjoern A. Zeeb DPRINTF("%s: F%d: Vendor %#04x product %#04x max block size %d bytes " 853*67ca7330SBjoern A. Zeeb "support_multiblk %s\n", 854*67ca7330SBjoern A. Zeeb __func__, fn, sc->cardinfo.f[fn].vendor, sc->cardinfo.f[fn].device, 855*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].max_blksize, 856*67ca7330SBjoern A. Zeeb sc->cardinfo.support_multiblk ? "yes" : "no"); 857*67ca7330SBjoern A. Zeeb 858*67ca7330SBjoern A. Zeeb /* mmcp->sdio_func_count contains the number of functions w/o F0. */ 859*67ca7330SBjoern A. Zeeb mmcp = &sc->ccb->ccb_h.path->device->mmc_ident_data; 860*67ca7330SBjoern A. Zeeb fn_max = MIN(mmcp->sdio_func_count + 1, nitems(sc->cardinfo.f)); 861*67ca7330SBjoern A. Zeeb for (fn = 1; fn < fn_max; fn++) { 862*67ca7330SBjoern A. Zeeb 863*67ca7330SBjoern A. Zeeb fbr_addr = SD_IO_FBR_START * fn + SD_IO_FBR_CIS_OFFSET; 864*67ca7330SBjoern A. Zeeb 865*67ca7330SBjoern A. Zeeb error = sdio_read_direct_sc(sc, 0, fbr_addr++, &val); 866*67ca7330SBjoern A. Zeeb if (error != 0) 867*67ca7330SBjoern A. Zeeb break; 868*67ca7330SBjoern A. Zeeb cis_addr = val; 869*67ca7330SBjoern A. Zeeb error = sdio_read_direct_sc(sc, 0, fbr_addr++, &val); 870*67ca7330SBjoern A. Zeeb if (error != 0) 871*67ca7330SBjoern A. Zeeb break; 872*67ca7330SBjoern A. Zeeb cis_addr |= (val << 8); 873*67ca7330SBjoern A. Zeeb error = sdio_read_direct_sc(sc, 0, fbr_addr++, &val); 874*67ca7330SBjoern A. Zeeb if (error != 0) 875*67ca7330SBjoern A. Zeeb break; 876*67ca7330SBjoern A. Zeeb cis_addr |= (val << 16); 877*67ca7330SBjoern A. Zeeb 878*67ca7330SBjoern A. Zeeb error = sdio_func_read_cis(sc, fn, cis_addr); 879*67ca7330SBjoern A. Zeeb if (error != 0) 880*67ca7330SBjoern A. Zeeb break; 881*67ca7330SBjoern A. Zeeb 882*67ca7330SBjoern A. Zeeb /* Read the Standard SDIO Function Interface Code. */ 883*67ca7330SBjoern A. Zeeb fbr_addr = SD_IO_FBR_START * fn; 884*67ca7330SBjoern A. Zeeb error = sdio_read_direct_sc(sc, 0, fbr_addr++, &val); 885*67ca7330SBjoern A. Zeeb if (error != 0) 886*67ca7330SBjoern A. Zeeb break; 887*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].class = (val & 0x0f); 888*67ca7330SBjoern A. Zeeb if (sc->cardinfo.f[fn].class == 0x0f) { 889*67ca7330SBjoern A. Zeeb error = sdio_read_direct_sc(sc, 0, fbr_addr, &val); 890*67ca7330SBjoern A. Zeeb if (error != 0) 891*67ca7330SBjoern A. Zeeb break; 892*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].class = val; 893*67ca7330SBjoern A. Zeeb } 894*67ca7330SBjoern A. Zeeb 895*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].fn = fn; 896*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].cur_blksize = sc->cardinfo.f[fn].max_blksize; 897*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].retries = 0; 898*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].timeout = 5000; 899*67ca7330SBjoern A. Zeeb 900*67ca7330SBjoern A. Zeeb DPRINTF("%s: F%d: Class %d Vendor %#04x product %#04x " 901*67ca7330SBjoern A. Zeeb "max_blksize %d bytes\n", __func__, fn, 902*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].class, 903*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].vendor, sc->cardinfo.f[fn].device, 904*67ca7330SBjoern A. Zeeb sc->cardinfo.f[fn].max_blksize); 905*67ca7330SBjoern A. Zeeb if (sc->cardinfo.f[fn].vendor == 0) { 906*67ca7330SBjoern A. Zeeb DPRINTF("%s: F%d doesn't exist\n", __func__, fn); 907*67ca7330SBjoern A. Zeeb break; 908*67ca7330SBjoern A. Zeeb } 909*67ca7330SBjoern A. Zeeb sc->cardinfo.num_funcs++; 910*67ca7330SBjoern A. Zeeb } 911*67ca7330SBjoern A. Zeeb return (error); 912*67ca7330SBjoern A. Zeeb } 913*67ca7330SBjoern A. Zeeb 914*67ca7330SBjoern A. Zeeb 915*67ca7330SBjoern A. Zeeb /* -------------------------------------------------------------------------- */ 916*67ca7330SBjoern A. Zeeb /* 917*67ca7330SBjoern A. Zeeb * CAM periph registration, allocation, and detached from that a discovery 918*67ca7330SBjoern A. Zeeb * task, which goes off reads cardinfo, and then adds ourselves to our SIM's 919*67ca7330SBjoern A. Zeeb * device adding the devclass and registering the driver. This keeps the 920*67ca7330SBjoern A. Zeeb * newbus chain connected though we will talk CAM in the middle (until one 921*67ca7330SBjoern A. Zeeb * day CAM might be newbusyfied). 922*67ca7330SBjoern A. Zeeb */ 923*67ca7330SBjoern A. Zeeb 924*67ca7330SBjoern A. Zeeb static int 925*67ca7330SBjoern A. Zeeb sdio_newbus_sim_add(struct sdiob_softc *sc) 926*67ca7330SBjoern A. Zeeb { 927*67ca7330SBjoern A. Zeeb device_t pdev; 928*67ca7330SBjoern A. Zeeb devclass_t bus_devclass; 929*67ca7330SBjoern A. Zeeb int error; 930*67ca7330SBjoern A. Zeeb 931*67ca7330SBjoern A. Zeeb /* Add ourselves to our parent (SIM) device. */ 932*67ca7330SBjoern A. Zeeb 933*67ca7330SBjoern A. Zeeb /* Add ourselves to our parent. That way we can become a parent. */ 934*67ca7330SBjoern A. Zeeb KASSERT(sc->periph->sim->sim_dev != NULL, ("%s: sim_dev is NULL, sc %p " 935*67ca7330SBjoern A. Zeeb "periph %p sim %p\n", __func__, sc, sc->periph, sc->periph->sim)); 936*67ca7330SBjoern A. Zeeb 937*67ca7330SBjoern A. Zeeb if (sc->dev == NULL) 938*67ca7330SBjoern A. Zeeb sc->dev = BUS_ADD_CHILD(sc->periph->sim->sim_dev, 0, 939*67ca7330SBjoern A. Zeeb SDIOB_NAME_S, -1); 940*67ca7330SBjoern A. Zeeb if (sc->dev == NULL) 941*67ca7330SBjoern A. Zeeb return (ENXIO); 942*67ca7330SBjoern A. Zeeb device_set_softc(sc->dev, sc); 943*67ca7330SBjoern A. Zeeb /* 944*67ca7330SBjoern A. Zeeb * Don't set description here; devclass_add_driver() -> 945*67ca7330SBjoern A. Zeeb * device_probe_child() -> device_set_driver() will nuke it again. 946*67ca7330SBjoern A. Zeeb */ 947*67ca7330SBjoern A. Zeeb 948*67ca7330SBjoern A. Zeeb pdev = device_get_parent(sc->dev); 949*67ca7330SBjoern A. Zeeb KASSERT(pdev != NULL, ("%s: sc %p dev %p (%s) parent is NULL\n", 950*67ca7330SBjoern A. Zeeb __func__, sc, sc->dev, device_get_nameunit(sc->dev))); 951*67ca7330SBjoern A. Zeeb bus_devclass = device_get_devclass(pdev); 952*67ca7330SBjoern A. Zeeb if (bus_devclass == NULL) { 953*67ca7330SBjoern A. Zeeb printf("%s: Failed to get devclass from %s.\n", __func__, 954*67ca7330SBjoern A. Zeeb device_get_nameunit(pdev)); 955*67ca7330SBjoern A. Zeeb return (ENXIO); 956*67ca7330SBjoern A. Zeeb } 957*67ca7330SBjoern A. Zeeb 958*67ca7330SBjoern A. Zeeb mtx_lock(&Giant); 959*67ca7330SBjoern A. Zeeb error = devclass_add_driver(bus_devclass, &sdiob_driver, 960*67ca7330SBjoern A. Zeeb BUS_PASS_DEFAULT, &sdiob_devclass); 961*67ca7330SBjoern A. Zeeb mtx_unlock(&Giant); 962*67ca7330SBjoern A. Zeeb if (error != 0) { 963*67ca7330SBjoern A. Zeeb printf("%s: Failed to add driver to devclass: %d.\n", 964*67ca7330SBjoern A. Zeeb __func__, error); 965*67ca7330SBjoern A. Zeeb return (error); 966*67ca7330SBjoern A. Zeeb } 967*67ca7330SBjoern A. Zeeb 968*67ca7330SBjoern A. Zeeb /* Done. */ 969*67ca7330SBjoern A. Zeeb sc->nb_state = NB_STATE_SIM_ADDED; 970*67ca7330SBjoern A. Zeeb 971*67ca7330SBjoern A. Zeeb return (0); 972*67ca7330SBjoern A. Zeeb } 973*67ca7330SBjoern A. Zeeb 974*67ca7330SBjoern A. Zeeb static void 975*67ca7330SBjoern A. Zeeb sdiobdiscover(void *context, int pending) 976*67ca7330SBjoern A. Zeeb { 977*67ca7330SBjoern A. Zeeb struct cam_periph *periph; 978*67ca7330SBjoern A. Zeeb struct sdiob_softc *sc; 979*67ca7330SBjoern A. Zeeb int error; 980*67ca7330SBjoern A. Zeeb 981*67ca7330SBjoern A. Zeeb KASSERT(context != NULL, ("%s: context is NULL\n", __func__)); 982*67ca7330SBjoern A. Zeeb periph = (struct cam_periph *)context; 983*67ca7330SBjoern A. Zeeb CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s\n", __func__)); 984*67ca7330SBjoern A. Zeeb 985*67ca7330SBjoern A. Zeeb /* Periph was held for us when this task was enqueued. */ 986*67ca7330SBjoern A. Zeeb if ((periph->flags & CAM_PERIPH_INVALID) != 0) { 987*67ca7330SBjoern A. Zeeb cam_periph_release(periph); 988*67ca7330SBjoern A. Zeeb return; 989*67ca7330SBjoern A. Zeeb } 990*67ca7330SBjoern A. Zeeb 991*67ca7330SBjoern A. Zeeb sc = periph->softc; 992*67ca7330SBjoern A. Zeeb sc->sdio_state = SDIO_STATE_INITIALIZING; 993*67ca7330SBjoern A. Zeeb 994*67ca7330SBjoern A. Zeeb if (sc->ccb == NULL) 995*67ca7330SBjoern A. Zeeb sc->ccb = xpt_alloc_ccb(); 996*67ca7330SBjoern A. Zeeb else 997*67ca7330SBjoern A. Zeeb memset(sc->ccb, 0, sizeof(*sc->ccb)); 998*67ca7330SBjoern A. Zeeb xpt_setup_ccb(&sc->ccb->ccb_h, periph->path, CAM_PRIORITY_NONE); 999*67ca7330SBjoern A. Zeeb 1000*67ca7330SBjoern A. Zeeb /* 1001*67ca7330SBjoern A. Zeeb * Read CCCR and FBR of each function, get manufacturer and device IDs, 1002*67ca7330SBjoern A. Zeeb * max block size, and whatever else we deem necessary. 1003*67ca7330SBjoern A. Zeeb */ 1004*67ca7330SBjoern A. Zeeb cam_periph_lock(periph); 1005*67ca7330SBjoern A. Zeeb error = sdiob_get_card_info(sc); 1006*67ca7330SBjoern A. Zeeb if (error == 0) 1007*67ca7330SBjoern A. Zeeb sc->sdio_state = SDIO_STATE_READY; 1008*67ca7330SBjoern A. Zeeb else 1009*67ca7330SBjoern A. Zeeb sc->sdio_state = SDIO_STATE_DEAD; 1010*67ca7330SBjoern A. Zeeb cam_periph_unlock(periph); 1011*67ca7330SBjoern A. Zeeb 1012*67ca7330SBjoern A. Zeeb if (error) 1013*67ca7330SBjoern A. Zeeb return; 1014*67ca7330SBjoern A. Zeeb 1015*67ca7330SBjoern A. Zeeb CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s: num_func %d\n", 1016*67ca7330SBjoern A. Zeeb __func__, sc->cardinfo.num_funcs)); 1017*67ca7330SBjoern A. Zeeb 1018*67ca7330SBjoern A. Zeeb /* 1019*67ca7330SBjoern A. Zeeb * Now CAM portion of the driver has been initialized and 1020*67ca7330SBjoern A. Zeeb * we know VID/PID of all the functions on the card. 1021*67ca7330SBjoern A. Zeeb * Time to hook into the newbus. 1022*67ca7330SBjoern A. Zeeb */ 1023*67ca7330SBjoern A. Zeeb error = sdio_newbus_sim_add(sc); 1024*67ca7330SBjoern A. Zeeb if (error != 0) 1025*67ca7330SBjoern A. Zeeb sc->nb_state = NB_STATE_DEAD; 1026*67ca7330SBjoern A. Zeeb 1027*67ca7330SBjoern A. Zeeb return; 1028*67ca7330SBjoern A. Zeeb } 1029*67ca7330SBjoern A. Zeeb 1030*67ca7330SBjoern A. Zeeb /* Called at the end of cam_periph_alloc() for us to finish allocation. */ 1031*67ca7330SBjoern A. Zeeb static cam_status 1032*67ca7330SBjoern A. Zeeb sdiobregister(struct cam_periph *periph, void *arg) 1033*67ca7330SBjoern A. Zeeb { 1034*67ca7330SBjoern A. Zeeb struct sdiob_softc *sc; 1035*67ca7330SBjoern A. Zeeb int error; 1036*67ca7330SBjoern A. Zeeb 1037*67ca7330SBjoern A. Zeeb CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s: arg %p\n", __func__, arg)); 1038*67ca7330SBjoern A. Zeeb if (arg == NULL) { 1039*67ca7330SBjoern A. Zeeb printf("%s: no getdev CCB, can't register device pariph %p\n", 1040*67ca7330SBjoern A. Zeeb __func__, periph); 1041*67ca7330SBjoern A. Zeeb return(CAM_REQ_CMP_ERR); 1042*67ca7330SBjoern A. Zeeb } 1043*67ca7330SBjoern A. Zeeb if (periph->sim == NULL || periph->sim->sim_dev == NULL) { 1044*67ca7330SBjoern A. Zeeb printf("%s: no sim %p or sim_dev %p\n", __func__, periph->sim, 1045*67ca7330SBjoern A. Zeeb (periph->sim != NULL) ? periph->sim->sim_dev : NULL); 1046*67ca7330SBjoern A. Zeeb return(CAM_REQ_CMP_ERR); 1047*67ca7330SBjoern A. Zeeb } 1048*67ca7330SBjoern A. Zeeb 1049*67ca7330SBjoern A. Zeeb sc = (struct sdiob_softc *) malloc(sizeof(*sc), M_DEVBUF, 1050*67ca7330SBjoern A. Zeeb M_NOWAIT|M_ZERO); 1051*67ca7330SBjoern A. Zeeb if (sc == NULL) { 1052*67ca7330SBjoern A. Zeeb printf("%s: unable to allocate sc\n", __func__); 1053*67ca7330SBjoern A. Zeeb return (CAM_REQ_CMP_ERR); 1054*67ca7330SBjoern A. Zeeb } 1055*67ca7330SBjoern A. Zeeb sc->sdio_state = SDIO_STATE_DEAD; 1056*67ca7330SBjoern A. Zeeb sc->nb_state = NB_STATE_DEAD; 1057*67ca7330SBjoern A. Zeeb TASK_INIT(&sc->discover_task, 0, sdiobdiscover, periph); 1058*67ca7330SBjoern A. Zeeb 1059*67ca7330SBjoern A. Zeeb /* Refcount until we are setup. Can't block. */ 1060*67ca7330SBjoern A. Zeeb error = cam_periph_hold(periph, PRIBIO); 1061*67ca7330SBjoern A. Zeeb if (error != 0) { 1062*67ca7330SBjoern A. Zeeb printf("%s: lost periph during registration!\n", __func__); 1063*67ca7330SBjoern A. Zeeb free(sc, M_DEVBUF); 1064*67ca7330SBjoern A. Zeeb return(CAM_REQ_CMP_ERR); 1065*67ca7330SBjoern A. Zeeb } 1066*67ca7330SBjoern A. Zeeb periph->softc = sc; 1067*67ca7330SBjoern A. Zeeb sc->periph = periph; 1068*67ca7330SBjoern A. Zeeb cam_periph_unlock(periph); 1069*67ca7330SBjoern A. Zeeb 1070*67ca7330SBjoern A. Zeeb error = taskqueue_enqueue(taskqueue_thread, &sc->discover_task); 1071*67ca7330SBjoern A. Zeeb 1072*67ca7330SBjoern A. Zeeb cam_periph_lock(periph); 1073*67ca7330SBjoern A. Zeeb /* We will continue to hold a refcount for discover_task. */ 1074*67ca7330SBjoern A. Zeeb /* cam_periph_unhold(periph); */ 1075*67ca7330SBjoern A. Zeeb 1076*67ca7330SBjoern A. Zeeb xpt_schedule(periph, CAM_PRIORITY_XPT); 1077*67ca7330SBjoern A. Zeeb 1078*67ca7330SBjoern A. Zeeb return (CAM_REQ_CMP); 1079*67ca7330SBjoern A. Zeeb } 1080*67ca7330SBjoern A. Zeeb 1081*67ca7330SBjoern A. Zeeb static void 1082*67ca7330SBjoern A. Zeeb sdioboninvalidate(struct cam_periph *periph) 1083*67ca7330SBjoern A. Zeeb { 1084*67ca7330SBjoern A. Zeeb 1085*67ca7330SBjoern A. Zeeb CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s:\n", __func__)); 1086*67ca7330SBjoern A. Zeeb 1087*67ca7330SBjoern A. Zeeb return; 1088*67ca7330SBjoern A. Zeeb } 1089*67ca7330SBjoern A. Zeeb 1090*67ca7330SBjoern A. Zeeb static void 1091*67ca7330SBjoern A. Zeeb sdiobcleanup(struct cam_periph *periph) 1092*67ca7330SBjoern A. Zeeb { 1093*67ca7330SBjoern A. Zeeb 1094*67ca7330SBjoern A. Zeeb CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s:\n", __func__)); 1095*67ca7330SBjoern A. Zeeb 1096*67ca7330SBjoern A. Zeeb return; 1097*67ca7330SBjoern A. Zeeb } 1098*67ca7330SBjoern A. Zeeb 1099*67ca7330SBjoern A. Zeeb static void 1100*67ca7330SBjoern A. Zeeb sdiobstart(struct cam_periph *periph, union ccb *ccb) 1101*67ca7330SBjoern A. Zeeb { 1102*67ca7330SBjoern A. Zeeb 1103*67ca7330SBjoern A. Zeeb CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("%s: ccb %p\n", __func__, ccb)); 1104*67ca7330SBjoern A. Zeeb 1105*67ca7330SBjoern A. Zeeb return; 1106*67ca7330SBjoern A. Zeeb } 1107*67ca7330SBjoern A. Zeeb 1108*67ca7330SBjoern A. Zeeb static void 1109*67ca7330SBjoern A. Zeeb sdiobasync(void *softc, uint32_t code, struct cam_path *path, void *arg) 1110*67ca7330SBjoern A. Zeeb { 1111*67ca7330SBjoern A. Zeeb struct cam_periph *periph; 1112*67ca7330SBjoern A. Zeeb struct ccb_getdev *cgd; 1113*67ca7330SBjoern A. Zeeb cam_status status; 1114*67ca7330SBjoern A. Zeeb 1115*67ca7330SBjoern A. Zeeb periph = (struct cam_periph *)softc; 1116*67ca7330SBjoern A. Zeeb 1117*67ca7330SBjoern A. Zeeb CAM_DEBUG(path, CAM_DEBUG_TRACE, ("%s(code=%d)\n", __func__, code)); 1118*67ca7330SBjoern A. Zeeb switch (code) { 1119*67ca7330SBjoern A. Zeeb case AC_FOUND_DEVICE: 1120*67ca7330SBjoern A. Zeeb if (arg == NULL) 1121*67ca7330SBjoern A. Zeeb break; 1122*67ca7330SBjoern A. Zeeb cgd = (struct ccb_getdev *)arg; 1123*67ca7330SBjoern A. Zeeb if (cgd->protocol != PROTO_MMCSD) 1124*67ca7330SBjoern A. Zeeb break; 1125*67ca7330SBjoern A. Zeeb 1126*67ca7330SBjoern A. Zeeb /* We do not support SD memory (Combo) Cards. */ 1127*67ca7330SBjoern A. Zeeb if ((path->device->mmc_ident_data.card_features & 1128*67ca7330SBjoern A. Zeeb CARD_FEATURE_MEMORY)) { 1129*67ca7330SBjoern A. Zeeb CAM_DEBUG(path, CAM_DEBUG_TRACE, 1130*67ca7330SBjoern A. Zeeb ("Memory card, not interested\n")); 1131*67ca7330SBjoern A. Zeeb break; 1132*67ca7330SBjoern A. Zeeb } 1133*67ca7330SBjoern A. Zeeb 1134*67ca7330SBjoern A. Zeeb /* 1135*67ca7330SBjoern A. Zeeb * Allocate a peripheral instance for this device which starts 1136*67ca7330SBjoern A. Zeeb * the probe process. 1137*67ca7330SBjoern A. Zeeb */ 1138*67ca7330SBjoern A. Zeeb status = cam_periph_alloc(sdiobregister, sdioboninvalidate, 1139*67ca7330SBjoern A. Zeeb sdiobcleanup, sdiobstart, SDIOB_NAME_S, CAM_PERIPH_BIO, path, 1140*67ca7330SBjoern A. Zeeb sdiobasync, AC_FOUND_DEVICE, cgd); 1141*67ca7330SBjoern A. Zeeb if (status != CAM_REQ_CMP && status != CAM_REQ_INPROG) 1142*67ca7330SBjoern A. Zeeb CAM_DEBUG(path, CAM_DEBUG_PERIPH, 1143*67ca7330SBjoern A. Zeeb ("%s: Unable to attach to new device due to " 1144*67ca7330SBjoern A. Zeeb "status %#02x\n", __func__, status)); 1145*67ca7330SBjoern A. Zeeb break; 1146*67ca7330SBjoern A. Zeeb default: 1147*67ca7330SBjoern A. Zeeb CAM_DEBUG(path, CAM_DEBUG_PERIPH, 1148*67ca7330SBjoern A. Zeeb ("%s: cannot handle async code %#02x\n", __func__, code)); 1149*67ca7330SBjoern A. Zeeb cam_periph_async(periph, code, path, arg); 1150*67ca7330SBjoern A. Zeeb break; 1151*67ca7330SBjoern A. Zeeb } 1152*67ca7330SBjoern A. Zeeb } 1153*67ca7330SBjoern A. Zeeb 1154*67ca7330SBjoern A. Zeeb static void 1155*67ca7330SBjoern A. Zeeb sdiobinit(void) 1156*67ca7330SBjoern A. Zeeb { 1157*67ca7330SBjoern A. Zeeb cam_status status; 1158*67ca7330SBjoern A. Zeeb 1159*67ca7330SBjoern A. Zeeb /* 1160*67ca7330SBjoern A. Zeeb * Register for new device notification. We will be notified for all 1161*67ca7330SBjoern A. Zeeb * already existing ones. 1162*67ca7330SBjoern A. Zeeb */ 1163*67ca7330SBjoern A. Zeeb status = xpt_register_async(AC_FOUND_DEVICE, sdiobasync, NULL, NULL); 1164*67ca7330SBjoern A. Zeeb if (status != CAM_REQ_CMP) 1165*67ca7330SBjoern A. Zeeb printf("%s: Failed to attach async callback, statux %#02x", 1166*67ca7330SBjoern A. Zeeb __func__, status); 1167*67ca7330SBjoern A. Zeeb } 1168*67ca7330SBjoern A. Zeeb 1169*67ca7330SBjoern A. Zeeb /* This function will allow unloading the KLD. */ 1170*67ca7330SBjoern A. Zeeb static int 1171*67ca7330SBjoern A. Zeeb sdiobdeinit(void) 1172*67ca7330SBjoern A. Zeeb { 1173*67ca7330SBjoern A. Zeeb 1174*67ca7330SBjoern A. Zeeb return (EOPNOTSUPP); 1175*67ca7330SBjoern A. Zeeb } 1176*67ca7330SBjoern A. Zeeb 1177*67ca7330SBjoern A. Zeeb static struct periph_driver sdiobdriver = 1178*67ca7330SBjoern A. Zeeb { 1179*67ca7330SBjoern A. Zeeb .init = sdiobinit, 1180*67ca7330SBjoern A. Zeeb .driver_name = SDIOB_NAME_S, 1181*67ca7330SBjoern A. Zeeb .units = TAILQ_HEAD_INITIALIZER(sdiobdriver.units), 1182*67ca7330SBjoern A. Zeeb .generation = 0, 1183*67ca7330SBjoern A. Zeeb .flags = 0, 1184*67ca7330SBjoern A. Zeeb .deinit = sdiobdeinit, 1185*67ca7330SBjoern A. Zeeb }; 1186*67ca7330SBjoern A. Zeeb 1187*67ca7330SBjoern A. Zeeb PERIPHDRIVER_DECLARE(SDIOB_NAME, sdiobdriver); 1188*67ca7330SBjoern A. Zeeb MODULE_VERSION(SDIOB_NAME, 1); 1189