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 12449da0242SEmmanuel Vadot if (bs > f->max_blksize) 12549da0242SEmmanuel Vadot return (EOPNOTSUPP); 12649da0242SEmmanuel Vadot 12767ca7330SBjoern A. Zeeb if (!sdio_get_support_multiblk(f->dev)) 12867ca7330SBjoern A. Zeeb return (EOPNOTSUPP); 12967ca7330SBjoern A. Zeeb 13067ca7330SBjoern A. Zeeb pdev = device_get_parent(f->dev); 13167ca7330SBjoern A. Zeeb addr = SD_IO_FBR_START * f->fn + SD_IO_FBR_IOBLKSZ; 13267ca7330SBjoern A. Zeeb v = htole16(bs); 13367ca7330SBjoern A. Zeeb /* Always write through F0. */ 13467ca7330SBjoern A. Zeeb error = SDIO_WRITE_DIRECT(pdev, 0, addr, v & 0xff); 13567ca7330SBjoern A. Zeeb if (error == 0) 13667ca7330SBjoern A. Zeeb error = SDIO_WRITE_DIRECT(pdev, 0, addr + 1, 13767ca7330SBjoern A. Zeeb (v >> 8) & 0xff); 13867ca7330SBjoern A. Zeeb if (error == 0) 13967ca7330SBjoern A. Zeeb f->cur_blksize = bs; 14067ca7330SBjoern A. Zeeb 14167ca7330SBjoern A. Zeeb return (error); 14267ca7330SBjoern A. Zeeb } 14367ca7330SBjoern A. Zeeb 14467ca7330SBjoern A. Zeeb uint8_t 145b9db5e0aSEmmanuel Vadot sdio_read_1(struct sdio_func *f, uint32_t addr, int *err) 14667ca7330SBjoern A. Zeeb { 14767ca7330SBjoern A. Zeeb int error; 14867ca7330SBjoern A. Zeeb uint8_t v; 14967ca7330SBjoern A. Zeeb 15067ca7330SBjoern A. Zeeb error = SDIO_READ_DIRECT(device_get_parent(f->dev), f->fn, addr, &v); 15167ca7330SBjoern A. Zeeb if (error) { 15267ca7330SBjoern A. Zeeb if (err != NULL) 15367ca7330SBjoern A. Zeeb *err = error; 15467ca7330SBjoern A. Zeeb return (0xff); 15567ca7330SBjoern A. Zeeb } else { 15667ca7330SBjoern A. Zeeb if (err != NULL) 15767ca7330SBjoern A. Zeeb *err = 0; 15867ca7330SBjoern A. Zeeb return (v); 15967ca7330SBjoern A. Zeeb } 16067ca7330SBjoern A. Zeeb } 16167ca7330SBjoern A. Zeeb 16267ca7330SBjoern A. Zeeb void 163b9db5e0aSEmmanuel Vadot sdio_write_1(struct sdio_func *f, uint32_t addr, uint8_t val, int *err) 16467ca7330SBjoern A. Zeeb { 16567ca7330SBjoern A. Zeeb int error; 16667ca7330SBjoern A. Zeeb 16767ca7330SBjoern A. Zeeb error = SDIO_WRITE_DIRECT(device_get_parent(f->dev), f->fn, addr, val); 16867ca7330SBjoern A. Zeeb if (err != NULL) 16967ca7330SBjoern A. Zeeb *err = error; 17067ca7330SBjoern A. Zeeb } 17167ca7330SBjoern A. Zeeb 17267ca7330SBjoern A. Zeeb uint32_t 173b9db5e0aSEmmanuel Vadot sdio_read_4(struct sdio_func *f, uint32_t addr, int *err) 17467ca7330SBjoern A. Zeeb { 17567ca7330SBjoern A. Zeeb int error; 17667ca7330SBjoern A. Zeeb uint32_t v; 17767ca7330SBjoern A. Zeeb 17867ca7330SBjoern A. Zeeb error = SDIO_READ_EXTENDED(device_get_parent(f->dev), f->fn, addr, 1791ee7a804SEmmanuel Vadot sizeof(v), (uint8_t *)&v, true); 18067ca7330SBjoern A. Zeeb if (error) { 18167ca7330SBjoern A. Zeeb if (err != NULL) 18267ca7330SBjoern A. Zeeb *err = error; 18367ca7330SBjoern A. Zeeb return (0xffffffff); 18467ca7330SBjoern A. Zeeb } else { 18567ca7330SBjoern A. Zeeb if (err != NULL) 18667ca7330SBjoern A. Zeeb *err = 0; 18767ca7330SBjoern A. Zeeb return (le32toh(v)); 18867ca7330SBjoern A. Zeeb } 18967ca7330SBjoern A. Zeeb } 19067ca7330SBjoern A. Zeeb 19167ca7330SBjoern A. Zeeb void 192b9db5e0aSEmmanuel Vadot sdio_write_4(struct sdio_func *f, uint32_t addr, uint32_t val, int *err) 19367ca7330SBjoern A. Zeeb { 19467ca7330SBjoern A. Zeeb int error; 19567ca7330SBjoern A. Zeeb 19667ca7330SBjoern A. Zeeb error = SDIO_WRITE_EXTENDED(device_get_parent(f->dev), f->fn, addr, 1971ee7a804SEmmanuel Vadot sizeof(val), (uint8_t *)&val, true); 19867ca7330SBjoern A. Zeeb if (err != NULL) 19967ca7330SBjoern A. Zeeb *err = error; 20067ca7330SBjoern A. Zeeb } 20167ca7330SBjoern A. Zeeb 20267ca7330SBjoern A. Zeeb uint8_t 203b9db5e0aSEmmanuel Vadot sdio_f0_read_1(struct sdio_func *f, uint32_t addr, int *err) 20467ca7330SBjoern A. Zeeb { 20567ca7330SBjoern A. Zeeb int error; 20667ca7330SBjoern A. Zeeb uint8_t v; 20767ca7330SBjoern A. Zeeb 20867ca7330SBjoern A. Zeeb error = SDIO_READ_DIRECT(device_get_parent(f->dev), 0, addr, &v); 20967ca7330SBjoern A. Zeeb if (error) { 21067ca7330SBjoern A. Zeeb if (err != NULL) 21167ca7330SBjoern A. Zeeb *err = error; 21267ca7330SBjoern A. Zeeb return (0xff); 21367ca7330SBjoern A. Zeeb } else { 21467ca7330SBjoern A. Zeeb if (err != NULL) 21567ca7330SBjoern A. Zeeb *err = 0; 21667ca7330SBjoern A. Zeeb return (v); 21767ca7330SBjoern A. Zeeb } 21867ca7330SBjoern A. Zeeb } 21967ca7330SBjoern A. Zeeb 22067ca7330SBjoern A. Zeeb void 221b9db5e0aSEmmanuel Vadot sdio_f0_write_1(struct sdio_func *f, uint32_t addr, uint8_t val, int *err) 22267ca7330SBjoern A. Zeeb { 22367ca7330SBjoern A. Zeeb int error; 22467ca7330SBjoern A. Zeeb 22567ca7330SBjoern A. Zeeb error = SDIO_WRITE_DIRECT(device_get_parent(f->dev), 0, addr, val); 22667ca7330SBjoern A. Zeeb if (err != NULL) 22767ca7330SBjoern A. Zeeb *err = error; 22867ca7330SBjoern A. Zeeb } 22967ca7330SBjoern A. Zeeb 23067ca7330SBjoern A. Zeeb /* end */ 231