167ca7330SBjoern A. Zeeb /*- 267ca7330SBjoern A. Zeeb * Copyright (c) 2017 Ilya Bakulin. All rights reserved. 367ca7330SBjoern A. Zeeb * Copyright (c) 2018-2019 The FreeBSD Foundation 467ca7330SBjoern A. Zeeb * 567ca7330SBjoern A. Zeeb * Portions of this software were developed by Björn Zeeb 667ca7330SBjoern A. Zeeb * under sponsorship from the FreeBSD Foundation. 767ca7330SBjoern A. Zeeb * 867ca7330SBjoern A. Zeeb * Redistribution and use in source and binary forms, with or without 967ca7330SBjoern A. Zeeb * modification, are permitted provided that the following conditions 1067ca7330SBjoern A. Zeeb * are met: 1167ca7330SBjoern A. Zeeb * 1. Redistributions of source code must retain the above copyright 1267ca7330SBjoern A. Zeeb * notice, this list of conditions and the following disclaimer. 1367ca7330SBjoern A. Zeeb * 2. Redistributions in binary form must reproduce the above copyright 1467ca7330SBjoern A. Zeeb * notice, this list of conditions and the following disclaimer in the 1567ca7330SBjoern A. Zeeb * documentation and/or other materials provided with the distribution. 1667ca7330SBjoern A. Zeeb * 1767ca7330SBjoern A. Zeeb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1867ca7330SBjoern A. Zeeb * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1967ca7330SBjoern A. Zeeb * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2067ca7330SBjoern A. Zeeb * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2167ca7330SBjoern A. Zeeb * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2267ca7330SBjoern A. Zeeb * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2367ca7330SBjoern A. Zeeb * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2467ca7330SBjoern A. Zeeb * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2567ca7330SBjoern A. Zeeb * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2667ca7330SBjoern A. Zeeb * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2767ca7330SBjoern A. Zeeb * 2867ca7330SBjoern A. Zeeb * 2967ca7330SBjoern A. Zeeb * Portions of this software may have been developed with reference to 3067ca7330SBjoern A. Zeeb * the SD Simplified Specification. The following disclaimer may apply: 3167ca7330SBjoern A. Zeeb * 3267ca7330SBjoern A. Zeeb * The following conditions apply to the release of the simplified 3367ca7330SBjoern A. Zeeb * specification ("Simplified Specification") by the SD Card Association and 3467ca7330SBjoern A. Zeeb * the SD Group. The Simplified Specification is a subset of the complete SD 3567ca7330SBjoern A. Zeeb * Specification which is owned by the SD Card Association and the SD 3667ca7330SBjoern A. Zeeb * Group. This Simplified Specification is provided on a non-confidential 3767ca7330SBjoern A. Zeeb * basis subject to the disclaimers below. Any implementation of the 3867ca7330SBjoern A. Zeeb * Simplified Specification may require a license from the SD Card 3967ca7330SBjoern A. Zeeb * Association, SD Group, SD-3C LLC or other third parties. 4067ca7330SBjoern A. Zeeb * 4167ca7330SBjoern A. Zeeb * Disclaimers: 4267ca7330SBjoern A. Zeeb * 4367ca7330SBjoern A. Zeeb * The information contained in the Simplified Specification is presented only 4467ca7330SBjoern A. Zeeb * as a standard specification for SD Cards and SD Host/Ancillary products and 4567ca7330SBjoern A. Zeeb * is provided "AS-IS" without any representations or warranties of any 4667ca7330SBjoern A. Zeeb * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD 4767ca7330SBjoern A. Zeeb * Card Association for any damages, any infringements of patents or other 4867ca7330SBjoern A. Zeeb * right of the SD Group, SD-3C LLC, the SD Card Association or any third 4967ca7330SBjoern A. Zeeb * parties, which may result from its use. No license is granted by 5067ca7330SBjoern A. Zeeb * implication, estoppel or otherwise under any patent or other rights of the 5167ca7330SBjoern A. Zeeb * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing 5267ca7330SBjoern A. Zeeb * herein shall be construed as an obligation by the SD Group, the SD-3C LLC 5367ca7330SBjoern A. Zeeb * or the SD Card Association to disclose or distribute any technical 5467ca7330SBjoern A. Zeeb * information, know-how or other confidential information to any third party. 5567ca7330SBjoern A. Zeeb */ 5667ca7330SBjoern A. Zeeb 5767ca7330SBjoern A. Zeeb #include <sys/cdefs.h> 5867ca7330SBjoern A. Zeeb __FBSDID("$FreeBSD$"); 5967ca7330SBjoern A. Zeeb 6067ca7330SBjoern A. Zeeb #include <sys/types.h> 6167ca7330SBjoern A. Zeeb #include <sys/param.h> 6267ca7330SBjoern A. Zeeb #include <sys/kernel.h> 6367ca7330SBjoern A. Zeeb #include <sys/systm.h> 6467ca7330SBjoern A. Zeeb #include <sys/bus.h> 6567ca7330SBjoern A. Zeeb #include <sys/endian.h> 6667ca7330SBjoern A. Zeeb 6767ca7330SBjoern A. Zeeb #include <dev/mmc/mmcreg.h> 6867ca7330SBjoern A. Zeeb 6967ca7330SBjoern A. Zeeb #include <dev/sdio/sdiob.h> 7067ca7330SBjoern A. Zeeb #include <dev/sdio/sdio_subr.h> 7167ca7330SBjoern A. Zeeb 7267ca7330SBjoern A. Zeeb #include "sdio_if.h" 7367ca7330SBjoern A. Zeeb 7467ca7330SBjoern A. Zeeb /* Works on F0. */ 7567ca7330SBjoern A. Zeeb static int 7667ca7330SBjoern A. Zeeb sdio_set_bool_for_func(device_t dev, uint32_t addr, uint8_t fn, bool enable) 7767ca7330SBjoern A. Zeeb { 7867ca7330SBjoern A. Zeeb device_t pdev; 7967ca7330SBjoern A. Zeeb int error; 8067ca7330SBjoern A. Zeeb uint8_t val; 8167ca7330SBjoern A. Zeeb bool enabled; 8267ca7330SBjoern A. Zeeb 8367ca7330SBjoern A. Zeeb pdev = device_get_parent(dev); 8467ca7330SBjoern A. Zeeb error = SDIO_READ_DIRECT(pdev, 0, addr, &val); 8567ca7330SBjoern A. Zeeb if (error != 0) 8667ca7330SBjoern A. Zeeb return (error); 8767ca7330SBjoern A. Zeeb 8867ca7330SBjoern A. Zeeb enabled = (val & (1 << fn)) ? true : false; 8967ca7330SBjoern A. Zeeb if (enabled == enable) 9067ca7330SBjoern A. Zeeb return (0); 9167ca7330SBjoern A. Zeeb 9267ca7330SBjoern A. Zeeb if (enable) 9367ca7330SBjoern A. Zeeb val |= (1 << fn); 9467ca7330SBjoern A. Zeeb else 9567ca7330SBjoern A. Zeeb val &= ~(1 << fn); 9667ca7330SBjoern A. Zeeb error = SDIO_WRITE_DIRECT(pdev, 0, addr, val); 9767ca7330SBjoern A. Zeeb return (error); 9867ca7330SBjoern A. Zeeb } 9967ca7330SBjoern A. Zeeb 10067ca7330SBjoern A. Zeeb int 10167ca7330SBjoern A. Zeeb sdio_enable_func(struct sdio_func *f) 10267ca7330SBjoern A. Zeeb { 10367ca7330SBjoern A. Zeeb 10467ca7330SBjoern A. Zeeb return (sdio_set_bool_for_func(f->dev, SD_IO_CCCR_FN_ENABLE, 10567ca7330SBjoern A. Zeeb f->fn, true)); 10667ca7330SBjoern A. Zeeb } 10767ca7330SBjoern A. Zeeb 10867ca7330SBjoern A. Zeeb int 10967ca7330SBjoern A. Zeeb sdio_disable_func(struct sdio_func *f) 11067ca7330SBjoern A. Zeeb { 11167ca7330SBjoern A. Zeeb 11267ca7330SBjoern A. Zeeb return (sdio_set_bool_for_func(f->dev, SD_IO_CCCR_FN_ENABLE, 11367ca7330SBjoern A. Zeeb f->fn, false)); 11467ca7330SBjoern A. Zeeb } 11567ca7330SBjoern A. Zeeb 11667ca7330SBjoern A. Zeeb int 11767ca7330SBjoern A. Zeeb sdio_set_block_size(struct sdio_func *f, uint16_t bs) 11867ca7330SBjoern A. Zeeb { 11967ca7330SBjoern A. Zeeb device_t pdev; 12067ca7330SBjoern A. Zeeb int error; 12167ca7330SBjoern A. Zeeb uint32_t addr; 12267ca7330SBjoern A. Zeeb uint16_t v; 12367ca7330SBjoern A. Zeeb 12467ca7330SBjoern A. Zeeb if (!sdio_get_support_multiblk(f->dev)) 12567ca7330SBjoern A. Zeeb return (EOPNOTSUPP); 12667ca7330SBjoern A. Zeeb 12767ca7330SBjoern A. Zeeb pdev = device_get_parent(f->dev); 12867ca7330SBjoern A. Zeeb addr = SD_IO_FBR_START * f->fn + SD_IO_FBR_IOBLKSZ; 12967ca7330SBjoern A. Zeeb v = htole16(bs); 13067ca7330SBjoern A. Zeeb /* Always write through F0. */ 13167ca7330SBjoern A. Zeeb error = SDIO_WRITE_DIRECT(pdev, 0, addr, v & 0xff); 13267ca7330SBjoern A. Zeeb if (error == 0) 13367ca7330SBjoern A. Zeeb error = SDIO_WRITE_DIRECT(pdev, 0, addr + 1, 13467ca7330SBjoern A. Zeeb (v >> 8) & 0xff); 13567ca7330SBjoern A. Zeeb if (error == 0) 13667ca7330SBjoern A. Zeeb f->cur_blksize = bs; 13767ca7330SBjoern A. Zeeb 13867ca7330SBjoern A. Zeeb return (error); 13967ca7330SBjoern A. Zeeb } 14067ca7330SBjoern A. Zeeb 14167ca7330SBjoern A. Zeeb uint8_t 142b9db5e0aSEmmanuel Vadot sdio_read_1(struct sdio_func *f, uint32_t addr, int *err) 14367ca7330SBjoern A. Zeeb { 14467ca7330SBjoern A. Zeeb int error; 14567ca7330SBjoern A. Zeeb uint8_t v; 14667ca7330SBjoern A. Zeeb 14767ca7330SBjoern A. Zeeb error = SDIO_READ_DIRECT(device_get_parent(f->dev), f->fn, addr, &v); 14867ca7330SBjoern A. Zeeb if (error) { 14967ca7330SBjoern A. Zeeb if (err != NULL) 15067ca7330SBjoern A. Zeeb *err = error; 15167ca7330SBjoern A. Zeeb return (0xff); 15267ca7330SBjoern A. Zeeb } else { 15367ca7330SBjoern A. Zeeb if (err != NULL) 15467ca7330SBjoern A. Zeeb *err = 0; 15567ca7330SBjoern A. Zeeb return (v); 15667ca7330SBjoern A. Zeeb } 15767ca7330SBjoern A. Zeeb } 15867ca7330SBjoern A. Zeeb 15967ca7330SBjoern A. Zeeb void 160b9db5e0aSEmmanuel Vadot sdio_write_1(struct sdio_func *f, uint32_t addr, uint8_t val, int *err) 16167ca7330SBjoern A. Zeeb { 16267ca7330SBjoern A. Zeeb int error; 16367ca7330SBjoern A. Zeeb 16467ca7330SBjoern A. Zeeb error = SDIO_WRITE_DIRECT(device_get_parent(f->dev), f->fn, addr, val); 16567ca7330SBjoern A. Zeeb if (err != NULL) 16667ca7330SBjoern A. Zeeb *err = error; 16767ca7330SBjoern A. Zeeb } 16867ca7330SBjoern A. Zeeb 16967ca7330SBjoern A. Zeeb uint32_t 170b9db5e0aSEmmanuel Vadot sdio_read_4(struct sdio_func *f, uint32_t addr, int *err) 17167ca7330SBjoern A. Zeeb { 17267ca7330SBjoern A. Zeeb int error; 17367ca7330SBjoern A. Zeeb uint32_t v; 17467ca7330SBjoern A. Zeeb 17567ca7330SBjoern A. Zeeb error = SDIO_READ_EXTENDED(device_get_parent(f->dev), f->fn, addr, 176*1ee7a804SEmmanuel Vadot sizeof(v), (uint8_t *)&v, true); 17767ca7330SBjoern A. Zeeb if (error) { 17867ca7330SBjoern A. Zeeb if (err != NULL) 17967ca7330SBjoern A. Zeeb *err = error; 18067ca7330SBjoern A. Zeeb return (0xffffffff); 18167ca7330SBjoern A. Zeeb } else { 18267ca7330SBjoern A. Zeeb if (err != NULL) 18367ca7330SBjoern A. Zeeb *err = 0; 18467ca7330SBjoern A. Zeeb return (le32toh(v)); 18567ca7330SBjoern A. Zeeb } 18667ca7330SBjoern A. Zeeb } 18767ca7330SBjoern A. Zeeb 18867ca7330SBjoern A. Zeeb void 189b9db5e0aSEmmanuel Vadot sdio_write_4(struct sdio_func *f, uint32_t addr, uint32_t val, int *err) 19067ca7330SBjoern A. Zeeb { 19167ca7330SBjoern A. Zeeb int error; 19267ca7330SBjoern A. Zeeb 19367ca7330SBjoern A. Zeeb error = SDIO_WRITE_EXTENDED(device_get_parent(f->dev), f->fn, addr, 194*1ee7a804SEmmanuel Vadot sizeof(val), (uint8_t *)&val, true); 19567ca7330SBjoern A. Zeeb if (err != NULL) 19667ca7330SBjoern A. Zeeb *err = error; 19767ca7330SBjoern A. Zeeb } 19867ca7330SBjoern A. Zeeb 19967ca7330SBjoern A. Zeeb uint8_t 200b9db5e0aSEmmanuel Vadot sdio_f0_read_1(struct sdio_func *f, uint32_t addr, int *err) 20167ca7330SBjoern A. Zeeb { 20267ca7330SBjoern A. Zeeb int error; 20367ca7330SBjoern A. Zeeb uint8_t v; 20467ca7330SBjoern A. Zeeb 20567ca7330SBjoern A. Zeeb error = SDIO_READ_DIRECT(device_get_parent(f->dev), 0, addr, &v); 20667ca7330SBjoern A. Zeeb if (error) { 20767ca7330SBjoern A. Zeeb if (err != NULL) 20867ca7330SBjoern A. Zeeb *err = error; 20967ca7330SBjoern A. Zeeb return (0xff); 21067ca7330SBjoern A. Zeeb } else { 21167ca7330SBjoern A. Zeeb if (err != NULL) 21267ca7330SBjoern A. Zeeb *err = 0; 21367ca7330SBjoern A. Zeeb return (v); 21467ca7330SBjoern A. Zeeb } 21567ca7330SBjoern A. Zeeb } 21667ca7330SBjoern A. Zeeb 21767ca7330SBjoern A. Zeeb void 218b9db5e0aSEmmanuel Vadot sdio_f0_write_1(struct sdio_func *f, uint32_t addr, uint8_t val, int *err) 21967ca7330SBjoern A. Zeeb { 22067ca7330SBjoern A. Zeeb int error; 22167ca7330SBjoern A. Zeeb 22267ca7330SBjoern A. Zeeb error = SDIO_WRITE_DIRECT(device_get_parent(f->dev), 0, addr, val); 22367ca7330SBjoern A. Zeeb if (err != NULL) 22467ca7330SBjoern A. Zeeb *err = error; 22567ca7330SBjoern A. Zeeb } 22667ca7330SBjoern A. Zeeb 22767ca7330SBjoern A. Zeeb /* end */ 228