Author: bz
Date: Sat Jun  8 16:26:56 2019
New Revision: 348805
URL: https://svnweb.freebsd.org/changeset/base/348805

Log:
  Add SDIO support.
  
  Add a CAM-Newbus SDIO support module.  This works provides a newbus
  infrastructure for device drivers wanting to use SDIO.  On the lower end
  while it is connected by newbus to SDHCI, it talks CAM using the MMCCAM
  framework to get to it.
  
  This also duplicates the usbdevs framework to equally create sdiodev
  header files with #defines for "vendors" and "products".
  
  Submitted by: kibab (initial work, see https://reviews.freebsd.org/D12467)
  Reviewed by:  kibab, imp (comments on earlier version)
  MFC after:    6 weeks
  Relnotes:     yes
  Sponsored by: The FreeBSD Foundation
  Differential Revision:        https://reviews.freebsd.org/D19749

Added:
  head/sys/dev/sdio/
  head/sys/dev/sdio/sdio_if.m   (contents, props changed)
  head/sys/dev/sdio/sdio_subr.c   (contents, props changed)
  head/sys/dev/sdio/sdio_subr.h   (contents, props changed)
  head/sys/dev/sdio/sdiob.c   (contents, props changed)
  head/sys/dev/sdio/sdiob.h   (contents, props changed)
  head/sys/dev/sdio/sdiodevs   (contents, props changed)
  head/sys/modules/sdio/
  head/sys/modules/sdio/Makefile   (contents, props changed)
  head/sys/tools/sdiodevs2h.awk   (contents, props changed)
Modified:
  head/sys/conf/files
  head/sys/conf/kmod.mk
  head/sys/modules/Makefile

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files Sat Jun  8 16:15:00 2019        (r348804)
+++ head/sys/conf/files Sat Jun  8 16:26:56 2019        (r348805)
@@ -68,6 +68,16 @@ usbdevs_data.h                       optional usb            
                   \
        compile-with    "${AWK} -f $S/tools/usbdevs2h.awk $S/dev/usb/usbdevs 
-d" \
        no-obj no-implicit-rule before-depend                              \
        clean           "usbdevs_data.h"
+sdiodevs.h                     optional mmccam                            \
+       dependency      "$S/tools/sdiodevs2h.awk $S/dev/sdio/sdiodevs" \
+       compile-with    "${AWK} -f $S/tools/sdiodevs2h.awk $S/dev/sdio/sdiodevs 
-h" \
+       no-obj no-implicit-rule before-depend                              \
+       clean           "sdiodevs.h"
+sdiodevs_data.h                        optional mmccam                         
   \
+       dependency      "$S/tools/sdiodevs2h.awk $S/dev/sdio/sdiodevs" \
+       compile-with    "${AWK} -f $S/tools/sdiodevs2h.awk $S/dev/sdio/sdiodevs 
-d" \
+       no-obj no-implicit-rule before-depend                              \
+       clean           "sdiodevs_data.h"
 cam/cam.c                      optional scbus
 cam/cam_compat.c               optional scbus
 cam/cam_iosched.c              optional scbus
@@ -3009,6 +3019,9 @@ dev/sdhci/sdhci_fdt_gpio.c        optional sdhci fdt gpio
 dev/sdhci/sdhci_if.m           optional sdhci
 dev/sdhci/sdhci_acpi.c         optional sdhci acpi
 dev/sdhci/sdhci_pci.c          optional sdhci pci
++dev/sdio/sdio_if.m            optional mmccam
++dev/sdio/sdio_subr.c          optional mmccam
++dev/sdio/sdiob.c              optional mmccam
 dev/sge/if_sge.c               optional sge pci
 dev/siis/siis.c                        optional siis pci
 dev/sis/if_sis.c               optional sis pci

Modified: head/sys/conf/kmod.mk
==============================================================================
--- head/sys/conf/kmod.mk       Sat Jun  8 16:15:00 2019        (r348804)
+++ head/sys/conf/kmod.mk       Sat Jun  8 16:26:56 2019        (r348805)
@@ -475,6 +475,18 @@ usbdevs_data.h: ${SYSDIR}/tools/usbdevs2h.awk ${SYSDIR
        ${AWK} -f ${SYSDIR}/tools/usbdevs2h.awk ${SYSDIR}/dev/usb/usbdevs -d
 .endif
 
+.if !empty(SRCS:Msdiodevs.h)
+CLEANFILES+=   sdiodevs.h
+sdiodevs.h: ${SYSDIR}/tools/sdiodevs2h.awk ${SYSDIR}/dev/sdio/sdiodevs
+       ${AWK} -f ${SYSDIR}/tools/sdiodevs2h.awk ${SYSDIR}/dev/sdio/sdiodevs -h
+.endif
+
+.if !empty(SRCS:Msdiodevs_data.h)
+CLEANFILES+=   sdiodevs_data.h
+sdiodevs_data.h: ${SYSDIR}/tools/sdiodevs2h.awk ${SYSDIR}/dev/sdio/sdiodevs
+       ${AWK} -f ${SYSDIR}/tools/sdiodevs2h.awk ${SYSDIR}/dev/sdio/sdiodevs -d
+.endif
+
 .if !empty(SRCS:Macpi_quirks.h)
 CLEANFILES+=   acpi_quirks.h
 acpi_quirks.h: ${SYSDIR}/tools/acpi_quirks2h.awk 
${SYSDIR}/dev/acpica/acpi_quirks

Added: head/sys/dev/sdio/sdio_if.m
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/sdio/sdio_if.m Sat Jun  8 16:26:56 2019        (r348805)
@@ -0,0 +1,79 @@
+#-
+# Copyright (c) 2019 The FreeBSD Foundation
+#
+# Portions of this software were developed by Björn Zeeb
+# under sponsorship from the FreeBSD Foundation.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+#include <sys/bus.h>
+#include <machine/bus.h>
+
+INTERFACE sdio;
+
+#
+# READ DIRECT (1byte)
+#
+METHOD int read_direct {
+       device_t dev;
+       uint8_t fn;
+       uint32_t addr;
+       uint8_t *val;
+};
+
+#
+# WRITE DIRECT (1byte)
+#
+METHOD int write_direct {
+       device_t dev;
+       uint8_t fn;
+       uint32_t addr;
+       uint8_t val;
+};
+
+#
+# READ EXTENDED
+#
+METHOD int read_extended {
+       device_t dev;
+       uint8_t fn;
+       uint32_t addr;
+       uint32_t size;
+       uint8_t *buffer;
+       bool incaddr;
+};
+
+#
+# WRITE EXTENDED
+#
+METHOD int write_extended {
+       device_t dev;
+       uint8_t fn;
+       uint32_t addr;
+       uint32_t size;
+       uint8_t *buffer;
+       bool incaddr;
+};
+
+# end

Added: head/sys/dev/sdio/sdio_subr.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/sdio/sdio_subr.c       Sat Jun  8 16:26:56 2019        
(r348805)
@@ -0,0 +1,227 @@
+/*-
+ * Copyright (c) 2017 Ilya Bakulin.  All rights reserved.
+ * Copyright (c) 2018-2019 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * Portions of this software may have been developed with reference to
+ * the SD Simplified Specification.  The following disclaimer may apply:
+ *
+ * The following conditions apply to the release of the simplified
+ * specification ("Simplified Specification") by the SD Card Association and
+ * the SD Group. The Simplified Specification is a subset of the complete SD
+ * Specification which is owned by the SD Card Association and the SD
+ * Group. This Simplified Specification is provided on a non-confidential
+ * basis subject to the disclaimers below. Any implementation of the
+ * Simplified Specification may require a license from the SD Card
+ * Association, SD Group, SD-3C LLC or other third parties.
+ *
+ * Disclaimers:
+ *
+ * The information contained in the Simplified Specification is presented only
+ * as a standard specification for SD Cards and SD Host/Ancillary products and
+ * is provided "AS-IS" without any representations or warranties of any
+ * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
+ * Card Association for any damages, any infringements of patents or other
+ * right of the SD Group, SD-3C LLC, the SD Card Association or any third
+ * parties, which may result from its use. No license is granted by
+ * implication, estoppel or otherwise under any patent or other rights of the
+ * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
+ * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
+ * or the SD Card Association to disclose or distribute any technical
+ * information, know-how or other confidential information to any third party.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <dev/mmc/mmcreg.h>
+
+#include <dev/sdio/sdiob.h>
+#include <dev/sdio/sdio_subr.h>
+
+#include "sdio_if.h"
+
+/* Works on F0. */
+static int
+sdio_set_bool_for_func(device_t dev, uint32_t addr, uint8_t fn, bool enable)
+{
+       device_t pdev;
+       int error;
+       uint8_t val;
+       bool enabled;
+
+       pdev = device_get_parent(dev);
+       error = SDIO_READ_DIRECT(pdev, 0, addr, &val);
+       if (error != 0)
+               return (error);
+
+       enabled = (val & (1 << fn)) ? true : false;
+       if (enabled == enable)
+               return (0);
+
+       if (enable)
+               val |= (1 << fn);
+       else
+               val &= ~(1 << fn);
+       error = SDIO_WRITE_DIRECT(pdev, 0, addr, val);
+       return (error);
+}
+
+int
+sdio_enable_func(struct sdio_func *f)
+{
+
+       return (sdio_set_bool_for_func(f->dev, SD_IO_CCCR_FN_ENABLE,
+           f->fn, true));
+}
+
+int
+sdio_disable_func(struct sdio_func *f)
+{
+
+       return (sdio_set_bool_for_func(f->dev, SD_IO_CCCR_FN_ENABLE,
+           f->fn, false));
+}
+
+int
+sdio_set_block_size(struct sdio_func *f, uint16_t bs)
+{
+       device_t pdev;
+       int error;
+       uint32_t addr;
+       uint16_t v;
+
+       if (!sdio_get_support_multiblk(f->dev))
+               return (EOPNOTSUPP);
+
+       pdev = device_get_parent(f->dev);
+       addr = SD_IO_FBR_START * f->fn + SD_IO_FBR_IOBLKSZ;
+       v = htole16(bs);
+       /* Always write through F0. */
+       error = SDIO_WRITE_DIRECT(pdev, 0, addr, v & 0xff);
+       if (error == 0)
+               error = SDIO_WRITE_DIRECT(pdev, 0, addr + 1,
+                   (v >> 8) & 0xff);
+       if (error == 0)
+               f->cur_blksize = bs;
+
+       return (error);
+}
+
+uint8_t
+sdio_readb(struct sdio_func *f, uint32_t addr, int *err)
+{
+       int error;
+       uint8_t v;
+
+       error = SDIO_READ_DIRECT(device_get_parent(f->dev), f->fn, addr, &v);
+       if (error) {
+               if (err != NULL)
+                       *err = error;
+               return (0xff);
+       } else {
+               if (err != NULL)
+                       *err = 0;
+               return (v);
+       }
+}
+
+void
+sdio_writeb(struct sdio_func *f, uint8_t val, uint32_t addr, int *err)
+{
+       int error;
+
+       error = SDIO_WRITE_DIRECT(device_get_parent(f->dev), f->fn, addr, val);
+       if (err != NULL)
+               *err = error;
+}
+
+uint32_t
+sdio_readl(struct sdio_func *f, uint32_t addr, int *err)
+{
+       int error;
+       uint32_t v;
+
+       error = SDIO_READ_EXTENDED(device_get_parent(f->dev), f->fn, addr,
+           sizeof(v), (uint8_t *)&v, false);
+       if (error) {
+               if (err != NULL)
+                       *err = error;
+               return (0xffffffff);
+       } else {
+               if (err != NULL)
+                       *err = 0;
+               return (le32toh(v));
+       }
+}
+
+void
+sdio_writel(struct sdio_func *f, uint32_t val, uint32_t addr, int *err)
+{
+       int error;
+
+       error = SDIO_WRITE_EXTENDED(device_get_parent(f->dev), f->fn, addr,
+           sizeof(val), (uint8_t *)&val, false);
+       if (err != NULL)
+               *err = error;
+}
+
+uint8_t
+sdio_f0_readb(struct sdio_func *f, uint32_t addr, int *err)
+{
+       int error;
+       uint8_t v;
+
+       error = SDIO_READ_DIRECT(device_get_parent(f->dev), 0, addr, &v);
+       if (error) {
+               if (err != NULL)
+                       *err = error;
+               return (0xff);
+       } else {
+               if (err != NULL)
+                       *err = 0;
+               return (v);
+       }
+}
+
+void
+sdio_f0_writeb(struct sdio_func *f, uint8_t val, uint32_t addr, int *err)
+{
+       int error;
+
+       error = SDIO_WRITE_DIRECT(device_get_parent(f->dev), 0, addr, val);
+       if (err != NULL)
+               *err = error;
+}
+
+/* end */

Added: head/sys/dev/sdio/sdio_subr.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/sdio/sdio_subr.h       Sat Jun  8 16:26:56 2019        
(r348805)
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 2017 Ilya Bakulin.  All rights reserved.
+ * Copyright (c) 2018-2019 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * Portions of this software may have been developed with reference to
+ * the SD Simplified Specification.  The following disclaimer may apply:
+ *
+ * The following conditions apply to the release of the simplified
+ * specification ("Simplified Specification") by the SD Card Association and
+ * the SD Group. The Simplified Specification is a subset of the complete SD
+ * Specification which is owned by the SD Card Association and the SD
+ * Group. This Simplified Specification is provided on a non-confidential
+ * basis subject to the disclaimers below. Any implementation of the
+ * Simplified Specification may require a license from the SD Card
+ * Association, SD Group, SD-3C LLC or other third parties.
+ *
+ * Disclaimers:
+ *
+ * The information contained in the Simplified Specification is presented only
+ * as a standard specification for SD Cards and SD Host/Ancillary products and
+ * is provided "AS-IS" without any representations or warranties of any
+ * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
+ * Card Association for any damages, any infringements of patents or other
+ * right of the SD Group, SD-3C LLC, the SD Card Association or any third
+ * parties, which may result from its use. No license is granted by
+ * implication, estoppel or otherwise under any patent or other rights of the
+ * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
+ * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
+ * or the SD Card Association to disclose or distribute any technical
+ * information, know-how or other confidential information to any third party.
+ *
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SDIO_SUBR_H_
+#define _SDIO_SUBR_H_
+
+/*
+ * This file contains structures and functions to work with SDIO cards.
+ */
+
+struct sdio_func {
+       device_t        dev;            /* The device to talk to CAM. */
+       uintptr_t       drvdata;        /* Driver specific data. */
+
+       uint8_t         fn;             /* Function number. */
+
+       uint8_t         class;          /* Class of function. */
+       uint16_t        vendor;         /* Manufacturer ID. */
+       uint16_t        device;         /* Card ID. */
+
+       uint16_t        max_blksize;    /* Maximum block size of function. */
+       uint16_t        cur_blksize;    /* Current block size of function. */
+
+       uint16_t        retries;        /* Retires for CAM operations. */
+       uint32_t        timeout;        /* Timeout. */
+};
+
+struct card_info {
+       struct sdio_func f[8];
+
+       /* Compared to R4 Number of I/O Functions we DO count F0 here. */
+       uint8_t         num_funcs;
+
+       bool            support_multiblk; /* Support Multiple Block Transfer */
+};
+
+#ifdef _KERNEL
+int sdio_enable_func(struct sdio_func *);
+int sdio_disable_func(struct sdio_func *);
+int sdio_set_block_size(struct sdio_func *, uint16_t);
+
+uint8_t sdio_readb(struct sdio_func *, uint32_t, int *);
+void sdio_writeb(struct sdio_func *, uint8_t, uint32_t, int *);
+uint32_t sdio_readl(struct sdio_func *, uint32_t, int *);
+void sdio_writel(struct sdio_func *, uint32_t, uint32_t, int *);
+
+uint8_t sdio_f0_readb(struct sdio_func *, uint32_t, int *);
+void sdio_f0_writeb(struct sdio_func *, uint8_t, uint32_t, int *);
+#endif /* _KERNEL */
+
+#endif /* _SDIO_SUBR_H_ */

Added: head/sys/dev/sdio/sdiob.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/sdio/sdiob.c   Sat Jun  8 16:26:56 2019        (r348805)
@@ -0,0 +1,1188 @@
+/*-
+ * Copyright (c) 2017 Ilya Bakulin.  All rights reserved.
+ * Copyright (c) 2018-2019 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * Portions of this software may have been developed with reference to
+ * the SD Simplified Specification.  The following disclaimer may apply:
+ *
+ * The following conditions apply to the release of the simplified
+ * specification ("Simplified Specification") by the SD Card Association and
+ * the SD Group. The Simplified Specification is a subset of the complete SD
+ * Specification which is owned by the SD Card Association and the SD
+ * Group. This Simplified Specification is provided on a non-confidential
+ * basis subject to the disclaimers below. Any implementation of the
+ * Simplified Specification may require a license from the SD Card
+ * Association, SD Group, SD-3C LLC or other third parties.
+ *
+ * Disclaimers:
+ *
+ * The information contained in the Simplified Specification is presented only
+ * as a standard specification for SD Cards and SD Host/Ancillary products and
+ * is provided "AS-IS" without any representations or warranties of any
+ * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
+ * Card Association for any damages, any infringements of patents or other
+ * right of the SD Group, SD-3C LLC, the SD Card Association or any third
+ * parties, which may result from its use. No license is granted by
+ * implication, estoppel or otherwise under any patent or other rights of the
+ * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
+ * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
+ * or the SD Card Association to disclose or distribute any technical
+ * information, know-how or other confidential information to any third party.
+ */
+/*
+ * Implements the (kernel specific) SDIO parts.
+ * This will hide all cam(4) functionality from the SDIO driver implementations
+ * which will just be newbus/device(9) and hence look like any other driver 
for,
+ * e.g., PCI.
+ * The sdiob(4) parts effetively "translate" between the two worlds "bridging"
+ * messages from MMCCAM to newbus and back.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_cam.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_queue.h>
+#include <cam/cam_periph.h>
+#include <cam/cam_xpt.h>
+#include <cam/cam_xpt_periph.h>
+#include <cam/cam_xpt_internal.h> /* for cam_path */
+#include <cam/cam_debug.h>
+
+#include <dev/mmc/mmcreg.h>
+
+#include <dev/sdio/sdiob.h>
+#include <dev/sdio/sdio_subr.h>
+
+#include "sdio_if.h"
+
+#ifdef DEBUG
+#define        DPRINTF(...)            printf(__VA_ARGS__)
+#define        DPRINTFDEV(_dev, ...)   device_printf((_dev), __VA_ARGS__)
+#else
+#define        DPRINTF(...)
+#define        DPRINTFDEV(_dev, ...)
+#endif
+
+struct sdiob_softc {
+       uint32_t                        sdio_state;
+#define        SDIO_STATE_DEAD                 0x0001
+#define        SDIO_STATE_INITIALIZING         0x0002
+#define        SDIO_STATE_READY                0x0004
+       uint32_t                        nb_state;
+#define        NB_STATE_DEAD                   0x0001
+#define        NB_STATE_SIM_ADDED              0x0002
+#define        NB_STATE_READY                  0x0004
+
+       /* CAM side (including sim_dev). */
+       struct card_info                cardinfo;
+       struct cam_periph               *periph;
+       union ccb                       *ccb;
+       struct task                     discover_task;
+
+       /* Newbus side. */
+       device_t                        dev;    /* Ourselves. */
+       device_t                        child[8];
+};
+
+/* -------------------------------------------------------------------------- 
*/
+/*
+ * SDIO CMD52 and CM53 implementations along with wrapper functions for
+ * read/write and a CAM periph helper function.
+ * These are the backend implementations of the sdio_if.m framework talking
+ * through CAM to sdhci.
+ * Note: these functions are also called during early discovery stage when
+ * we are not a device(9) yet. Hence they cannot always use device_printf()
+ * to log errors and have to call CAM_DEBUG() during these early stages.
+ */
+
+static int
+sdioerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
+{
+
+       return (cam_periph_error(ccb, cam_flags, sense_flags));
+}
+
+/* CMD52: direct byte access. */
+static int
+sdiob_rw_direct_sc(struct sdiob_softc *sc, uint8_t fn, uint32_t addr, bool wr,
+    uint8_t *val)
+{
+       uint32_t arg, flags;
+       int error;
+
+       KASSERT((val != NULL), ("%s val passed as NULL\n", __func__));
+
+       if (sc->ccb == NULL)
+               sc->ccb = xpt_alloc_ccb();
+       else
+               memset(sc->ccb, 0, sizeof(*sc->ccb));
+       xpt_setup_ccb(&sc->ccb->ccb_h, sc->periph->path, CAM_PRIORITY_NONE);
+       CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_TRACE,
+           ("%s(fn=%d, addr=%#02x, wr=%d, *val=%#02x)\n", __func__,
+           fn, addr, wr, *val));
+
+       flags = MMC_RSP_R5 | MMC_CMD_AC;
+       arg = SD_IO_RW_FUNC(fn) | SD_IO_RW_ADR(addr);
+       if (wr)
+               arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*val);
+
+       cam_fill_mmcio(&sc->ccb->mmcio,
+               /*retries*/ 0,
+               /*cbfcnp*/ NULL,
+               /*flags*/ CAM_DIR_NONE,
+               /*mmc_opcode*/ SD_IO_RW_DIRECT,
+               /*mmc_arg*/ arg,
+               /*mmc_flags*/ flags,
+               /*mmc_data*/ 0,
+               /*timeout*/ sc->cardinfo.f[fn].timeout);
+       error = cam_periph_runccb(sc->ccb, sdioerror, CAM_FLAG_NONE, 0, NULL);
+       if (error != 0) {
+               if (sc->dev != NULL)
+                       device_printf(sc->dev,
+                           "%s: Failed to %s address %#10x error=%d\n",
+                           __func__, (wr) ? "write" : "read", addr, error);
+               else
+                       CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_INFO,
+                           ("%s: Failed to %s address: %#10x error=%d\n",
+                           __func__, (wr) ? "write" : "read", addr, error));
+               return (error);
+       }
+
+       /* TODO: Add handling of MMC errors */
+       /* ccb->mmcio.cmd.error ? */
+       if (wr == false)
+               *val = sc->ccb->mmcio.cmd.resp[0] & 0xff;
+
+       return (0);
+}
+
+static int
+sdio_rw_direct(device_t dev, uint8_t fn, uint32_t addr, bool wr,
+    uint8_t *val)
+{
+       struct sdiob_softc *sc;
+       int error;
+
+       sc = device_get_softc(dev);
+       cam_periph_lock(sc->periph);
+       error = sdiob_rw_direct_sc(sc, fn, addr, wr, val);
+       cam_periph_unlock(sc->periph);
+       return (error);
+}
+
+static int
+sdiob_read_direct(device_t dev, uint8_t fn, uint32_t addr, uint8_t *val)
+{
+       int error;
+       uint8_t v;
+
+       error = sdio_rw_direct(dev, fn, addr, false, &v);
+       /* Be polite and do not touch the value on read error. */
+       if (error == 0 && val != NULL)
+               *val = v;
+       return (error);
+}
+
+static int
+sdiob_write_direct(device_t dev, uint8_t fn, uint32_t addr, uint8_t val)
+{
+
+       return (sdio_rw_direct(dev, fn, addr, true, &val));
+}
+
+/*
+ * CMD53: IO_RW_EXTENDED, read and write multiple I/O registers.
+ * Increment false gets FIFO mode (single register address).
+ */
+/*
+ * A b_count of 0 means byte mode, b_count > 0 gets block mode.
+ * A b_count of >= 512 would mean infinitive block transfer, which would become
+ * b_count = 0, is not yet supported.
+ * For b_count == 0, blksz is the len of bytes, otherwise it is the amount of
+ * full sized blocks (you must not round the blocks up and leave the last one
+ * partial!)
+ * For byte mode, the maximum of blksz is the functions cur_blksize.
+ * This function should ever only be called by sdio_rw_extended_sc()! 
+ */
+static int
+sdiob_rw_extended_cam(struct sdiob_softc *sc, uint8_t fn, uint32_t addr,
+    bool wr, uint8_t *buffer, bool incaddr, uint32_t b_count, uint16_t blksz)
+{
+       struct mmc_data mmcd;
+       uint32_t arg, cam_flags, flags, len;
+       int error;
+
+       if (sc->ccb == NULL)
+               sc->ccb = xpt_alloc_ccb();
+       else
+               memset(sc->ccb, 0, sizeof(*sc->ccb));
+       xpt_setup_ccb(&sc->ccb->ccb_h, sc->periph->path, CAM_PRIORITY_NONE);
+       CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_TRACE,
+           ("%s(fn=%d addr=%#0x wr=%d b_count=%u blksz=%u buf=%p incr=%d)\n",
+           __func__, fn, addr, wr, b_count, blksz, buffer, incaddr));
+
+       KASSERT((b_count <= 511), ("%s: infinitive block transfer not yet "
+           "supported: b_count %u blksz %u, sc %p, fn %u, addr %#10x, %s, "
+           "buffer %p, %s\n", __func__, b_count, blksz, sc, fn, addr,
+           wr ? "wr" : "rd", buffer, incaddr ? "incaddr" : "fifo"));
+       /* Blksz needs to be within bounds for both byte and block mode! */
+       KASSERT((blksz <= sc->cardinfo.f[fn].cur_blksize), ("%s: blksz "
+           "%u > bur_blksize %u, sc %p, fn %u, addr %#10x, %s, "
+           "buffer %p, %s, b_count %u\n", __func__, blksz,
+           sc->cardinfo.f[fn].cur_blksize, sc, fn, addr,
+           wr ? "wr" : "rd", buffer, incaddr ? "incaddr" : "fifo",
+           b_count));
+       if (b_count == 0) {
+               /* Byte mode */
+               len = blksz;
+               if (blksz == 512)
+                       blksz = 0;
+               arg = SD_IOE_RW_LEN(blksz);
+       } else {
+               /* Block mode. */
+#ifdef __notyet__
+               if (b_count > 511) {
+                       /* Infinitive block transfer. */
+                       b_count = 0;
+               }
+#endif
+               len = b_count * blksz;
+               arg = SD_IOE_RW_BLK | SD_IOE_RW_LEN(b_count);
+       }
+
+       flags = MMC_RSP_R5 | MMC_CMD_ADTC;
+       arg |= SD_IOE_RW_FUNC(fn) | SD_IOE_RW_ADR(addr);
+       if (incaddr)
+               arg |= SD_IOE_RW_INCR;
+
+       memset(&mmcd, 0, sizeof(mmcd));
+       mmcd.data = buffer;
+       mmcd.len = len;
+       if (arg & SD_IOE_RW_BLK) {
+               /* XXX both should be known from elsewhere, aren't they? */
+               mmcd.block_size = blksz;
+               mmcd.block_count = b_count;
+       }
+
+       if (wr) {
+               arg |= SD_IOE_RW_WR;
+               cam_flags = CAM_DIR_OUT;
+               mmcd.flags = MMC_DATA_WRITE;
+       } else {
+               cam_flags = CAM_DIR_IN;
+               mmcd.flags = MMC_DATA_READ;
+       }
+#ifdef __notyet__
+       if (b_count == 0) {
+               /* XXX-BZ TODO FIXME.  Cancel I/O: CCCR -> ASx */
+               /* Stop cmd. */
+       }
+#endif
+       cam_fill_mmcio(&sc->ccb->mmcio,
+               /*retries*/ 0,
+               /*cbfcnp*/ NULL,
+               /*flags*/ cam_flags,
+               /*mmc_opcode*/ SD_IO_RW_EXTENDED,
+               /*mmc_arg*/ arg,
+               /*mmc_flags*/ flags,
+               /*mmc_data*/ &mmcd,
+               /*timeout*/ sc->cardinfo.f[fn].timeout);
+       if (arg & SD_IOE_RW_BLK) {
+               mmcd.flags |= MMC_DATA_BLOCK_SIZE;
+               if (b_count != 1)
+                       sc->ccb->mmcio.cmd.data->flags |= MMC_DATA_MULTI;
+       }
+
+       /* Execute. */
+       error = cam_periph_runccb(sc->ccb, sdioerror, CAM_FLAG_NONE, 0, NULL);
+       if (error != 0) {
+               if (sc->dev != NULL)
+                       device_printf(sc->dev,
+                           "%s: Failed to %s address %#10x buffer %p size %u "
+                           "%s b_count %u blksz %u error=%d\n",
+                           __func__, (wr) ? "write to" : "read from", addr,
+                           buffer, len, (incaddr) ? "incr" : "fifo",
+                           b_count, blksz, error);
+               else
+                       CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_INFO,
+                           ("%s: Failed to %s address %#10x buffer %p size %u "
+                           "%s b_count %u blksz %u error=%d\n",
+                           __func__, (wr) ? "write to" : "read from", addr,
+                           buffer, len, (incaddr) ? "incr" : "fifo",
+                           b_count, blksz, error));
+               return (error);
+       }
+
+       /* TODO: Add handling of MMC errors */
+       /* ccb->mmcio.cmd.error ? */
+       error = sc->ccb->mmcio.cmd.resp[0] & 0xff;
+       if (error != 0) {
+               if (sc->dev != NULL)
+                       device_printf(sc->dev,
+                           "%s: Failed to %s address %#10x buffer %p size %u "
+                           "%s b_count %u blksz %u mmcio resp error=%d\n",
+                           __func__, (wr) ? "write to" : "read from", addr,
+                           buffer, len, (incaddr) ? "incr" : "fifo",
+                           b_count, blksz, error);
+               else
+                       CAM_DEBUG(sc->ccb->ccb_h.path, CAM_DEBUG_INFO,
+                           ("%s: Failed to %s address %#10x buffer %p size %u "
+                           "%s b_count %u blksz %u mmcio resp error=%d\n",
+                           __func__, (wr) ? "write to" : "read from", addr,
+                           buffer, len, (incaddr) ? "incr" : "fifo",
+                           b_count, blksz, error));
+       }
+       return (error);
+}
+
+static int
+sdiob_rw_extended_sc(struct sdiob_softc *sc, uint8_t fn, uint32_t addr,
+    bool wr, uint32_t size, uint8_t *buffer, bool incaddr)
+{
+       int error;
+       uint32_t len;
+       uint32_t b_count;
+
+       /*
+        * If block mode is supported and we have at least 4 bytes to write and
+        * the size is at least one block, then start doing blk transfers.
+        */
+       while (sc->cardinfo.support_multiblk &&
+           size > 4 && size >= sc->cardinfo.f[fn].cur_blksize) {
+
+               b_count = size / sc->cardinfo.f[fn].cur_blksize;
+               KASSERT(b_count >= 1, ("%s: block count too small %u size %u "
+                   "cur_blksize %u\n", __func__, b_count, size,
+                   sc->cardinfo.f[fn].cur_blksize));
+
+#ifdef __notyet__
+               /* XXX support inifinite transfer with b_count = 0. */
+#else
+               if (b_count > 511)
+                       b_count = 511;
+#endif
+               len = b_count * sc->cardinfo.f[fn].cur_blksize;
+               error = sdiob_rw_extended_cam(sc, fn, addr, wr, buffer, incaddr,
+                   b_count, sc->cardinfo.f[fn].cur_blksize);
+               if (error != 0)
+                       return (error);
+
+               size -= len;
+               buffer += len;
+               if (incaddr)
+                       addr += len;
+       }
+
+       while (size > 0) {
+               len = MIN(size, sc->cardinfo.f[fn].cur_blksize);
+
+               error = sdiob_rw_extended_cam(sc, fn, addr, wr, buffer, incaddr,
+                   0, len);
+               if (error != 0)
+                       return (error);
+
+               /* Prepare for next iteration. */
+               size -= len;
+               buffer += len;
+               if (incaddr)
+                       addr += len;
+       }
+
+       return (0);
+}
+
+static int
+sdiob_rw_extended(device_t dev, uint8_t fn, uint32_t addr, bool wr,
+    uint32_t size, uint8_t *buffer, bool incaddr)
+{
+       struct sdiob_softc *sc;
+       int error;
+
+       sc = device_get_softc(dev);
+       cam_periph_lock(sc->periph);
+       error = sdiob_rw_extended_sc(sc, fn, addr, wr, size, buffer, incaddr);
+       cam_periph_unlock(sc->periph);
+       return (error);
+}
+
+static int
+sdiob_read_extended(device_t dev, uint8_t fn, uint32_t addr, uint32_t size,
+    uint8_t *buffer, bool incaddr)
+{
+
+       return (sdiob_rw_extended(dev, fn, addr, false, size, buffer, incaddr));
+}
+
+static int
+sdiob_write_extended(device_t dev, uint8_t fn, uint32_t addr, uint32_t size,
+    uint8_t *buffer, bool incaddr)
+{
+
+       return (sdiob_rw_extended(dev, fn, addr, true, size, buffer, incaddr));
+}
+
+/* -------------------------------------------------------------------------- 
*/
+/* Bus interface, ivars handling. */
+
+static int
+sdiob_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+       struct sdiob_softc *sc;
+       struct sdio_func *f;
+
+       f = device_get_ivars(child);
+       KASSERT(f != NULL, ("%s: dev %p child %p which %d, child ivars NULL\n",
+           __func__, dev, child, which));
+
+       switch (which) {
+       case SDIOB_IVAR_SUPPORT_MULTIBLK:
+               sc = device_get_softc(dev);
+               KASSERT(sc != NULL, ("%s: dev %p child %p which %d, sc NULL\n",
+                   __func__, dev, child, which));
+               *result = sc->cardinfo.support_multiblk;
+               break;
+       case SDIOB_IVAR_FUNCTION:
+               *result = (uintptr_t)f;
+               break;
+       case SDIOB_IVAR_FUNCNUM:
+               *result = f->fn;
+               break;
+       case SDIOB_IVAR_CLASS:
+               *result = f->class;
+               break;
+       case SDIOB_IVAR_VENDOR:
+               *result = f->vendor;
+               break;
+       case SDIOB_IVAR_DEVICE:
+               *result = f->device;
+               break;
+       case SDIOB_IVAR_DRVDATA:
+               *result = f->drvdata;
+               break;
+       default:
+               return (ENOENT);
+       }
+       return (0);
+}
+
+static int
+sdiob_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+       struct sdio_func *f;
+
+       f = device_get_ivars(child);
+       KASSERT(f != NULL, ("%s: dev %p child %p which %d, child ivars NULL\n",
+           __func__, dev, child, which));
+
+       switch (which) {
+       case SDIOB_IVAR_SUPPORT_MULTIBLK:
+       case SDIOB_IVAR_FUNCTION:
+       case SDIOB_IVAR_FUNCNUM:
+       case SDIOB_IVAR_CLASS:
+       case SDIOB_IVAR_VENDOR:
+       case SDIOB_IVAR_DEVICE:
+               return (EINVAL);        /* Disallowed. */
+       case SDIOB_IVAR_DRVDATA:
+               f->drvdata = value;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to