Date: Wed, 2 Sep 2020 12:15:48 +0200 From: Marcin Wojtas <mw@semihalf.com> To: Mateusz Guzik <mjguzik@gmail.com> Cc: Marcin Wojtas <mw@freebsd.org>, src-committers <src-committers@freebsd.org>, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: Re: svn commit: r365054 - in head/sys: conf dev/sdhci Message-ID: <CAPv3WKdQ0jUNx9igtHH4OcdYoogpd_ZfGRa0a7ru8X8wiWNgzg@mail.gmail.com> In-Reply-To: <CAGudoHHgKQ0EZ6AOTMG4MRHUTWM9VaVoUku_uA1V%2BCDX%2BLzNBw@mail.gmail.com> References: <202009011617.081GHL8e031671@repo.freebsd.org> <CAGudoHHgKQ0EZ6AOTMG4MRHUTWM9VaVoUku_uA1V%2BCDX%2BLzNBw@mail.gmail.com>
next in thread | previous in thread | raw e-mail | index | archive | help
wt., 1 wrz 2020 o 22:37 Mateusz Guzik <mjguzik@gmail.com> napisa=C5=82(a): > This commit breaks numerous kernels, e.g. _.arm.RPI-B: > > In file included from /usr/src/sys/dev/sdhci/sdhci_fsl_fdt.c:45: > /usr/src/sys/dev/extres/clk/clk.h:37:10: fatal error: 'clknode_if.h' > file not found > #include "clknode_if.h" > > Unfortunately yes, fixing it. > On 9/1/20, Marcin Wojtas <mw@freebsd.org> wrote: > > Author: mw > > Date: Tue Sep 1 16:17:21 2020 > > New Revision: 365054 > > URL: https://svnweb.freebsd.org/changeset/base/365054 > > > > Log: > > Introduce the SDHCI driver for NXP QorIQ Layerscape SoCs > > > > Implement support for an eSDHC controller found in NXP QorIQ Layersca= pe > > SoCs. > > > > This driver has been tested with NXP LS1046A and LX2160A (Honeycomb > > board), > > which is incompatible with the existing sdhci_fsl driver (aiming at > older > > chips from this family). As such, it is not intended as replacement f= or > > the old driver, but rather serves as an improved alternative for SoCs > > that > > support it. > > It comes with support for both PIO and Single DMA modes and samples t= he > > clock from the extres clk API. > > > > Submitted by: Artur Rojek <ar@semihalf.com> > > Reviewed by: manu, mmel, kibab > > Obtained from: Semihalf > > Sponsored by: Alstom Group > > Differential Revision: https://reviews.freebsd.org/D26153 > > > > Added: > > head/sys/dev/sdhci/sdhci_fsl_fdt.c (contents, props changed) > > Modified: > > head/sys/conf/files > > > > Modified: head/sys/conf/files > > > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > > --- head/sys/conf/files Tue Sep 1 16:13:09 2020 (r365053) > > +++ head/sys/conf/files Tue Sep 1 16:17:21 2020 (r365054) > > @@ -3058,6 +3058,7 @@ dev/scc/scc_dev_z8530.c optional scc > > dev/sdhci/sdhci.c optional sdhci > > dev/sdhci/sdhci_fdt.c optional sdhci fdt > > dev/sdhci/sdhci_fdt_gpio.c optional sdhci fdt gpio > > +dev/sdhci/sdhci_fsl_fdt.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 > > > > Added: head/sys/dev/sdhci/sdhci_fsl_fdt.c > > > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > > --- /dev/null 00:00:00 1970 (empty, because file is newly added) > > +++ head/sys/dev/sdhci/sdhci_fsl_fdt.c Tue Sep 1 16:17:21 2020 > (r365054) > > @@ -0,0 +1,680 @@ > > +/*- > > + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD > > + * > > + * Copyright (c) 2020 Alstom Group. > > + * Copyright (c) 2020 Semihalf. > > + * > > + * 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 copyrigh= t > > + * 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 AND CONTRIBUTORS ``AS IS'' > AND > > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, T= HE > > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR > > PURPOSE > > + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 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 INTERRUPTIO= N) > > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, > > STRICT > > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN A= NY > > WAY > > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY > OF > > + * SUCH DAMAGE. > > + */ > > + > > +/* eSDHC controller driver for NXP QorIQ Layerscape SoCs. */ > > + > > +#include <sys/cdefs.h> > > +__FBSDID("$FreeBSD$"); > > + > > +#include <sys/param.h> > > +#include <sys/endian.h> > > +#include <sys/kernel.h> > > +#include <sys/module.h> > > +#include <sys/rman.h> > > +#include <sys/sysctl.h> > > +#include <sys/taskqueue.h> > > + > > +#include <machine/bus.h> > > +#include <machine/resource.h> > > + > > +#include <dev/extres/clk/clk.h> > > +#include <dev/mmc/bridge.h> > > +#include <dev/mmc/mmcbrvar.h> > > +#include <dev/ofw/ofw_bus.h> > > +#include <dev/ofw/ofw_bus_subr.h> > > +#include <dev/sdhci/sdhci.h> > > +#include <dev/sdhci/sdhci_fdt_gpio.h> > > + > > +#include "mmcbr_if.h" > > +#include "sdhci_if.h" > > + > > +#define RD4 (sc->read) > > +#define WR4 (sc->write) > > + > > +#define SDHCI_FSL_PRES_STATE 0x24 > > +#define SDHCI_FSL_PRES_SDSTB (1 << 3) > > +#define SDHCI_FSL_PRES_COMPAT_MASK 0x000f0f07 > > + > > +#define SDHCI_FSL_PROT_CTRL 0x28 > > +#define SDHCI_FSL_PROT_CTRL_WIDTH_1BIT (0 << 1) > > +#define SDHCI_FSL_PROT_CTRL_WIDTH_4BIT (1 << 1) > > +#define SDHCI_FSL_PROT_CTRL_WIDTH_8BIT (2 << 1) > > +#define SDHCI_FSL_PROT_CTRL_WIDTH_MASK (3 << 1) > > +#define SDHCI_FSL_PROT_CTRL_BYTE_SWAP (0 << 4) > > +#define SDHCI_FSL_PROT_CTRL_BYTE_NATIVE (2 << 4) > > +#define SDHCI_FSL_PROT_CTRL_BYTE_MASK (3 << 4) > > +#define SDHCI_FSL_PROT_CTRL_DMA_MASK (3 << 8) > > + > > +#define SDHCI_FSL_SYS_CTRL 0x2c > > +#define SDHCI_FSL_CLK_IPGEN (1 << 0) > > +#define SDHCI_FSL_CLK_SDCLKEN (1 << 3) > > +#define SDHCI_FSL_CLK_DIVIDER_MASK 0x000000f0 > > +#define SDHCI_FSL_CLK_DIVIDER_SHIFT 4 > > +#define SDHCI_FSL_CLK_PRESCALE_MASK 0x0000ff00 > > +#define SDHCI_FSL_CLK_PRESCALE_SHIFT 8 > > + > > +#define SDHCI_FSL_WTMK_LVL 0x44 > > +#define SDHCI_FSL_WTMK_RD_512B (0 << 0) > > +#define SDHCI_FSL_WTMK_WR_512B (0 << 15) > > + > > +#define SDHCI_FSL_HOST_VERSION 0xfc > > +#define SDHCI_FSL_CAPABILITIES2 0x114 > > + > > +#define SDHCI_FSL_ESDHC_CTRL 0x40c > > +#define SDHCI_FSL_ESDHC_CTRL_SNOOP (1 << 6) > > +#define SDHCI_FSL_ESDHC_CTRL_CLK_DIV2 (1 << 19) > > + > > +struct sdhci_fsl_fdt_softc { > > + device_t dev; > > + const struct sdhci_fsl_fdt_soc_data *soc_data; > > + struct resource *mem_res; > > + struct resource *irq_res; > > + void *irq_cookie; > > + uint32_t baseclk_hz; > > + struct sdhci_fdt_gpio *gpio; > > + struct sdhci_slot slot; > > + bool slot_init_done; > > + uint32_t cmd_and_mode; > > + uint16_t sdclk_bits; > > + > > + uint32_t (* read)(struct sdhci_fsl_fdt_softc *, bus_size_t); > > + void (* write)(struct sdhci_fsl_fdt_softc *, bus_size_t, uint32_t= ); > > +}; > > + > > +struct sdhci_fsl_fdt_soc_data { > > + int quirks; > > +}; > > + > > +static const struct sdhci_fsl_fdt_soc_data > sdhci_fsl_fdt_ls1046a_soc_data =3D > > { > > + .quirks =3D SDHCI_QUIRK_DONT_SET_HISPD_BIT | > SDHCI_QUIRK_BROKEN_AUTO_STOP > > +}; > > + > > +static const struct sdhci_fsl_fdt_soc_data sdhci_fsl_fdt_gen_data =3D = { > > + .quirks =3D 0, > > +}; > > + > > +static const struct ofw_compat_data sdhci_fsl_fdt_compat_data[] =3D { > > + {"fsl,ls1046a-esdhc", > (uintptr_t)&sdhci_fsl_fdt_ls1046a_soc_data}, > > + {"fsl,esdhc", (uintptr_t)&sdhci_fsl_fdt_gen_data}, > > + {NULL, 0} > > +}; > > + > > +static uint32_t > > +read_be(struct sdhci_fsl_fdt_softc *sc, bus_size_t off) > > +{ > > + > > + return (be32toh(bus_read_4(sc->mem_res, off))); > > +} > > + > > +static void > > +write_be(struct sdhci_fsl_fdt_softc *sc, bus_size_t off, uint32_t val) > > +{ > > + > > + bus_write_4(sc->mem_res, off, htobe32(val)); > > +} > > + > > +static uint32_t > > +read_le(struct sdhci_fsl_fdt_softc *sc, bus_size_t off) > > +{ > > + > > + return (bus_read_4(sc->mem_res, off)); > > +} > > + > > +static void > > +write_le(struct sdhci_fsl_fdt_softc *sc, bus_size_t off, uint32_t val) > > +{ > > + > > + bus_write_4(sc->mem_res, off, val); > > +} > > + > > + > > +static uint16_t > > +sdhci_fsl_fdt_get_clock(struct sdhci_fsl_fdt_softc *sc) > > +{ > > + uint16_t val; > > + > > + val =3D sc->sdclk_bits | SDHCI_CLOCK_INT_EN; > > + if (RD4(sc, SDHCI_FSL_PRES_STATE) & SDHCI_FSL_PRES_SDSTB) > > + val |=3D SDHCI_CLOCK_INT_STABLE; > > + if (RD4(sc, SDHCI_FSL_SYS_CTRL) & SDHCI_FSL_CLK_SDCLKEN) > > + val |=3D SDHCI_CLOCK_CARD_EN; > > + > > + return (val); > > +} > > + > > +static void > > +fsl_sdhc_fdt_set_clock(struct sdhci_fsl_fdt_softc *sc, uint16_t val) > > +{ > > + uint32_t div, freq, prescale, val32; > > + > > + sc->sdclk_bits =3D val & SDHCI_DIVIDERS_MASK; > > + val32 =3D RD4(sc, SDHCI_CLOCK_CONTROL); > > + > > + if ((val & SDHCI_CLOCK_CARD_EN) =3D=3D 0) { > > + WR4(sc, SDHCI_CLOCK_CONTROL, val32 & > ~SDHCI_FSL_CLK_SDCLKEN); > > + return; > > + } > > + > > + div =3D ((val >> SDHCI_DIVIDER_SHIFT) & SDHCI_DIVIDER_MASK) | > > + ((val >> SDHCI_DIVIDER_HI_SHIFT) & SDHCI_DIVIDER_HI_MASK) << > > + SDHCI_DIVIDER_MASK_LEN; > > + if (div =3D=3D 0) > > + freq =3D sc->baseclk_hz; > > + else > > + freq =3D sc->baseclk_hz / (2 * div); > > + > > + for (prescale =3D 2; freq < sc->baseclk_hz / (prescale * 16); ) > > + prescale <<=3D 1; > > + for (div =3D 1; freq < sc->baseclk_hz / (prescale * div); ) > > + ++div; > > + > > +#ifdef DEBUG > > + device_printf(sc->dev, > > + "Desired SD/MMC freq: %d, actual: %d; base %d prescale %d > divisor > > %d\n", > > + freq, sc->baseclk_hz / (prescale * div), > > + sc->baseclk_hz, prescale, div); > > +#endif > > + > > + prescale >>=3D 1; > > + div -=3D 1; > > + > > + val32 &=3D ~(SDHCI_FSL_CLK_DIVIDER_MASK | > SDHCI_FSL_CLK_PRESCALE_MASK); > > + val32 |=3D div << SDHCI_FSL_CLK_DIVIDER_SHIFT; > > + val32 |=3D prescale << SDHCI_FSL_CLK_PRESCALE_SHIFT; > > + val32 |=3D SDHCI_FSL_CLK_IPGEN | SDHCI_FSL_CLK_SDCLKEN; > > + WR4(sc, SDHCI_CLOCK_CONTROL, val32); > > +} > > + > > +static uint8_t > > +sdhci_fsl_fdt_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t > > off) > > +{ > > + struct sdhci_fsl_fdt_softc *sc; > > + uint32_t wrk32, val32; > > + > > + sc =3D device_get_softc(dev); > > + > > + switch (off) { > > + case SDHCI_HOST_CONTROL: > > + wrk32 =3D RD4(sc, SDHCI_FSL_PROT_CTRL); > > + val32 =3D wrk32 & (SDHCI_CTRL_LED | SDHCI_CTRL_CARD_DET | > > + SDHCI_CTRL_FORCE_CARD); > > + if (wrk32 & SDHCI_FSL_PROT_CTRL_WIDTH_4BIT) > > + val32 |=3D SDHCI_CTRL_4BITBUS; > > + else if (wrk32 & SDHCI_FSL_PROT_CTRL_WIDTH_8BIT) > > + val32 |=3D SDHCI_CTRL_8BITBUS; > > + return (val32); > > + case SDHCI_POWER_CONTROL: > > + return (SDHCI_POWER_ON | SDHCI_POWER_300); > > + default: > > + break; > > + } > > + > > + return ((RD4(sc, off & ~3) >> (off & 3) * 8) & UINT8_MAX); > > +} > > + > > +static uint16_t > > +sdhci_fsl_fdt_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t > > off) > > +{ > > + struct sdhci_fsl_fdt_softc *sc; > > + uint32_t val32; > > + > > + sc =3D device_get_softc(dev); > > + > > + switch (off) { > > + case SDHCI_CLOCK_CONTROL: > > + return (sdhci_fsl_fdt_get_clock(sc)); > > + case SDHCI_HOST_VERSION: > > + return (RD4(sc, SDHCI_FSL_HOST_VERSION) & UINT16_MAX); > > + case SDHCI_TRANSFER_MODE: > > + return (sc->cmd_and_mode & UINT16_MAX); > > + case SDHCI_COMMAND_FLAGS: > > + return (sc->cmd_and_mode >> 16); > > + case SDHCI_SLOT_INT_STATUS: > > + /* > > + * eSDHC hardware manages only a single slot. > > + * Synthesize a slot interrupt status register for slot 1 below. > > + */ > > + val32 =3D RD4(sc, SDHCI_INT_STATUS); > > + val32 &=3D RD4(sc, SDHCI_SIGNAL_ENABLE); > > + return (!!val32); > > + default: > > + return ((RD4(sc, off & ~3) >> (off & 3) * 8) & UINT16_MAX= ); > > + } > > +} > > + > > +static uint32_t > > +sdhci_fsl_fdt_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t > > off) > > +{ > > + struct sdhci_fsl_fdt_softc *sc; > > + uint32_t wrk32, val32; > > + > > + sc =3D device_get_softc(dev); > > + > > + if (off =3D=3D SDHCI_BUFFER) > > + return (bus_read_4(sc->mem_res, off)); > > + if (off =3D=3D SDHCI_CAPABILITIES2) > > + off =3D SDHCI_FSL_CAPABILITIES2; > > + > > + val32 =3D RD4(sc, off); > > + > > + switch (off) { > > + case SDHCI_CAPABILITIES: > > + val32 &=3D ~(SDHCI_CAN_DO_SUSPEND | SDHCI_CAN_VDD_180); > > + break; > > + case SDHCI_PRESENT_STATE: > > + wrk32 =3D val32; > > + val32 &=3D SDHCI_FSL_PRES_COMPAT_MASK; > > + val32 |=3D (wrk32 >> 4) & SDHCI_STATE_DAT_MASK; > > + val32 |=3D (wrk32 << 1) & SDHCI_STATE_CMD; > > + break; > > + default: > > + break; > > + } > > + > > + return (val32); > > +} > > + > > +static void > > +sdhci_fsl_fdt_read_multi_4(device_t dev, struct sdhci_slot *slot, > > bus_size_t off, > > + uint32_t *data, bus_size_t count) > > +{ > > + struct sdhci_fsl_fdt_softc *sc; > > + > > + sc =3D device_get_softc(dev); > > + bus_read_multi_4(sc->mem_res, off, data, count); > > +} > > + > > +static void > > +sdhci_fsl_fdt_write_1(device_t dev, struct sdhci_slot *slot, bus_size_= t > > off, > > + uint8_t val) > > +{ > > + struct sdhci_fsl_fdt_softc *sc; > > + uint32_t val32; > > + > > + sc =3D device_get_softc(dev); > > + > > + switch (off) { > > + case SDHCI_HOST_CONTROL: > > + val32 =3D RD4(sc, SDHCI_FSL_PROT_CTRL); > > + val32 &=3D ~SDHCI_FSL_PROT_CTRL_WIDTH_MASK; > > + val32 |=3D (val & SDHCI_CTRL_LED); > > + > > + if (val & SDHCI_CTRL_8BITBUS) > > + val32 |=3D SDHCI_FSL_PROT_CTRL_WIDTH_8BIT; > > + else > > + /* Bus width is 1-bit when this flag is not set. = */ > > + val32 |=3D (val & SDHCI_CTRL_4BITBUS); > > + /* Enable SDMA by masking out this field. */ > > + val32 &=3D ~SDHCI_FSL_PROT_CTRL_DMA_MASK; > > + val32 &=3D ~(SDHCI_CTRL_CARD_DET | SDHCI_CTRL_FORCE_CARD)= ; > > + val32 |=3D (val & (SDHCI_CTRL_CARD_DET | > > + SDHCI_CTRL_FORCE_CARD)); > > + WR4(sc, SDHCI_FSL_PROT_CTRL, val32); > > + return; > > + case SDHCI_POWER_CONTROL: > > + return; > > + case SDHCI_SOFTWARE_RESET: > > + val &=3D ~SDHCI_RESET_ALL; > > + /* FALLTHROUGH. */ > > + default: > > + val32 =3D RD4(sc, off & ~3); > > + val32 &=3D ~(UINT8_MAX << (off & 3) * 8); > > + val32 |=3D (val << (off & 3) * 8); > > + WR4(sc, off & ~3, val32); > > + return; > > + } > > +} > > + > > +static void > > +sdhci_fsl_fdt_write_2(device_t dev, struct sdhci_slot *slot, bus_size_= t > > off, > > + uint16_t val) > > +{ > > + struct sdhci_fsl_fdt_softc *sc; > > + uint32_t val32; > > + > > + sc =3D device_get_softc(dev); > > + > > + switch (off) { > > + case SDHCI_CLOCK_CONTROL: > > + fsl_sdhc_fdt_set_clock(sc, val); > > + return; > > + /* > > + * eSDHC hardware combines command and mode into a single > > + * register. Cache it here, so that command isn't written > > + * until after mode. > > + */ > > + case SDHCI_TRANSFER_MODE: > > + sc->cmd_and_mode =3D val; > > + return; > > + case SDHCI_COMMAND_FLAGS: > > + sc->cmd_and_mode =3D > > + (sc->cmd_and_mode & UINT16_MAX) | (val << 16); > > + WR4(sc, SDHCI_TRANSFER_MODE, sc->cmd_and_mode); > > + sc->cmd_and_mode =3D 0; > > + return; > > + default: > > + val32 =3D RD4(sc, off & ~3); > > + val32 &=3D ~(UINT16_MAX << (off & 3) * 8); > > + val32 |=3D ((val & UINT16_MAX) << (off & 3) * 8); > > + WR4(sc, off & ~3, val32); > > + return; > > + } > > +} > > + > > +static void > > +sdhci_fsl_fdt_write_4(device_t dev, struct sdhci_slot *slot, bus_size_= t > > off, > > + uint32_t val) > > +{ > > + struct sdhci_fsl_fdt_softc *sc; > > + > > + sc =3D device_get_softc(dev); > > + > > + switch (off) { > > + case SDHCI_BUFFER: > > + bus_write_4(sc->mem_res, off, val); > > + return; > > + /* > > + * eSDHC hardware lacks support for the SDMA buffer boundary > > + * feature and instead generates SDHCI_INT_DMA_END interrupts > > + * after each completed DMA data transfer. > > + * Since this duplicates the SDHCI_INT_DATA_END functionality, > > + * mask out the unneeded SDHCI_INT_DMA_END interrupt. > > + */ > > + case SDHCI_INT_ENABLE: > > + case SDHCI_SIGNAL_ENABLE: > > + val &=3D ~SDHCI_INT_DMA_END; > > + /* FALLTHROUGH. */ > > + default: > > + WR4(sc, off, val); > > + return; > > + } > > +} > > + > > +static void > > +sdhci_fsl_fdt_write_multi_4(device_t dev, struct sdhci_slot *slot, > > + bus_size_t off, uint32_t *data, bus_size_t count) > > +{ > > + struct sdhci_fsl_fdt_softc *sc; > > + > > + sc =3D device_get_softc(dev); > > + bus_write_multi_4(sc->mem_res, off, data, count); > > +} > > + > > +static void > > +sdhci_fsl_fdt_irq(void *arg) > > +{ > > + struct sdhci_fsl_fdt_softc *sc; > > + > > + sc =3D arg; > > + sdhci_generic_intr(&sc->slot); > > + return; > > +} > > + > > +static int > > +sdhci_fsl_fdt_get_ro(device_t bus, device_t child) > > +{ > > + struct sdhci_fsl_fdt_softc *sc; > > + > > + sc =3D device_get_softc(bus); > > + return (sdhci_fdt_gpio_get_readonly(sc->gpio)); > > +} > > + > > +static bool > > +sdhci_fsl_fdt_get_card_present(device_t dev, struct sdhci_slot *slot) > > +{ > > + struct sdhci_fsl_fdt_softc *sc; > > + > > + sc =3D device_get_softc(dev); > > + return (sdhci_fdt_gpio_get_present(sc->gpio)); > > +} > > + > > +static int > > +sdhci_fsl_fdt_attach(device_t dev) > > +{ > > + struct sdhci_fsl_fdt_softc *sc; > > + uint32_t val, buf_order; > > + uintptr_t ocd_data; > > + uint64_t clk_hz; > > + phandle_t node; > > + int rid, ret; > > + clk_t clk; > > + > > + node =3D ofw_bus_get_node(dev); > > + sc =3D device_get_softc(dev); > > + ocd_data =3D ofw_bus_search_compatible(dev, > > + sdhci_fsl_fdt_compat_data)->ocd_data; > > + sc->soc_data =3D (struct sdhci_fsl_fdt_soc_data *)ocd_data; > > + sc->dev =3D dev; > > + sc->slot.quirks =3D sc->soc_data->quirks; > > + > > + rid =3D 0; > > + sc->mem_res =3D bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, > > + RF_ACTIVE); > > + if (sc->mem_res =3D=3D NULL) { > > + device_printf(dev, > > + "Could not allocate resources for controller\n"); > > + return (ENOMEM); > > + } > > + > > + rid =3D 0; > > + sc->irq_res =3D bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, > > + RF_ACTIVE); > > + if (sc->irq_res =3D=3D NULL) { > > + device_printf(dev, > > + "Could not allocate irq resources for controller\n"); > > + ret =3D ENOMEM; > > + goto err_free_mem; > > + } > > + > > + ret =3D bus_setup_intr(dev, sc->irq_res, INTR_TYPE_BIO | INTR_MPS= AFE, > > + NULL, sdhci_fsl_fdt_irq, sc, &sc->irq_cookie); > > + if (ret !=3D 0) { > > + device_printf(dev, "Could not setup IRQ handler\n"); > > + goto err_free_irq_res; > > + } > > + > > + ret =3D clk_get_by_ofw_index(dev, node, 0, &clk); > > + if (ret !=3D 0) { > > + device_printf(dev, "Parent clock not found\n"); > > + goto err_free_irq; > > + } > > + > > + ret =3D clk_get_freq(clk, &clk_hz); > > + if (ret !=3D 0) { > > + device_printf(dev, > > + "Could not get parent clock frequency\n"); > > + goto err_free_irq; > > + } > > + > > + sc->baseclk_hz =3D clk_hz / 2; > > + > > + /* Figure out eSDHC block endianness before we touch any HW regs. > */ > > + if (OF_hasprop(node, "little-endian")) { > > + sc->read =3D read_le; > > + sc->write =3D write_le; > > + buf_order =3D SDHCI_FSL_PROT_CTRL_BYTE_NATIVE; > > + } else { > > + sc->read =3D read_be; > > + sc->write =3D write_be; > > + buf_order =3D SDHCI_FSL_PROT_CTRL_BYTE_SWAP; > > + } > > + > > + /* > > + * Setting this register affects byte order in SDHCI_BUFFER only. > > + * If the eSDHC block is connected over a big-endian bus, the dat= a > > + * read from/written to the buffer will be already byte swapped. > > + * In such a case, setting SDHCI_FSL_PROT_CTRL_BYTE_SWAP will > convert > > + * the byte order again, resulting in a native byte order. > > + * The read/write callbacks accommodate for this behavior. > > + */ > > + val =3D RD4(sc, SDHCI_FSL_PROT_CTRL); > > + val &=3D ~SDHCI_FSL_PROT_CTRL_BYTE_MASK; > > + WR4(sc, SDHCI_FSL_PROT_CTRL, val | buf_order); > > + > > + /* > > + * Gate the SD clock and set its source to peripheral clock / 2. > > + * The frequency in baseclk_hz is set to match this. > > + */ > > + val =3D RD4(sc, SDHCI_CLOCK_CONTROL); > > + WR4(sc, SDHCI_CLOCK_CONTROL, val & ~SDHCI_FSL_CLK_SDCLKEN); > > + val =3D RD4(sc, SDHCI_FSL_ESDHC_CTRL); > > + WR4(sc, SDHCI_FSL_ESDHC_CTRL, val | SDHCI_FSL_ESDHC_CTRL_CLK_DIV2= ); > > + sc->slot.max_clk =3D sc->baseclk_hz; > > + sc->gpio =3D sdhci_fdt_gpio_setup(dev, &sc->slot); > > + > > + /* > > + * Set the buffer watermark level to 128 words (512 bytes) for bo= th > > + * read and write. The hardware has a restriction that when the > read or > > + * write ready status is asserted, that means you can read exactl= y > the > > + * number of words set in the watermark register before you have = to > > + * re-check the status and potentially wait for more data. The ma= in > > + * sdhci driver provides no hook for doing status checking on les= s > than > > + * a full block boundary, so we set the watermark level to be a > full > > + * block. Reads and writes where the block size is less than the > > + * watermark size will work correctly too, no need to change the > > + * watermark for different size blocks. However, 128 is the maxim= um > > + * allowed for the watermark, so PIO is limitted to 512 byte > blocks. > > + */ > > + WR4(sc, SDHCI_FSL_WTMK_LVL, SDHCI_FSL_WTMK_WR_512B | > > + SDHCI_FSL_WTMK_RD_512B); > > + > > + ret =3D sdhci_init_slot(dev, &sc->slot, 0); > > + if (ret !=3D 0) > > + goto err_free_gpio; > > + sc->slot_init_done =3D true; > > + sdhci_start_slot(&sc->slot); > > + > > + return (bus_generic_attach(dev)); > > + > > +err_free_gpio: > > + sdhci_fdt_gpio_teardown(sc->gpio); > > +err_free_irq: > > + bus_teardown_intr(dev, sc->irq_res, sc->irq_cookie); > > +err_free_irq_res: > > + bus_free_resource(dev, SYS_RES_IRQ, sc->irq_res); > > +err_free_mem: > > + bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res); > > + return (ret); > > +} > > + > > +static int > > +sdhci_fsl_fdt_detach(device_t dev) > > +{ > > + struct sdhci_fsl_fdt_softc *sc; > > + > > + sc =3D device_get_softc(dev); > > + if (sc->slot_init_done) > > + sdhci_cleanup_slot(&sc->slot); > > + if (sc->gpio !=3D NULL) > > + sdhci_fdt_gpio_teardown(sc->gpio); > > + if (sc->irq_cookie !=3D NULL) > > + bus_teardown_intr(dev, sc->irq_res, sc->irq_cookie); > > + if (sc->irq_res !=3D NULL) > > + bus_free_resource(dev, SYS_RES_IRQ, sc->irq_res); > > + if (sc->mem_res !=3D NULL) > > + bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res); > > + return (0); > > +} > > + > > +static int > > +sdhci_fsl_fdt_probe(device_t dev) > > +{ > > + > > + if (!ofw_bus_status_okay(dev)) > > + return (ENXIO); > > + > > + if (!ofw_bus_search_compatible(dev, > > + sdhci_fsl_fdt_compat_data)->ocd_data) > > + return (ENXIO); > > + > > + device_set_desc(dev, "NXP QorIQ Layerscape eSDHC controller"); > > + return (BUS_PROBE_DEFAULT); > > +} > > + > > +static int > > +sdhci_fsl_fdt_read_ivar(device_t bus, device_t child, int which, > > + uintptr_t *result) > > +{ > > + struct sdhci_slot *slot =3D device_get_ivars(child); > > + > > + if (which =3D=3D MMCBR_IVAR_MAX_DATA && (slot->opt & SDHCI_HAVE_D= MA)) { > > + /* > > + * In the absence of SDMA buffer boundary functionality, > > + * limit the maximum data length per read/write command > > + * to bounce buffer size. > > + */ > > + *result =3D howmany(slot->sdma_bbufsz, 512); > > + return (0); > > + } > > + return (sdhci_generic_read_ivar(bus, child, which, result)); > > +} > > + > > +static const device_method_t sdhci_fsl_fdt_methods[] =3D { > > + /* Device interface. */ > > + DEVMETHOD(device_probe, sdhci_fsl_fdt_probe), > > + DEVMETHOD(device_attach, sdhci_fsl_fdt_attach), > > + DEVMETHOD(device_detach, sdhci_fsl_fdt_detach), > > + > > + /* Bus interface. */ > > + DEVMETHOD(bus_read_ivar, sdhci_fsl_fdt_read_ivar), > > + DEVMETHOD(bus_write_ivar, sdhci_generic_write_ivar)= , > > + > > + /* MMC bridge interface. */ > > + DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios)= , > > + DEVMETHOD(mmcbr_request, sdhci_generic_request), > > + DEVMETHOD(mmcbr_get_ro, sdhci_fsl_fdt_get_ro), > > + DEVMETHOD(mmcbr_acquire_host, > sdhci_generic_acquire_host), > > + DEVMETHOD(mmcbr_release_host, > sdhci_generic_release_host), > > + > > + /* SDHCI accessors. */ > > + DEVMETHOD(sdhci_read_1, sdhci_fsl_fdt_read_1), > > + DEVMETHOD(sdhci_read_2, sdhci_fsl_fdt_read_2), > > + DEVMETHOD(sdhci_read_4, sdhci_fsl_fdt_read_4), > > + DEVMETHOD(sdhci_read_multi_4, > sdhci_fsl_fdt_read_multi_4), > > + DEVMETHOD(sdhci_write_1, sdhci_fsl_fdt_write_1), > > + DEVMETHOD(sdhci_write_2, sdhci_fsl_fdt_write_2), > > + DEVMETHOD(sdhci_write_4, sdhci_fsl_fdt_write_4), > > + DEVMETHOD(sdhci_write_multi_4, > sdhci_fsl_fdt_write_multi_4), > > + DEVMETHOD(sdhci_get_card_present, > sdhci_fsl_fdt_get_card_present), > > + DEVMETHOD_END > > +}; > > + > > +static devclass_t sdhci_fsl_fdt_devclass; > > +static driver_t sdhci_fsl_fdt_driver =3D { > > + "sdhci_fsl_fdt", > > + sdhci_fsl_fdt_methods, > > + sizeof(struct sdhci_fsl_fdt_softc), > > +}; > > + > > +DRIVER_MODULE(sdhci_fsl_fdt, simplebus, sdhci_fsl_fdt_driver, > > + sdhci_fsl_fdt_devclass, NULL, NULL); > > +SDHCI_DEPEND(sdhci_fsl_fdt); > > + > > +#ifndef MMCCAM > > +MMC_DECLARE_BRIDGE(sdhci_fsl_fdt); > > +#endif > > _______________________________________________ > > svn-src-all@freebsd.org mailing list > > https://lists.freebsd.org/mailman/listinfo/svn-src-all > > To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org" > > > > > -- > Mateusz Guzik <mjguzik gmail.com> >
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAPv3WKdQ0jUNx9igtHH4OcdYoogpd_ZfGRa0a7ru8X8wiWNgzg>