diff --git a/sys/arm/allwinner/a10_ahci.c b/sys/arm/allwinner/a10_ahci.c index a0717a0e9dfa..b7aa991b6543 100644 --- a/sys/arm/allwinner/a10_ahci.c +++ b/sys/arm/allwinner/a10_ahci.c @@ -1,423 +1,423 @@ /*- * Copyright (c) 2015 Luiz Otavio O Souza All rights reserved. * Copyright (c) 2014-2015 M. Warner Losh * * 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 AND CONTRIBUTORS ``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 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 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. * * The magic-bit-bang sequence used in this code may be based on a linux * platform driver in the Allwinner SDK from Allwinner Technology Co., Ltd. * www.allwinnertech.com, by Daniel Wang * though none of the original code was copied. */ #include "opt_bus.h" #include #include #include #include #include #include #include #include #include #include #include -#include +#include /* * Allwinner a1x/a2x/a8x SATA attachment. This is just the AHCI register * set with a few extra implementation-specific registers that need to * be accounted for. There's only one PHY in the system, and it needs * to be trained to bring the link up. In addition, there's some DMA * specific things that need to be done as well. These things are also * just about completely undocumented, except in ugly code in the Linux * SDK Allwinner releases. */ /* BITx -- Unknown bit that needs to be set/cleared at position x */ /* UFx -- Uknown multi-bit field frobbed during init */ #define AHCI_BISTAFR 0x00A0 #define AHCI_BISTCR 0x00A4 #define AHCI_BISTFCTR 0x00A8 #define AHCI_BISTSR 0x00AC #define AHCI_BISTDECR 0x00B0 #define AHCI_DIAGNR 0x00B4 #define AHCI_DIAGNR1 0x00B8 #define AHCI_OOBR 0x00BC #define AHCI_PHYCS0R 0x00C0 /* Bits 0..17 are a mystery */ #define PHYCS0R_BIT18 (1 << 18) #define PHYCS0R_POWER_ENABLE (1 << 19) #define PHYCS0R_UF1_MASK (7 << 20) /* Unknown Field 1 */ #define PHYCS0R_UF1_INIT (3 << 20) #define PHYCS0R_BIT23 (1 << 23) #define PHYCS0R_UF2_MASK (7 << 24) /* Uknown Field 2 */ #define PHYCS0R_UF2_INIT (5 << 24) /* Bit 27 mystery */ #define PHYCS0R_POWER_STATUS_MASK (7 << 28) #define PHYCS0R_PS_GOOD (2 << 28) /* Bit 31 mystery */ #define AHCI_PHYCS1R 0x00C4 /* Bits 0..5 are a mystery */ #define PHYCS1R_UF1_MASK (3 << 6) #define PHYCS1R_UF1_INIT (2 << 6) #define PHYCS1R_UF2_MASK (0x1f << 8) #define PHYCS1R_UF2_INIT (6 << 8) /* Bits 13..14 are a mystery */ #define PHYCS1R_BIT15 (1 << 15) #define PHYCS1R_UF3_MASK (3 << 16) #define PHYCS1R_UF3_INIT (2 << 16) /* Bit 18 mystery */ #define PHYCS1R_HIGHZ (1 << 19) /* Bits 20..27 mystery */ #define PHYCS1R_BIT28 (1 << 28) /* Bits 29..31 mystery */ #define AHCI_PHYCS2R 0x00C8 /* bits 0..4 mystery */ #define PHYCS2R_UF1_MASK (0x1f << 5) #define PHYCS2R_UF1_INIT (0x19 << 5) /* Bits 10..23 mystery */ #define PHYCS2R_CALIBRATE (1 << 24) /* Bits 25..31 mystery */ #define AHCI_TIMER1MS 0x00E0 #define AHCI_GPARAM1R 0x00E8 #define AHCI_GPARAM2R 0x00EC #define AHCI_PPARAMR 0x00F0 #define AHCI_TESTR 0x00F4 #define AHCI_VERSIONR 0x00F8 #define AHCI_IDR 0x00FC #define AHCI_RWCR 0x00FC #define AHCI_P0DMACR 0x0070 #define AHCI_P0PHYCR 0x0078 #define AHCI_P0PHYSR 0x007C #define PLL_FREQ 100000000 struct ahci_a10_softc { struct ahci_controller ahci_ctlr; regulator_t ahci_reg; clk_t clk_pll; clk_t clk_gate; }; static void inline ahci_set(struct resource *m, bus_size_t off, uint32_t set) { uint32_t val = ATA_INL(m, off); val |= set; ATA_OUTL(m, off, val); } static void inline ahci_clr(struct resource *m, bus_size_t off, uint32_t clr) { uint32_t val = ATA_INL(m, off); val &= ~clr; ATA_OUTL(m, off, val); } static void inline ahci_mask_set(struct resource *m, bus_size_t off, uint32_t mask, uint32_t set) { uint32_t val = ATA_INL(m, off); val &= mask; val |= set; ATA_OUTL(m, off, val); } /* * Should this be phy_reset or phy_init */ #define PHY_RESET_TIMEOUT 1000 static void ahci_a10_phy_reset(device_t dev) { uint32_t to, val; struct ahci_controller *ctlr = device_get_softc(dev); /* * Here starts the magic -- most of the comments are based * on guesswork, names of routines and printf error * messages. The code works, but it will do that even if the * comments are 100% BS. */ /* * Lock out other access while we initialize. Or at least that * seems to be the case based on Linux SDK #defines. Maybe this * put things into reset? */ ATA_OUTL(ctlr->r_mem, AHCI_RWCR, 0); DELAY(100); /* * Set bit 19 in PHYCS1R. Guessing this disables driving the PHY * port for a bit while we reset things. */ ahci_set(ctlr->r_mem, AHCI_PHYCS1R, PHYCS1R_HIGHZ); /* * Frob PHYCS0R... */ ahci_mask_set(ctlr->r_mem, AHCI_PHYCS0R, ~PHYCS0R_UF2_MASK, PHYCS0R_UF2_INIT | PHYCS0R_BIT23 | PHYCS0R_BIT18); /* * Set three fields in PHYCS1R */ ahci_mask_set(ctlr->r_mem, AHCI_PHYCS1R, ~(PHYCS1R_UF1_MASK | PHYCS1R_UF2_MASK | PHYCS1R_UF3_MASK), PHYCS1R_UF1_INIT | PHYCS1R_UF2_INIT | PHYCS1R_UF3_INIT); /* * Two more mystery bits in PHYCS1R. -- can these be combined above? */ ahci_set(ctlr->r_mem, AHCI_PHYCS1R, PHYCS1R_BIT15 | PHYCS1R_BIT28); /* * Now clear that first mysery bit. Perhaps this starts * driving the PHY again so we can power it up and start * talking to the SATA drive, if any below. */ ahci_clr(ctlr->r_mem, AHCI_PHYCS1R, PHYCS1R_HIGHZ); /* * Frob PHYCS0R again... */ ahci_mask_set(ctlr->r_mem, AHCI_PHYCS0R, ~PHYCS0R_UF1_MASK, PHYCS0R_UF1_INIT); /* * Frob PHYCS2R, because 25 means something? */ ahci_mask_set(ctlr->r_mem, AHCI_PHYCS2R, ~PHYCS2R_UF1_MASK, PHYCS2R_UF1_INIT); DELAY(100); /* WAG */ /* * Turn on the power to the PHY and wait for it to report back * good? */ ahci_set(ctlr->r_mem, AHCI_PHYCS0R, PHYCS0R_POWER_ENABLE); for (to = PHY_RESET_TIMEOUT; to > 0; to--) { val = ATA_INL(ctlr->r_mem, AHCI_PHYCS0R); if ((val & PHYCS0R_POWER_STATUS_MASK) == PHYCS0R_PS_GOOD) break; DELAY(10); } if (to == 0 && bootverbose) device_printf(dev, "PHY Power Failed PHYCS0R = %#x\n", val); /* * Calibrate the clocks between the device and the host. This appears * to be an automated process that clears the bit when it is done. */ ahci_set(ctlr->r_mem, AHCI_PHYCS2R, PHYCS2R_CALIBRATE); for (to = PHY_RESET_TIMEOUT; to > 0; to--) { val = ATA_INL(ctlr->r_mem, AHCI_PHYCS2R); if ((val & PHYCS2R_CALIBRATE) == 0) break; DELAY(10); } if (to == 0 && bootverbose) device_printf(dev, "PHY Cal Failed PHYCS2R %#x\n", val); /* * OK, let things settle down a bit. */ DELAY(1000); /* * Go back into normal mode now that we've calibrated the PHY. */ ATA_OUTL(ctlr->r_mem, AHCI_RWCR, 7); } static void ahci_a10_ch_start(struct ahci_channel *ch) { uint32_t reg; /* * Magical values from Allwinner SDK, setup the DMA before start * operations on this channel. */ reg = ATA_INL(ch->r_mem, AHCI_P0DMACR); reg &= ~0xff00; reg |= 0x4400; ATA_OUTL(ch->r_mem, AHCI_P0DMACR, reg); } static int ahci_a10_ctlr_reset(device_t dev) { ahci_a10_phy_reset(dev); return (ahci_ctlr_reset(dev)); } static int ahci_a10_probe(device_t dev) { if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-ahci")) return (ENXIO); device_set_desc(dev, "Allwinner Integrated AHCI controller"); return (BUS_PROBE_DEFAULT); } static int ahci_a10_attach(device_t dev) { int error; struct ahci_a10_softc *sc; struct ahci_controller *ctlr; sc = device_get_softc(dev); ctlr = &sc->ahci_ctlr; ctlr->quirks = AHCI_Q_NOPMP; ctlr->vendorid = 0; ctlr->deviceid = 0; ctlr->subvendorid = 0; ctlr->subdeviceid = 0; ctlr->r_rid = 0; if (!(ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &ctlr->r_rid, RF_ACTIVE))) return (ENXIO); /* Enable the (optional) regulator */ if (regulator_get_by_ofw_property(dev, 0, "target-supply", &sc->ahci_reg) == 0) { error = regulator_enable(sc->ahci_reg); if (error != 0) { device_printf(dev, "Could not enable regulator\n"); goto fail; } } /* Enable clocks */ error = clk_get_by_ofw_index(dev, 0, 0, &sc->clk_gate); if (error != 0) { device_printf(dev, "Cannot get gate clock\n"); goto fail; } error = clk_get_by_ofw_index(dev, 0, 1, &sc->clk_pll); if (error != 0) { device_printf(dev, "Cannot get PLL clock\n"); goto fail; } error = clk_set_freq(sc->clk_pll, PLL_FREQ, CLK_SET_ROUND_DOWN); if (error != 0) { device_printf(dev, "Cannot set PLL frequency\n"); goto fail; } error = clk_enable(sc->clk_pll); if (error != 0) { device_printf(dev, "Cannot enable PLL\n"); goto fail; } error = clk_enable(sc->clk_gate); if (error != 0) { device_printf(dev, "Cannot enable clk gate\n"); goto fail; } /* Reset controller */ if ((error = ahci_a10_ctlr_reset(dev)) != 0) goto fail; /* * No MSI registers on this platform. */ ctlr->msi = 0; ctlr->numirqs = 1; /* Channel start callback(). */ ctlr->ch_start = ahci_a10_ch_start; /* * Note: ahci_attach will release ctlr->r_mem on errors automatically */ return (ahci_attach(dev)); fail: if (sc->ahci_reg != NULL) regulator_disable(sc->ahci_reg); if (sc->clk_gate != NULL) clk_release(sc->clk_gate); if (sc->clk_pll != NULL) clk_release(sc->clk_pll); bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem); return (error); } static int ahci_a10_detach(device_t dev) { struct ahci_a10_softc *sc; struct ahci_controller *ctlr; sc = device_get_softc(dev); ctlr = &sc->ahci_ctlr; if (sc->ahci_reg != NULL) regulator_disable(sc->ahci_reg); if (sc->clk_gate != NULL) clk_release(sc->clk_gate); if (sc->clk_pll != NULL) clk_release(sc->clk_pll); bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem); return (ahci_detach(dev)); } static device_method_t ahci_ata_methods[] = { DEVMETHOD(device_probe, ahci_a10_probe), DEVMETHOD(device_attach, ahci_a10_attach), DEVMETHOD(device_detach, ahci_a10_detach), DEVMETHOD(bus_print_child, ahci_print_child), DEVMETHOD(bus_alloc_resource, ahci_alloc_resource), DEVMETHOD(bus_release_resource, ahci_release_resource), DEVMETHOD(bus_setup_intr, ahci_setup_intr), DEVMETHOD(bus_teardown_intr,ahci_teardown_intr), DEVMETHOD(bus_child_location, ahci_child_location), DEVMETHOD_END }; static driver_t ahci_ata_driver = { "ahci", ahci_ata_methods, sizeof(struct ahci_a10_softc) }; DRIVER_MODULE(a10_ahci, simplebus, ahci_ata_driver, 0, 0); diff --git a/sys/arm/allwinner/a64/sun50i_a64_acodec.c b/sys/arm/allwinner/a64/sun50i_a64_acodec.c index f9ada20ec554..12c9a86cf361 100644 --- a/sys/arm/allwinner/a64/sun50i_a64_acodec.c +++ b/sys/arm/allwinner/a64/sun50i_a64_acodec.c @@ -1,481 +1,481 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2020 Oleksandr Tymoshenko * Copyright (c) 2018 Jared McNeill * * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include "syscon_if.h" #include "opt_snd.h" #include #include #include "audio_dai_if.h" #include "mixer_if.h" #define A64_PR_CFG 0x00 #define A64_AC_PR_RST (1 << 28) #define A64_AC_PR_RW (1 << 24) #define A64_AC_PR_ADDR_MASK (0x1f << 16) #define A64_AC_PR_ADDR(n) (((n) & 0x1f) << 16) #define A64_ACDA_PR_WDAT_MASK (0xff << 8) #define A64_ACDA_PR_WDAT(n) (((n) & 0xff) << 8) #define A64_ACDA_PR_RDAT(n) ((n) & 0xff) #define A64_HP_CTRL 0x00 #define A64_HPPA_EN (1 << 6) #define A64_HPVOL_MASK 0x3f #define A64_HPVOL(n) ((n) & 0x3f) #define A64_OL_MIX_CTRL 0x01 #define A64_LMIXMUTE_LDAC (1 << 1) #define A64_OR_MIX_CTRL 0x02 #define A64_RMIXMUTE_RDAC (1 << 1) #define A64_LINEOUT_CTRL0 0x05 #define A64_LINEOUT_LEFT_EN (1 << 7) #define A64_LINEOUT_RIGHT_EN (1 << 6) #define A64_LINEOUT_EN (A64_LINEOUT_LEFT_EN|A64_LINEOUT_RIGHT_EN) #define A64_LINEOUT_CTRL1 0x06 #define A64_LINEOUT_VOL __BITS(4,0) #define A64_MIC1_CTRL 0x07 #define A64_MIC1G __BITS(6,4) #define A64_MIC1AMPEN (1 << 3) #define A64_MIC1BOOST __BITS(2,0) #define A64_MIC2_CTRL 0x08 #define A64_MIC2_SEL (1 << 7) #define A64_MIC2G_MASK (7 << 4) #define A64_MIC2G(n) (((n) & 7) << 4) #define A64_MIC2AMPEN (1 << 3) #define A64_MIC2BOOST_MASK (7 << 0) #define A64_MIC2BOOST(n) (((n) & 7) << 0) #define A64_LINEIN_CTRL 0x09 #define A64_LINEING __BITS(6,4) #define A64_MIX_DAC_CTRL 0x0a #define A64_DACAREN (1 << 7) #define A64_DACALEN (1 << 6) #define A64_RMIXEN (1 << 5) #define A64_LMIXEN (1 << 4) #define A64_RHPPAMUTE (1 << 3) #define A64_LHPPAMUTE (1 << 2) #define A64_RHPIS (1 << 1) #define A64_LHPIS (1 << 0) #define A64_L_ADCMIX_SRC 0x0b #define A64_R_ADCMIX_SRC 0x0c #define A64_ADCMIX_SRC_MIC1 (1 << 6) #define A64_ADCMIX_SRC_MIC2 (1 << 5) #define A64_ADCMIX_SRC_LINEIN (1 << 2) #define A64_ADCMIX_SRC_OMIXER (1 << 1) #define A64_ADC_CTRL 0x0d #define A64_ADCREN (1 << 7) #define A64_ADCLEN (1 << 6) #define A64_ADCG __BITS(2,0) #define A64_JACK_MIC_CTRL 0x1d #define A64_JACKDETEN (1 << 7) #define A64_INNERRESEN (1 << 6) #define A64_HMICBIASEN (1 << 5) #define A64_AUTOPLEN (1 << 1) #define A64CODEC_MIXER_DEVS ((1 << SOUND_MIXER_VOLUME) | \ (1 << SOUND_MIXER_MIC)) static struct ofw_compat_data compat_data[] = { { "allwinner,sun50i-a64-codec-analog", 1}, { NULL, 0 } }; struct a64codec_softc { device_t dev; struct resource *res; struct mtx mtx; u_int regaddr; /* address for the sysctl */ }; #define A64CODEC_LOCK(sc) mtx_lock(&(sc)->mtx) #define A64CODEC_UNLOCK(sc) mtx_unlock(&(sc)->mtx) #define A64CODEC_READ(sc, reg) bus_read_4((sc)->res, (reg)) #define A64CODEC_WRITE(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) static int a64codec_probe(device_t dev); static int a64codec_attach(device_t dev); static int a64codec_detach(device_t dev); static u_int a64_acodec_pr_read(struct a64codec_softc *sc, u_int addr) { uint32_t val; /* Read current value */ val = A64CODEC_READ(sc, A64_PR_CFG); /* De-assert reset */ val |= A64_AC_PR_RST; A64CODEC_WRITE(sc, A64_PR_CFG, val); /* Read mode */ val &= ~A64_AC_PR_RW; A64CODEC_WRITE(sc, A64_PR_CFG, val); /* Set address */ val &= ~A64_AC_PR_ADDR_MASK; val |= A64_AC_PR_ADDR(addr); A64CODEC_WRITE(sc, A64_PR_CFG, val); /* Read data */ val = A64CODEC_READ(sc, A64_PR_CFG); return A64_ACDA_PR_RDAT(val); } static void a64_acodec_pr_write(struct a64codec_softc *sc, u_int addr, u_int data) { uint32_t val; /* Read current value */ val = A64CODEC_READ(sc, A64_PR_CFG); /* De-assert reset */ val |= A64_AC_PR_RST; A64CODEC_WRITE(sc, A64_PR_CFG, val); /* Set address */ val &= ~A64_AC_PR_ADDR_MASK; val |= A64_AC_PR_ADDR(addr); A64CODEC_WRITE(sc, A64_PR_CFG, val); /* Write data */ val &= ~A64_ACDA_PR_WDAT_MASK; val |= A64_ACDA_PR_WDAT(data); A64CODEC_WRITE(sc, A64_PR_CFG, val); /* Write mode */ val |= A64_AC_PR_RW; A64CODEC_WRITE(sc, A64_PR_CFG, val); /* Clear write mode */ val &= ~A64_AC_PR_RW; A64CODEC_WRITE(sc, A64_PR_CFG, val); } static void a64_acodec_pr_set_clear(struct a64codec_softc *sc, u_int addr, u_int set, u_int clr) { u_int old, new; old = a64_acodec_pr_read(sc, addr); new = set | (old & ~clr); a64_acodec_pr_write(sc, addr, new); } static int a64codec_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "Allwinner A64 Analog Codec"); return (BUS_PROBE_DEFAULT); } static int a64codec_attach(device_t dev) { struct a64codec_softc *sc; int error, rid; phandle_t node; regulator_t reg; sc = device_get_softc(dev); sc->dev = dev; mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); rid = 0; sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->res) { device_printf(dev, "cannot allocate resource for device\n"); error = ENXIO; goto fail; } if (regulator_get_by_ofw_property(dev, 0, "cpvdd-supply", ®) == 0) { error = regulator_enable(reg); if (error != 0) { device_printf(dev, "cannot enable PHY regulator\n"); goto fail; } } /* Right & Left Headphone PA enable */ a64_acodec_pr_set_clear(sc, A64_HP_CTRL, A64_HPPA_EN, 0); /* Microphone BIAS enable */ a64_acodec_pr_set_clear(sc, A64_JACK_MIC_CTRL, A64_HMICBIASEN | A64_INNERRESEN, 0); /* Unmute DAC to output mixer */ a64_acodec_pr_set_clear(sc, A64_OL_MIX_CTRL, A64_LMIXMUTE_LDAC, 0); a64_acodec_pr_set_clear(sc, A64_OR_MIX_CTRL, A64_RMIXMUTE_RDAC, 0); /* For now we work only with headphones */ a64_acodec_pr_set_clear(sc, A64_LINEOUT_CTRL0, 0, A64_LINEOUT_EN); a64_acodec_pr_set_clear(sc, A64_HP_CTRL, A64_HPPA_EN, 0); u_int val = a64_acodec_pr_read(sc, A64_HP_CTRL); val &= ~(0x3f); val |= 0x25; a64_acodec_pr_write(sc, A64_HP_CTRL, val); a64_acodec_pr_set_clear(sc, A64_MIC2_CTRL, A64_MIC2AMPEN | A64_MIC2_SEL | A64_MIC2G(0x3) | A64_MIC2BOOST(0x4), A64_MIC2G_MASK | A64_MIC2BOOST_MASK); a64_acodec_pr_write(sc, A64_L_ADCMIX_SRC, A64_ADCMIX_SRC_MIC2); a64_acodec_pr_write(sc, A64_R_ADCMIX_SRC, A64_ADCMIX_SRC_MIC2); /* Max out MIC2 gain */ val = a64_acodec_pr_read(sc, A64_MIC2_CTRL); val &= ~(0x7); val |= (0x7); val &= ~(7 << 4); val |= (7 << 4); a64_acodec_pr_write(sc, A64_MIC2_CTRL, val); node = ofw_bus_get_node(dev); OF_device_register_xref(OF_xref_from_node(node), dev); return (0); fail: a64codec_detach(dev); return (error); } static int a64codec_detach(device_t dev) { struct a64codec_softc *sc; sc = device_get_softc(dev); if (sc->res) bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->res); mtx_destroy(&sc->mtx); return (0); } static int a64codec_mixer_init(struct snd_mixer *m) { mix_setdevs(m, A64CODEC_MIXER_DEVS); return (0); } static int a64codec_mixer_uninit(struct snd_mixer *m) { return (0); } static int a64codec_mixer_reinit(struct snd_mixer *m) { return (0); } static int a64codec_mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) { struct a64codec_softc *sc; struct mtx *mixer_lock; uint8_t do_unlock; u_int val; sc = device_get_softc(mix_getdevinfo(m)); mixer_lock = mixer_get_lock(m); if (mtx_owned(mixer_lock)) { do_unlock = 0; } else { do_unlock = 1; mtx_lock(mixer_lock); } right = left; A64CODEC_LOCK(sc); switch(dev) { case SOUND_MIXER_VOLUME: val = a64_acodec_pr_read(sc, A64_HP_CTRL); val &= ~(A64_HPVOL_MASK); val |= A64_HPVOL(left * 63 / 100); a64_acodec_pr_write(sc, A64_HP_CTRL, val); break; case SOUND_MIXER_MIC: val = a64_acodec_pr_read(sc, A64_MIC2_CTRL); val &= ~(A64_MIC2BOOST_MASK); val |= A64_MIC2BOOST(left * 7 / 100); a64_acodec_pr_write(sc, A64_MIC2_CTRL, val); break; default: break; } A64CODEC_UNLOCK(sc); if (do_unlock) { mtx_unlock(mixer_lock); } return (left | (right << 8)); } static unsigned a64codec_mixer_setrecsrc(struct snd_mixer *m, unsigned src) { return (0); } static kobj_method_t a64codec_mixer_methods[] = { KOBJMETHOD(mixer_init, a64codec_mixer_init), KOBJMETHOD(mixer_uninit, a64codec_mixer_uninit), KOBJMETHOD(mixer_reinit, a64codec_mixer_reinit), KOBJMETHOD(mixer_set, a64codec_mixer_set), KOBJMETHOD(mixer_setrecsrc, a64codec_mixer_setrecsrc), KOBJMETHOD_END }; MIXER_DECLARE(a64codec_mixer); static int a64codec_dai_init(device_t dev, uint32_t format) { return (0); } static int a64codec_dai_trigger(device_t dev, int go, int pcm_dir) { struct a64codec_softc *sc = device_get_softc(dev); if ((pcm_dir != PCMDIR_PLAY) && (pcm_dir != PCMDIR_REC)) return (EINVAL); switch (go) { case PCMTRIG_START: if (pcm_dir == PCMDIR_PLAY) { /* Enable DAC analog l/r channels, HP PA, and output mixer */ a64_acodec_pr_set_clear(sc, A64_MIX_DAC_CTRL, A64_DACAREN | A64_DACALEN | A64_RMIXEN | A64_LMIXEN | A64_RHPPAMUTE | A64_LHPPAMUTE, 0); } else if (pcm_dir == PCMDIR_REC) { /* Enable ADC analog l/r channels */ a64_acodec_pr_set_clear(sc, A64_ADC_CTRL, A64_ADCREN | A64_ADCLEN, 0); } break; case PCMTRIG_STOP: case PCMTRIG_ABORT: if (pcm_dir == PCMDIR_PLAY) { /* Disable DAC analog l/r channels, HP PA, and output mixer */ a64_acodec_pr_set_clear(sc, A64_MIX_DAC_CTRL, 0, A64_DACAREN | A64_DACALEN | A64_RMIXEN | A64_LMIXEN | A64_RHPPAMUTE | A64_LHPPAMUTE); } else if (pcm_dir == PCMDIR_REC) { /* Disable ADC analog l/r channels */ a64_acodec_pr_set_clear(sc, A64_ADC_CTRL, 0, A64_ADCREN | A64_ADCLEN); } break; } return (0); } static int a64codec_dai_setup_mixer(device_t dev, device_t pcmdev) { mixer_init(pcmdev, &a64codec_mixer_class, dev); return (0); } static device_method_t a64codec_methods[] = { /* Device interface */ DEVMETHOD(device_probe, a64codec_probe), DEVMETHOD(device_attach, a64codec_attach), DEVMETHOD(device_detach, a64codec_detach), DEVMETHOD(audio_dai_init, a64codec_dai_init), DEVMETHOD(audio_dai_setup_mixer, a64codec_dai_setup_mixer), DEVMETHOD(audio_dai_trigger, a64codec_dai_trigger), DEVMETHOD_END }; static driver_t a64codec_driver = { "a64codec", a64codec_methods, sizeof(struct a64codec_softc), }; DRIVER_MODULE(a64codec, simplebus, a64codec_driver, 0, 0); SIMPLEBUS_PNP_INFO(compat_data); diff --git a/sys/arm/allwinner/aw_gpio.c b/sys/arm/allwinner/aw_gpio.c index f72dbf88099f..cee2cf056f42 100644 --- a/sys/arm/allwinner/aw_gpio.c +++ b/sys/arm/allwinner/aw_gpio.c @@ -1,1483 +1,1483 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2013 Ganbold Tsagaankhuu * Copyright (c) 2012 Oleksandr Tymoshenko * Copyright (c) 2012 Luiz Otavio O Souza. * All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #if defined(__aarch64__) #include "opt_soc.h" #endif #include "pic_if.h" #include "gpio_if.h" #define AW_GPIO_DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \ GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN); #define AW_GPIO_INTR_CAPS (GPIO_INTR_LEVEL_LOW | GPIO_INTR_LEVEL_HIGH | \ GPIO_INTR_EDGE_RISING | GPIO_INTR_EDGE_FALLING | GPIO_INTR_EDGE_BOTH) #define AW_GPIO_NONE 0 #define AW_GPIO_PULLUP 1 #define AW_GPIO_PULLDOWN 2 #define AW_GPIO_INPUT 0 #define AW_GPIO_OUTPUT 1 #define AW_GPIO_DRV_MASK 0x3 #define AW_GPIO_PUD_MASK 0x3 #define AW_PINCTRL 1 #define AW_R_PINCTRL 2 struct aw_gpio_conf { struct allwinner_padconf *padconf; const char *banks; }; /* Defined in aw_padconf.c */ #ifdef SOC_ALLWINNER_A10 extern struct allwinner_padconf a10_padconf; struct aw_gpio_conf a10_gpio_conf = { .padconf = &a10_padconf, .banks = "abcdefghi", }; #endif /* Defined in a13_padconf.c */ #ifdef SOC_ALLWINNER_A13 extern struct allwinner_padconf a13_padconf; struct aw_gpio_conf a13_gpio_conf = { .padconf = &a13_padconf, .banks = "bcdefg", }; #endif /* Defined in a20_padconf.c */ #ifdef SOC_ALLWINNER_A20 extern struct allwinner_padconf a20_padconf; struct aw_gpio_conf a20_gpio_conf = { .padconf = &a20_padconf, .banks = "abcdefghi", }; #endif /* Defined in a31_padconf.c */ #ifdef SOC_ALLWINNER_A31 extern struct allwinner_padconf a31_padconf; struct aw_gpio_conf a31_gpio_conf = { .padconf = &a31_padconf, .banks = "abcdefgh", }; #endif /* Defined in a31s_padconf.c */ #ifdef SOC_ALLWINNER_A31S extern struct allwinner_padconf a31s_padconf; struct aw_gpio_conf a31s_gpio_conf = { .padconf = &a31s_padconf, .banks = "abcdefgh", }; #endif #if defined(SOC_ALLWINNER_A31) || defined(SOC_ALLWINNER_A31S) extern struct allwinner_padconf a31_r_padconf; struct aw_gpio_conf a31_r_gpio_conf = { .padconf = &a31_r_padconf, .banks = "lm", }; #endif /* Defined in a33_padconf.c */ #ifdef SOC_ALLWINNER_A33 extern struct allwinner_padconf a33_padconf; struct aw_gpio_conf a33_gpio_conf = { .padconf = &a33_padconf, .banks = "bcdefgh", }; #endif /* Defined in h3_padconf.c */ #if defined(SOC_ALLWINNER_H3) || defined(SOC_ALLWINNER_H5) extern struct allwinner_padconf h3_padconf; extern struct allwinner_padconf h3_r_padconf; struct aw_gpio_conf h3_gpio_conf = { .padconf = &h3_padconf, .banks = "acdefg", }; struct aw_gpio_conf h3_r_gpio_conf = { .padconf = &h3_r_padconf, .banks = "l", }; #endif /* Defined in a83t_padconf.c */ #ifdef SOC_ALLWINNER_A83T extern struct allwinner_padconf a83t_padconf; extern struct allwinner_padconf a83t_r_padconf; struct aw_gpio_conf a83t_gpio_conf = { .padconf = &a83t_padconf, .banks = "bcdefgh" }; struct aw_gpio_conf a83t_r_gpio_conf = { .padconf = &a83t_r_padconf, .banks = "l", }; #endif /* Defined in a64_padconf.c */ #ifdef SOC_ALLWINNER_A64 extern struct allwinner_padconf a64_padconf; extern struct allwinner_padconf a64_r_padconf; struct aw_gpio_conf a64_gpio_conf = { .padconf = &a64_padconf, .banks = "bcdefgh", }; struct aw_gpio_conf a64_r_gpio_conf = { .padconf = &a64_r_padconf, .banks = "l", }; #endif /* Defined in h6_padconf.c */ #ifdef SOC_ALLWINNER_H6 extern struct allwinner_padconf h6_padconf; extern struct allwinner_padconf h6_r_padconf; struct aw_gpio_conf h6_gpio_conf = { .padconf = &h6_padconf, .banks = "cdfgh", }; struct aw_gpio_conf h6_r_gpio_conf = { .padconf = &h6_r_padconf, .banks = "lm", }; #endif static struct ofw_compat_data compat_data[] = { #ifdef SOC_ALLWINNER_A10 {"allwinner,sun4i-a10-pinctrl", (uintptr_t)&a10_gpio_conf}, #endif #ifdef SOC_ALLWINNER_A13 {"allwinner,sun5i-a13-pinctrl", (uintptr_t)&a13_gpio_conf}, #endif #ifdef SOC_ALLWINNER_A20 {"allwinner,sun7i-a20-pinctrl", (uintptr_t)&a20_gpio_conf}, #endif #ifdef SOC_ALLWINNER_A31 {"allwinner,sun6i-a31-pinctrl", (uintptr_t)&a31_gpio_conf}, #endif #ifdef SOC_ALLWINNER_A31S {"allwinner,sun6i-a31s-pinctrl", (uintptr_t)&a31s_gpio_conf}, #endif #if defined(SOC_ALLWINNER_A31) || defined(SOC_ALLWINNER_A31S) {"allwinner,sun6i-a31-r-pinctrl", (uintptr_t)&a31_r_gpio_conf}, #endif #ifdef SOC_ALLWINNER_A33 {"allwinner,sun6i-a33-pinctrl", (uintptr_t)&a33_gpio_conf}, #endif #ifdef SOC_ALLWINNER_A83T {"allwinner,sun8i-a83t-pinctrl", (uintptr_t)&a83t_gpio_conf}, {"allwinner,sun8i-a83t-r-pinctrl", (uintptr_t)&a83t_r_gpio_conf}, #endif #if defined(SOC_ALLWINNER_H3) || defined(SOC_ALLWINNER_H5) {"allwinner,sun8i-h3-pinctrl", (uintptr_t)&h3_gpio_conf}, {"allwinner,sun50i-h5-pinctrl", (uintptr_t)&h3_gpio_conf}, {"allwinner,sun8i-h3-r-pinctrl", (uintptr_t)&h3_r_gpio_conf}, #endif #ifdef SOC_ALLWINNER_A64 {"allwinner,sun50i-a64-pinctrl", (uintptr_t)&a64_gpio_conf}, {"allwinner,sun50i-a64-r-pinctrl", (uintptr_t)&a64_r_gpio_conf}, #endif #ifdef SOC_ALLWINNER_H6 {"allwinner,sun50i-h6-pinctrl", (uintptr_t)&h6_gpio_conf}, {"allwinner,sun50i-h6-r-pinctrl", (uintptr_t)&h6_r_gpio_conf}, #endif {NULL, 0} }; struct clk_list { TAILQ_ENTRY(clk_list) next; clk_t clk; }; struct gpio_irqsrc { struct intr_irqsrc isrc; u_int irq; uint32_t mode; uint32_t pin; uint32_t bank; uint32_t intnum; uint32_t intfunc; uint32_t oldfunc; bool enabled; }; #define AW_GPIO_MEMRES 0 #define AW_GPIO_IRQRES 1 #define AW_GPIO_RESSZ 2 struct aw_gpio_softc { device_t sc_dev; device_t sc_busdev; struct resource * sc_res[AW_GPIO_RESSZ]; struct mtx sc_mtx; struct resource * sc_mem_res; struct resource * sc_irq_res; void * sc_intrhand; struct aw_gpio_conf *conf; TAILQ_HEAD(, clk_list) clk_list; struct gpio_irqsrc *gpio_pic_irqsrc; int nirqs; }; static struct resource_spec aw_gpio_res_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, { -1, 0, 0 } }; #define AW_GPIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx) #define AW_GPIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx) #define AW_GPIO_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) #define AW_GPIO_GP_CFG(_bank, _idx) 0x00 + ((_bank) * 0x24) + ((_idx) << 2) #define AW_GPIO_GP_DAT(_bank) 0x10 + ((_bank) * 0x24) #define AW_GPIO_GP_DRV(_bank, _idx) 0x14 + ((_bank) * 0x24) + ((_idx) << 2) #define AW_GPIO_GP_PUL(_bank, _idx) 0x1c + ((_bank) * 0x24) + ((_idx) << 2) #define AW_GPIO_GP_INT_BASE(_bank) (0x200 + 0x20 * _bank) #define AW_GPIO_GP_INT_CFG(_bank, _pin) (AW_GPIO_GP_INT_BASE(_bank) + (0x4 * ((_pin) / 8))) #define AW_GPIO_GP_INT_CTL(_bank) (AW_GPIO_GP_INT_BASE(_bank) + 0x10) #define AW_GPIO_GP_INT_STA(_bank) (AW_GPIO_GP_INT_BASE(_bank) + 0x14) #define AW_GPIO_GP_INT_DEB(_bank) (AW_GPIO_GP_INT_BASE(_bank) + 0x18) #define AW_GPIO_INT_EDGE_POSITIVE 0x0 #define AW_GPIO_INT_EDGE_NEGATIVE 0x1 #define AW_GPIO_INT_LEVEL_HIGH 0x2 #define AW_GPIO_INT_LEVEL_LOW 0x3 #define AW_GPIO_INT_EDGE_BOTH 0x4 static char *aw_gpio_parse_function(phandle_t node); static const char **aw_gpio_parse_pins(phandle_t node, int *pins_nb); static uint32_t aw_gpio_parse_bias(phandle_t node); static int aw_gpio_parse_drive_strength(phandle_t node, uint32_t *drive); static int aw_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value); static int aw_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value); static int aw_gpio_pin_get_locked(struct aw_gpio_softc *sc, uint32_t pin, unsigned int *value); static int aw_gpio_pin_set_locked(struct aw_gpio_softc *sc, uint32_t pin, unsigned int value); static void aw_gpio_intr(void *arg); static void aw_gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc); static void aw_gpio_pic_disable_intr_locked(struct aw_gpio_softc *sc, struct intr_irqsrc *isrc); static void aw_gpio_pic_post_filter(device_t dev, struct intr_irqsrc *isrc); static int aw_gpio_register_isrcs(struct aw_gpio_softc *sc); #define AW_GPIO_WRITE(_sc, _off, _val) \ bus_write_4((_sc)->sc_res[AW_GPIO_MEMRES], _off, _val) #define AW_GPIO_READ(_sc, _off) \ bus_read_4((_sc)->sc_res[AW_GPIO_MEMRES], _off) static uint32_t aw_gpio_get_function(struct aw_gpio_softc *sc, uint32_t pin) { uint32_t bank, func, offset; /* Must be called with lock held. */ AW_GPIO_LOCK_ASSERT(sc); if (pin > sc->conf->padconf->npins) return (0); bank = sc->conf->padconf->pins[pin].port; pin = sc->conf->padconf->pins[pin].pin; offset = ((pin & 0x07) << 2); func = AW_GPIO_READ(sc, AW_GPIO_GP_CFG(bank, pin >> 3)); return ((func >> offset) & 0x7); } static int aw_gpio_set_function(struct aw_gpio_softc *sc, uint32_t pin, uint32_t f) { uint32_t bank, data, offset; /* Check if the function exists in the padconf data */ if (sc->conf->padconf->pins[pin].functions[f] == NULL) return (EINVAL); /* Must be called with lock held. */ AW_GPIO_LOCK_ASSERT(sc); bank = sc->conf->padconf->pins[pin].port; pin = sc->conf->padconf->pins[pin].pin; offset = ((pin & 0x07) << 2); data = AW_GPIO_READ(sc, AW_GPIO_GP_CFG(bank, pin >> 3)); data &= ~(7 << offset); data |= (f << offset); AW_GPIO_WRITE(sc, AW_GPIO_GP_CFG(bank, pin >> 3), data); return (0); } static uint32_t aw_gpio_get_pud(struct aw_gpio_softc *sc, uint32_t pin) { uint32_t bank, offset, val; /* Must be called with lock held. */ AW_GPIO_LOCK_ASSERT(sc); bank = sc->conf->padconf->pins[pin].port; pin = sc->conf->padconf->pins[pin].pin; offset = ((pin & 0x0f) << 1); val = AW_GPIO_READ(sc, AW_GPIO_GP_PUL(bank, pin >> 4)); return ((val >> offset) & AW_GPIO_PUD_MASK); } static void aw_gpio_set_pud(struct aw_gpio_softc *sc, uint32_t pin, uint32_t state) { uint32_t bank, offset, val; if (aw_gpio_get_pud(sc, pin) == state) return; /* Must be called with lock held. */ AW_GPIO_LOCK_ASSERT(sc); bank = sc->conf->padconf->pins[pin].port; pin = sc->conf->padconf->pins[pin].pin; offset = ((pin & 0x0f) << 1); val = AW_GPIO_READ(sc, AW_GPIO_GP_PUL(bank, pin >> 4)); val &= ~(AW_GPIO_PUD_MASK << offset); val |= (state << offset); AW_GPIO_WRITE(sc, AW_GPIO_GP_PUL(bank, pin >> 4), val); } static uint32_t aw_gpio_get_drv(struct aw_gpio_softc *sc, uint32_t pin) { uint32_t bank, offset, val; /* Must be called with lock held. */ AW_GPIO_LOCK_ASSERT(sc); bank = sc->conf->padconf->pins[pin].port; pin = sc->conf->padconf->pins[pin].pin; offset = ((pin & 0x0f) << 1); val = AW_GPIO_READ(sc, AW_GPIO_GP_DRV(bank, pin >> 4)); return ((val >> offset) & AW_GPIO_DRV_MASK); } static void aw_gpio_set_drv(struct aw_gpio_softc *sc, uint32_t pin, uint32_t drive) { uint32_t bank, offset, val; if (aw_gpio_get_drv(sc, pin) == drive) return; /* Must be called with lock held. */ AW_GPIO_LOCK_ASSERT(sc); bank = sc->conf->padconf->pins[pin].port; pin = sc->conf->padconf->pins[pin].pin; offset = ((pin & 0x0f) << 1); val = AW_GPIO_READ(sc, AW_GPIO_GP_DRV(bank, pin >> 4)); val &= ~(AW_GPIO_DRV_MASK << offset); val |= (drive << offset); AW_GPIO_WRITE(sc, AW_GPIO_GP_DRV(bank, pin >> 4), val); } static int aw_gpio_pin_configure(struct aw_gpio_softc *sc, uint32_t pin, uint32_t flags) { u_int val; int err = 0; /* Must be called with lock held. */ AW_GPIO_LOCK_ASSERT(sc); if (pin > sc->conf->padconf->npins) return (EINVAL); /* Manage input/output. */ if (flags & GPIO_PIN_INPUT) { err = aw_gpio_set_function(sc, pin, AW_GPIO_INPUT); } else if ((flags & GPIO_PIN_OUTPUT) && aw_gpio_get_function(sc, pin) != AW_GPIO_OUTPUT) { if (flags & GPIO_PIN_PRESET_LOW) { aw_gpio_pin_set_locked(sc, pin, 0); } else if (flags & GPIO_PIN_PRESET_HIGH) { aw_gpio_pin_set_locked(sc, pin, 1); } else { /* Read the pin and preset output to current state. */ err = aw_gpio_set_function(sc, pin, AW_GPIO_INPUT); if (err == 0) { aw_gpio_pin_get_locked(sc, pin, &val); aw_gpio_pin_set_locked(sc, pin, val); } } if (err == 0) err = aw_gpio_set_function(sc, pin, AW_GPIO_OUTPUT); } if (err) return (err); /* Manage Pull-up/pull-down. */ if (flags & GPIO_PIN_PULLUP) aw_gpio_set_pud(sc, pin, AW_GPIO_PULLUP); else if (flags & GPIO_PIN_PULLDOWN) aw_gpio_set_pud(sc, pin, AW_GPIO_PULLDOWN); else aw_gpio_set_pud(sc, pin, AW_GPIO_NONE); return (0); } static device_t aw_gpio_get_bus(device_t dev) { struct aw_gpio_softc *sc; sc = device_get_softc(dev); return (sc->sc_busdev); } static int aw_gpio_pin_max(device_t dev, int *maxpin) { struct aw_gpio_softc *sc; sc = device_get_softc(dev); *maxpin = sc->conf->padconf->npins - 1; return (0); } static int aw_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) { struct aw_gpio_softc *sc; sc = device_get_softc(dev); if (pin >= sc->conf->padconf->npins) return (EINVAL); *caps = AW_GPIO_DEFAULT_CAPS; if (sc->conf->padconf->pins[pin].eint_func != 0) *caps |= AW_GPIO_INTR_CAPS; return (0); } static int aw_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) { struct aw_gpio_softc *sc; uint32_t func; uint32_t pud; sc = device_get_softc(dev); if (pin >= sc->conf->padconf->npins) return (EINVAL); AW_GPIO_LOCK(sc); func = aw_gpio_get_function(sc, pin); switch (func) { case AW_GPIO_INPUT: *flags = GPIO_PIN_INPUT; break; case AW_GPIO_OUTPUT: *flags = GPIO_PIN_OUTPUT; break; default: *flags = 0; break; } pud = aw_gpio_get_pud(sc, pin); switch (pud) { case AW_GPIO_PULLDOWN: *flags |= GPIO_PIN_PULLDOWN; break; case AW_GPIO_PULLUP: *flags |= GPIO_PIN_PULLUP; break; default: break; } AW_GPIO_UNLOCK(sc); return (0); } static int aw_gpio_pin_getname(device_t dev, uint32_t pin, char *name) { struct aw_gpio_softc *sc; sc = device_get_softc(dev); if (pin >= sc->conf->padconf->npins) return (EINVAL); snprintf(name, GPIOMAXNAME - 1, "%s", sc->conf->padconf->pins[pin].name); name[GPIOMAXNAME - 1] = '\0'; return (0); } static int aw_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) { struct aw_gpio_softc *sc; int err; sc = device_get_softc(dev); if (pin > sc->conf->padconf->npins) return (EINVAL); AW_GPIO_LOCK(sc); err = aw_gpio_pin_configure(sc, pin, flags); AW_GPIO_UNLOCK(sc); return (err); } static int aw_gpio_pin_set_locked(struct aw_gpio_softc *sc, uint32_t pin, unsigned int value) { uint32_t bank, data; AW_GPIO_LOCK_ASSERT(sc); if (pin > sc->conf->padconf->npins) return (EINVAL); bank = sc->conf->padconf->pins[pin].port; pin = sc->conf->padconf->pins[pin].pin; data = AW_GPIO_READ(sc, AW_GPIO_GP_DAT(bank)); if (value) data |= (1 << pin); else data &= ~(1 << pin); AW_GPIO_WRITE(sc, AW_GPIO_GP_DAT(bank), data); return (0); } static int aw_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) { struct aw_gpio_softc *sc; int ret; sc = device_get_softc(dev); AW_GPIO_LOCK(sc); ret = aw_gpio_pin_set_locked(sc, pin, value); AW_GPIO_UNLOCK(sc); return (ret); } static int aw_gpio_pin_get_locked(struct aw_gpio_softc *sc,uint32_t pin, unsigned int *val) { uint32_t bank, reg_data; AW_GPIO_LOCK_ASSERT(sc); if (pin > sc->conf->padconf->npins) return (EINVAL); bank = sc->conf->padconf->pins[pin].port; pin = sc->conf->padconf->pins[pin].pin; reg_data = AW_GPIO_READ(sc, AW_GPIO_GP_DAT(bank)); *val = (reg_data & (1 << pin)) ? 1 : 0; return (0); } static char * aw_gpio_parse_function(phandle_t node) { char *function; if (OF_getprop_alloc(node, "function", (void **)&function) != -1) return (function); if (OF_getprop_alloc(node, "allwinner,function", (void **)&function) != -1) return (function); return (NULL); } static const char ** aw_gpio_parse_pins(phandle_t node, int *pins_nb) { const char **pinlist; *pins_nb = ofw_bus_string_list_to_array(node, "pins", &pinlist); if (*pins_nb > 0) return (pinlist); *pins_nb = ofw_bus_string_list_to_array(node, "allwinner,pins", &pinlist); if (*pins_nb > 0) return (pinlist); return (NULL); } static uint32_t aw_gpio_parse_bias(phandle_t node) { uint32_t bias; if (OF_getencprop(node, "pull", &bias, sizeof(bias)) != -1) return (bias); if (OF_getencprop(node, "allwinner,pull", &bias, sizeof(bias)) != -1) return (bias); if (OF_hasprop(node, "bias-disable")) return (AW_GPIO_NONE); if (OF_hasprop(node, "bias-pull-up")) return (AW_GPIO_PULLUP); if (OF_hasprop(node, "bias-pull-down")) return (AW_GPIO_PULLDOWN); return (AW_GPIO_NONE); } static int aw_gpio_parse_drive_strength(phandle_t node, uint32_t *drive) { uint32_t drive_str; if (OF_getencprop(node, "drive", drive, sizeof(*drive)) != -1) return (0); if (OF_getencprop(node, "allwinner,drive", drive, sizeof(*drive)) != -1) return (0); if (OF_getencprop(node, "drive-strength", &drive_str, sizeof(drive_str)) != -1) { *drive = (drive_str / 10) - 1; return (0); } return (1); } static int aw_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) { struct aw_gpio_softc *sc; int ret; sc = device_get_softc(dev); AW_GPIO_LOCK(sc); ret = aw_gpio_pin_get_locked(sc, pin, val); AW_GPIO_UNLOCK(sc); return (ret); } static int aw_gpio_pin_toggle(device_t dev, uint32_t pin) { struct aw_gpio_softc *sc; uint32_t bank, data; sc = device_get_softc(dev); if (pin > sc->conf->padconf->npins) return (EINVAL); bank = sc->conf->padconf->pins[pin].port; pin = sc->conf->padconf->pins[pin].pin; AW_GPIO_LOCK(sc); data = AW_GPIO_READ(sc, AW_GPIO_GP_DAT(bank)); if (data & (1 << pin)) data &= ~(1 << pin); else data |= (1 << pin); AW_GPIO_WRITE(sc, AW_GPIO_GP_DAT(bank), data); AW_GPIO_UNLOCK(sc); return (0); } static int aw_gpio_pin_access_32(device_t dev, uint32_t first_pin, uint32_t clear_pins, uint32_t change_pins, uint32_t *orig_pins) { struct aw_gpio_softc *sc; uint32_t bank, data, pin; sc = device_get_softc(dev); if (first_pin > sc->conf->padconf->npins) return (EINVAL); /* * We require that first_pin refers to the first pin in a bank, because * this API is not about convenience, it's for making a set of pins * change simultaneously (required) with reasonably high performance * (desired); we need to do a read-modify-write on a single register. */ bank = sc->conf->padconf->pins[first_pin].port; pin = sc->conf->padconf->pins[first_pin].pin; if (pin != 0) return (EINVAL); AW_GPIO_LOCK(sc); data = AW_GPIO_READ(sc, AW_GPIO_GP_DAT(bank)); if ((clear_pins | change_pins) != 0) AW_GPIO_WRITE(sc, AW_GPIO_GP_DAT(bank), (data & ~clear_pins) ^ change_pins); AW_GPIO_UNLOCK(sc); if (orig_pins != NULL) *orig_pins = data; return (0); } static int aw_gpio_pin_config_32(device_t dev, uint32_t first_pin, uint32_t num_pins, uint32_t *pin_flags) { struct aw_gpio_softc *sc; uint32_t pin; int err; sc = device_get_softc(dev); if (first_pin > sc->conf->padconf->npins) return (EINVAL); if (sc->conf->padconf->pins[first_pin].pin != 0) return (EINVAL); /* * The configuration for a bank of pins is scattered among several * registers; we cannot g'tee to simultaneously change the state of all * the pins in the flags array. So just loop through the array * configuring each pin for now. If there was a strong need, it might * be possible to support some limited simultaneous config, such as * adjacent groups of 8 pins that line up the same as the config regs. */ for (err = 0, pin = first_pin; err == 0 && pin < num_pins; ++pin) { if (pin_flags[pin] & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) err = aw_gpio_pin_configure(sc, pin, pin_flags[pin]); } return (err); } static int aw_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags) { struct aw_gpio_softc *sc; int i; sc = device_get_softc(bus); /* The GPIO pins are mapped as: . */ for (i = 0; i < sc->conf->padconf->npins; i++) if (sc->conf->padconf->pins[i].port == gpios[0] && sc->conf->padconf->pins[i].pin == gpios[1]) { *pin = i; break; } *flags = gpios[gcells - 1]; return (0); } static int aw_find_pinnum_by_name(struct aw_gpio_softc *sc, const char *pinname) { int i; for (i = 0; i < sc->conf->padconf->npins; i++) if (!strcmp(pinname, sc->conf->padconf->pins[i].name)) return i; return (-1); } static int aw_find_pin_func(struct aw_gpio_softc *sc, int pin, const char *func) { int i; for (i = 0; i < AW_MAX_FUNC_BY_PIN; i++) if (sc->conf->padconf->pins[pin].functions[i] && !strcmp(func, sc->conf->padconf->pins[pin].functions[i])) return (i); return (-1); } static int aw_fdt_configure_pins(device_t dev, phandle_t cfgxref) { struct aw_gpio_softc *sc; phandle_t node; const char **pinlist = NULL; char *pin_function = NULL; uint32_t pin_drive, pin_pull; int pins_nb, pin_num, pin_func, i, ret; bool set_drive; sc = device_get_softc(dev); node = OF_node_from_xref(cfgxref); ret = 0; set_drive = false; /* Getting all prop for configuring pins */ pinlist = aw_gpio_parse_pins(node, &pins_nb); if (pinlist == NULL) return (ENOENT); pin_function = aw_gpio_parse_function(node); if (pin_function == NULL) { ret = ENOENT; goto out; } if (aw_gpio_parse_drive_strength(node, &pin_drive) == 0) set_drive = true; pin_pull = aw_gpio_parse_bias(node); /* Configure each pin to the correct function, drive and pull */ for (i = 0; i < pins_nb; i++) { pin_num = aw_find_pinnum_by_name(sc, pinlist[i]); if (pin_num == -1) { ret = ENOENT; goto out; } pin_func = aw_find_pin_func(sc, pin_num, pin_function); if (pin_func == -1) { ret = ENOENT; goto out; } AW_GPIO_LOCK(sc); if (aw_gpio_get_function(sc, pin_num) != pin_func) aw_gpio_set_function(sc, pin_num, pin_func); if (set_drive) aw_gpio_set_drv(sc, pin_num, pin_drive); if (pin_pull != AW_GPIO_NONE) aw_gpio_set_pud(sc, pin_num, pin_pull); AW_GPIO_UNLOCK(sc); } out: OF_prop_free(pinlist); OF_prop_free(pin_function); return (ret); } static void aw_gpio_enable_bank_supply(void *arg) { struct aw_gpio_softc *sc = arg; regulator_t vcc_supply; char bank_reg_name[16]; int i, nbanks; nbanks = strlen(sc->conf->banks); for (i = 0; i < nbanks; i++) { snprintf(bank_reg_name, sizeof(bank_reg_name), "vcc-p%c-supply", sc->conf->banks[i]); if (regulator_get_by_ofw_property(sc->sc_dev, 0, bank_reg_name, &vcc_supply) == 0) { if (bootverbose) device_printf(sc->sc_dev, "Enabling regulator for gpio bank %c\n", sc->conf->banks[i]); if (regulator_enable(vcc_supply) != 0) { device_printf(sc->sc_dev, "Cannot enable regulator for bank %c\n", sc->conf->banks[i]); } } } } static int aw_gpio_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Allwinner GPIO/Pinmux controller"); return (BUS_PROBE_DEFAULT); } static int aw_gpio_attach(device_t dev) { int error; phandle_t gpio; struct aw_gpio_softc *sc; struct clk_list *clkp, *clkp_tmp; clk_t clk; hwreset_t rst = NULL; int off, err, clkret; sc = device_get_softc(dev); sc->sc_dev = dev; mtx_init(&sc->sc_mtx, "aw gpio", "gpio", MTX_SPIN); if (bus_alloc_resources(dev, aw_gpio_res_spec, sc->sc_res) != 0) { device_printf(dev, "cannot allocate device resources\n"); return (ENXIO); } if (bus_setup_intr(dev, sc->sc_res[AW_GPIO_IRQRES], INTR_TYPE_CLK | INTR_MPSAFE, NULL, aw_gpio_intr, sc, &sc->sc_intrhand)) { device_printf(dev, "cannot setup interrupt handler\n"); goto fail; } /* Find our node. */ gpio = ofw_bus_get_node(sc->sc_dev); if (!OF_hasprop(gpio, "gpio-controller")) /* Node is not a GPIO controller. */ goto fail; /* Use the right pin data for the current SoC */ sc->conf = (struct aw_gpio_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; if (hwreset_get_by_ofw_idx(dev, 0, 0, &rst) == 0) { error = hwreset_deassert(rst); if (error != 0) { device_printf(dev, "cannot de-assert reset\n"); goto fail; } } TAILQ_INIT(&sc->clk_list); for (off = 0, clkret = 0; clkret == 0; off++) { clkret = clk_get_by_ofw_index(dev, 0, off, &clk); if (clkret != 0) break; err = clk_enable(clk); if (err != 0) { device_printf(dev, "Could not enable clock %s\n", clk_get_name(clk)); goto fail; } clkp = malloc(sizeof(*clkp), M_DEVBUF, M_WAITOK | M_ZERO); clkp->clk = clk; TAILQ_INSERT_TAIL(&sc->clk_list, clkp, next); } if (clkret != 0 && clkret != ENOENT) { device_printf(dev, "Could not find clock at offset %d (%d)\n", off, clkret); goto fail; } aw_gpio_register_isrcs(sc); intr_pic_register(dev, OF_xref_from_node(ofw_bus_get_node(dev))); sc->sc_busdev = gpiobus_attach_bus(dev); if (sc->sc_busdev == NULL) goto fail; /* * Register as a pinctrl device */ fdt_pinctrl_register(dev, "pins"); fdt_pinctrl_configure_tree(dev); fdt_pinctrl_register(dev, "allwinner,pins"); fdt_pinctrl_configure_tree(dev); config_intrhook_oneshot(aw_gpio_enable_bank_supply, sc); return (0); fail: if (sc->sc_irq_res) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); if (sc->sc_mem_res) bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); mtx_destroy(&sc->sc_mtx); /* Disable clock */ TAILQ_FOREACH_SAFE(clkp, &sc->clk_list, next, clkp_tmp) { err = clk_disable(clkp->clk); if (err != 0) device_printf(dev, "Could not disable clock %s\n", clk_get_name(clkp->clk)); err = clk_release(clkp->clk); if (err != 0) device_printf(dev, "Could not release clock %s\n", clk_get_name(clkp->clk)); TAILQ_REMOVE(&sc->clk_list, clkp, next); free(clkp, M_DEVBUF); } /* Assert resets */ if (rst) { hwreset_assert(rst); hwreset_release(rst); } return (ENXIO); } static int aw_gpio_detach(device_t dev) { return (EBUSY); } static void aw_gpio_intr(void *arg) { struct aw_gpio_softc *sc; struct intr_irqsrc *isrc; uint32_t reg; int irq; sc = (struct aw_gpio_softc *)arg; AW_GPIO_LOCK(sc); for (irq = 0; irq < sc->nirqs; irq++) { if (!sc->gpio_pic_irqsrc[irq].enabled) continue; reg = AW_GPIO_READ(sc, AW_GPIO_GP_INT_STA(sc->gpio_pic_irqsrc[irq].bank)); if (!(reg & (1 << sc->gpio_pic_irqsrc[irq].intnum))) continue; isrc = &sc->gpio_pic_irqsrc[irq].isrc; if (intr_isrc_dispatch(isrc, curthread->td_intr_frame) != 0) { aw_gpio_pic_disable_intr_locked(sc, isrc); aw_gpio_pic_post_filter(sc->sc_dev, isrc); device_printf(sc->sc_dev, "Stray irq %u disabled\n", irq); } } AW_GPIO_UNLOCK(sc); } /* * Interrupts support */ static int aw_gpio_register_isrcs(struct aw_gpio_softc *sc) { const char *name; int nirqs; int pin; int err; name = device_get_nameunit(sc->sc_dev); for (nirqs = 0, pin = 0; pin < sc->conf->padconf->npins; pin++) { if (sc->conf->padconf->pins[pin].eint_func == 0) continue; nirqs++; } sc->gpio_pic_irqsrc = malloc(sizeof(*sc->gpio_pic_irqsrc) * nirqs, M_DEVBUF, M_WAITOK | M_ZERO); for (nirqs = 0, pin = 0; pin < sc->conf->padconf->npins; pin++) { if (sc->conf->padconf->pins[pin].eint_func == 0) continue; sc->gpio_pic_irqsrc[nirqs].pin = pin; sc->gpio_pic_irqsrc[nirqs].bank = sc->conf->padconf->pins[pin].eint_bank; sc->gpio_pic_irqsrc[nirqs].intnum = sc->conf->padconf->pins[pin].eint_num; sc->gpio_pic_irqsrc[nirqs].intfunc = sc->conf->padconf->pins[pin].eint_func; sc->gpio_pic_irqsrc[nirqs].irq = nirqs; sc->gpio_pic_irqsrc[nirqs].mode = GPIO_INTR_CONFORM; err = intr_isrc_register(&sc->gpio_pic_irqsrc[nirqs].isrc, sc->sc_dev, 0, "%s,%s", name, sc->conf->padconf->pins[pin].functions[sc->conf->padconf->pins[pin].eint_func]); if (err) { device_printf(sc->sc_dev, "intr_isrs_register failed for irq %d\n", nirqs); } nirqs++; } sc->nirqs = nirqs; return (0); } static void aw_gpio_pic_disable_intr_locked(struct aw_gpio_softc *sc, struct intr_irqsrc *isrc) { u_int irq; uint32_t reg; AW_GPIO_LOCK_ASSERT(sc); irq = ((struct gpio_irqsrc *)isrc)->irq; reg = AW_GPIO_READ(sc, AW_GPIO_GP_INT_CTL(sc->gpio_pic_irqsrc[irq].bank)); reg &= ~(1 << sc->gpio_pic_irqsrc[irq].intnum); AW_GPIO_WRITE(sc, AW_GPIO_GP_INT_CTL(sc->gpio_pic_irqsrc[irq].bank), reg); sc->gpio_pic_irqsrc[irq].enabled = false; } static void aw_gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc) { struct aw_gpio_softc *sc; sc = device_get_softc(dev); AW_GPIO_LOCK(sc); aw_gpio_pic_disable_intr_locked(sc, isrc); AW_GPIO_UNLOCK(sc); } static void aw_gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc) { struct aw_gpio_softc *sc; u_int irq; uint32_t reg; sc = device_get_softc(dev); irq = ((struct gpio_irqsrc *)isrc)->irq; AW_GPIO_LOCK(sc); reg = AW_GPIO_READ(sc, AW_GPIO_GP_INT_CTL(sc->gpio_pic_irqsrc[irq].bank)); reg |= 1 << sc->gpio_pic_irqsrc[irq].intnum; AW_GPIO_WRITE(sc, AW_GPIO_GP_INT_CTL(sc->gpio_pic_irqsrc[irq].bank), reg); AW_GPIO_UNLOCK(sc); sc->gpio_pic_irqsrc[irq].enabled = true; } static int aw_gpio_pic_map_gpio(struct aw_gpio_softc *sc, struct intr_map_data_gpio *dag, u_int *irqp, u_int *mode) { u_int irq; int pin; irq = dag->gpio_pin_num; for (pin = 0; pin < sc->nirqs; pin++) if (sc->gpio_pic_irqsrc[pin].pin == irq) break; if (pin == sc->nirqs) { device_printf(sc->sc_dev, "Invalid interrupt number %u\n", irq); return (EINVAL); } switch (dag->gpio_intr_mode) { case GPIO_INTR_LEVEL_LOW: case GPIO_INTR_LEVEL_HIGH: case GPIO_INTR_EDGE_RISING: case GPIO_INTR_EDGE_FALLING: case GPIO_INTR_EDGE_BOTH: break; default: device_printf(sc->sc_dev, "Unsupported interrupt mode 0x%8x\n", dag->gpio_intr_mode); return (EINVAL); } *irqp = pin; if (mode != NULL) *mode = dag->gpio_intr_mode; return (0); } static int aw_gpio_pic_map_intr(device_t dev, struct intr_map_data *data, struct intr_irqsrc **isrcp) { struct aw_gpio_softc *sc; u_int irq; int err; sc = device_get_softc(dev); switch (data->type) { case INTR_MAP_DATA_GPIO: err = aw_gpio_pic_map_gpio(sc, (struct intr_map_data_gpio *)data, &irq, NULL); break; default: return (ENOTSUP); }; if (err == 0) *isrcp = &sc->gpio_pic_irqsrc[irq].isrc; return (0); } static int aw_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc, struct resource *res, struct intr_map_data *data) { struct aw_gpio_softc *sc; uint32_t irqcfg; uint32_t pinidx, reg; u_int irq, mode; int err; sc = device_get_softc(dev); err = 0; switch (data->type) { case INTR_MAP_DATA_GPIO: err = aw_gpio_pic_map_gpio(sc, (struct intr_map_data_gpio *)data, &irq, &mode); if (err != 0) return (err); break; default: return (ENOTSUP); }; pinidx = (sc->gpio_pic_irqsrc[irq].intnum % 8) * 4; AW_GPIO_LOCK(sc); switch (mode) { case GPIO_INTR_LEVEL_LOW: irqcfg = AW_GPIO_INT_LEVEL_LOW << pinidx; break; case GPIO_INTR_LEVEL_HIGH: irqcfg = AW_GPIO_INT_LEVEL_HIGH << pinidx; break; case GPIO_INTR_EDGE_RISING: irqcfg = AW_GPIO_INT_EDGE_POSITIVE << pinidx; break; case GPIO_INTR_EDGE_FALLING: irqcfg = AW_GPIO_INT_EDGE_NEGATIVE << pinidx; break; case GPIO_INTR_EDGE_BOTH: irqcfg = AW_GPIO_INT_EDGE_BOTH << pinidx; break; } /* Switch the pin to interrupt mode */ sc->gpio_pic_irqsrc[irq].oldfunc = aw_gpio_get_function(sc, sc->gpio_pic_irqsrc[irq].pin); aw_gpio_set_function(sc, sc->gpio_pic_irqsrc[irq].pin, sc->gpio_pic_irqsrc[irq].intfunc); /* Write interrupt mode */ reg = AW_GPIO_READ(sc, AW_GPIO_GP_INT_CFG(sc->gpio_pic_irqsrc[irq].bank, sc->gpio_pic_irqsrc[irq].intnum)); reg &= ~(0xF << pinidx); reg |= irqcfg; AW_GPIO_WRITE(sc, AW_GPIO_GP_INT_CFG(sc->gpio_pic_irqsrc[irq].bank, sc->gpio_pic_irqsrc[irq].intnum), reg); AW_GPIO_UNLOCK(sc); return (0); } static int aw_gpio_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc, struct resource *res, struct intr_map_data *data) { struct aw_gpio_softc *sc; struct gpio_irqsrc *gi; sc = device_get_softc(dev); gi = (struct gpio_irqsrc *)isrc; /* Switch back the pin to it's original function */ AW_GPIO_LOCK(sc); aw_gpio_set_function(sc, gi->pin, gi->oldfunc); AW_GPIO_UNLOCK(sc); return (0); } static void aw_gpio_pic_post_filter(device_t dev, struct intr_irqsrc *isrc) { struct aw_gpio_softc *sc; struct gpio_irqsrc *gi; sc = device_get_softc(dev); gi = (struct gpio_irqsrc *)isrc; arm_irq_memory_barrier(0); AW_GPIO_WRITE(sc, AW_GPIO_GP_INT_STA(gi->bank), 1 << gi->intnum); } static void aw_gpio_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc) { struct aw_gpio_softc *sc; struct gpio_irqsrc *gi; sc = device_get_softc(dev); gi = (struct gpio_irqsrc *)isrc; arm_irq_memory_barrier(0); AW_GPIO_WRITE(sc, AW_GPIO_GP_INT_STA(gi->bank), 1 << gi->intnum); aw_gpio_pic_enable_intr(dev, isrc); } static void aw_gpio_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) { struct aw_gpio_softc *sc; sc = device_get_softc(dev); aw_gpio_pic_disable_intr_locked(sc, isrc); } /* * OFWBUS Interface */ static phandle_t aw_gpio_get_node(device_t dev, device_t bus) { /* We only have one child, the GPIO bus, which needs our own node. */ return (ofw_bus_get_node(dev)); } static device_method_t aw_gpio_methods[] = { /* Device interface */ DEVMETHOD(device_probe, aw_gpio_probe), DEVMETHOD(device_attach, aw_gpio_attach), DEVMETHOD(device_detach, aw_gpio_detach), /* Interrupt controller interface */ DEVMETHOD(pic_disable_intr, aw_gpio_pic_disable_intr), DEVMETHOD(pic_enable_intr, aw_gpio_pic_enable_intr), DEVMETHOD(pic_map_intr, aw_gpio_pic_map_intr), DEVMETHOD(pic_setup_intr, aw_gpio_pic_setup_intr), DEVMETHOD(pic_teardown_intr, aw_gpio_pic_teardown_intr), DEVMETHOD(pic_post_filter, aw_gpio_pic_post_filter), DEVMETHOD(pic_post_ithread, aw_gpio_pic_post_ithread), DEVMETHOD(pic_pre_ithread, aw_gpio_pic_pre_ithread), /* GPIO protocol */ DEVMETHOD(gpio_get_bus, aw_gpio_get_bus), DEVMETHOD(gpio_pin_max, aw_gpio_pin_max), DEVMETHOD(gpio_pin_getname, aw_gpio_pin_getname), DEVMETHOD(gpio_pin_getflags, aw_gpio_pin_getflags), DEVMETHOD(gpio_pin_getcaps, aw_gpio_pin_getcaps), DEVMETHOD(gpio_pin_setflags, aw_gpio_pin_setflags), DEVMETHOD(gpio_pin_get, aw_gpio_pin_get), DEVMETHOD(gpio_pin_set, aw_gpio_pin_set), DEVMETHOD(gpio_pin_toggle, aw_gpio_pin_toggle), DEVMETHOD(gpio_pin_access_32, aw_gpio_pin_access_32), DEVMETHOD(gpio_pin_config_32, aw_gpio_pin_config_32), DEVMETHOD(gpio_map_gpios, aw_gpio_map_gpios), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_node, aw_gpio_get_node), /* fdt_pinctrl interface */ DEVMETHOD(fdt_pinctrl_configure,aw_fdt_configure_pins), DEVMETHOD_END }; static driver_t aw_gpio_driver = { "gpio", aw_gpio_methods, sizeof(struct aw_gpio_softc), }; EARLY_DRIVER_MODULE(aw_gpio, simplebus, aw_gpio_driver, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); diff --git a/sys/arm/allwinner/aw_mmc.c b/sys/arm/allwinner/aw_mmc.c index d229fba1e07d..929cbd8f3ed8 100644 --- a/sys/arm/allwinner/aw_mmc.c +++ b/sys/arm/allwinner/aw_mmc.c @@ -1,1520 +1,1520 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018 Emmanuel Vadot * Copyright (c) 2013 Alexander Fedorov * All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include "opt_mmccam.h" #ifdef MMCCAM #include #include #include #include #include #include #include "mmc_sim_if.h" #endif #include "mmc_pwrseq_if.h" #define AW_MMC_MEMRES 0 #define AW_MMC_IRQRES 1 #define AW_MMC_RESSZ 2 #define AW_MMC_DMA_SEGS (PAGE_SIZE / sizeof(struct aw_mmc_dma_desc)) #define AW_MMC_DMA_DESC_SIZE (sizeof(struct aw_mmc_dma_desc) * AW_MMC_DMA_SEGS) #define AW_MMC_DMA_FTRGLEVEL 0x20070008 #define AW_MMC_RESET_RETRY 1000 #define CARD_ID_FREQUENCY 400000 struct aw_mmc_conf { uint32_t dma_xferlen; bool mask_data0; bool can_calibrate; bool new_timing; }; static const struct aw_mmc_conf a10_mmc_conf = { .dma_xferlen = 0x2000, }; static const struct aw_mmc_conf a13_mmc_conf = { .dma_xferlen = 0x10000, }; static const struct aw_mmc_conf a64_mmc_conf = { .dma_xferlen = 0x10000, .mask_data0 = true, .can_calibrate = true, .new_timing = true, }; static const struct aw_mmc_conf a64_emmc_conf = { .dma_xferlen = 0x2000, .can_calibrate = true, }; static struct ofw_compat_data compat_data[] = { {"allwinner,sun4i-a10-mmc", (uintptr_t)&a10_mmc_conf}, {"allwinner,sun5i-a13-mmc", (uintptr_t)&a13_mmc_conf}, {"allwinner,sun7i-a20-mmc", (uintptr_t)&a13_mmc_conf}, {"allwinner,sun50i-a64-mmc", (uintptr_t)&a64_mmc_conf}, {"allwinner,sun50i-a64-emmc", (uintptr_t)&a64_emmc_conf}, {NULL, 0} }; struct aw_mmc_softc { device_t aw_dev; clk_t aw_clk_ahb; clk_t aw_clk_mmc; hwreset_t aw_rst_ahb; int aw_bus_busy; int aw_resid; int aw_timeout; struct callout aw_timeoutc; struct mmc_host aw_host; struct mmc_helper mmc_helper; #ifdef MMCCAM union ccb * ccb; struct mmc_sim mmc_sim; #else struct mmc_request * aw_req; #endif struct mtx aw_mtx; struct resource * aw_res[AW_MMC_RESSZ]; struct aw_mmc_conf * aw_mmc_conf; uint32_t aw_intr; uint32_t aw_intr_wait; void * aw_intrhand; unsigned int aw_clock; device_t child; /* Fields required for DMA access. */ bus_addr_t aw_dma_desc_phys; bus_dmamap_t aw_dma_map; bus_dma_tag_t aw_dma_tag; void * aw_dma_desc; bus_dmamap_t aw_dma_buf_map; bus_dma_tag_t aw_dma_buf_tag; int aw_dma_map_err; }; static struct resource_spec aw_mmc_res_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, { -1, 0, 0 } }; static int aw_mmc_probe(device_t); static int aw_mmc_attach(device_t); static int aw_mmc_detach(device_t); static int aw_mmc_setup_dma(struct aw_mmc_softc *); static void aw_mmc_teardown_dma(struct aw_mmc_softc *sc); static int aw_mmc_reset(struct aw_mmc_softc *); static int aw_mmc_init(struct aw_mmc_softc *); static void aw_mmc_intr(void *); static int aw_mmc_update_clock(struct aw_mmc_softc *, uint32_t); static void aw_mmc_helper_cd_handler(device_t, bool); static void aw_mmc_print_error(uint32_t); static int aw_mmc_update_ios(device_t, device_t); static int aw_mmc_request(device_t, device_t, struct mmc_request *); #ifndef MMCCAM static int aw_mmc_get_ro(device_t, device_t); static int aw_mmc_acquire_host(device_t, device_t); static int aw_mmc_release_host(device_t, device_t); #endif #define AW_MMC_LOCK(_sc) mtx_lock(&(_sc)->aw_mtx) #define AW_MMC_UNLOCK(_sc) mtx_unlock(&(_sc)->aw_mtx) #define AW_MMC_READ_4(_sc, _reg) \ bus_read_4((_sc)->aw_res[AW_MMC_MEMRES], _reg) #define AW_MMC_WRITE_4(_sc, _reg, _value) \ bus_write_4((_sc)->aw_res[AW_MMC_MEMRES], _reg, _value) SYSCTL_NODE(_hw, OID_AUTO, aw_mmc, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "aw_mmc driver"); static int aw_mmc_debug = 0; SYSCTL_INT(_hw_aw_mmc, OID_AUTO, debug, CTLFLAG_RWTUN, &aw_mmc_debug, 0, "Debug level bit0=card changes bit1=ios changes, bit2=interrupts, bit3=commands"); #define AW_MMC_DEBUG_CARD 0x1 #define AW_MMC_DEBUG_IOS 0x2 #define AW_MMC_DEBUG_INT 0x4 #define AW_MMC_DEBUG_CMD 0x8 #ifdef MMCCAM static int aw_mmc_get_tran_settings(device_t dev, struct ccb_trans_settings_mmc *cts) { struct aw_mmc_softc *sc; sc = device_get_softc(dev); cts->host_ocr = sc->aw_host.host_ocr; cts->host_f_min = sc->aw_host.f_min; cts->host_f_max = sc->aw_host.f_max; cts->host_caps = sc->aw_host.caps; cts->host_max_data = (sc->aw_mmc_conf->dma_xferlen * AW_MMC_DMA_SEGS) / MMC_SECTOR_SIZE; memcpy(&cts->ios, &sc->aw_host.ios, sizeof(struct mmc_ios)); return (0); } static int aw_mmc_set_tran_settings(device_t dev, struct ccb_trans_settings_mmc *cts) { struct aw_mmc_softc *sc; struct mmc_ios *ios; struct mmc_ios *new_ios; sc = device_get_softc(dev); ios = &sc->aw_host.ios; new_ios = &cts->ios; /* Update only requested fields */ if (cts->ios_valid & MMC_CLK) { ios->clock = new_ios->clock; if (__predict_false(aw_mmc_debug & AW_MMC_DEBUG_IOS)) device_printf(sc->aw_dev, "Clock => %d\n", ios->clock); } if (cts->ios_valid & MMC_VDD) { ios->vdd = new_ios->vdd; if (__predict_false(aw_mmc_debug & AW_MMC_DEBUG_IOS)) device_printf(sc->aw_dev, "VDD => %d\n", ios->vdd); } if (cts->ios_valid & MMC_CS) { ios->chip_select = new_ios->chip_select; if (__predict_false(aw_mmc_debug & AW_MMC_DEBUG_IOS)) device_printf(sc->aw_dev, "CS => %d\n", ios->chip_select); } if (cts->ios_valid & MMC_BW) { ios->bus_width = new_ios->bus_width; if (__predict_false(aw_mmc_debug & AW_MMC_DEBUG_IOS)) device_printf(sc->aw_dev, "Bus width => %d\n", ios->bus_width); } if (cts->ios_valid & MMC_PM) { ios->power_mode = new_ios->power_mode; if (__predict_false(aw_mmc_debug & AW_MMC_DEBUG_IOS)) device_printf(sc->aw_dev, "Power mode => %d\n", ios->power_mode); } if (cts->ios_valid & MMC_BT) { ios->timing = new_ios->timing; if (__predict_false(aw_mmc_debug & AW_MMC_DEBUG_IOS)) device_printf(sc->aw_dev, "Timing => %d\n", ios->timing); } if (cts->ios_valid & MMC_BM) { ios->bus_mode = new_ios->bus_mode; if (__predict_false(aw_mmc_debug & AW_MMC_DEBUG_IOS)) device_printf(sc->aw_dev, "Bus mode => %d\n", ios->bus_mode); } return (aw_mmc_update_ios(sc->aw_dev, NULL)); } static int aw_mmc_cam_request(device_t dev, union ccb *ccb) { struct aw_mmc_softc *sc; struct ccb_mmcio *mmcio; sc = device_get_softc(dev); mmcio = &ccb->mmcio; AW_MMC_LOCK(sc); if (__predict_false(aw_mmc_debug & AW_MMC_DEBUG_CMD)) { device_printf(sc->aw_dev, "CMD%u arg %#x flags %#x dlen %u dflags %#x\n", mmcio->cmd.opcode, mmcio->cmd.arg, mmcio->cmd.flags, mmcio->cmd.data != NULL ? (unsigned int) mmcio->cmd.data->len : 0, mmcio->cmd.data != NULL ? mmcio->cmd.data->flags: 0); } if (mmcio->cmd.data != NULL) { if (mmcio->cmd.data->len == 0 || mmcio->cmd.data->flags == 0) panic("data->len = %d, data->flags = %d -- something is b0rked", (int)mmcio->cmd.data->len, mmcio->cmd.data->flags); } if (sc->ccb != NULL) { device_printf(sc->aw_dev, "Controller still has an active command\n"); return (EBUSY); } sc->ccb = ccb; /* aw_mmc_request locks again */ AW_MMC_UNLOCK(sc); aw_mmc_request(sc->aw_dev, NULL, NULL); return (0); } static void aw_mmc_cam_poll(device_t dev) { struct aw_mmc_softc *sc; sc = device_get_softc(dev); aw_mmc_intr(sc); } #endif /* MMCCAM */ static void aw_mmc_helper_cd_handler(device_t dev, bool present) { struct aw_mmc_softc *sc; sc = device_get_softc(dev); #ifdef MMCCAM mmc_cam_sim_discover(&sc->mmc_sim); #else AW_MMC_LOCK(sc); if (present) { if (sc->child == NULL) { if (__predict_false(aw_mmc_debug & AW_MMC_DEBUG_CARD)) device_printf(sc->aw_dev, "Card inserted\n"); sc->child = device_add_child(sc->aw_dev, "mmc", -1); AW_MMC_UNLOCK(sc); if (sc->child) { device_set_ivars(sc->child, sc); (void)device_probe_and_attach(sc->child); } } else AW_MMC_UNLOCK(sc); } else { /* Card isn't present, detach if necessary */ if (sc->child != NULL) { if (__predict_false(aw_mmc_debug & AW_MMC_DEBUG_CARD)) device_printf(sc->aw_dev, "Card removed\n"); AW_MMC_UNLOCK(sc); device_delete_child(sc->aw_dev, sc->child); sc->child = NULL; } else AW_MMC_UNLOCK(sc); } #endif /* MMCCAM */ } static int aw_mmc_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Allwinner Integrated MMC/SD controller"); return (BUS_PROBE_DEFAULT); } static int aw_mmc_attach(device_t dev) { struct aw_mmc_softc *sc; struct sysctl_ctx_list *ctx; struct sysctl_oid_list *tree; int error; sc = device_get_softc(dev); sc->aw_dev = dev; sc->aw_mmc_conf = (struct aw_mmc_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; #ifndef MMCCAM sc->aw_req = NULL; #endif if (bus_alloc_resources(dev, aw_mmc_res_spec, sc->aw_res) != 0) { device_printf(dev, "cannot allocate device resources\n"); return (ENXIO); } if (bus_setup_intr(dev, sc->aw_res[AW_MMC_IRQRES], INTR_TYPE_NET | INTR_MPSAFE, NULL, aw_mmc_intr, sc, &sc->aw_intrhand)) { bus_release_resources(dev, aw_mmc_res_spec, sc->aw_res); device_printf(dev, "cannot setup interrupt handler\n"); return (ENXIO); } mtx_init(&sc->aw_mtx, device_get_nameunit(sc->aw_dev), "aw_mmc", MTX_DEF); callout_init_mtx(&sc->aw_timeoutc, &sc->aw_mtx, 0); /* De-assert reset */ if (hwreset_get_by_ofw_name(dev, 0, "ahb", &sc->aw_rst_ahb) == 0) { error = hwreset_deassert(sc->aw_rst_ahb); if (error != 0) { device_printf(dev, "cannot de-assert reset\n"); goto fail; } } /* Activate the module clock. */ error = clk_get_by_ofw_name(dev, 0, "ahb", &sc->aw_clk_ahb); if (error != 0) { device_printf(dev, "cannot get ahb clock\n"); goto fail; } error = clk_enable(sc->aw_clk_ahb); if (error != 0) { device_printf(dev, "cannot enable ahb clock\n"); goto fail; } error = clk_get_by_ofw_name(dev, 0, "mmc", &sc->aw_clk_mmc); if (error != 0) { device_printf(dev, "cannot get mmc clock\n"); goto fail; } error = clk_set_freq(sc->aw_clk_mmc, CARD_ID_FREQUENCY, CLK_SET_ROUND_DOWN); if (error != 0) { device_printf(dev, "cannot init mmc clock\n"); goto fail; } error = clk_enable(sc->aw_clk_mmc); if (error != 0) { device_printf(dev, "cannot enable mmc clock\n"); goto fail; } sc->aw_timeout = 10; ctx = device_get_sysctl_ctx(dev); tree = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); SYSCTL_ADD_INT(ctx, tree, OID_AUTO, "req_timeout", CTLFLAG_RW, &sc->aw_timeout, 0, "Request timeout in seconds"); /* Soft Reset controller. */ if (aw_mmc_reset(sc) != 0) { device_printf(dev, "cannot reset the controller\n"); goto fail; } if (aw_mmc_setup_dma(sc) != 0) { device_printf(sc->aw_dev, "Couldn't setup DMA!\n"); goto fail; } /* Set some defaults for freq and supported mode */ sc->aw_host.f_min = 400000; sc->aw_host.f_max = 52000000; sc->aw_host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340; sc->aw_host.caps |= MMC_CAP_HSPEED | MMC_CAP_SIGNALING_330; mmc_fdt_parse(dev, 0, &sc->mmc_helper, &sc->aw_host); mmc_fdt_gpio_setup(dev, 0, &sc->mmc_helper, aw_mmc_helper_cd_handler); #ifdef MMCCAM sc->ccb = NULL; if (mmc_cam_sim_alloc(dev, "aw_mmc", &sc->mmc_sim) != 0) { device_printf(dev, "cannot alloc cam sim\n"); goto fail; } #endif /* MMCCAM */ return (0); fail: callout_drain(&sc->aw_timeoutc); mtx_destroy(&sc->aw_mtx); bus_teardown_intr(dev, sc->aw_res[AW_MMC_IRQRES], sc->aw_intrhand); bus_release_resources(dev, aw_mmc_res_spec, sc->aw_res); return (ENXIO); } static int aw_mmc_detach(device_t dev) { struct aw_mmc_softc *sc; device_t d; sc = device_get_softc(dev); clk_disable(sc->aw_clk_mmc); clk_disable(sc->aw_clk_ahb); hwreset_assert(sc->aw_rst_ahb); mmc_fdt_gpio_teardown(&sc->mmc_helper); callout_drain(&sc->aw_timeoutc); AW_MMC_LOCK(sc); d = sc->child; sc->child = NULL; AW_MMC_UNLOCK(sc); if (d != NULL) device_delete_child(sc->aw_dev, d); aw_mmc_teardown_dma(sc); mtx_destroy(&sc->aw_mtx); bus_teardown_intr(dev, sc->aw_res[AW_MMC_IRQRES], sc->aw_intrhand); bus_release_resources(dev, aw_mmc_res_spec, sc->aw_res); #ifdef MMCCAM mmc_cam_sim_free(&sc->mmc_sim); #endif return (0); } static void aw_dma_desc_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int err) { struct aw_mmc_softc *sc; sc = (struct aw_mmc_softc *)arg; if (err) { sc->aw_dma_map_err = err; return; } sc->aw_dma_desc_phys = segs[0].ds_addr; } static int aw_mmc_setup_dma(struct aw_mmc_softc *sc) { int error; /* Allocate the DMA descriptor memory. */ error = bus_dma_tag_create( bus_get_dma_tag(sc->aw_dev), /* parent */ AW_MMC_DMA_ALIGN, 0, /* align, boundary */ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg*/ AW_MMC_DMA_DESC_SIZE, 1, /* maxsize, nsegment */ AW_MMC_DMA_DESC_SIZE, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lock, lockarg*/ &sc->aw_dma_tag); if (error) return (error); error = bus_dmamem_alloc(sc->aw_dma_tag, &sc->aw_dma_desc, BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->aw_dma_map); if (error) return (error); error = bus_dmamap_load(sc->aw_dma_tag, sc->aw_dma_map, sc->aw_dma_desc, AW_MMC_DMA_DESC_SIZE, aw_dma_desc_cb, sc, 0); if (error) return (error); if (sc->aw_dma_map_err) return (sc->aw_dma_map_err); /* Create the DMA map for data transfers. */ error = bus_dma_tag_create( bus_get_dma_tag(sc->aw_dev), /* parent */ AW_MMC_DMA_ALIGN, 0, /* align, boundary */ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg*/ sc->aw_mmc_conf->dma_xferlen * AW_MMC_DMA_SEGS, AW_MMC_DMA_SEGS, /* maxsize, nsegments */ sc->aw_mmc_conf->dma_xferlen, /* maxsegsize */ BUS_DMA_ALLOCNOW, /* flags */ NULL, NULL, /* lock, lockarg*/ &sc->aw_dma_buf_tag); if (error) return (error); error = bus_dmamap_create(sc->aw_dma_buf_tag, 0, &sc->aw_dma_buf_map); if (error) return (error); return (0); } static void aw_mmc_teardown_dma(struct aw_mmc_softc *sc) { bus_dmamap_unload(sc->aw_dma_tag, sc->aw_dma_map); bus_dmamem_free(sc->aw_dma_tag, sc->aw_dma_desc, sc->aw_dma_map); if (bus_dma_tag_destroy(sc->aw_dma_tag) != 0) device_printf(sc->aw_dev, "Cannot destroy the dma tag\n"); bus_dmamap_unload(sc->aw_dma_buf_tag, sc->aw_dma_buf_map); bus_dmamap_destroy(sc->aw_dma_buf_tag, sc->aw_dma_buf_map); if (bus_dma_tag_destroy(sc->aw_dma_buf_tag) != 0) device_printf(sc->aw_dev, "Cannot destroy the dma buf tag\n"); } static void aw_dma_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int err) { int i; struct aw_mmc_dma_desc *dma_desc; struct aw_mmc_softc *sc; sc = (struct aw_mmc_softc *)arg; sc->aw_dma_map_err = err; if (err) return; dma_desc = sc->aw_dma_desc; for (i = 0; i < nsegs; i++) { if (segs[i].ds_len == sc->aw_mmc_conf->dma_xferlen) dma_desc[i].buf_size = 0; /* Size of 0 indicate max len */ else dma_desc[i].buf_size = segs[i].ds_len; dma_desc[i].buf_addr = segs[i].ds_addr; dma_desc[i].config = AW_MMC_DMA_CONFIG_CH | AW_MMC_DMA_CONFIG_OWN | AW_MMC_DMA_CONFIG_DIC; dma_desc[i].next = sc->aw_dma_desc_phys + ((i + 1) * sizeof(struct aw_mmc_dma_desc)); } dma_desc[0].config |= AW_MMC_DMA_CONFIG_FD; dma_desc[nsegs - 1].config |= AW_MMC_DMA_CONFIG_LD | AW_MMC_DMA_CONFIG_ER; dma_desc[nsegs - 1].config &= ~AW_MMC_DMA_CONFIG_DIC; dma_desc[nsegs - 1].next = 0; } static int aw_mmc_prepare_dma(struct aw_mmc_softc *sc) { bus_dmasync_op_t sync_op; int error; struct mmc_command *cmd; uint32_t val; #ifdef MMCCAM cmd = &sc->ccb->mmcio.cmd; #else cmd = sc->aw_req->cmd; #endif if (cmd->data->len > (sc->aw_mmc_conf->dma_xferlen * AW_MMC_DMA_SEGS)) return (EFBIG); error = bus_dmamap_load(sc->aw_dma_buf_tag, sc->aw_dma_buf_map, cmd->data->data, cmd->data->len, aw_dma_cb, sc, 0); if (error) return (error); if (sc->aw_dma_map_err) return (sc->aw_dma_map_err); if (cmd->data->flags & MMC_DATA_WRITE) sync_op = BUS_DMASYNC_PREWRITE; else sync_op = BUS_DMASYNC_PREREAD; bus_dmamap_sync(sc->aw_dma_buf_tag, sc->aw_dma_buf_map, sync_op); bus_dmamap_sync(sc->aw_dma_tag, sc->aw_dma_map, BUS_DMASYNC_PREWRITE); /* Enable DMA */ val = AW_MMC_READ_4(sc, AW_MMC_GCTL); val &= ~AW_MMC_GCTL_FIFO_AC_MOD; val |= AW_MMC_GCTL_DMA_ENB; AW_MMC_WRITE_4(sc, AW_MMC_GCTL, val); /* Reset DMA */ val |= AW_MMC_GCTL_DMA_RST; AW_MMC_WRITE_4(sc, AW_MMC_GCTL, val); AW_MMC_WRITE_4(sc, AW_MMC_DMAC, AW_MMC_DMAC_IDMAC_SOFT_RST); AW_MMC_WRITE_4(sc, AW_MMC_DMAC, AW_MMC_DMAC_IDMAC_IDMA_ON | AW_MMC_DMAC_IDMAC_FIX_BURST); /* Enable RX or TX DMA interrupt */ val = AW_MMC_READ_4(sc, AW_MMC_IDIE); if (cmd->data->flags & MMC_DATA_WRITE) val |= AW_MMC_IDST_TX_INT; else val |= AW_MMC_IDST_RX_INT; AW_MMC_WRITE_4(sc, AW_MMC_IDIE, val); /* Set DMA descritptor list address */ AW_MMC_WRITE_4(sc, AW_MMC_DLBA, sc->aw_dma_desc_phys); /* FIFO trigger level */ AW_MMC_WRITE_4(sc, AW_MMC_FWLR, AW_MMC_DMA_FTRGLEVEL); return (0); } static int aw_mmc_reset(struct aw_mmc_softc *sc) { uint32_t reg; int timeout; reg = AW_MMC_READ_4(sc, AW_MMC_GCTL); reg |= AW_MMC_GCTL_RESET; AW_MMC_WRITE_4(sc, AW_MMC_GCTL, reg); timeout = AW_MMC_RESET_RETRY; while (--timeout > 0) { if ((AW_MMC_READ_4(sc, AW_MMC_GCTL) & AW_MMC_GCTL_RESET) == 0) break; DELAY(100); } if (timeout == 0) return (ETIMEDOUT); return (0); } static int aw_mmc_init(struct aw_mmc_softc *sc) { uint32_t reg; int ret; ret = aw_mmc_reset(sc); if (ret != 0) return (ret); /* Set the timeout. */ AW_MMC_WRITE_4(sc, AW_MMC_TMOR, AW_MMC_TMOR_DTO_LMT_SHIFT(AW_MMC_TMOR_DTO_LMT_MASK) | AW_MMC_TMOR_RTO_LMT_SHIFT(AW_MMC_TMOR_RTO_LMT_MASK)); /* Unmask interrupts. */ AW_MMC_WRITE_4(sc, AW_MMC_IMKR, 0); /* Clear pending interrupts. */ AW_MMC_WRITE_4(sc, AW_MMC_RISR, 0xffffffff); /* Debug register, undocumented */ AW_MMC_WRITE_4(sc, AW_MMC_DBGC, 0xdeb); /* Function select register */ AW_MMC_WRITE_4(sc, AW_MMC_FUNS, 0xceaa0000); AW_MMC_WRITE_4(sc, AW_MMC_IDST, 0xffffffff); /* Enable interrupts and disable AHB access. */ reg = AW_MMC_READ_4(sc, AW_MMC_GCTL); reg |= AW_MMC_GCTL_INT_ENB; reg &= ~AW_MMC_GCTL_FIFO_AC_MOD; reg &= ~AW_MMC_GCTL_WAIT_MEM_ACCESS; AW_MMC_WRITE_4(sc, AW_MMC_GCTL, reg); return (0); } static void aw_mmc_req_done(struct aw_mmc_softc *sc) { struct mmc_command *cmd; #ifdef MMCCAM union ccb *ccb; #else struct mmc_request *req; #endif uint32_t val, mask; int retry; #ifdef MMCCAM ccb = sc->ccb; cmd = &ccb->mmcio.cmd; #else cmd = sc->aw_req->cmd; #endif if (__predict_false(aw_mmc_debug & AW_MMC_DEBUG_CMD)) { device_printf(sc->aw_dev, "%s: cmd %d err %d\n", __func__, cmd->opcode, cmd->error); } if (cmd->error != MMC_ERR_NONE) { /* Reset the FIFO and DMA engines. */ mask = AW_MMC_GCTL_FIFO_RST | AW_MMC_GCTL_DMA_RST; val = AW_MMC_READ_4(sc, AW_MMC_GCTL); AW_MMC_WRITE_4(sc, AW_MMC_GCTL, val | mask); retry = AW_MMC_RESET_RETRY; while (--retry > 0) { if ((AW_MMC_READ_4(sc, AW_MMC_GCTL) & AW_MMC_GCTL_RESET) == 0) break; DELAY(100); } if (retry == 0) device_printf(sc->aw_dev, "timeout resetting DMA/FIFO\n"); aw_mmc_update_clock(sc, 1); } if (!dumping) callout_stop(&sc->aw_timeoutc); sc->aw_intr = 0; sc->aw_resid = 0; sc->aw_dma_map_err = 0; sc->aw_intr_wait = 0; #ifdef MMCCAM sc->ccb = NULL; ccb->ccb_h.status = (ccb->mmcio.cmd.error == 0 ? CAM_REQ_CMP : CAM_REQ_CMP_ERR); xpt_done(ccb); #else req = sc->aw_req; sc->aw_req = NULL; req->done(req); #endif } static void aw_mmc_req_ok(struct aw_mmc_softc *sc) { int timeout; struct mmc_command *cmd; uint32_t status; timeout = 1000; while (--timeout > 0) { status = AW_MMC_READ_4(sc, AW_MMC_STAR); if ((status & AW_MMC_STAR_CARD_BUSY) == 0) break; DELAY(1000); } #ifdef MMCCAM cmd = &sc->ccb->mmcio.cmd; #else cmd = sc->aw_req->cmd; #endif if (timeout == 0) { cmd->error = MMC_ERR_FAILED; aw_mmc_req_done(sc); return; } if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_136) { cmd->resp[0] = AW_MMC_READ_4(sc, AW_MMC_RESP3); cmd->resp[1] = AW_MMC_READ_4(sc, AW_MMC_RESP2); cmd->resp[2] = AW_MMC_READ_4(sc, AW_MMC_RESP1); cmd->resp[3] = AW_MMC_READ_4(sc, AW_MMC_RESP0); } else cmd->resp[0] = AW_MMC_READ_4(sc, AW_MMC_RESP0); } /* All data has been transferred ? */ if (cmd->data != NULL && (sc->aw_resid << 2) < cmd->data->len) cmd->error = MMC_ERR_FAILED; aw_mmc_req_done(sc); } static inline void set_mmc_error(struct aw_mmc_softc *sc, int error_code) { #ifdef MMCCAM sc->ccb->mmcio.cmd.error = error_code; #else sc->aw_req->cmd->error = error_code; #endif } static void aw_mmc_timeout(void *arg) { struct aw_mmc_softc *sc; sc = (struct aw_mmc_softc *)arg; #ifdef MMCCAM if (sc->ccb != NULL) { #else if (sc->aw_req != NULL) { #endif device_printf(sc->aw_dev, "controller timeout\n"); set_mmc_error(sc, MMC_ERR_TIMEOUT); aw_mmc_req_done(sc); } else device_printf(sc->aw_dev, "Spurious timeout - no active request\n"); } static void aw_mmc_print_error(uint32_t err) { if(err & AW_MMC_INT_RESP_ERR) printf("AW_MMC_INT_RESP_ERR "); if (err & AW_MMC_INT_RESP_CRC_ERR) printf("AW_MMC_INT_RESP_CRC_ERR "); if (err & AW_MMC_INT_DATA_CRC_ERR) printf("AW_MMC_INT_DATA_CRC_ERR "); if (err & AW_MMC_INT_RESP_TIMEOUT) printf("AW_MMC_INT_RESP_TIMEOUT "); if (err & AW_MMC_INT_FIFO_RUN_ERR) printf("AW_MMC_INT_FIFO_RUN_ERR "); if (err & AW_MMC_INT_CMD_BUSY) printf("AW_MMC_INT_CMD_BUSY "); if (err & AW_MMC_INT_DATA_START_ERR) printf("AW_MMC_INT_DATA_START_ERR "); if (err & AW_MMC_INT_DATA_END_BIT_ERR) printf("AW_MMC_INT_DATA_END_BIT_ERR"); printf("\n"); } static void aw_mmc_intr(void *arg) { bus_dmasync_op_t sync_op; struct aw_mmc_softc *sc; struct mmc_data *data; uint32_t idst, imask, rint; sc = (struct aw_mmc_softc *)arg; AW_MMC_LOCK(sc); rint = AW_MMC_READ_4(sc, AW_MMC_RISR); idst = AW_MMC_READ_4(sc, AW_MMC_IDST); imask = AW_MMC_READ_4(sc, AW_MMC_IMKR); if (idst == 0 && imask == 0 && rint == 0) { AW_MMC_UNLOCK(sc); return; } if (__predict_false(aw_mmc_debug & AW_MMC_DEBUG_INT)) { device_printf(sc->aw_dev, "idst: %#x, imask: %#x, rint: %#x\n", idst, imask, rint); } #ifdef MMCCAM if (sc->ccb == NULL) { #else if (sc->aw_req == NULL) { #endif device_printf(sc->aw_dev, "Spurious interrupt - no active request, rint: 0x%08X\n", rint); aw_mmc_print_error(rint); goto end; } if (rint & AW_MMC_INT_ERR_BIT) { if (__predict_false(aw_mmc_debug & AW_MMC_DEBUG_INT)) { device_printf(sc->aw_dev, "error rint: 0x%08X\n", rint); aw_mmc_print_error(rint); } if (rint & AW_MMC_INT_RESP_TIMEOUT) set_mmc_error(sc, MMC_ERR_TIMEOUT); else set_mmc_error(sc, MMC_ERR_FAILED); aw_mmc_req_done(sc); goto end; } if (idst & AW_MMC_IDST_ERROR) { if (__predict_false(aw_mmc_debug & AW_MMC_DEBUG_INT)) device_printf(sc->aw_dev, "error idst: 0x%08x\n", idst); set_mmc_error(sc, MMC_ERR_FAILED); aw_mmc_req_done(sc); goto end; } sc->aw_intr |= rint; #ifdef MMCCAM data = sc->ccb->mmcio.cmd.data; #else data = sc->aw_req->cmd->data; #endif if (data != NULL && (idst & AW_MMC_IDST_COMPLETE) != 0) { if (data->flags & MMC_DATA_WRITE) sync_op = BUS_DMASYNC_POSTWRITE; else sync_op = BUS_DMASYNC_POSTREAD; bus_dmamap_sync(sc->aw_dma_buf_tag, sc->aw_dma_buf_map, sync_op); bus_dmamap_sync(sc->aw_dma_tag, sc->aw_dma_map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->aw_dma_buf_tag, sc->aw_dma_buf_map); sc->aw_resid = data->len >> 2; } if ((sc->aw_intr & sc->aw_intr_wait) == sc->aw_intr_wait) aw_mmc_req_ok(sc); end: AW_MMC_WRITE_4(sc, AW_MMC_IDST, idst); AW_MMC_WRITE_4(sc, AW_MMC_RISR, rint); AW_MMC_UNLOCK(sc); } static int aw_mmc_request(device_t bus, device_t child, struct mmc_request *req) { int blksz; struct aw_mmc_softc *sc; struct mmc_command *cmd; uint32_t cmdreg, imask; int err; sc = device_get_softc(bus); AW_MMC_LOCK(sc); #ifdef MMCCAM KASSERT(req == NULL, ("req should be NULL in MMCCAM case!")); /* * For MMCCAM, sc->ccb has been NULL-checked and populated * by aw_mmc_cam_request() already. */ cmd = &sc->ccb->mmcio.cmd; #else if (sc->aw_req) { AW_MMC_UNLOCK(sc); return (EBUSY); } sc->aw_req = req; cmd = req->cmd; if (__predict_false(aw_mmc_debug & AW_MMC_DEBUG_CMD)) { device_printf(sc->aw_dev, "CMD%u arg %#x flags %#x dlen %u dflags %#x\n", cmd->opcode, cmd->arg, cmd->flags, cmd->data != NULL ? (unsigned int)cmd->data->len : 0, cmd->data != NULL ? cmd->data->flags: 0); } #endif cmdreg = AW_MMC_CMDR_LOAD; imask = AW_MMC_INT_ERR_BIT; sc->aw_intr_wait = 0; sc->aw_intr = 0; sc->aw_resid = 0; cmd->error = MMC_ERR_NONE; if (cmd->opcode == MMC_GO_IDLE_STATE) cmdreg |= AW_MMC_CMDR_SEND_INIT_SEQ; if (cmd->flags & MMC_RSP_PRESENT) cmdreg |= AW_MMC_CMDR_RESP_RCV; if (cmd->flags & MMC_RSP_136) cmdreg |= AW_MMC_CMDR_LONG_RESP; if (cmd->flags & MMC_RSP_CRC) cmdreg |= AW_MMC_CMDR_CHK_RESP_CRC; if (cmd->data) { cmdreg |= AW_MMC_CMDR_DATA_TRANS | AW_MMC_CMDR_WAIT_PRE_OVER; if (cmd->data->flags & MMC_DATA_MULTI) { cmdreg |= AW_MMC_CMDR_STOP_CMD_FLAG; imask |= AW_MMC_INT_AUTO_STOP_DONE; sc->aw_intr_wait |= AW_MMC_INT_AUTO_STOP_DONE; } else { sc->aw_intr_wait |= AW_MMC_INT_DATA_OVER; imask |= AW_MMC_INT_DATA_OVER; } if (cmd->data->flags & MMC_DATA_WRITE) cmdreg |= AW_MMC_CMDR_DIR_WRITE; #ifdef MMCCAM if (cmd->data->flags & MMC_DATA_BLOCK_SIZE) { AW_MMC_WRITE_4(sc, AW_MMC_BKSR, cmd->data->block_size); AW_MMC_WRITE_4(sc, AW_MMC_BYCR, cmd->data->len); } else #endif { blksz = min(cmd->data->len, MMC_SECTOR_SIZE); AW_MMC_WRITE_4(sc, AW_MMC_BKSR, blksz); AW_MMC_WRITE_4(sc, AW_MMC_BYCR, cmd->data->len); } } else { imask |= AW_MMC_INT_CMD_DONE; } /* Enable the interrupts we are interested in */ AW_MMC_WRITE_4(sc, AW_MMC_IMKR, imask); AW_MMC_WRITE_4(sc, AW_MMC_RISR, 0xffffffff); /* Enable auto stop if needed */ AW_MMC_WRITE_4(sc, AW_MMC_A12A, cmdreg & AW_MMC_CMDR_STOP_CMD_FLAG ? 0 : 0xffff); /* Write the command argument */ AW_MMC_WRITE_4(sc, AW_MMC_CAGR, cmd->arg); /* * If we don't have data start the request * if we do prepare the dma request and start the request */ if (cmd->data == NULL) { AW_MMC_WRITE_4(sc, AW_MMC_CMDR, cmdreg | cmd->opcode); } else { err = aw_mmc_prepare_dma(sc); if (err != 0) device_printf(sc->aw_dev, "prepare_dma failed: %d\n", err); AW_MMC_WRITE_4(sc, AW_MMC_CMDR, cmdreg | cmd->opcode); } if (!dumping) { callout_reset(&sc->aw_timeoutc, sc->aw_timeout * hz, aw_mmc_timeout, sc); } AW_MMC_UNLOCK(sc); return (0); } static int aw_mmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) { struct aw_mmc_softc *sc; sc = device_get_softc(bus); switch (which) { default: return (EINVAL); case MMCBR_IVAR_BUS_MODE: *(int *)result = sc->aw_host.ios.bus_mode; break; case MMCBR_IVAR_BUS_WIDTH: *(int *)result = sc->aw_host.ios.bus_width; break; case MMCBR_IVAR_CHIP_SELECT: *(int *)result = sc->aw_host.ios.chip_select; break; case MMCBR_IVAR_CLOCK: *(int *)result = sc->aw_host.ios.clock; break; case MMCBR_IVAR_F_MIN: *(int *)result = sc->aw_host.f_min; break; case MMCBR_IVAR_F_MAX: *(int *)result = sc->aw_host.f_max; break; case MMCBR_IVAR_HOST_OCR: *(int *)result = sc->aw_host.host_ocr; break; case MMCBR_IVAR_MODE: *(int *)result = sc->aw_host.mode; break; case MMCBR_IVAR_OCR: *(int *)result = sc->aw_host.ocr; break; case MMCBR_IVAR_POWER_MODE: *(int *)result = sc->aw_host.ios.power_mode; break; case MMCBR_IVAR_VDD: *(int *)result = sc->aw_host.ios.vdd; break; case MMCBR_IVAR_VCCQ: *(int *)result = sc->aw_host.ios.vccq; break; case MMCBR_IVAR_CAPS: *(int *)result = sc->aw_host.caps; break; case MMCBR_IVAR_TIMING: *(int *)result = sc->aw_host.ios.timing; break; case MMCBR_IVAR_MAX_DATA: *(int *)result = (sc->aw_mmc_conf->dma_xferlen * AW_MMC_DMA_SEGS) / MMC_SECTOR_SIZE; break; case MMCBR_IVAR_RETUNE_REQ: *(int *)result = retune_req_none; break; } return (0); } static int aw_mmc_write_ivar(device_t bus, device_t child, int which, uintptr_t value) { struct aw_mmc_softc *sc; sc = device_get_softc(bus); switch (which) { default: return (EINVAL); case MMCBR_IVAR_BUS_MODE: sc->aw_host.ios.bus_mode = value; break; case MMCBR_IVAR_BUS_WIDTH: sc->aw_host.ios.bus_width = value; break; case MMCBR_IVAR_CHIP_SELECT: sc->aw_host.ios.chip_select = value; break; case MMCBR_IVAR_CLOCK: sc->aw_host.ios.clock = value; break; case MMCBR_IVAR_MODE: sc->aw_host.mode = value; break; case MMCBR_IVAR_OCR: sc->aw_host.ocr = value; break; case MMCBR_IVAR_POWER_MODE: sc->aw_host.ios.power_mode = value; break; case MMCBR_IVAR_VDD: sc->aw_host.ios.vdd = value; break; case MMCBR_IVAR_VCCQ: sc->aw_host.ios.vccq = value; break; case MMCBR_IVAR_TIMING: sc->aw_host.ios.timing = value; break; /* These are read-only */ case MMCBR_IVAR_CAPS: case MMCBR_IVAR_HOST_OCR: case MMCBR_IVAR_F_MIN: case MMCBR_IVAR_F_MAX: case MMCBR_IVAR_MAX_DATA: return (EINVAL); } return (0); } static int aw_mmc_update_clock(struct aw_mmc_softc *sc, uint32_t clkon) { uint32_t reg; int retry; reg = AW_MMC_READ_4(sc, AW_MMC_CKCR); reg &= ~(AW_MMC_CKCR_ENB | AW_MMC_CKCR_LOW_POWER | AW_MMC_CKCR_MASK_DATA0); if (clkon) reg |= AW_MMC_CKCR_ENB; if (sc->aw_mmc_conf->mask_data0) reg |= AW_MMC_CKCR_MASK_DATA0; AW_MMC_WRITE_4(sc, AW_MMC_CKCR, reg); reg = AW_MMC_CMDR_LOAD | AW_MMC_CMDR_PRG_CLK | AW_MMC_CMDR_WAIT_PRE_OVER; AW_MMC_WRITE_4(sc, AW_MMC_CMDR, reg); retry = 0xfffff; while (reg & AW_MMC_CMDR_LOAD && --retry > 0) { reg = AW_MMC_READ_4(sc, AW_MMC_CMDR); DELAY(10); } AW_MMC_WRITE_4(sc, AW_MMC_RISR, 0xffffffff); if (reg & AW_MMC_CMDR_LOAD) { device_printf(sc->aw_dev, "timeout updating clock\n"); return (ETIMEDOUT); } if (sc->aw_mmc_conf->mask_data0) { reg = AW_MMC_READ_4(sc, AW_MMC_CKCR); reg &= ~AW_MMC_CKCR_MASK_DATA0; AW_MMC_WRITE_4(sc, AW_MMC_CKCR, reg); } return (0); } #ifndef MMCCAM static int aw_mmc_switch_vccq(device_t bus, device_t child) { struct aw_mmc_softc *sc; int uvolt, err; sc = device_get_softc(bus); if (sc->mmc_helper.vqmmc_supply == NULL) return EOPNOTSUPP; switch (sc->aw_host.ios.vccq) { case vccq_180: uvolt = 1800000; break; case vccq_330: uvolt = 3300000; break; default: return EINVAL; } err = regulator_set_voltage(sc->mmc_helper.vqmmc_supply, uvolt, uvolt); if (err != 0) { device_printf(sc->aw_dev, "Cannot set vqmmc to %d<->%d\n", uvolt, uvolt); return (err); } return (0); } #endif static int aw_mmc_update_ios(device_t bus, device_t child) { int error; struct aw_mmc_softc *sc; struct mmc_ios *ios; unsigned int clock; uint32_t reg, div = 1; int reg_status; int rv; sc = device_get_softc(bus); ios = &sc->aw_host.ios; /* Set the bus width. */ switch (ios->bus_width) { case bus_width_1: AW_MMC_WRITE_4(sc, AW_MMC_BWDR, AW_MMC_BWDR1); break; case bus_width_4: AW_MMC_WRITE_4(sc, AW_MMC_BWDR, AW_MMC_BWDR4); break; case bus_width_8: AW_MMC_WRITE_4(sc, AW_MMC_BWDR, AW_MMC_BWDR8); break; } switch (ios->power_mode) { case power_on: break; case power_off: if (__predict_false(aw_mmc_debug & AW_MMC_DEBUG_CARD)) device_printf(sc->aw_dev, "Powering down sd/mmc\n"); if (sc->mmc_helper.vmmc_supply) { rv = regulator_status(sc->mmc_helper.vmmc_supply, ®_status); if (rv == 0 && reg_status == REGULATOR_STATUS_ENABLED) regulator_disable(sc->mmc_helper.vmmc_supply); } if (sc->mmc_helper.vqmmc_supply) { rv = regulator_status(sc->mmc_helper.vqmmc_supply, ®_status); if (rv == 0 && reg_status == REGULATOR_STATUS_ENABLED) regulator_disable(sc->mmc_helper.vqmmc_supply); } if (sc->mmc_helper.mmc_pwrseq) MMC_PWRSEQ_SET_POWER(sc->mmc_helper.mmc_pwrseq, false); aw_mmc_reset(sc); break; case power_up: if (__predict_false(aw_mmc_debug & AW_MMC_DEBUG_CARD)) device_printf(sc->aw_dev, "Powering up sd/mmc\n"); if (sc->mmc_helper.vmmc_supply) { rv = regulator_status(sc->mmc_helper.vmmc_supply, ®_status); if (rv == 0 && reg_status != REGULATOR_STATUS_ENABLED) regulator_enable(sc->mmc_helper.vmmc_supply); } if (sc->mmc_helper.vqmmc_supply) { rv = regulator_status(sc->mmc_helper.vqmmc_supply, ®_status); if (rv == 0 && reg_status != REGULATOR_STATUS_ENABLED) regulator_enable(sc->mmc_helper.vqmmc_supply); } if (sc->mmc_helper.mmc_pwrseq) MMC_PWRSEQ_SET_POWER(sc->mmc_helper.mmc_pwrseq, true); aw_mmc_init(sc); break; }; /* Enable ddr mode if needed */ reg = AW_MMC_READ_4(sc, AW_MMC_GCTL); if (ios->timing == bus_timing_uhs_ddr50 || ios->timing == bus_timing_mmc_ddr52) reg |= AW_MMC_GCTL_DDR_MOD_SEL; else reg &= ~AW_MMC_GCTL_DDR_MOD_SEL; AW_MMC_WRITE_4(sc, AW_MMC_GCTL, reg); if (ios->clock && ios->clock != sc->aw_clock) { sc->aw_clock = clock = ios->clock; /* Disable clock */ error = aw_mmc_update_clock(sc, 0); if (error != 0) return (error); if (ios->timing == bus_timing_mmc_ddr52 && (sc->aw_mmc_conf->new_timing || ios->bus_width == bus_width_8)) { div = 2; clock <<= 1; } /* Reset the divider. */ reg = AW_MMC_READ_4(sc, AW_MMC_CKCR); reg &= ~AW_MMC_CKCR_DIV; reg |= div - 1; AW_MMC_WRITE_4(sc, AW_MMC_CKCR, reg); /* New timing mode if needed */ if (sc->aw_mmc_conf->new_timing) { reg = AW_MMC_READ_4(sc, AW_MMC_NTSR); reg |= AW_MMC_NTSR_MODE_SELECT; AW_MMC_WRITE_4(sc, AW_MMC_NTSR, reg); } /* Set the MMC clock. */ error = clk_disable(sc->aw_clk_mmc); if (error != 0 && bootverbose) device_printf(sc->aw_dev, "failed to disable mmc clock: %d\n", error); error = clk_set_freq(sc->aw_clk_mmc, clock, CLK_SET_ROUND_DOWN); if (error != 0) { device_printf(sc->aw_dev, "failed to set frequency to %u Hz: %d\n", clock, error); return (error); } error = clk_enable(sc->aw_clk_mmc); if (error != 0 && bootverbose) device_printf(sc->aw_dev, "failed to re-enable mmc clock: %d\n", error); if (sc->aw_mmc_conf->can_calibrate) AW_MMC_WRITE_4(sc, AW_MMC_SAMP_DL, AW_MMC_SAMP_DL_SW_EN); /* Enable clock. */ error = aw_mmc_update_clock(sc, 1); if (error != 0) return (error); } return (0); } #ifndef MMCCAM static int aw_mmc_get_ro(device_t bus, device_t child) { struct aw_mmc_softc *sc; sc = device_get_softc(bus); return (mmc_fdt_gpio_get_readonly(&sc->mmc_helper)); } static int aw_mmc_acquire_host(device_t bus, device_t child) { struct aw_mmc_softc *sc; int error; sc = device_get_softc(bus); AW_MMC_LOCK(sc); while (sc->aw_bus_busy) { error = msleep(sc, &sc->aw_mtx, PCATCH, "mmchw", 0); if (error != 0) { AW_MMC_UNLOCK(sc); return (error); } } sc->aw_bus_busy++; AW_MMC_UNLOCK(sc); return (0); } static int aw_mmc_release_host(device_t bus, device_t child) { struct aw_mmc_softc *sc; sc = device_get_softc(bus); AW_MMC_LOCK(sc); sc->aw_bus_busy--; wakeup(sc); AW_MMC_UNLOCK(sc); return (0); } #endif static device_method_t aw_mmc_methods[] = { /* Device interface */ DEVMETHOD(device_probe, aw_mmc_probe), DEVMETHOD(device_attach, aw_mmc_attach), DEVMETHOD(device_detach, aw_mmc_detach), /* Bus interface */ DEVMETHOD(bus_read_ivar, aw_mmc_read_ivar), DEVMETHOD(bus_write_ivar, aw_mmc_write_ivar), DEVMETHOD(bus_add_child, bus_generic_add_child), #ifndef MMCCAM /* MMC bridge interface */ DEVMETHOD(mmcbr_update_ios, aw_mmc_update_ios), DEVMETHOD(mmcbr_request, aw_mmc_request), DEVMETHOD(mmcbr_get_ro, aw_mmc_get_ro), DEVMETHOD(mmcbr_switch_vccq, aw_mmc_switch_vccq), DEVMETHOD(mmcbr_acquire_host, aw_mmc_acquire_host), DEVMETHOD(mmcbr_release_host, aw_mmc_release_host), #endif #ifdef MMCCAM /* MMCCAM interface */ DEVMETHOD(mmc_sim_get_tran_settings, aw_mmc_get_tran_settings), DEVMETHOD(mmc_sim_set_tran_settings, aw_mmc_set_tran_settings), DEVMETHOD(mmc_sim_cam_request, aw_mmc_cam_request), DEVMETHOD(mmc_sim_cam_poll, aw_mmc_cam_poll), #endif DEVMETHOD_END }; static driver_t aw_mmc_driver = { "aw_mmc", aw_mmc_methods, sizeof(struct aw_mmc_softc), }; DRIVER_MODULE(aw_mmc, simplebus, aw_mmc_driver, NULL, NULL); #ifndef MMCCAM MMC_DECLARE_BRIDGE(aw_mmc); #endif SIMPLEBUS_PNP_INFO(compat_data); diff --git a/sys/arm/allwinner/aw_usb3phy.c b/sys/arm/allwinner/aw_usb3phy.c index b49a9a86b6e9..fdf54ef79250 100644 --- a/sys/arm/allwinner/aw_usb3phy.c +++ b/sys/arm/allwinner/aw_usb3phy.c @@ -1,294 +1,294 @@ /* $NetBSD: sunxi_usb3phy.c,v 1.1 2018/05/01 23:59:42 jmcneill Exp $ */ /*- * Copyright (c) 2018 Jared McNeill * All rights reserved. * * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``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 FOUNDATION 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 * 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. */ /* * Allwinner USB3PHY */ #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include "phynode_if.h" #define USB3PHY_APP 0x00 #define APP_FORCE_VBUS (0x3 << 12) #define USB3PHY_PIPE_CLOCK_CONTROL 0x14 #define PCC_PIPE_CLK_OPEN (1 << 6) #define USB3PHY_PHY_TUNE_LOW 0x18 #define PTL_MAGIC 0x0047fc87 #define USB3PHY_PHY_TUNE_HIGH 0x1c #define PTH_TX_DEEMPH_3P5DB (0x1F << 19) #define PTH_TX_DEEMPH_6DB (0x3F << 13) #define PTH_TX_SWING_FULL (0x7F << 6) #define PTH_LOS_BIAS (0x7 << 3) #define PTH_TX_BOOST_LVL (0x7 << 0) #define USB3PHY_PHY_EXTERNAL_CONTROL 0x20 #define PEC_REF_SSP_EN (1 << 26) #define PEC_SSC_EN (1 << 24) #define PEC_EXTERN_VBUS (0x3 << 1) #define __LOWEST_SET_BIT(__mask) ((((__mask) - 1) & (__mask)) ^ (__mask)) #define __SHIFTIN(__x, __mask) ((__x) * __LOWEST_SET_BIT(__mask)) static struct ofw_compat_data compat_data[] = { { "allwinner,sun50i-h6-usb3-phy", 1 }, { NULL, 0 } }; static struct resource_spec aw_usb3phy_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { -1, 0 } }; struct awusb3phy_softc { struct resource * res; regulator_t reg; int mode; }; /* Phy class and methods. */ static int awusb3phy_phy_enable(struct phynode *phy, bool enable); static int awusb3phy_get_mode(struct phynode *phy, int *mode); static int awusb3phy_set_mode(struct phynode *phy, int mode); static phynode_usb_method_t awusb3phy_phynode_methods[] = { PHYNODEMETHOD(phynode_enable, awusb3phy_phy_enable), PHYNODEMETHOD(phynode_usb_get_mode, awusb3phy_get_mode), PHYNODEMETHOD(phynode_usb_set_mode, awusb3phy_set_mode), PHYNODEMETHOD_END }; DEFINE_CLASS_1(awusb3phy_phynode, awusb3phy_phynode_class, awusb3phy_phynode_methods, sizeof(struct phynode_usb_sc), phynode_usb_class); #define RD4(res, o) bus_read_4(res, (o)) #define WR4(res, o, v) bus_write_4(res, (o), (v)) static int awusb3phy_phy_enable(struct phynode *phynode, bool enable) { struct awusb3phy_softc *sc; device_t dev; uint32_t val; int error = 0; dev = phynode_get_device(phynode); sc = device_get_softc(dev); device_printf(dev, "%s: called\n", __func__); if (enable) { val = RD4(sc->res, USB3PHY_PHY_EXTERNAL_CONTROL); device_printf(dev, "EXTERNAL_CONTROL: %x\n", val); val |= PEC_EXTERN_VBUS; val |= PEC_SSC_EN; val |= PEC_REF_SSP_EN; device_printf(dev, "EXTERNAL_CONTROL: %x\n", val); WR4(sc->res, USB3PHY_PHY_EXTERNAL_CONTROL, val); val = RD4(sc->res, USB3PHY_PIPE_CLOCK_CONTROL); device_printf(dev, "PIPE_CONTROL: %x\n", val); val |= PCC_PIPE_CLK_OPEN; device_printf(dev, "PIPE_CONTROL: %x\n", val); WR4(sc->res, USB3PHY_PIPE_CLOCK_CONTROL, val); val = RD4(sc->res, USB3PHY_APP); device_printf(dev, "APP: %x\n", val); val |= APP_FORCE_VBUS; device_printf(dev, "APP: %x\n", val); WR4(sc->res, USB3PHY_APP, val); WR4(sc->res, USB3PHY_PHY_TUNE_LOW, PTL_MAGIC); val = RD4(sc->res, USB3PHY_PHY_TUNE_HIGH); device_printf(dev, "PHY_TUNE_HIGH: %x\n", val); val |= PTH_TX_BOOST_LVL; val |= PTH_LOS_BIAS; val &= ~PTH_TX_SWING_FULL; val |= __SHIFTIN(0x55, PTH_TX_SWING_FULL); val &= ~PTH_TX_DEEMPH_6DB; val |= __SHIFTIN(0x20, PTH_TX_DEEMPH_6DB); val &= ~PTH_TX_DEEMPH_3P5DB; val |= __SHIFTIN(0x15, PTH_TX_DEEMPH_3P5DB); device_printf(dev, "PHY_TUNE_HIGH: %x\n", val); WR4(sc->res, USB3PHY_PHY_TUNE_HIGH, val); if (sc->reg) error = regulator_enable(sc->reg); } else { if (sc->reg) error = regulator_disable(sc->reg); } if (error != 0) { device_printf(dev, "couldn't %s regulator for phy\n", enable ? "enable" : "disable"); return (error); } return (0); } static int awusb3phy_get_mode(struct phynode *phynode, int *mode) { struct awusb3phy_softc *sc; device_t dev; dev = phynode_get_device(phynode); sc = device_get_softc(dev); *mode = sc->mode; return (0); } static int awusb3phy_set_mode(struct phynode *phynode, int mode) { device_t dev; struct awusb3phy_softc *sc; dev = phynode_get_device(phynode); sc = device_get_softc(dev); if (mode != PHY_USB_MODE_HOST) return (EINVAL); sc->mode = mode; return (0); } static int awusb3phy_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Allwinner USB3PHY"); return (BUS_PROBE_DEFAULT); } static int awusb3phy_attach(device_t dev) { struct phynode *phynode; struct phynode_init_def phy_init; struct awusb3phy_softc *sc; clk_t clk; hwreset_t rst; phandle_t node; int error, i; sc = device_get_softc(dev); node = ofw_bus_get_node(dev); if (bus_alloc_resources(dev, aw_usb3phy_spec, &sc->res) != 0) { device_printf(dev, "cannot allocate resources for device\n"); return (ENXIO); } /* Enable clocks */ for (i = 0; clk_get_by_ofw_index(dev, 0, i, &clk) == 0; i++) { error = clk_enable(clk); if (error != 0) { device_printf(dev, "couldn't enable clock %s\n", clk_get_name(clk)); return (error); } } /* De-assert resets */ for (i = 0; hwreset_get_by_ofw_idx(dev, 0, i, &rst) == 0; i++) { error = hwreset_deassert(rst); if (error != 0) { device_printf(dev, "couldn't de-assert reset %d\n", i); return (error); } } /* Get regulators */ regulator_get_by_ofw_property(dev, node, "phy-supply", &sc->reg); /* Create the phy */ phy_init.ofw_node = ofw_bus_get_node(dev); phynode = phynode_create(dev, &awusb3phy_phynode_class, &phy_init); if (phynode == NULL) { device_printf(dev, "failed to create USB PHY\n"); return (ENXIO); } if (phynode_register(phynode) == NULL) { device_printf(dev, "failed to create USB PHY\n"); return (ENXIO); } return (error); } static device_method_t awusb3phy_methods[] = { /* Device interface */ DEVMETHOD(device_probe, awusb3phy_probe), DEVMETHOD(device_attach, awusb3phy_attach), DEVMETHOD_END }; static driver_t awusb3phy_driver = { "awusb3phy", awusb3phy_methods, sizeof(struct awusb3phy_softc) }; /* aw_usb3phy needs to come up after regulators/gpio/etc, but before ehci/ohci */ EARLY_DRIVER_MODULE(awusb3phy, simplebus, awusb3phy_driver, 0, 0, BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE); MODULE_VERSION(awusb3phy, 1); diff --git a/sys/arm/allwinner/aw_usbphy.c b/sys/arm/allwinner/aw_usbphy.c index 09725783fd22..855be90d7fb8 100644 --- a/sys/arm/allwinner/aw_usbphy.c +++ b/sys/arm/allwinner/aw_usbphy.c @@ -1,524 +1,524 @@ /*- * Copyright (c) 2016 Jared McNeill * * 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. */ /* * Allwinner USB PHY */ #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include "phynode_if.h" enum awusbphy_type { AWUSBPHY_TYPE_A10 = 1, AWUSBPHY_TYPE_A13, AWUSBPHY_TYPE_A20, AWUSBPHY_TYPE_A31, AWUSBPHY_TYPE_H3, AWUSBPHY_TYPE_A64, AWUSBPHY_TYPE_A83T, AWUSBPHY_TYPE_H6, }; struct aw_usbphy_conf { int num_phys; enum awusbphy_type phy_type; bool pmu_unk1; bool phy0_route; }; static const struct aw_usbphy_conf a10_usbphy_conf = { .num_phys = 3, .phy_type = AWUSBPHY_TYPE_A10, .pmu_unk1 = false, .phy0_route = false, }; static const struct aw_usbphy_conf a13_usbphy_conf = { .num_phys = 2, .phy_type = AWUSBPHY_TYPE_A13, .pmu_unk1 = false, .phy0_route = false, }; static const struct aw_usbphy_conf a20_usbphy_conf = { .num_phys = 3, .phy_type = AWUSBPHY_TYPE_A20, .pmu_unk1 = false, .phy0_route = false, }; static const struct aw_usbphy_conf a31_usbphy_conf = { .num_phys = 3, .phy_type = AWUSBPHY_TYPE_A31, .pmu_unk1 = false, .phy0_route = false, }; static const struct aw_usbphy_conf h3_usbphy_conf = { .num_phys = 4, .phy_type = AWUSBPHY_TYPE_H3, .pmu_unk1 = true, .phy0_route = true, }; static const struct aw_usbphy_conf a64_usbphy_conf = { .num_phys = 2, .phy_type = AWUSBPHY_TYPE_A64, .pmu_unk1 = true, .phy0_route = true, }; static const struct aw_usbphy_conf a83t_usbphy_conf = { .num_phys = 3, .phy_type = AWUSBPHY_TYPE_A83T, .pmu_unk1 = false, .phy0_route = false, }; static const struct aw_usbphy_conf h6_usbphy_conf = { .num_phys = 4, .phy_type = AWUSBPHY_TYPE_H6, .pmu_unk1 = false, .phy0_route = true, }; static struct ofw_compat_data compat_data[] = { { "allwinner,sun4i-a10-usb-phy", (uintptr_t)&a10_usbphy_conf }, { "allwinner,sun5i-a13-usb-phy", (uintptr_t)&a13_usbphy_conf }, { "allwinner,sun6i-a31-usb-phy", (uintptr_t)&a31_usbphy_conf }, { "allwinner,sun7i-a20-usb-phy", (uintptr_t)&a20_usbphy_conf }, { "allwinner,sun8i-h3-usb-phy", (uintptr_t)&h3_usbphy_conf }, { "allwinner,sun50i-a64-usb-phy", (uintptr_t)&a64_usbphy_conf }, { "allwinner,sun8i-a83t-usb-phy", (uintptr_t)&a83t_usbphy_conf }, { "allwinner,sun50i-h6-usb-phy", (uintptr_t)&h6_usbphy_conf }, { NULL, 0 } }; struct awusbphy_softc { struct resource * phy_ctrl; struct resource ** pmu; regulator_t * reg; gpio_pin_t id_det_pin; int id_det_valid; gpio_pin_t vbus_det_pin; int vbus_det_valid; struct aw_usbphy_conf *phy_conf; int mode; }; /* Phy class and methods. */ static int awusbphy_phy_enable(struct phynode *phy, bool enable); static int awusbphy_get_mode(struct phynode *phy, int *mode); static int awusbphy_set_mode(struct phynode *phy, int mode); static phynode_usb_method_t awusbphy_phynode_methods[] = { PHYNODEMETHOD(phynode_enable, awusbphy_phy_enable), PHYNODEMETHOD(phynode_usb_get_mode, awusbphy_get_mode), PHYNODEMETHOD(phynode_usb_set_mode, awusbphy_set_mode), PHYNODEMETHOD_END }; DEFINE_CLASS_1(awusbphy_phynode, awusbphy_phynode_class, awusbphy_phynode_methods, sizeof(struct phynode_usb_sc), phynode_usb_class); #define RD4(res, o) bus_read_4(res, (o)) #define WR4(res, o, v) bus_write_4(res, (o), (v)) #define CLR4(res, o, m) WR4(res, o, RD4(res, o) & ~(m)) #define SET4(res, o, m) WR4(res, o, RD4(res, o) | (m)) #define PHY_CSR 0x00 #define ID_PULLUP_EN (1 << 17) #define DPDM_PULLUP_EN (1 << 16) #define FORCE_ID (0x3 << 14) #define FORCE_ID_SHIFT 14 #define FORCE_ID_LOW 2 #define FORCE_ID_HIGH 3 #define FORCE_VBUS_VALID (0x3 << 12) #define FORCE_VBUS_VALID_SHIFT 12 #define FORCE_VBUS_VALID_LOW 2 #define FORCE_VBUS_VALID_HIGH 3 #define VBUS_CHANGE_DET (1 << 6) #define ID_CHANGE_DET (1 << 5) #define DPDM_CHANGE_DET (1 << 4) #define OTG_PHY_CFG 0x20 #define OTG_PHY_ROUTE_OTG (1 << 0) #define PMU_IRQ_ENABLE 0x00 #define PMU_AHB_INCR8 (1 << 10) #define PMU_AHB_INCR4 (1 << 9) #define PMU_AHB_INCRX_ALIGN (1 << 8) #define PMU_ULPI_BYPASS (1 << 0) #define PMU_UNK_H3 0x10 #define PMU_UNK_H3_CLR 0x2 static void awusbphy_configure(device_t dev, int phyno) { struct awusbphy_softc *sc; sc = device_get_softc(dev); if (sc->pmu[phyno] == NULL) return; if (sc->phy_conf->pmu_unk1 == true) CLR4(sc->pmu[phyno], PMU_UNK_H3, PMU_UNK_H3_CLR); SET4(sc->pmu[phyno], PMU_IRQ_ENABLE, PMU_ULPI_BYPASS | PMU_AHB_INCR8 | PMU_AHB_INCR4 | PMU_AHB_INCRX_ALIGN); } static int awusbphy_init(device_t dev) { struct awusbphy_softc *sc; phandle_t node; char pname[20]; uint32_t val; int error, off, rid; regulator_t reg; hwreset_t rst; clk_t clk; sc = device_get_softc(dev); node = ofw_bus_get_node(dev); sc->phy_conf = (struct aw_usbphy_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; /* Get phy_ctrl region */ if (ofw_bus_find_string_index(node, "reg-names", "phy_ctrl", &rid) != 0) { device_printf(dev, "Cannot locate phy control resource\n"); return (ENXIO); } sc->phy_ctrl = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->phy_ctrl == NULL) { device_printf(dev, "Cannot allocate resource\n"); return (ENXIO); } /* Enable clocks */ for (off = 0; clk_get_by_ofw_index(dev, 0, off, &clk) == 0; off++) { error = clk_enable(clk); if (error != 0) { device_printf(dev, "couldn't enable clock %s\n", clk_get_name(clk)); return (error); } } /* De-assert resets */ for (off = 0; hwreset_get_by_ofw_idx(dev, 0, off, &rst) == 0; off++) { error = hwreset_deassert(rst); if (error != 0) { device_printf(dev, "couldn't de-assert reset %d\n", off); return (error); } } /* Get GPIOs */ error = gpio_pin_get_by_ofw_property(dev, node, "usb0_id_det-gpios", &sc->id_det_pin); if (error == 0) sc->id_det_valid = 1; error = gpio_pin_get_by_ofw_property(dev, node, "usb0_vbus_det-gpios", &sc->vbus_det_pin); if (error == 0) sc->vbus_det_valid = 1; sc->reg = malloc(sizeof(*(sc->reg)) * sc->phy_conf->num_phys, M_DEVBUF, M_WAITOK | M_ZERO); sc->pmu = malloc(sizeof(*(sc->pmu)) * sc->phy_conf->num_phys, M_DEVBUF, M_WAITOK | M_ZERO); /* Get regulators */ for (off = 0; off < sc->phy_conf->num_phys; off++) { snprintf(pname, sizeof(pname), "usb%d_vbus-supply", off); if (regulator_get_by_ofw_property(dev, 0, pname, ®) == 0) sc->reg[off] = reg; snprintf(pname, sizeof(pname), "pmu%d", off); if (ofw_bus_find_string_index(node, "reg-names", pname, &rid) != 0) continue; sc->pmu[off] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->pmu[off] == NULL) { device_printf(dev, "Cannot allocate resource\n"); return (ENXIO); } } /* Enable OTG PHY for host mode */ val = bus_read_4(sc->phy_ctrl, PHY_CSR); val &= ~(VBUS_CHANGE_DET | ID_CHANGE_DET | DPDM_CHANGE_DET); val |= (ID_PULLUP_EN | DPDM_PULLUP_EN); val &= ~FORCE_ID; val |= (FORCE_ID_LOW << FORCE_ID_SHIFT); val &= ~FORCE_VBUS_VALID; val |= (FORCE_VBUS_VALID_HIGH << FORCE_VBUS_VALID_SHIFT); bus_write_4(sc->phy_ctrl, PHY_CSR, val); return (0); } static int awusbphy_vbus_detect(device_t dev, int *val) { struct awusbphy_softc *sc; bool active; int error; sc = device_get_softc(dev); if (sc->vbus_det_valid) { error = gpio_pin_is_active(sc->vbus_det_pin, &active); if (error != 0) { device_printf(dev, "Cannot get status of id pin %d\n", error); return (error); } *val = active; return (0); } /* TODO check vbus_power-supply. */ /* * If there is no way to detect, assume present. */ *val = 1; return (0); } static int awusbphy_phy_enable(struct phynode *phynode, bool enable) { device_t dev; intptr_t phy; struct awusbphy_softc *sc; regulator_t reg; int error, vbus_det; dev = phynode_get_device(phynode); phy = phynode_get_id(phynode); sc = device_get_softc(dev); if (phy < 0 || phy >= sc->phy_conf->num_phys) return (ERANGE); /* Configure PHY */ awusbphy_configure(dev, phy); /* Regulators are optional. If not found, return success. */ reg = sc->reg[phy]; if (reg == NULL) return (0); if (phy == 0) { /* If an external vbus is detected, do not enable phy 0 */ error = awusbphy_vbus_detect(dev, &vbus_det); if (error) goto out; /* TODO check vbus_power-supply as well. */ if (sc->vbus_det_valid && vbus_det == 1) { if (bootverbose) device_printf(dev, "External VBUS detected, " "not enabling the regulator\n"); return (0); } } if (enable) { /* Depending on the PHY we need to route OTG to OHCI/EHCI */ error = regulator_enable(reg); } else error = regulator_disable(reg); out: if (error != 0) { device_printf(dev, "couldn't %s regulator for phy %jd\n", enable ? "enable" : "disable", (intmax_t)phy); return (error); } return (0); } static int awusbphy_get_mode(struct phynode *phynode, int *mode) { struct awusbphy_softc *sc; device_t dev; dev = phynode_get_device(phynode); sc = device_get_softc(dev); *mode = sc->mode; return (0); } static int awusbphy_set_mode(struct phynode *phynode, int mode) { device_t dev; intptr_t phy; struct awusbphy_softc *sc; uint32_t val; int error, vbus_det; dev = phynode_get_device(phynode); phy = phynode_get_id(phynode); sc = device_get_softc(dev); if (phy != 0) { if (mode != PHY_USB_MODE_HOST) return (EINVAL); return (0); } if (sc->mode == mode) return (0); if (mode == PHY_USB_MODE_OTG) /* TODO */ return (EOPNOTSUPP); error = awusbphy_vbus_detect(dev, &vbus_det); if (error != 0) return (error); val = bus_read_4(sc->phy_ctrl, PHY_CSR); val &= ~(VBUS_CHANGE_DET | ID_CHANGE_DET | DPDM_CHANGE_DET); val |= (ID_PULLUP_EN | DPDM_PULLUP_EN); val &= ~FORCE_VBUS_VALID; val |= (vbus_det ? FORCE_VBUS_VALID_HIGH : FORCE_VBUS_VALID_LOW) << FORCE_VBUS_VALID_SHIFT; val &= ~FORCE_ID; switch (mode) { case PHY_USB_MODE_HOST: val |= (FORCE_ID_LOW << FORCE_ID_SHIFT); if (sc->phy_conf->phy0_route) CLR4(sc->phy_ctrl, OTG_PHY_CFG, OTG_PHY_ROUTE_OTG); break; case PHY_USB_MODE_DEVICE: val |= (FORCE_ID_HIGH << FORCE_ID_SHIFT); if (sc->phy_conf->phy0_route) SET4(sc->phy_ctrl, OTG_PHY_CFG, OTG_PHY_ROUTE_OTG); break; default: return (EINVAL); } bus_write_4(sc->phy_ctrl, PHY_CSR, val); sc->mode = mode; return (0); } static int awusbphy_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Allwinner USB PHY"); return (BUS_PROBE_DEFAULT); } static int awusbphy_attach(device_t dev) { int error; struct phynode *phynode; struct phynode_init_def phy_init; struct awusbphy_softc *sc; int i; sc = device_get_softc(dev); error = awusbphy_init(dev); if (error) { device_printf(dev, "failed to initialize USB PHY, error %d\n", error); return (error); } /* Create and register phys. */ for (i = 0; i < sc->phy_conf->num_phys; i++) { bzero(&phy_init, sizeof(phy_init)); phy_init.id = i; phy_init.ofw_node = ofw_bus_get_node(dev); phynode = phynode_create(dev, &awusbphy_phynode_class, &phy_init); if (phynode == NULL) { device_printf(dev, "failed to create USB PHY\n"); return (ENXIO); } if (phynode_register(phynode) == NULL) { device_printf(dev, "failed to create USB PHY\n"); return (ENXIO); } } return (error); } static device_method_t awusbphy_methods[] = { /* Device interface */ DEVMETHOD(device_probe, awusbphy_probe), DEVMETHOD(device_attach, awusbphy_attach), DEVMETHOD_END }; static driver_t awusbphy_driver = { "awusbphy", awusbphy_methods, sizeof(struct awusbphy_softc) }; /* aw_usbphy needs to come up after regulators/gpio/etc, but before ehci/ohci */ EARLY_DRIVER_MODULE(awusbphy, simplebus, awusbphy_driver, 0, 0, BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE); MODULE_VERSION(awusbphy, 1); diff --git a/sys/arm/allwinner/axp209.c b/sys/arm/allwinner/axp209.c index b4e00988031e..239ead02d0e0 100644 --- a/sys/arm/allwinner/axp209.c +++ b/sys/arm/allwinner/axp209.c @@ -1,1419 +1,1419 @@ /*- * Copyright (c) 2015-2016 Emmanuel Vadot * Copyright (c) 2016 Jared McNeill * * 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 AND CONTRIBUTORS ``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 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 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. */ #include /* * X-Power AXP209/AXP211 PMU for Allwinner SoCs */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include "gpio_if.h" #include "regdev_if.h" MALLOC_DEFINE(M_AXP2XX_REG, "Axp2XX regulator", "Axp2XX power regulator"); struct axp2xx_regdef { intptr_t id; char *name; uint8_t enable_reg; uint8_t enable_mask; uint8_t voltage_reg; uint8_t voltage_mask; uint8_t voltage_shift; int voltage_min; int voltage_max; int voltage_step; int voltage_nstep; }; static struct axp2xx_regdef axp209_regdefs[] = { { .id = AXP209_REG_ID_DCDC2, .name = "dcdc2", .enable_reg = AXP209_POWERCTL, .enable_mask = AXP209_POWERCTL_DCDC2, .voltage_reg = AXP209_REG_DCDC2_VOLTAGE, .voltage_mask = 0x3f, .voltage_min = 700, .voltage_max = 2275, .voltage_step = 25, .voltage_nstep = 64, }, { .id = AXP209_REG_ID_DCDC3, .name = "dcdc3", .enable_reg = AXP209_POWERCTL, .enable_mask = AXP209_POWERCTL_DCDC3, .voltage_reg = AXP209_REG_DCDC3_VOLTAGE, .voltage_mask = 0x7f, .voltage_min = 700, .voltage_max = 3500, .voltage_step = 25, .voltage_nstep = 128, }, { .id = AXP209_REG_ID_LDO2, .name = "ldo2", .enable_reg = AXP209_POWERCTL, .enable_mask = AXP209_POWERCTL_LDO2, .voltage_reg = AXP209_REG_LDO24_VOLTAGE, .voltage_mask = 0xf0, .voltage_shift = 4, .voltage_min = 1800, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 16, }, { .id = AXP209_REG_ID_LDO3, .name = "ldo3", .enable_reg = AXP209_POWERCTL, .enable_mask = AXP209_POWERCTL_LDO3, .voltage_reg = AXP209_REG_LDO3_VOLTAGE, .voltage_mask = 0x7f, .voltage_min = 700, .voltage_max = 2275, .voltage_step = 25, .voltage_nstep = 128, }, }; static struct axp2xx_regdef axp221_regdefs[] = { { .id = AXP221_REG_ID_DLDO1, .name = "dldo1", .enable_reg = AXP221_POWERCTL_2, .enable_mask = AXP221_POWERCTL2_DLDO1, .voltage_reg = AXP221_REG_DLDO1_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_DLDO2, .name = "dldo2", .enable_reg = AXP221_POWERCTL_2, .enable_mask = AXP221_POWERCTL2_DLDO2, .voltage_reg = AXP221_REG_DLDO2_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_DLDO3, .name = "dldo3", .enable_reg = AXP221_POWERCTL_2, .enable_mask = AXP221_POWERCTL2_DLDO3, .voltage_reg = AXP221_REG_DLDO3_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_DLDO4, .name = "dldo4", .enable_reg = AXP221_POWERCTL_2, .enable_mask = AXP221_POWERCTL2_DLDO4, .voltage_reg = AXP221_REG_DLDO4_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_ELDO1, .name = "eldo1", .enable_reg = AXP221_POWERCTL_2, .enable_mask = AXP221_POWERCTL2_ELDO1, .voltage_reg = AXP221_REG_ELDO1_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_ELDO2, .name = "eldo2", .enable_reg = AXP221_POWERCTL_2, .enable_mask = AXP221_POWERCTL2_ELDO2, .voltage_reg = AXP221_REG_ELDO2_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_ELDO3, .name = "eldo3", .enable_reg = AXP221_POWERCTL_2, .enable_mask = AXP221_POWERCTL2_ELDO3, .voltage_reg = AXP221_REG_ELDO3_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_DC5LDO, .name = "dc5ldo", .enable_reg = AXP221_POWERCTL_1, .enable_mask = AXP221_POWERCTL1_DC5LDO, .voltage_reg = AXP221_REG_DC5LDO_VOLTAGE, .voltage_mask = 0x3, .voltage_min = 700, .voltage_max = 1400, .voltage_step = 100, .voltage_nstep = 7, }, { .id = AXP221_REG_ID_DCDC1, .name = "dcdc1", .enable_reg = AXP221_POWERCTL_1, .enable_mask = AXP221_POWERCTL1_DCDC1, .voltage_reg = AXP221_REG_DCDC1_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 1600, .voltage_max = 3400, .voltage_step = 100, .voltage_nstep = 18, }, { .id = AXP221_REG_ID_DCDC2, .name = "dcdc2", .enable_reg = AXP221_POWERCTL_1, .enable_mask = AXP221_POWERCTL1_DCDC2, .voltage_reg = AXP221_REG_DCDC2_VOLTAGE, .voltage_mask = 0x3f, .voltage_min = 600, .voltage_max = 1540, .voltage_step = 20, .voltage_nstep = 47, }, { .id = AXP221_REG_ID_DCDC3, .name = "dcdc3", .enable_reg = AXP221_POWERCTL_1, .enable_mask = AXP221_POWERCTL1_DCDC3, .voltage_reg = AXP221_REG_DCDC3_VOLTAGE, .voltage_mask = 0x3f, .voltage_min = 600, .voltage_max = 1860, .voltage_step = 20, .voltage_nstep = 63, }, { .id = AXP221_REG_ID_DCDC4, .name = "dcdc4", .enable_reg = AXP221_POWERCTL_1, .enable_mask = AXP221_POWERCTL1_DCDC4, .voltage_reg = AXP221_REG_DCDC4_VOLTAGE, .voltage_mask = 0x3f, .voltage_min = 600, .voltage_max = 1540, .voltage_step = 20, .voltage_nstep = 47, }, { .id = AXP221_REG_ID_DCDC5, .name = "dcdc5", .enable_reg = AXP221_POWERCTL_1, .enable_mask = AXP221_POWERCTL1_DCDC5, .voltage_reg = AXP221_REG_DCDC5_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 1000, .voltage_max = 2550, .voltage_step = 50, .voltage_nstep = 31, }, { .id = AXP221_REG_ID_ALDO1, .name = "aldo1", .enable_reg = AXP221_POWERCTL_1, .enable_mask = AXP221_POWERCTL1_ALDO1, .voltage_reg = AXP221_REG_ALDO1_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_ALDO2, .name = "aldo2", .enable_reg = AXP221_POWERCTL_1, .enable_mask = AXP221_POWERCTL1_ALDO2, .voltage_reg = AXP221_REG_ALDO2_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_ALDO3, .name = "aldo3", .enable_reg = AXP221_POWERCTL_3, .enable_mask = AXP221_POWERCTL3_ALDO3, .voltage_reg = AXP221_REG_ALDO3_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_DC1SW, .name = "dc1sw", .enable_reg = AXP221_POWERCTL_2, .enable_mask = AXP221_POWERCTL2_DC1SW, }, }; struct axp2xx_reg_sc { struct regnode *regnode; device_t base_dev; struct axp2xx_regdef *def; phandle_t xref; struct regnode_std_param *param; }; struct axp2xx_pins { const char *name; uint8_t ctrl_reg; uint8_t status_reg; uint8_t status_mask; uint8_t status_shift; }; /* GPIO3 is different, don't expose it for now */ static const struct axp2xx_pins axp209_pins[] = { { .name = "GPIO0", .ctrl_reg = AXP2XX_GPIO0_CTRL, .status_reg = AXP2XX_GPIO_STATUS, .status_mask = 0x10, .status_shift = 4, }, { .name = "GPIO1", .ctrl_reg = AXP2XX_GPIO1_CTRL, .status_reg = AXP2XX_GPIO_STATUS, .status_mask = 0x20, .status_shift = 5, }, { .name = "GPIO2", .ctrl_reg = AXP209_GPIO2_CTRL, .status_reg = AXP2XX_GPIO_STATUS, .status_mask = 0x40, .status_shift = 6, }, }; static const struct axp2xx_pins axp221_pins[] = { { .name = "GPIO0", .ctrl_reg = AXP2XX_GPIO0_CTRL, .status_reg = AXP2XX_GPIO_STATUS, .status_mask = 0x1, .status_shift = 0x0, }, { .name = "GPIO1", .ctrl_reg = AXP2XX_GPIO0_CTRL, .status_reg = AXP2XX_GPIO_STATUS, .status_mask = 0x2, .status_shift = 0x1, }, }; struct axp2xx_sensors { int id; const char *name; const char *desc; const char *format; uint8_t enable_reg; uint8_t enable_mask; uint8_t value_reg; uint8_t value_size; uint8_t h_value_mask; uint8_t h_value_shift; uint8_t l_value_mask; uint8_t l_value_shift; int value_step; int value_convert; }; static const struct axp2xx_sensors axp209_sensors[] = { { .id = AXP209_ACVOLT, .name = "acvolt", .desc = "AC Voltage (microvolt)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP209_ADC1_ACVOLT, .value_reg = AXP209_ACIN_VOLTAGE, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 4, .l_value_mask = 0xf, .l_value_shift = 0, .value_step = AXP209_VOLT_STEP, }, { .id = AXP209_ACCURRENT, .name = "accurrent", .desc = "AC Current (microAmpere)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP209_ADC1_ACCURRENT, .value_reg = AXP209_ACIN_CURRENT, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 4, .l_value_mask = 0xf, .l_value_shift = 0, .value_step = AXP209_ACCURRENT_STEP, }, { .id = AXP209_VBUSVOLT, .name = "vbusvolt", .desc = "VBUS Voltage (microVolt)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP209_ADC1_VBUSVOLT, .value_reg = AXP209_VBUS_VOLTAGE, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 4, .l_value_mask = 0xf, .l_value_shift = 0, .value_step = AXP209_VOLT_STEP, }, { .id = AXP209_VBUSCURRENT, .name = "vbuscurrent", .desc = "VBUS Current (microAmpere)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP209_ADC1_VBUSCURRENT, .value_reg = AXP209_VBUS_CURRENT, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 4, .l_value_mask = 0xf, .l_value_shift = 0, .value_step = AXP209_VBUSCURRENT_STEP, }, { .id = AXP2XX_BATVOLT, .name = "batvolt", .desc = "Battery Voltage (microVolt)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP2XX_ADC1_BATVOLT, .value_reg = AXP2XX_BAT_VOLTAGE, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 4, .l_value_mask = 0xf, .l_value_shift = 0, .value_step = AXP2XX_BATVOLT_STEP, }, { .id = AXP2XX_BATCHARGECURRENT, .name = "batchargecurrent", .desc = "Battery Charging Current (microAmpere)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP2XX_ADC1_BATCURRENT, .value_reg = AXP2XX_BAT_CHARGE_CURRENT, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 5, .l_value_mask = 0x1f, .l_value_shift = 0, .value_step = AXP2XX_BATCURRENT_STEP, }, { .id = AXP2XX_BATDISCHARGECURRENT, .name = "batdischargecurrent", .desc = "Battery Discharging Current (microAmpere)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP2XX_ADC1_BATCURRENT, .value_reg = AXP2XX_BAT_DISCHARGE_CURRENT, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 5, .l_value_mask = 0x1f, .l_value_shift = 0, .value_step = AXP2XX_BATCURRENT_STEP, }, { .id = AXP2XX_TEMP, .name = "temp", .desc = "Internal Temperature", .format = "IK", .enable_reg = AXP209_ADC_ENABLE2, .enable_mask = AXP209_ADC2_TEMP, .value_reg = AXP209_TEMPMON, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 4, .l_value_mask = 0xf, .l_value_shift = 0, .value_step = 1, .value_convert = -(AXP209_TEMPMON_MIN - AXP209_0C_TO_K), }, }; static const struct axp2xx_sensors axp221_sensors[] = { { .id = AXP2XX_BATVOLT, .name = "batvolt", .desc = "Battery Voltage (microVolt)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP2XX_ADC1_BATVOLT, .value_reg = AXP2XX_BAT_VOLTAGE, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 4, .l_value_mask = 0xf, .l_value_shift = 0, .value_step = AXP2XX_BATVOLT_STEP, }, { .id = AXP2XX_BATCHARGECURRENT, .name = "batchargecurrent", .desc = "Battery Charging Current (microAmpere)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP2XX_ADC1_BATCURRENT, .value_reg = AXP2XX_BAT_CHARGE_CURRENT, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 5, .l_value_mask = 0x1f, .l_value_shift = 0, .value_step = AXP2XX_BATCURRENT_STEP, }, { .id = AXP2XX_BATDISCHARGECURRENT, .name = "batdischargecurrent", .desc = "Battery Discharging Current (microAmpere)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP2XX_ADC1_BATCURRENT, .value_reg = AXP2XX_BAT_DISCHARGE_CURRENT, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 5, .l_value_mask = 0x1f, .l_value_shift = 0, .value_step = AXP2XX_BATCURRENT_STEP, }, { .id = AXP2XX_TEMP, .name = "temp", .desc = "Internal Temperature", .format = "IK", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP221_ADC1_TEMP, .value_reg = AXP221_TEMPMON, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 4, .l_value_mask = 0xf, .l_value_shift = 0, .value_step = 1, .value_convert = -(AXP221_TEMPMON_MIN - AXP209_0C_TO_K), }, }; enum AXP2XX_TYPE { AXP209 = 1, AXP221, }; struct axp2xx_softc { device_t dev; struct resource * res[1]; void * intrcookie; struct intr_config_hook intr_hook; struct mtx mtx; uint8_t type; /* GPIO */ device_t gpiodev; int npins; const struct axp2xx_pins *pins; /* Sensors */ const struct axp2xx_sensors *sensors; int nsensors; /* Regulators */ struct axp2xx_reg_sc **regs; int nregs; struct axp2xx_regdef *regdefs; }; static struct ofw_compat_data compat_data[] = { { "x-powers,axp209", AXP209 }, { "x-powers,axp221", AXP221 }, { NULL, 0 } }; static struct resource_spec axp_res_spec[] = { { SYS_RES_IRQ, 0, RF_ACTIVE }, { -1, 0, 0 } }; #define AXP_LOCK(sc) mtx_lock(&(sc)->mtx) #define AXP_UNLOCK(sc) mtx_unlock(&(sc)->mtx) static int axp2xx_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size) { return (iicdev_readfrom(dev, reg, data, size, IIC_INTRWAIT)); } static int axp2xx_write(device_t dev, uint8_t reg, uint8_t data) { return (iicdev_writeto(dev, reg, &data, sizeof(data), IIC_INTRWAIT)); } static int axp2xx_regnode_init(struct regnode *regnode) { return (0); } static int axp2xx_regnode_enable(struct regnode *regnode, bool enable, int *udelay) { struct axp2xx_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); axp2xx_read(sc->base_dev, sc->def->enable_reg, &val, 1); if (enable) val |= sc->def->enable_mask; else val &= ~sc->def->enable_mask; axp2xx_write(sc->base_dev, sc->def->enable_reg, val); *udelay = 0; return (0); } static void axp2xx_regnode_reg_to_voltage(struct axp2xx_reg_sc *sc, uint8_t val, int *uv) { if (val < sc->def->voltage_nstep) *uv = sc->def->voltage_min + val * sc->def->voltage_step; else *uv = sc->def->voltage_min + (sc->def->voltage_nstep * sc->def->voltage_step); *uv *= 1000; } static int axp2xx_regnode_voltage_to_reg(struct axp2xx_reg_sc *sc, int min_uvolt, int max_uvolt, uint8_t *val) { uint8_t nval; int nstep, uvolt; nval = 0; uvolt = sc->def->voltage_min * 1000; for (nstep = 0; nstep < sc->def->voltage_nstep && uvolt < min_uvolt; nstep++) { ++nval; uvolt += (sc->def->voltage_step * 1000); } if (uvolt > max_uvolt) return (EINVAL); *val = nval; return (0); } static int axp2xx_regnode_status(struct regnode *regnode, int *status) { struct axp2xx_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); *status = 0; axp2xx_read(sc->base_dev, sc->def->enable_reg, &val, 1); if (val & sc->def->enable_mask) *status = REGULATOR_STATUS_ENABLED; return (0); } static int axp2xx_regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay) { struct axp2xx_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); if (!sc->def->voltage_step) return (ENXIO); if (axp2xx_regnode_voltage_to_reg(sc, min_uvolt, max_uvolt, &val) != 0) return (ERANGE); axp2xx_write(sc->base_dev, sc->def->voltage_reg, val); *udelay = 0; return (0); } static int axp2xx_regnode_get_voltage(struct regnode *regnode, int *uvolt) { struct axp2xx_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); if (!sc->def->voltage_step) return (ENXIO); axp2xx_read(sc->base_dev, sc->def->voltage_reg, &val, 1); axp2xx_regnode_reg_to_voltage(sc, val & sc->def->voltage_mask, uvolt); return (0); } static regnode_method_t axp2xx_regnode_methods[] = { /* Regulator interface */ REGNODEMETHOD(regnode_init, axp2xx_regnode_init), REGNODEMETHOD(regnode_enable, axp2xx_regnode_enable), REGNODEMETHOD(regnode_status, axp2xx_regnode_status), REGNODEMETHOD(regnode_set_voltage, axp2xx_regnode_set_voltage), REGNODEMETHOD(regnode_get_voltage, axp2xx_regnode_get_voltage), REGNODEMETHOD(regnode_check_voltage, regnode_method_check_voltage), REGNODEMETHOD_END }; DEFINE_CLASS_1(axp2xx_regnode, axp2xx_regnode_class, axp2xx_regnode_methods, sizeof(struct axp2xx_reg_sc), regnode_class); static int axp2xx_sysctl(SYSCTL_HANDLER_ARGS) { struct axp2xx_softc *sc; device_t dev = arg1; enum axp2xx_sensor sensor = arg2; uint8_t data[2]; int val, error, i, found; sc = device_get_softc(dev); for (found = 0, i = 0; i < sc->nsensors; i++) { if (sc->sensors[i].id == sensor) { found = 1; break; } } if (found == 0) return (ENOENT); error = axp2xx_read(dev, sc->sensors[i].value_reg, data, 2); if (error != 0) return (error); val = ((data[0] & sc->sensors[i].h_value_mask) << sc->sensors[i].h_value_shift); val |= ((data[1] & sc->sensors[i].l_value_mask) << sc->sensors[i].l_value_shift); val *= sc->sensors[i].value_step; val += sc->sensors[i].value_convert; return sysctl_handle_opaque(oidp, &val, sizeof(val), req); } static void axp2xx_shutdown(void *devp, int howto) { device_t dev; if (!(howto & RB_POWEROFF)) return; dev = (device_t)devp; if (bootverbose) device_printf(dev, "Shutdown AXP2xx\n"); axp2xx_write(dev, AXP2XX_SHUTBAT, AXP2XX_SHUTBAT_SHUTDOWN); } static void axp2xx_intr(void *arg) { struct axp2xx_softc *sc; uint8_t reg; sc = arg; axp2xx_read(sc->dev, AXP2XX_IRQ1_STATUS, ®, 1); if (reg) { if (reg & AXP2XX_IRQ1_AC_OVERVOLT) devctl_notify("PMU", "AC", "overvoltage", NULL); if (reg & AXP2XX_IRQ1_VBUS_OVERVOLT) devctl_notify("PMU", "USB", "overvoltage", NULL); if (reg & AXP2XX_IRQ1_VBUS_LOW) devctl_notify("PMU", "USB", "undervoltage", NULL); if (reg & AXP2XX_IRQ1_AC_CONN) devctl_notify("PMU", "AC", "plugged", NULL); if (reg & AXP2XX_IRQ1_AC_DISCONN) devctl_notify("PMU", "AC", "unplugged", NULL); if (reg & AXP2XX_IRQ1_VBUS_CONN) devctl_notify("PMU", "USB", "plugged", NULL); if (reg & AXP2XX_IRQ1_VBUS_DISCONN) devctl_notify("PMU", "USB", "unplugged", NULL); axp2xx_write(sc->dev, AXP2XX_IRQ1_STATUS, AXP2XX_IRQ_ACK); } axp2xx_read(sc->dev, AXP2XX_IRQ2_STATUS, ®, 1); if (reg) { if (reg & AXP2XX_IRQ2_BATT_CHARGED) devctl_notify("PMU", "Battery", "charged", NULL); if (reg & AXP2XX_IRQ2_BATT_CHARGING) devctl_notify("PMU", "Battery", "charging", NULL); if (reg & AXP2XX_IRQ2_BATT_CONN) devctl_notify("PMU", "Battery", "connected", NULL); if (reg & AXP2XX_IRQ2_BATT_DISCONN) devctl_notify("PMU", "Battery", "disconnected", NULL); if (reg & AXP2XX_IRQ2_BATT_TEMP_LOW) devctl_notify("PMU", "Battery", "low-temp", NULL); if (reg & AXP2XX_IRQ2_BATT_TEMP_OVER) devctl_notify("PMU", "Battery", "high-temp", NULL); axp2xx_write(sc->dev, AXP2XX_IRQ2_STATUS, AXP2XX_IRQ_ACK); } axp2xx_read(sc->dev, AXP2XX_IRQ3_STATUS, ®, 1); if (reg) { if (reg & AXP2XX_IRQ3_PEK_SHORT) shutdown_nice(RB_POWEROFF); axp2xx_write(sc->dev, AXP2XX_IRQ3_STATUS, AXP2XX_IRQ_ACK); } axp2xx_read(sc->dev, AXP2XX_IRQ4_STATUS, ®, 1); if (reg) { axp2xx_write(sc->dev, AXP2XX_IRQ4_STATUS, AXP2XX_IRQ_ACK); } axp2xx_read(sc->dev, AXP2XX_IRQ5_STATUS, ®, 1); if (reg) { axp2xx_write(sc->dev, AXP2XX_IRQ5_STATUS, AXP2XX_IRQ_ACK); } } static device_t axp2xx_gpio_get_bus(device_t dev) { struct axp2xx_softc *sc; sc = device_get_softc(dev); return (sc->gpiodev); } static int axp2xx_gpio_pin_max(device_t dev, int *maxpin) { struct axp2xx_softc *sc; sc = device_get_softc(dev); *maxpin = sc->npins - 1; return (0); } static int axp2xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name) { struct axp2xx_softc *sc; sc = device_get_softc(dev); if (pin >= sc->npins) return (EINVAL); snprintf(name, GPIOMAXNAME, "%s", axp209_pins[pin].name); return (0); } static int axp2xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) { struct axp2xx_softc *sc; sc = device_get_softc(dev); if (pin >= sc->npins) return (EINVAL); *caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT; return (0); } static int axp2xx_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) { struct axp2xx_softc *sc; uint8_t data, func; int error; sc = device_get_softc(dev); if (pin >= sc->npins) return (EINVAL); AXP_LOCK(sc); error = axp2xx_read(dev, sc->pins[pin].ctrl_reg, &data, 1); if (error == 0) { func = data & AXP2XX_GPIO_FUNC_MASK; if (func == AXP2XX_GPIO_FUNC_INPUT) *flags = GPIO_PIN_INPUT; else if (func == AXP2XX_GPIO_FUNC_DRVLO || func == AXP2XX_GPIO_FUNC_DRVHI) *flags = GPIO_PIN_OUTPUT; else *flags = 0; } AXP_UNLOCK(sc); return (error); } static int axp2xx_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) { struct axp2xx_softc *sc; uint8_t data; int error; sc = device_get_softc(dev); if (pin >= sc->npins) return (EINVAL); AXP_LOCK(sc); error = axp2xx_read(dev, sc->pins[pin].ctrl_reg, &data, 1); if (error == 0) { data &= ~AXP2XX_GPIO_FUNC_MASK; if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) != 0) { if ((flags & GPIO_PIN_OUTPUT) == 0) data |= AXP2XX_GPIO_FUNC_INPUT; } error = axp2xx_write(dev, sc->pins[pin].ctrl_reg, data); } AXP_UNLOCK(sc); return (error); } static int axp2xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) { struct axp2xx_softc *sc; uint8_t data, func; int error; sc = device_get_softc(dev); if (pin >= sc->npins) return (EINVAL); AXP_LOCK(sc); error = axp2xx_read(dev, sc->pins[pin].ctrl_reg, &data, 1); if (error == 0) { func = data & AXP2XX_GPIO_FUNC_MASK; switch (func) { case AXP2XX_GPIO_FUNC_DRVLO: *val = 0; break; case AXP2XX_GPIO_FUNC_DRVHI: *val = 1; break; case AXP2XX_GPIO_FUNC_INPUT: error = axp2xx_read(dev, sc->pins[pin].status_reg, &data, 1); if (error == 0) { *val = (data & sc->pins[pin].status_mask); *val >>= sc->pins[pin].status_shift; } break; default: error = EIO; break; } } AXP_UNLOCK(sc); return (error); } static int axp2xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int val) { struct axp2xx_softc *sc; uint8_t data, func; int error; sc = device_get_softc(dev); if (pin >= sc->npins) return (EINVAL); AXP_LOCK(sc); error = axp2xx_read(dev, sc->pins[pin].ctrl_reg, &data, 1); if (error == 0) { func = data & AXP2XX_GPIO_FUNC_MASK; switch (func) { case AXP2XX_GPIO_FUNC_DRVLO: case AXP2XX_GPIO_FUNC_DRVHI: /* GPIO2 can't be set to 1 */ if (pin == 2 && val == 1) { error = EINVAL; break; } data &= ~AXP2XX_GPIO_FUNC_MASK; data |= val; break; default: error = EIO; break; } } if (error == 0) error = axp2xx_write(dev, sc->pins[pin].ctrl_reg, data); AXP_UNLOCK(sc); return (error); } static int axp2xx_gpio_pin_toggle(device_t dev, uint32_t pin) { struct axp2xx_softc *sc; uint8_t data, func; int error; sc = device_get_softc(dev); if (pin >= sc->npins) return (EINVAL); AXP_LOCK(sc); error = axp2xx_read(dev, sc->pins[pin].ctrl_reg, &data, 1); if (error == 0) { func = data & AXP2XX_GPIO_FUNC_MASK; switch (func) { case AXP2XX_GPIO_FUNC_DRVLO: /* Pin 2 can't be set to 1*/ if (pin == 2) { error = EINVAL; break; } data &= ~AXP2XX_GPIO_FUNC_MASK; data |= AXP2XX_GPIO_FUNC_DRVHI; break; case AXP2XX_GPIO_FUNC_DRVHI: data &= ~AXP2XX_GPIO_FUNC_MASK; data |= AXP2XX_GPIO_FUNC_DRVLO; break; default: error = EIO; break; } } if (error == 0) error = axp2xx_write(dev, sc->pins[pin].ctrl_reg, data); AXP_UNLOCK(sc); return (error); } static int axp2xx_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags) { struct axp2xx_softc *sc; sc = device_get_softc(bus); if (gpios[0] >= sc->npins) return (EINVAL); *pin = gpios[0]; *flags = gpios[1]; return (0); } static phandle_t axp2xx_get_node(device_t dev, device_t bus) { return (ofw_bus_get_node(dev)); } static struct axp2xx_reg_sc * axp2xx_reg_attach(device_t dev, phandle_t node, struct axp2xx_regdef *def) { struct axp2xx_reg_sc *reg_sc; struct regnode_init_def initdef; struct regnode *regnode; memset(&initdef, 0, sizeof(initdef)); if (regulator_parse_ofw_stdparam(dev, node, &initdef) != 0) { device_printf(dev, "cannot create regulator\n"); return (NULL); } if (initdef.std_param.min_uvolt == 0) initdef.std_param.min_uvolt = def->voltage_min * 1000; if (initdef.std_param.max_uvolt == 0) initdef.std_param.max_uvolt = def->voltage_max * 1000; initdef.id = def->id; initdef.ofw_node = node; regnode = regnode_create(dev, &axp2xx_regnode_class, &initdef); if (regnode == NULL) { device_printf(dev, "cannot create regulator\n"); return (NULL); } reg_sc = regnode_get_softc(regnode); reg_sc->regnode = regnode; reg_sc->base_dev = dev; reg_sc->def = def; reg_sc->xref = OF_xref_from_node(node); reg_sc->param = regnode_get_stdparam(regnode); regnode_register(regnode); return (reg_sc); } static int axp2xx_regdev_map(device_t dev, phandle_t xref, int ncells, pcell_t *cells, intptr_t *num) { struct axp2xx_softc *sc; int i; sc = device_get_softc(dev); for (i = 0; i < sc->nregs; i++) { if (sc->regs[i] == NULL) continue; if (sc->regs[i]->xref == xref) { *num = sc->regs[i]->def->id; return (0); } } return (ENXIO); } static void axp2xx_start(void *pdev) { device_t dev; struct axp2xx_softc *sc; const char *pwr_name[] = {"Battery", "AC", "USB", "AC and USB"}; int i; uint8_t reg, data; uint8_t pwr_src; dev = pdev; sc = device_get_softc(dev); sc->dev = dev; if (bootverbose) { /* * Read the Power State register. * Shift the AC presence into bit 0. * Shift the Battery presence into bit 1. */ axp2xx_read(dev, AXP2XX_PSR, &data, 1); pwr_src = ((data & AXP2XX_PSR_ACIN) >> AXP2XX_PSR_ACIN_SHIFT) | ((data & AXP2XX_PSR_VBUS) >> (AXP2XX_PSR_VBUS_SHIFT - 1)); device_printf(dev, "Powered by %s\n", pwr_name[pwr_src]); } /* Only enable interrupts that we are interested in */ axp2xx_write(dev, AXP2XX_IRQ1_ENABLE, AXP2XX_IRQ1_AC_OVERVOLT | AXP2XX_IRQ1_AC_DISCONN | AXP2XX_IRQ1_AC_CONN | AXP2XX_IRQ1_VBUS_OVERVOLT | AXP2XX_IRQ1_VBUS_DISCONN | AXP2XX_IRQ1_VBUS_CONN); axp2xx_write(dev, AXP2XX_IRQ2_ENABLE, AXP2XX_IRQ2_BATT_CONN | AXP2XX_IRQ2_BATT_DISCONN | AXP2XX_IRQ2_BATT_CHARGE_ACCT_ON | AXP2XX_IRQ2_BATT_CHARGE_ACCT_OFF | AXP2XX_IRQ2_BATT_CHARGING | AXP2XX_IRQ2_BATT_CHARGED | AXP2XX_IRQ2_BATT_TEMP_OVER | AXP2XX_IRQ2_BATT_TEMP_LOW); axp2xx_write(dev, AXP2XX_IRQ3_ENABLE, AXP2XX_IRQ3_PEK_SHORT | AXP2XX_IRQ3_PEK_LONG); axp2xx_write(dev, AXP2XX_IRQ4_ENABLE, AXP2XX_IRQ4_APS_LOW_2); axp2xx_write(dev, AXP2XX_IRQ5_ENABLE, 0x0); EVENTHANDLER_REGISTER(shutdown_final, axp2xx_shutdown, dev, SHUTDOWN_PRI_LAST); /* Enable ADC sensors */ for (i = 0; i < sc->nsensors; i++) { if (axp2xx_read(dev, sc->sensors[i].enable_reg, ®, 1) == -1) { device_printf(dev, "Cannot enable sensor '%s'\n", sc->sensors[i].name); continue; } reg |= sc->sensors[i].enable_mask; if (axp2xx_write(dev, sc->sensors[i].enable_reg, reg) == -1) { device_printf(dev, "Cannot enable sensor '%s'\n", sc->sensors[i].name); continue; } SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, sc->sensors[i].name, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, dev, sc->sensors[i].id, axp2xx_sysctl, sc->sensors[i].format, sc->sensors[i].desc); } if ((bus_setup_intr(dev, sc->res[0], INTR_TYPE_MISC | INTR_MPSAFE, NULL, axp2xx_intr, sc, &sc->intrcookie))) device_printf(dev, "unable to register interrupt handler\n"); config_intrhook_disestablish(&sc->intr_hook); } static int axp2xx_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) { case AXP209: device_set_desc(dev, "X-Powers AXP209 Power Management Unit"); break; case AXP221: device_set_desc(dev, "X-Powers AXP221 Power Management Unit"); break; default: return (ENXIO); } return (BUS_PROBE_DEFAULT); } static int axp2xx_attach(device_t dev) { struct axp2xx_softc *sc; struct axp2xx_reg_sc *reg; struct axp2xx_regdef *regdefs; phandle_t rnode, child; int i; sc = device_get_softc(dev); mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); if (bus_alloc_resources(dev, axp_res_spec, sc->res) != 0) { device_printf(dev, "can't allocate device resources\n"); return (ENXIO); } sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; switch (sc->type) { case AXP209: sc->pins = axp209_pins; sc->npins = nitems(axp209_pins); sc->gpiodev = gpiobus_attach_bus(dev); sc->sensors = axp209_sensors; sc->nsensors = nitems(axp209_sensors); regdefs = axp209_regdefs; sc->nregs = nitems(axp209_regdefs); break; case AXP221: sc->pins = axp221_pins; sc->npins = nitems(axp221_pins); sc->gpiodev = gpiobus_attach_bus(dev); sc->sensors = axp221_sensors; sc->nsensors = nitems(axp221_sensors); regdefs = axp221_regdefs; sc->nregs = nitems(axp221_regdefs); break; } sc->regs = malloc(sizeof(struct axp2xx_reg_sc *) * sc->nregs, M_AXP2XX_REG, M_WAITOK | M_ZERO); sc->intr_hook.ich_func = axp2xx_start; sc->intr_hook.ich_arg = dev; if (config_intrhook_establish(&sc->intr_hook) != 0) return (ENOMEM); /* Attach known regulators that exist in the DT */ rnode = ofw_bus_find_child(ofw_bus_get_node(dev), "regulators"); if (rnode > 0) { for (i = 0; i < sc->nregs; i++) { child = ofw_bus_find_child(rnode, regdefs[i].name); if (child == 0) continue; reg = axp2xx_reg_attach(dev, child, ®defs[i]); if (reg == NULL) { device_printf(dev, "cannot attach regulator %s\n", regdefs[i].name); continue; } sc->regs[i] = reg; if (bootverbose) device_printf(dev, "Regulator %s attached\n", regdefs[i].name); } } return (0); } static device_method_t axp2xx_methods[] = { DEVMETHOD(device_probe, axp2xx_probe), DEVMETHOD(device_attach, axp2xx_attach), /* GPIO interface */ DEVMETHOD(gpio_get_bus, axp2xx_gpio_get_bus), DEVMETHOD(gpio_pin_max, axp2xx_gpio_pin_max), DEVMETHOD(gpio_pin_getname, axp2xx_gpio_pin_getname), DEVMETHOD(gpio_pin_getcaps, axp2xx_gpio_pin_getcaps), DEVMETHOD(gpio_pin_getflags, axp2xx_gpio_pin_getflags), DEVMETHOD(gpio_pin_setflags, axp2xx_gpio_pin_setflags), DEVMETHOD(gpio_pin_get, axp2xx_gpio_pin_get), DEVMETHOD(gpio_pin_set, axp2xx_gpio_pin_set), DEVMETHOD(gpio_pin_toggle, axp2xx_gpio_pin_toggle), DEVMETHOD(gpio_map_gpios, axp2xx_gpio_map_gpios), /* Regdev interface */ DEVMETHOD(regdev_map, axp2xx_regdev_map), /* OFW bus interface */ DEVMETHOD(ofw_bus_get_node, axp2xx_get_node), DEVMETHOD_END }; static driver_t axp2xx_driver = { "axp2xx_pmu", axp2xx_methods, sizeof(struct axp2xx_softc), }; extern driver_t ofw_gpiobus_driver, gpioc_driver; EARLY_DRIVER_MODULE(axp2xx, iicbus, axp2xx_driver, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); EARLY_DRIVER_MODULE(ofw_gpiobus, axp2xx_pmu, ofw_gpiobus_driver, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); DRIVER_MODULE(gpioc, axp2xx_pmu, gpioc_driver, 0, 0); MODULE_VERSION(axp2xx, 1); MODULE_DEPEND(axp2xx, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); diff --git a/sys/arm/allwinner/axp81x.c b/sys/arm/allwinner/axp81x.c index ac9f9ee9e8ba..fc1a168595e5 100644 --- a/sys/arm/allwinner/axp81x.c +++ b/sys/arm/allwinner/axp81x.c @@ -1,1658 +1,1658 @@ /*- * Copyright (c) 2018 Emmanuel Vadot * Copyright (c) 2016 Jared McNeill * * 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. */ /* * X-Powers AXP803/813/818 PMU for Allwinner SoCs */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include "gpio_if.h" #include "iicbus_if.h" #include "regdev_if.h" MALLOC_DEFINE(M_AXP8XX_REG, "AXP8xx regulator", "AXP8xx power regulator"); #define AXP_POWERSRC 0x00 #define AXP_POWERSRC_ACIN (1 << 7) #define AXP_POWERSRC_VBUS (1 << 5) #define AXP_POWERSRC_VBAT (1 << 3) #define AXP_POWERSRC_CHARING (1 << 2) /* Charging Direction */ #define AXP_POWERSRC_SHORTED (1 << 1) #define AXP_POWERSRC_STARTUP (1 << 0) #define AXP_POWERMODE 0x01 #define AXP_POWERMODE_BAT_CHARGING (1 << 6) #define AXP_POWERMODE_BAT_PRESENT (1 << 5) #define AXP_POWERMODE_BAT_VALID (1 << 4) #define AXP_ICTYPE 0x03 #define AXP_POWERCTL1 0x10 #define AXP_POWERCTL1_DCDC7 (1 << 6) /* AXP813/818 only */ #define AXP_POWERCTL1_DCDC6 (1 << 5) #define AXP_POWERCTL1_DCDC5 (1 << 4) #define AXP_POWERCTL1_DCDC4 (1 << 3) #define AXP_POWERCTL1_DCDC3 (1 << 2) #define AXP_POWERCTL1_DCDC2 (1 << 1) #define AXP_POWERCTL1_DCDC1 (1 << 0) #define AXP_POWERCTL2 0x12 #define AXP_POWERCTL2_DC1SW (1 << 7) /* AXP803 only */ #define AXP_POWERCTL2_DLDO4 (1 << 6) #define AXP_POWERCTL2_DLDO3 (1 << 5) #define AXP_POWERCTL2_DLDO2 (1 << 4) #define AXP_POWERCTL2_DLDO1 (1 << 3) #define AXP_POWERCTL2_ELDO3 (1 << 2) #define AXP_POWERCTL2_ELDO2 (1 << 1) #define AXP_POWERCTL2_ELDO1 (1 << 0) #define AXP_POWERCTL3 0x13 #define AXP_POWERCTL3_ALDO3 (1 << 7) #define AXP_POWERCTL3_ALDO2 (1 << 6) #define AXP_POWERCTL3_ALDO1 (1 << 5) #define AXP_POWERCTL3_FLDO3 (1 << 4) /* AXP813/818 only */ #define AXP_POWERCTL3_FLDO2 (1 << 3) #define AXP_POWERCTL3_FLDO1 (1 << 2) #define AXP_VOLTCTL_DLDO1 0x15 #define AXP_VOLTCTL_DLDO2 0x16 #define AXP_VOLTCTL_DLDO3 0x17 #define AXP_VOLTCTL_DLDO4 0x18 #define AXP_VOLTCTL_ELDO1 0x19 #define AXP_VOLTCTL_ELDO2 0x1A #define AXP_VOLTCTL_ELDO3 0x1B #define AXP_VOLTCTL_FLDO1 0x1C #define AXP_VOLTCTL_FLDO2 0x1D #define AXP_VOLTCTL_DCDC1 0x20 #define AXP_VOLTCTL_DCDC2 0x21 #define AXP_VOLTCTL_DCDC3 0x22 #define AXP_VOLTCTL_DCDC4 0x23 #define AXP_VOLTCTL_DCDC5 0x24 #define AXP_VOLTCTL_DCDC6 0x25 #define AXP_VOLTCTL_DCDC7 0x26 #define AXP_VOLTCTL_ALDO1 0x28 #define AXP_VOLTCTL_ALDO2 0x29 #define AXP_VOLTCTL_ALDO3 0x2A #define AXP_VOLTCTL_STATUS (1 << 7) #define AXP_VOLTCTL_MASK 0x7f #define AXP_POWERBAT 0x32 #define AXP_POWERBAT_SHUTDOWN (1 << 7) #define AXP_CHARGERCTL1 0x33 #define AXP_CHARGERCTL1_MIN 0 #define AXP_CHARGERCTL1_MAX 13 #define AXP_CHARGERCTL1_CMASK 0xf #define AXP_IRQEN1 0x40 #define AXP_IRQEN1_ACIN_HI (1 << 6) #define AXP_IRQEN1_ACIN_LO (1 << 5) #define AXP_IRQEN1_VBUS_HI (1 << 3) #define AXP_IRQEN1_VBUS_LO (1 << 2) #define AXP_IRQEN2 0x41 #define AXP_IRQEN2_BAT_IN (1 << 7) #define AXP_IRQEN2_BAT_NO (1 << 6) #define AXP_IRQEN2_BATCHGC (1 << 3) #define AXP_IRQEN2_BATCHGD (1 << 2) #define AXP_IRQEN3 0x42 #define AXP_IRQEN4 0x43 #define AXP_IRQEN4_BATLVL_LO1 (1 << 1) #define AXP_IRQEN4_BATLVL_LO0 (1 << 0) #define AXP_IRQEN5 0x44 #define AXP_IRQEN5_POKSIRQ (1 << 4) #define AXP_IRQEN5_POKLIRQ (1 << 3) #define AXP_IRQEN6 0x45 #define AXP_IRQSTAT1 0x48 #define AXP_IRQSTAT1_ACIN_HI (1 << 6) #define AXP_IRQSTAT1_ACIN_LO (1 << 5) #define AXP_IRQSTAT1_VBUS_HI (1 << 3) #define AXP_IRQSTAT1_VBUS_LO (1 << 2) #define AXP_IRQSTAT2 0x49 #define AXP_IRQSTAT2_BAT_IN (1 << 7) #define AXP_IRQSTAT2_BAT_NO (1 << 6) #define AXP_IRQSTAT2_BATCHGC (1 << 3) #define AXP_IRQSTAT2_BATCHGD (1 << 2) #define AXP_IRQSTAT3 0x4a #define AXP_IRQSTAT4 0x4b #define AXP_IRQSTAT4_BATLVL_LO1 (1 << 1) #define AXP_IRQSTAT4_BATLVL_LO0 (1 << 0) #define AXP_IRQSTAT5 0x4c #define AXP_IRQSTAT5_POKSIRQ (1 << 4) #define AXP_IRQEN5_POKLIRQ (1 << 3) #define AXP_IRQSTAT6 0x4d #define AXP_BATSENSE_HI 0x78 #define AXP_BATSENSE_LO 0x79 #define AXP_BATCHG_HI 0x7a #define AXP_BATCHG_LO 0x7b #define AXP_BATDISCHG_HI 0x7c #define AXP_BATDISCHG_LO 0x7d #define AXP_GPIO0_CTRL 0x90 #define AXP_GPIO0LDO_CTRL 0x91 #define AXP_GPIO1_CTRL 0x92 #define AXP_GPIO1LDO_CTRL 0x93 #define AXP_GPIO_FUNC (0x7 << 0) #define AXP_GPIO_FUNC_SHIFT 0 #define AXP_GPIO_FUNC_DRVLO 0 #define AXP_GPIO_FUNC_DRVHI 1 #define AXP_GPIO_FUNC_INPUT 2 #define AXP_GPIO_FUNC_LDO_ON 3 #define AXP_GPIO_FUNC_LDO_OFF 4 #define AXP_GPIO_SIGBIT 0x94 #define AXP_GPIO_PD 0x97 #define AXP_FUEL_GAUGECTL 0xb8 #define AXP_FUEL_GAUGECTL_EN (1 << 7) #define AXP_BAT_CAP 0xb9 #define AXP_BAT_CAP_VALID (1 << 7) #define AXP_BAT_CAP_PERCENT 0x7f #define AXP_BAT_MAX_CAP_HI 0xe0 #define AXP_BAT_MAX_CAP_VALID (1 << 7) #define AXP_BAT_MAX_CAP_LO 0xe1 #define AXP_BAT_COULOMB_HI 0xe2 #define AXP_BAT_COULOMB_VALID (1 << 7) #define AXP_BAT_COULOMB_LO 0xe3 #define AXP_BAT_CAP_WARN 0xe6 #define AXP_BAT_CAP_WARN_LV1 0xf0 /* Bits 4, 5, 6, 7 */ #define AXP_BAP_CAP_WARN_LV1BASE 5 /* 5-20%, 1% per step */ #define AXP_BAT_CAP_WARN_LV2 0xf /* Bits 0, 1, 2, 3 */ /* Sensor conversion macros */ #define AXP_SENSOR_BAT_H(hi) ((hi) << 4) #define AXP_SENSOR_BAT_L(lo) ((lo) & 0xf) #define AXP_SENSOR_COULOMB(hi, lo) (((hi & ~(1 << 7)) << 8) | (lo)) static const struct { const char *name; uint8_t ctrl_reg; } axp8xx_pins[] = { { "GPIO0", AXP_GPIO0_CTRL }, { "GPIO1", AXP_GPIO1_CTRL }, }; enum AXP8XX_TYPE { AXP803 = 1, AXP813, }; static struct ofw_compat_data compat_data[] = { { "x-powers,axp803", AXP803 }, { "x-powers,axp813", AXP813 }, { "x-powers,axp818", AXP813 }, { NULL, 0 } }; static struct resource_spec axp8xx_spec[] = { { SYS_RES_IRQ, 0, RF_ACTIVE }, { -1, 0 } }; struct axp8xx_regdef { intptr_t id; char *name; char *supply_name; uint8_t enable_reg; uint8_t enable_mask; uint8_t enable_value; uint8_t disable_value; uint8_t voltage_reg; int voltage_min; int voltage_max; int voltage_step1; int voltage_nstep1; int voltage_step2; int voltage_nstep2; }; enum axp8xx_reg_id { AXP8XX_REG_ID_DCDC1 = 100, AXP8XX_REG_ID_DCDC2, AXP8XX_REG_ID_DCDC3, AXP8XX_REG_ID_DCDC4, AXP8XX_REG_ID_DCDC5, AXP8XX_REG_ID_DCDC6, AXP813_REG_ID_DCDC7, AXP803_REG_ID_DC1SW, AXP8XX_REG_ID_DLDO1, AXP8XX_REG_ID_DLDO2, AXP8XX_REG_ID_DLDO3, AXP8XX_REG_ID_DLDO4, AXP8XX_REG_ID_ELDO1, AXP8XX_REG_ID_ELDO2, AXP8XX_REG_ID_ELDO3, AXP8XX_REG_ID_ALDO1, AXP8XX_REG_ID_ALDO2, AXP8XX_REG_ID_ALDO3, AXP8XX_REG_ID_FLDO1, AXP8XX_REG_ID_FLDO2, AXP813_REG_ID_FLDO3, AXP8XX_REG_ID_GPIO0_LDO, AXP8XX_REG_ID_GPIO1_LDO, }; static struct axp8xx_regdef axp803_regdefs[] = { { .id = AXP803_REG_ID_DC1SW, .name = "dc1sw", .enable_reg = AXP_POWERCTL2, .enable_mask = (uint8_t) AXP_POWERCTL2_DC1SW, .enable_value = AXP_POWERCTL2_DC1SW, }, }; static struct axp8xx_regdef axp813_regdefs[] = { { .id = AXP813_REG_ID_DCDC7, .name = "dcdc7", .enable_reg = AXP_POWERCTL1, .enable_mask = (uint8_t) AXP_POWERCTL1_DCDC7, .enable_value = AXP_POWERCTL1_DCDC7, .voltage_reg = AXP_VOLTCTL_DCDC7, .voltage_min = 600, .voltage_max = 1520, .voltage_step1 = 10, .voltage_nstep1 = 50, .voltage_step2 = 20, .voltage_nstep2 = 21, }, }; static struct axp8xx_regdef axp8xx_common_regdefs[] = { { .id = AXP8XX_REG_ID_DCDC1, .name = "dcdc1", .enable_reg = AXP_POWERCTL1, .enable_mask = (uint8_t) AXP_POWERCTL1_DCDC1, .enable_value = AXP_POWERCTL1_DCDC1, .voltage_reg = AXP_VOLTCTL_DCDC1, .voltage_min = 1600, .voltage_max = 3400, .voltage_step1 = 100, .voltage_nstep1 = 18, }, { .id = AXP8XX_REG_ID_DCDC2, .name = "dcdc2", .enable_reg = AXP_POWERCTL1, .enable_mask = (uint8_t) AXP_POWERCTL1_DCDC2, .enable_value = AXP_POWERCTL1_DCDC2, .voltage_reg = AXP_VOLTCTL_DCDC2, .voltage_min = 500, .voltage_max = 1300, .voltage_step1 = 10, .voltage_nstep1 = 70, .voltage_step2 = 20, .voltage_nstep2 = 5, }, { .id = AXP8XX_REG_ID_DCDC3, .name = "dcdc3", .enable_reg = AXP_POWERCTL1, .enable_mask = (uint8_t) AXP_POWERCTL1_DCDC3, .enable_value = AXP_POWERCTL1_DCDC3, .voltage_reg = AXP_VOLTCTL_DCDC3, .voltage_min = 500, .voltage_max = 1300, .voltage_step1 = 10, .voltage_nstep1 = 70, .voltage_step2 = 20, .voltage_nstep2 = 5, }, { .id = AXP8XX_REG_ID_DCDC4, .name = "dcdc4", .enable_reg = AXP_POWERCTL1, .enable_mask = (uint8_t) AXP_POWERCTL1_DCDC4, .enable_value = AXP_POWERCTL1_DCDC4, .voltage_reg = AXP_VOLTCTL_DCDC4, .voltage_min = 500, .voltage_max = 1300, .voltage_step1 = 10, .voltage_nstep1 = 70, .voltage_step2 = 20, .voltage_nstep2 = 5, }, { .id = AXP8XX_REG_ID_DCDC5, .name = "dcdc5", .enable_reg = AXP_POWERCTL1, .enable_mask = (uint8_t) AXP_POWERCTL1_DCDC5, .enable_value = AXP_POWERCTL1_DCDC5, .voltage_reg = AXP_VOLTCTL_DCDC5, .voltage_min = 800, .voltage_max = 1840, .voltage_step1 = 10, .voltage_nstep1 = 42, .voltage_step2 = 20, .voltage_nstep2 = 36, }, { .id = AXP8XX_REG_ID_DCDC6, .name = "dcdc6", .enable_reg = AXP_POWERCTL1, .enable_mask = (uint8_t) AXP_POWERCTL1_DCDC6, .enable_value = AXP_POWERCTL1_DCDC6, .voltage_reg = AXP_VOLTCTL_DCDC6, .voltage_min = 600, .voltage_max = 1520, .voltage_step1 = 10, .voltage_nstep1 = 50, .voltage_step2 = 20, .voltage_nstep2 = 21, }, { .id = AXP8XX_REG_ID_DLDO1, .name = "dldo1", .enable_reg = AXP_POWERCTL2, .enable_mask = (uint8_t) AXP_POWERCTL2_DLDO1, .enable_value = AXP_POWERCTL2_DLDO1, .voltage_reg = AXP_VOLTCTL_DLDO1, .voltage_min = 700, .voltage_max = 3300, .voltage_step1 = 100, .voltage_nstep1 = 26, }, { .id = AXP8XX_REG_ID_DLDO2, .name = "dldo2", .enable_reg = AXP_POWERCTL2, .enable_mask = (uint8_t) AXP_POWERCTL2_DLDO2, .enable_value = AXP_POWERCTL2_DLDO2, .voltage_reg = AXP_VOLTCTL_DLDO2, .voltage_min = 700, .voltage_max = 4200, .voltage_step1 = 100, .voltage_nstep1 = 27, .voltage_step2 = 200, .voltage_nstep2 = 4, }, { .id = AXP8XX_REG_ID_DLDO3, .name = "dldo3", .enable_reg = AXP_POWERCTL2, .enable_mask = (uint8_t) AXP_POWERCTL2_DLDO3, .enable_value = AXP_POWERCTL2_DLDO3, .voltage_reg = AXP_VOLTCTL_DLDO3, .voltage_min = 700, .voltage_max = 3300, .voltage_step1 = 100, .voltage_nstep1 = 26, }, { .id = AXP8XX_REG_ID_DLDO4, .name = "dldo4", .enable_reg = AXP_POWERCTL2, .enable_mask = (uint8_t) AXP_POWERCTL2_DLDO4, .enable_value = AXP_POWERCTL2_DLDO4, .voltage_reg = AXP_VOLTCTL_DLDO4, .voltage_min = 700, .voltage_max = 3300, .voltage_step1 = 100, .voltage_nstep1 = 26, }, { .id = AXP8XX_REG_ID_ALDO1, .name = "aldo1", .enable_reg = AXP_POWERCTL3, .enable_mask = (uint8_t) AXP_POWERCTL3_ALDO1, .enable_value = AXP_POWERCTL3_ALDO1, .voltage_reg = AXP_VOLTCTL_ALDO1, .voltage_min = 700, .voltage_max = 3300, .voltage_step1 = 100, .voltage_nstep1 = 26, }, { .id = AXP8XX_REG_ID_ALDO2, .name = "aldo2", .enable_reg = AXP_POWERCTL3, .enable_mask = (uint8_t) AXP_POWERCTL3_ALDO2, .enable_value = AXP_POWERCTL3_ALDO2, .voltage_reg = AXP_VOLTCTL_ALDO2, .voltage_min = 700, .voltage_max = 3300, .voltage_step1 = 100, .voltage_nstep1 = 26, }, { .id = AXP8XX_REG_ID_ALDO3, .name = "aldo3", .enable_reg = AXP_POWERCTL3, .enable_mask = (uint8_t) AXP_POWERCTL3_ALDO3, .enable_value = AXP_POWERCTL3_ALDO3, .voltage_reg = AXP_VOLTCTL_ALDO3, .voltage_min = 700, .voltage_max = 3300, .voltage_step1 = 100, .voltage_nstep1 = 26, }, { .id = AXP8XX_REG_ID_ELDO1, .name = "eldo1", .enable_reg = AXP_POWERCTL2, .enable_mask = (uint8_t) AXP_POWERCTL2_ELDO1, .enable_value = AXP_POWERCTL2_ELDO1, .voltage_reg = AXP_VOLTCTL_ELDO1, .voltage_min = 700, .voltage_max = 1900, .voltage_step1 = 50, .voltage_nstep1 = 24, }, { .id = AXP8XX_REG_ID_ELDO2, .name = "eldo2", .enable_reg = AXP_POWERCTL2, .enable_mask = (uint8_t) AXP_POWERCTL2_ELDO2, .enable_value = AXP_POWERCTL2_ELDO2, .voltage_reg = AXP_VOLTCTL_ELDO2, .voltage_min = 700, .voltage_max = 1900, .voltage_step1 = 50, .voltage_nstep1 = 24, }, { .id = AXP8XX_REG_ID_ELDO3, .name = "eldo3", .enable_reg = AXP_POWERCTL2, .enable_mask = (uint8_t) AXP_POWERCTL2_ELDO3, .enable_value = AXP_POWERCTL2_ELDO3, .voltage_reg = AXP_VOLTCTL_ELDO3, .voltage_min = 700, .voltage_max = 1900, .voltage_step1 = 50, .voltage_nstep1 = 24, }, { .id = AXP8XX_REG_ID_FLDO1, .name = "fldo1", .enable_reg = AXP_POWERCTL3, .enable_mask = (uint8_t) AXP_POWERCTL3_FLDO1, .enable_value = AXP_POWERCTL3_FLDO1, .voltage_reg = AXP_VOLTCTL_FLDO1, .voltage_min = 700, .voltage_max = 1450, .voltage_step1 = 50, .voltage_nstep1 = 15, }, { .id = AXP8XX_REG_ID_FLDO2, .name = "fldo2", .enable_reg = AXP_POWERCTL3, .enable_mask = (uint8_t) AXP_POWERCTL3_FLDO2, .enable_value = AXP_POWERCTL3_FLDO2, .voltage_reg = AXP_VOLTCTL_FLDO2, .voltage_min = 700, .voltage_max = 1450, .voltage_step1 = 50, .voltage_nstep1 = 15, }, { .id = AXP8XX_REG_ID_GPIO0_LDO, .name = "ldo-io0", .enable_reg = AXP_GPIO0_CTRL, .enable_mask = (uint8_t) AXP_GPIO_FUNC, .enable_value = AXP_GPIO_FUNC_LDO_ON, .disable_value = AXP_GPIO_FUNC_LDO_OFF, .voltage_reg = AXP_GPIO0LDO_CTRL, .voltage_min = 700, .voltage_max = 3300, .voltage_step1 = 100, .voltage_nstep1 = 26, }, { .id = AXP8XX_REG_ID_GPIO1_LDO, .name = "ldo-io1", .enable_reg = AXP_GPIO1_CTRL, .enable_mask = (uint8_t) AXP_GPIO_FUNC, .enable_value = AXP_GPIO_FUNC_LDO_ON, .disable_value = AXP_GPIO_FUNC_LDO_OFF, .voltage_reg = AXP_GPIO1LDO_CTRL, .voltage_min = 700, .voltage_max = 3300, .voltage_step1 = 100, .voltage_nstep1 = 26, }, }; enum axp8xx_sensor { AXP_SENSOR_ACIN_PRESENT, AXP_SENSOR_VBUS_PRESENT, AXP_SENSOR_BATT_PRESENT, AXP_SENSOR_BATT_CHARGING, AXP_SENSOR_BATT_CHARGE_STATE, AXP_SENSOR_BATT_VOLTAGE, AXP_SENSOR_BATT_CHARGE_CURRENT, AXP_SENSOR_BATT_DISCHARGE_CURRENT, AXP_SENSOR_BATT_CAPACITY_PERCENT, AXP_SENSOR_BATT_MAXIMUM_CAPACITY, AXP_SENSOR_BATT_CURRENT_CAPACITY, }; enum battery_capacity_state { BATT_CAPACITY_NORMAL = 1, /* normal cap in battery */ BATT_CAPACITY_WARNING, /* warning cap in battery */ BATT_CAPACITY_CRITICAL, /* critical cap in battery */ BATT_CAPACITY_HIGH, /* high cap in battery */ BATT_CAPACITY_MAX, /* maximum cap in battery */ BATT_CAPACITY_LOW /* low cap in battery */ }; struct axp8xx_sensors { int id; const char *name; const char *desc; const char *format; }; static const struct axp8xx_sensors axp8xx_common_sensors[] = { { .id = AXP_SENSOR_ACIN_PRESENT, .name = "acin", .format = "I", .desc = "ACIN Present", }, { .id = AXP_SENSOR_VBUS_PRESENT, .name = "vbus", .format = "I", .desc = "VBUS Present", }, { .id = AXP_SENSOR_BATT_PRESENT, .name = "bat", .format = "I", .desc = "Battery Present", }, { .id = AXP_SENSOR_BATT_CHARGING, .name = "batcharging", .format = "I", .desc = "Battery Charging", }, { .id = AXP_SENSOR_BATT_CHARGE_STATE, .name = "batchargestate", .format = "I", .desc = "Battery Charge State", }, { .id = AXP_SENSOR_BATT_VOLTAGE, .name = "batvolt", .format = "I", .desc = "Battery Voltage", }, { .id = AXP_SENSOR_BATT_CHARGE_CURRENT, .name = "batchargecurrent", .format = "I", .desc = "Average Battery Charging Current", }, { .id = AXP_SENSOR_BATT_DISCHARGE_CURRENT, .name = "batdischargecurrent", .format = "I", .desc = "Average Battery Discharging Current", }, { .id = AXP_SENSOR_BATT_CAPACITY_PERCENT, .name = "batcapacitypercent", .format = "I", .desc = "Battery Capacity Percentage", }, { .id = AXP_SENSOR_BATT_MAXIMUM_CAPACITY, .name = "batmaxcapacity", .format = "I", .desc = "Battery Maximum Capacity", }, { .id = AXP_SENSOR_BATT_CURRENT_CAPACITY, .name = "batcurrentcapacity", .format = "I", .desc = "Battery Current Capacity", }, }; struct axp8xx_config { const char *name; int batsense_step; /* uV */ int charge_step; /* uA */ int discharge_step; /* uA */ int maxcap_step; /* uAh */ int coulomb_step; /* uAh */ }; static struct axp8xx_config axp803_config = { .name = "AXP803", .batsense_step = 1100, .charge_step = 1000, .discharge_step = 1000, .maxcap_step = 1456, .coulomb_step = 1456, }; struct axp8xx_softc; struct axp8xx_reg_sc { struct regnode *regnode; device_t base_dev; struct axp8xx_regdef *def; phandle_t xref; struct regnode_std_param *param; }; struct axp8xx_softc { struct resource *res; uint16_t addr; void *ih; device_t gpiodev; struct mtx mtx; int busy; int type; /* Configs */ const struct axp8xx_config *config; /* Sensors */ const struct axp8xx_sensors *sensors; int nsensors; /* Regulators */ struct axp8xx_reg_sc **regs; int nregs; /* Warning, shutdown thresholds */ int warn_thres; int shut_thres; }; #define AXP_LOCK(sc) mtx_lock(&(sc)->mtx) #define AXP_UNLOCK(sc) mtx_unlock(&(sc)->mtx) static int axp8xx_regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay); static int axp8xx_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size) { struct axp8xx_softc *sc; struct iic_msg msg[2]; sc = device_get_softc(dev); msg[0].slave = sc->addr; msg[0].flags = IIC_M_WR; msg[0].len = 1; msg[0].buf = ® msg[1].slave = sc->addr; msg[1].flags = IIC_M_RD; msg[1].len = size; msg[1].buf = data; return (iicbus_transfer(dev, msg, 2)); } static int axp8xx_write(device_t dev, uint8_t reg, uint8_t val) { struct axp8xx_softc *sc; struct iic_msg msg[2]; sc = device_get_softc(dev); msg[0].slave = sc->addr; msg[0].flags = IIC_M_WR; msg[0].len = 1; msg[0].buf = ® msg[1].slave = sc->addr; msg[1].flags = IIC_M_WR; msg[1].len = 1; msg[1].buf = &val; return (iicbus_transfer(dev, msg, 2)); } static int axp8xx_regnode_init(struct regnode *regnode) { struct regnode_std_param *param; int rv, udelay; param = regnode_get_stdparam(regnode); if (param->min_uvolt == 0) return (0); /* * Set the regulator at the correct voltage * Do not enable it, this is will be done either by a * consumer or by regnode_set_constraint if boot_on is true */ rv = axp8xx_regnode_set_voltage(regnode, param->min_uvolt, param->max_uvolt, &udelay); if (rv != 0) DELAY(udelay); return (rv); } static int axp8xx_regnode_enable(struct regnode *regnode, bool enable, int *udelay) { struct axp8xx_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); if (bootverbose) device_printf(sc->base_dev, "%sable %s (%s)\n", enable ? "En" : "Dis", regnode_get_name(regnode), sc->def->name); axp8xx_read(sc->base_dev, sc->def->enable_reg, &val, 1); val &= ~sc->def->enable_mask; if (enable) val |= sc->def->enable_value; else { if (sc->def->disable_value) val |= sc->def->disable_value; else val &= ~sc->def->enable_value; } axp8xx_write(sc->base_dev, sc->def->enable_reg, val); *udelay = 0; return (0); } static void axp8xx_regnode_reg_to_voltage(struct axp8xx_reg_sc *sc, uint8_t val, int *uv) { if (val < sc->def->voltage_nstep1) *uv = sc->def->voltage_min + val * sc->def->voltage_step1; else *uv = sc->def->voltage_min + (sc->def->voltage_nstep1 * sc->def->voltage_step1) + ((val - sc->def->voltage_nstep1) * sc->def->voltage_step2); *uv *= 1000; } static int axp8xx_regnode_voltage_to_reg(struct axp8xx_reg_sc *sc, int min_uvolt, int max_uvolt, uint8_t *val) { uint8_t nval; int nstep, uvolt; nval = 0; uvolt = sc->def->voltage_min * 1000; for (nstep = 0; nstep < sc->def->voltage_nstep1 && uvolt < min_uvolt; nstep++) { ++nval; uvolt += (sc->def->voltage_step1 * 1000); } for (nstep = 0; nstep < sc->def->voltage_nstep2 && uvolt < min_uvolt; nstep++) { ++nval; uvolt += (sc->def->voltage_step2 * 1000); } if (uvolt > max_uvolt) return (EINVAL); *val = nval; return (0); } static int axp8xx_regnode_status(struct regnode *regnode, int *status) { struct axp8xx_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); *status = 0; axp8xx_read(sc->base_dev, sc->def->enable_reg, &val, 1); if (val & sc->def->enable_mask) *status = REGULATOR_STATUS_ENABLED; return (0); } static int axp8xx_regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay) { struct axp8xx_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); if (bootverbose) device_printf(sc->base_dev, "Setting %s (%s) to %d<->%d\n", regnode_get_name(regnode), sc->def->name, min_uvolt, max_uvolt); if (sc->def->voltage_step1 == 0) return (ENXIO); if (axp8xx_regnode_voltage_to_reg(sc, min_uvolt, max_uvolt, &val) != 0) return (ERANGE); axp8xx_write(sc->base_dev, sc->def->voltage_reg, val); *udelay = 0; return (0); } static int axp8xx_regnode_get_voltage(struct regnode *regnode, int *uvolt) { struct axp8xx_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); if (!sc->def->voltage_step1 || !sc->def->voltage_step2) return (ENXIO); axp8xx_read(sc->base_dev, sc->def->voltage_reg, &val, 1); axp8xx_regnode_reg_to_voltage(sc, val & AXP_VOLTCTL_MASK, uvolt); return (0); } static regnode_method_t axp8xx_regnode_methods[] = { /* Regulator interface */ REGNODEMETHOD(regnode_init, axp8xx_regnode_init), REGNODEMETHOD(regnode_enable, axp8xx_regnode_enable), REGNODEMETHOD(regnode_status, axp8xx_regnode_status), REGNODEMETHOD(regnode_set_voltage, axp8xx_regnode_set_voltage), REGNODEMETHOD(regnode_get_voltage, axp8xx_regnode_get_voltage), REGNODEMETHOD(regnode_check_voltage, regnode_method_check_voltage), REGNODEMETHOD_END }; DEFINE_CLASS_1(axp8xx_regnode, axp8xx_regnode_class, axp8xx_regnode_methods, sizeof(struct axp8xx_reg_sc), regnode_class); static void axp8xx_shutdown(void *devp, int howto) { device_t dev; if ((howto & RB_POWEROFF) == 0) return; dev = devp; if (bootverbose) device_printf(dev, "Shutdown Axp8xx\n"); axp8xx_write(dev, AXP_POWERBAT, AXP_POWERBAT_SHUTDOWN); } static int axp8xx_sysctl_chargecurrent(SYSCTL_HANDLER_ARGS) { device_t dev = arg1; uint8_t data; int val, error; error = axp8xx_read(dev, AXP_CHARGERCTL1, &data, 1); if (error != 0) return (error); if (bootverbose) device_printf(dev, "Raw CHARGECTL1 val: 0x%0x\n", data); val = (data & AXP_CHARGERCTL1_CMASK); error = sysctl_handle_int(oidp, &val, 0, req); if (error || !req->newptr) /* error || read request */ return (error); if ((val < AXP_CHARGERCTL1_MIN) || (val > AXP_CHARGERCTL1_MAX)) return (EINVAL); val |= (data & (AXP_CHARGERCTL1_CMASK << 4)); axp8xx_write(dev, AXP_CHARGERCTL1, val); return (0); } static int axp8xx_sysctl(SYSCTL_HANDLER_ARGS) { struct axp8xx_softc *sc; device_t dev = arg1; enum axp8xx_sensor sensor = arg2; const struct axp8xx_config *c; uint8_t data; int val, i, found, batt_val; uint8_t lo, hi; sc = device_get_softc(dev); c = sc->config; for (found = 0, i = 0; i < sc->nsensors; i++) { if (sc->sensors[i].id == sensor) { found = 1; break; } } if (found == 0) return (ENOENT); switch (sensor) { case AXP_SENSOR_ACIN_PRESENT: if (axp8xx_read(dev, AXP_POWERSRC, &data, 1) == 0) val = !!(data & AXP_POWERSRC_ACIN); break; case AXP_SENSOR_VBUS_PRESENT: if (axp8xx_read(dev, AXP_POWERSRC, &data, 1) == 0) val = !!(data & AXP_POWERSRC_VBUS); break; case AXP_SENSOR_BATT_PRESENT: if (axp8xx_read(dev, AXP_POWERMODE, &data, 1) == 0) { if (data & AXP_POWERMODE_BAT_VALID) val = !!(data & AXP_POWERMODE_BAT_PRESENT); } break; case AXP_SENSOR_BATT_CHARGING: if (axp8xx_read(dev, AXP_POWERMODE, &data, 1) == 0) val = !!(data & AXP_POWERMODE_BAT_CHARGING); break; case AXP_SENSOR_BATT_CHARGE_STATE: if (axp8xx_read(dev, AXP_BAT_CAP, &data, 1) == 0 && (data & AXP_BAT_CAP_VALID) != 0) { batt_val = (data & AXP_BAT_CAP_PERCENT); if (batt_val <= sc->shut_thres) val = BATT_CAPACITY_CRITICAL; else if (batt_val <= sc->warn_thres) val = BATT_CAPACITY_WARNING; else val = BATT_CAPACITY_NORMAL; } break; case AXP_SENSOR_BATT_CAPACITY_PERCENT: if (axp8xx_read(dev, AXP_BAT_CAP, &data, 1) == 0 && (data & AXP_BAT_CAP_VALID) != 0) val = (data & AXP_BAT_CAP_PERCENT); break; case AXP_SENSOR_BATT_VOLTAGE: if (axp8xx_read(dev, AXP_BATSENSE_HI, &hi, 1) == 0 && axp8xx_read(dev, AXP_BATSENSE_LO, &lo, 1) == 0) { val = (AXP_SENSOR_BAT_H(hi) | AXP_SENSOR_BAT_L(lo)); val *= c->batsense_step; } break; case AXP_SENSOR_BATT_CHARGE_CURRENT: if (axp8xx_read(dev, AXP_POWERSRC, &data, 1) == 0 && (data & AXP_POWERSRC_CHARING) != 0 && axp8xx_read(dev, AXP_BATCHG_HI, &hi, 1) == 0 && axp8xx_read(dev, AXP_BATCHG_LO, &lo, 1) == 0) { val = (AXP_SENSOR_BAT_H(hi) | AXP_SENSOR_BAT_L(lo)); val *= c->charge_step; } break; case AXP_SENSOR_BATT_DISCHARGE_CURRENT: if (axp8xx_read(dev, AXP_POWERSRC, &data, 1) == 0 && (data & AXP_POWERSRC_CHARING) == 0 && axp8xx_read(dev, AXP_BATDISCHG_HI, &hi, 1) == 0 && axp8xx_read(dev, AXP_BATDISCHG_LO, &lo, 1) == 0) { val = (AXP_SENSOR_BAT_H(hi) | AXP_SENSOR_BAT_L(lo)); val *= c->discharge_step; } break; case AXP_SENSOR_BATT_MAXIMUM_CAPACITY: if (axp8xx_read(dev, AXP_BAT_MAX_CAP_HI, &hi, 1) == 0 && axp8xx_read(dev, AXP_BAT_MAX_CAP_LO, &lo, 1) == 0) { val = AXP_SENSOR_COULOMB(hi, lo); val *= c->maxcap_step; } break; case AXP_SENSOR_BATT_CURRENT_CAPACITY: if (axp8xx_read(dev, AXP_BAT_COULOMB_HI, &hi, 1) == 0 && axp8xx_read(dev, AXP_BAT_COULOMB_LO, &lo, 1) == 0) { val = AXP_SENSOR_COULOMB(hi, lo); val *= c->coulomb_step; } break; } return sysctl_handle_opaque(oidp, &val, sizeof(val), req); } static void axp8xx_intr(void *arg) { device_t dev; uint8_t val; int error; dev = arg; error = axp8xx_read(dev, AXP_IRQSTAT1, &val, 1); if (error != 0) return; if (val) { if (bootverbose) device_printf(dev, "AXP_IRQSTAT1 val: %x\n", val); if (val & AXP_IRQSTAT1_ACIN_HI) devctl_notify("PMU", "AC", "plugged", NULL); if (val & AXP_IRQSTAT1_ACIN_LO) devctl_notify("PMU", "AC", "unplugged", NULL); if (val & AXP_IRQSTAT1_VBUS_HI) devctl_notify("PMU", "USB", "plugged", NULL); if (val & AXP_IRQSTAT1_VBUS_LO) devctl_notify("PMU", "USB", "unplugged", NULL); /* Acknowledge */ axp8xx_write(dev, AXP_IRQSTAT1, val); } error = axp8xx_read(dev, AXP_IRQSTAT2, &val, 1); if (error != 0) return; if (val) { if (bootverbose) device_printf(dev, "AXP_IRQSTAT2 val: %x\n", val); if (val & AXP_IRQSTAT2_BATCHGD) devctl_notify("PMU", "Battery", "charged", NULL); if (val & AXP_IRQSTAT2_BATCHGC) devctl_notify("PMU", "Battery", "charging", NULL); if (val & AXP_IRQSTAT2_BAT_NO) devctl_notify("PMU", "Battery", "absent", NULL); if (val & AXP_IRQSTAT2_BAT_IN) devctl_notify("PMU", "Battery", "plugged", NULL); /* Acknowledge */ axp8xx_write(dev, AXP_IRQSTAT2, val); } error = axp8xx_read(dev, AXP_IRQSTAT3, &val, 1); if (error != 0) return; if (val) { /* Acknowledge */ axp8xx_write(dev, AXP_IRQSTAT3, val); } error = axp8xx_read(dev, AXP_IRQSTAT4, &val, 1); if (error != 0) return; if (val) { if (bootverbose) device_printf(dev, "AXP_IRQSTAT4 val: %x\n", val); if (val & AXP_IRQSTAT4_BATLVL_LO0) devctl_notify("PMU", "Battery", "shutdown-threshold", NULL); if (val & AXP_IRQSTAT4_BATLVL_LO1) devctl_notify("PMU", "Battery", "warning-threshold", NULL); /* Acknowledge */ axp8xx_write(dev, AXP_IRQSTAT4, val); } error = axp8xx_read(dev, AXP_IRQSTAT5, &val, 1); if (error != 0) return; if (val != 0) { if ((val & AXP_IRQSTAT5_POKSIRQ) != 0) { if (bootverbose) device_printf(dev, "Power button pressed\n"); shutdown_nice(RB_POWEROFF); } /* Acknowledge */ axp8xx_write(dev, AXP_IRQSTAT5, val); } error = axp8xx_read(dev, AXP_IRQSTAT6, &val, 1); if (error != 0) return; if (val) { /* Acknowledge */ axp8xx_write(dev, AXP_IRQSTAT6, val); } } static device_t axp8xx_gpio_get_bus(device_t dev) { struct axp8xx_softc *sc; sc = device_get_softc(dev); return (sc->gpiodev); } static int axp8xx_gpio_pin_max(device_t dev, int *maxpin) { *maxpin = nitems(axp8xx_pins) - 1; return (0); } static int axp8xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name) { if (pin >= nitems(axp8xx_pins)) return (EINVAL); snprintf(name, GPIOMAXNAME, "%s", axp8xx_pins[pin].name); return (0); } static int axp8xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) { if (pin >= nitems(axp8xx_pins)) return (EINVAL); *caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT; return (0); } static int axp8xx_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) { struct axp8xx_softc *sc; uint8_t data, func; int error; if (pin >= nitems(axp8xx_pins)) return (EINVAL); sc = device_get_softc(dev); AXP_LOCK(sc); error = axp8xx_read(dev, axp8xx_pins[pin].ctrl_reg, &data, 1); if (error == 0) { func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT; if (func == AXP_GPIO_FUNC_INPUT) *flags = GPIO_PIN_INPUT; else if (func == AXP_GPIO_FUNC_DRVLO || func == AXP_GPIO_FUNC_DRVHI) *flags = GPIO_PIN_OUTPUT; else *flags = 0; } AXP_UNLOCK(sc); return (error); } static int axp8xx_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) { struct axp8xx_softc *sc; uint8_t data; int error; if (pin >= nitems(axp8xx_pins)) return (EINVAL); sc = device_get_softc(dev); AXP_LOCK(sc); error = axp8xx_read(dev, axp8xx_pins[pin].ctrl_reg, &data, 1); if (error == 0) { data &= ~AXP_GPIO_FUNC; if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) != 0) { if ((flags & GPIO_PIN_OUTPUT) == 0) data |= AXP_GPIO_FUNC_INPUT; } error = axp8xx_write(dev, axp8xx_pins[pin].ctrl_reg, data); } AXP_UNLOCK(sc); return (error); } static int axp8xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) { struct axp8xx_softc *sc; uint8_t data, func; int error; if (pin >= nitems(axp8xx_pins)) return (EINVAL); sc = device_get_softc(dev); AXP_LOCK(sc); error = axp8xx_read(dev, axp8xx_pins[pin].ctrl_reg, &data, 1); if (error == 0) { func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT; switch (func) { case AXP_GPIO_FUNC_DRVLO: *val = 0; break; case AXP_GPIO_FUNC_DRVHI: *val = 1; break; case AXP_GPIO_FUNC_INPUT: error = axp8xx_read(dev, AXP_GPIO_SIGBIT, &data, 1); if (error == 0) *val = (data & (1 << pin)) ? 1 : 0; break; default: error = EIO; break; } } AXP_UNLOCK(sc); return (error); } static int axp8xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int val) { struct axp8xx_softc *sc; uint8_t data, func; int error; if (pin >= nitems(axp8xx_pins)) return (EINVAL); sc = device_get_softc(dev); AXP_LOCK(sc); error = axp8xx_read(dev, axp8xx_pins[pin].ctrl_reg, &data, 1); if (error == 0) { func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT; switch (func) { case AXP_GPIO_FUNC_DRVLO: case AXP_GPIO_FUNC_DRVHI: data &= ~AXP_GPIO_FUNC; data |= (val << AXP_GPIO_FUNC_SHIFT); break; default: error = EIO; break; } } if (error == 0) error = axp8xx_write(dev, axp8xx_pins[pin].ctrl_reg, data); AXP_UNLOCK(sc); return (error); } static int axp8xx_gpio_pin_toggle(device_t dev, uint32_t pin) { struct axp8xx_softc *sc; uint8_t data, func; int error; if (pin >= nitems(axp8xx_pins)) return (EINVAL); sc = device_get_softc(dev); AXP_LOCK(sc); error = axp8xx_read(dev, axp8xx_pins[pin].ctrl_reg, &data, 1); if (error == 0) { func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT; switch (func) { case AXP_GPIO_FUNC_DRVLO: data &= ~AXP_GPIO_FUNC; data |= (AXP_GPIO_FUNC_DRVHI << AXP_GPIO_FUNC_SHIFT); break; case AXP_GPIO_FUNC_DRVHI: data &= ~AXP_GPIO_FUNC; data |= (AXP_GPIO_FUNC_DRVLO << AXP_GPIO_FUNC_SHIFT); break; default: error = EIO; break; } } if (error == 0) error = axp8xx_write(dev, axp8xx_pins[pin].ctrl_reg, data); AXP_UNLOCK(sc); return (error); } static int axp8xx_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags) { if (gpios[0] >= nitems(axp8xx_pins)) return (EINVAL); *pin = gpios[0]; *flags = gpios[1]; return (0); } static phandle_t axp8xx_get_node(device_t dev, device_t bus) { return (ofw_bus_get_node(dev)); } static struct axp8xx_reg_sc * axp8xx_reg_attach(device_t dev, phandle_t node, struct axp8xx_regdef *def) { struct axp8xx_reg_sc *reg_sc; struct regnode_init_def initdef; struct regnode *regnode; memset(&initdef, 0, sizeof(initdef)); if (regulator_parse_ofw_stdparam(dev, node, &initdef) != 0) return (NULL); if (initdef.std_param.min_uvolt == 0) initdef.std_param.min_uvolt = def->voltage_min * 1000; if (initdef.std_param.max_uvolt == 0) initdef.std_param.max_uvolt = def->voltage_max * 1000; initdef.id = def->id; initdef.ofw_node = node; regnode = regnode_create(dev, &axp8xx_regnode_class, &initdef); if (regnode == NULL) { device_printf(dev, "cannot create regulator\n"); return (NULL); } reg_sc = regnode_get_softc(regnode); reg_sc->regnode = regnode; reg_sc->base_dev = dev; reg_sc->def = def; reg_sc->xref = OF_xref_from_node(node); reg_sc->param = regnode_get_stdparam(regnode); regnode_register(regnode); return (reg_sc); } static int axp8xx_regdev_map(device_t dev, phandle_t xref, int ncells, pcell_t *cells, intptr_t *num) { struct axp8xx_softc *sc; int i; sc = device_get_softc(dev); for (i = 0; i < sc->nregs; i++) { if (sc->regs[i] == NULL) continue; if (sc->regs[i]->xref == xref) { *num = sc->regs[i]->def->id; return (0); } } return (ENXIO); } static int axp8xx_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) { case AXP803: device_set_desc(dev, "X-Powers AXP803 Power Management Unit"); break; case AXP813: device_set_desc(dev, "X-Powers AXP813 Power Management Unit"); break; default: return (ENXIO); } return (BUS_PROBE_DEFAULT); } static int axp8xx_attach(device_t dev) { struct axp8xx_softc *sc; struct axp8xx_reg_sc *reg; uint8_t chip_id, val; phandle_t rnode, child; int error, i; sc = device_get_softc(dev); sc->addr = iicbus_get_addr(dev); mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); error = bus_alloc_resources(dev, axp8xx_spec, &sc->res); if (error != 0) { device_printf(dev, "cannot allocate resources for device\n"); return (error); } if (bootverbose) { axp8xx_read(dev, AXP_ICTYPE, &chip_id, 1); device_printf(dev, "chip ID 0x%02x\n", chip_id); } sc->nregs = nitems(axp8xx_common_regdefs); sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; switch (sc->type) { case AXP803: sc->nregs += nitems(axp803_regdefs); break; case AXP813: sc->nregs += nitems(axp813_regdefs); break; } sc->config = &axp803_config; sc->sensors = axp8xx_common_sensors; sc->nsensors = nitems(axp8xx_common_sensors); sc->regs = malloc(sizeof(struct axp8xx_reg_sc *) * sc->nregs, M_AXP8XX_REG, M_WAITOK | M_ZERO); /* Attach known regulators that exist in the DT */ rnode = ofw_bus_find_child(ofw_bus_get_node(dev), "regulators"); if (rnode > 0) { for (i = 0; i < sc->nregs; i++) { char *regname; struct axp8xx_regdef *regdef; if (i <= nitems(axp8xx_common_regdefs)) { regname = axp8xx_common_regdefs[i].name; regdef = &axp8xx_common_regdefs[i]; } else { int off; off = i - nitems(axp8xx_common_regdefs); switch (sc->type) { case AXP803: regname = axp803_regdefs[off].name; regdef = &axp803_regdefs[off]; break; case AXP813: regname = axp813_regdefs[off].name; regdef = &axp813_regdefs[off]; break; } } child = ofw_bus_find_child(rnode, regname); if (child == 0) continue; reg = axp8xx_reg_attach(dev, child, regdef); if (reg == NULL) { device_printf(dev, "cannot attach regulator %s\n", regname); continue; } sc->regs[i] = reg; } } /* Add sensors */ for (i = 0; i < sc->nsensors; i++) { SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, sc->sensors[i].name, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, dev, sc->sensors[i].id, axp8xx_sysctl, sc->sensors[i].format, sc->sensors[i].desc); } SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "batchargecurrentstep", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, dev, 0, axp8xx_sysctl_chargecurrent, "I", "Battery Charging Current Step, " "0: 200mA, 1: 400mA, 2: 600mA, 3: 800mA, " "4: 1000mA, 5: 1200mA, 6: 1400mA, 7: 1600mA, " "8: 1800mA, 9: 2000mA, 10: 2200mA, 11: 2400mA, " "12: 2600mA, 13: 2800mA"); /* Get thresholds */ if (axp8xx_read(dev, AXP_BAT_CAP_WARN, &val, 1) == 0) { sc->warn_thres = (val & AXP_BAT_CAP_WARN_LV1) >> 4; sc->warn_thres += AXP_BAP_CAP_WARN_LV1BASE; sc->shut_thres = (val & AXP_BAT_CAP_WARN_LV2); if (bootverbose) { device_printf(dev, "Raw reg val: 0x%02x\n", val); device_printf(dev, "Warning threshold: 0x%02x\n", sc->warn_thres); device_printf(dev, "Shutdown threshold: 0x%02x\n", sc->shut_thres); } } /* Enable interrupts */ axp8xx_write(dev, AXP_IRQEN1, AXP_IRQEN1_VBUS_LO | AXP_IRQEN1_VBUS_HI | AXP_IRQEN1_ACIN_LO | AXP_IRQEN1_ACIN_HI); axp8xx_write(dev, AXP_IRQEN2, AXP_IRQEN2_BATCHGD | AXP_IRQEN2_BATCHGC | AXP_IRQEN2_BAT_NO | AXP_IRQEN2_BAT_IN); axp8xx_write(dev, AXP_IRQEN3, 0); axp8xx_write(dev, AXP_IRQEN4, AXP_IRQEN4_BATLVL_LO0 | AXP_IRQEN4_BATLVL_LO1); axp8xx_write(dev, AXP_IRQEN5, AXP_IRQEN5_POKSIRQ | AXP_IRQEN5_POKLIRQ); axp8xx_write(dev, AXP_IRQEN6, 0); /* Install interrupt handler */ error = bus_setup_intr(dev, sc->res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, axp8xx_intr, dev, &sc->ih); if (error != 0) { device_printf(dev, "cannot setup interrupt handler\n"); return (error); } EVENTHANDLER_REGISTER(shutdown_final, axp8xx_shutdown, dev, SHUTDOWN_PRI_LAST); sc->gpiodev = gpiobus_attach_bus(dev); return (0); } static device_method_t axp8xx_methods[] = { /* Device interface */ DEVMETHOD(device_probe, axp8xx_probe), DEVMETHOD(device_attach, axp8xx_attach), /* GPIO interface */ DEVMETHOD(gpio_get_bus, axp8xx_gpio_get_bus), DEVMETHOD(gpio_pin_max, axp8xx_gpio_pin_max), DEVMETHOD(gpio_pin_getname, axp8xx_gpio_pin_getname), DEVMETHOD(gpio_pin_getcaps, axp8xx_gpio_pin_getcaps), DEVMETHOD(gpio_pin_getflags, axp8xx_gpio_pin_getflags), DEVMETHOD(gpio_pin_setflags, axp8xx_gpio_pin_setflags), DEVMETHOD(gpio_pin_get, axp8xx_gpio_pin_get), DEVMETHOD(gpio_pin_set, axp8xx_gpio_pin_set), DEVMETHOD(gpio_pin_toggle, axp8xx_gpio_pin_toggle), DEVMETHOD(gpio_map_gpios, axp8xx_gpio_map_gpios), /* Regdev interface */ DEVMETHOD(regdev_map, axp8xx_regdev_map), /* OFW bus interface */ DEVMETHOD(ofw_bus_get_node, axp8xx_get_node), DEVMETHOD_END }; static driver_t axp8xx_driver = { "axp8xx_pmu", axp8xx_methods, sizeof(struct axp8xx_softc), }; extern driver_t ofw_gpiobus_driver, gpioc_driver; EARLY_DRIVER_MODULE(axp8xx, iicbus, axp8xx_driver, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); EARLY_DRIVER_MODULE(ofw_gpiobus, axp8xx_pmu, ofw_gpiobus_driver, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); DRIVER_MODULE(gpioc, axp8xx_pmu, gpioc_driver, 0, 0); MODULE_VERSION(axp8xx, 1); MODULE_DEPEND(axp8xx, iicbus, 1, 1, 1); SIMPLEBUS_PNP_INFO(compat_data); diff --git a/sys/arm/allwinner/if_awg.c b/sys/arm/allwinner/if_awg.c index 6c38a65b5040..9834be083870 100644 --- a/sys/arm/allwinner/if_awg.c +++ b/sys/arm/allwinner/if_awg.c @@ -1,2018 +1,2018 @@ /*- * Copyright (c) 2016 Jared McNeill * * 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. */ /* * Allwinner Gigabit Ethernet MAC (EMAC) controller */ #include "opt_device_polling.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include "syscon_if.h" #include "miibus_if.h" #include "gpio_if.h" #define RD4(sc, reg) bus_read_4((sc)->res[_RES_EMAC], (reg)) #define WR4(sc, reg, val) bus_write_4((sc)->res[_RES_EMAC], (reg), (val)) #define AWG_LOCK(sc) mtx_lock(&(sc)->mtx) #define AWG_UNLOCK(sc) mtx_unlock(&(sc)->mtx); #define AWG_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED) #define AWG_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED) #define DESC_ALIGN 4 #define TX_DESC_COUNT 1024 #define TX_DESC_SIZE (sizeof(struct emac_desc) * TX_DESC_COUNT) #define RX_DESC_COUNT 256 #define RX_DESC_SIZE (sizeof(struct emac_desc) * RX_DESC_COUNT) #define DESC_OFF(n) ((n) * sizeof(struct emac_desc)) #define TX_NEXT(n) (((n) + 1) & (TX_DESC_COUNT - 1)) #define TX_SKIP(n, o) (((n) + (o)) & (TX_DESC_COUNT - 1)) #define RX_NEXT(n) (((n) + 1) & (RX_DESC_COUNT - 1)) #define TX_MAX_SEGS 20 #define SOFT_RST_RETRY 1000 #define MII_BUSY_RETRY 1000 #define MDIO_FREQ 2500000 #define BURST_LEN_DEFAULT 8 #define RX_TX_PRI_DEFAULT 0 #define PAUSE_TIME_DEFAULT 0x400 #define TX_INTERVAL_DEFAULT 64 #define RX_BATCH_DEFAULT 64 /* syscon EMAC clock register */ #define EMAC_CLK_REG 0x30 #define EMAC_CLK_EPHY_ADDR (0x1f << 20) /* H3 */ #define EMAC_CLK_EPHY_ADDR_SHIFT 20 #define EMAC_CLK_EPHY_LED_POL (1 << 17) /* H3 */ #define EMAC_CLK_EPHY_SHUTDOWN (1 << 16) /* H3 */ #define EMAC_CLK_EPHY_SELECT (1 << 15) /* H3 */ #define EMAC_CLK_RMII_EN (1 << 13) #define EMAC_CLK_ETXDC (0x7 << 10) #define EMAC_CLK_ETXDC_SHIFT 10 #define EMAC_CLK_ERXDC (0x1f << 5) #define EMAC_CLK_ERXDC_SHIFT 5 #define EMAC_CLK_PIT (0x1 << 2) #define EMAC_CLK_PIT_MII (0 << 2) #define EMAC_CLK_PIT_RGMII (1 << 2) #define EMAC_CLK_SRC (0x3 << 0) #define EMAC_CLK_SRC_MII (0 << 0) #define EMAC_CLK_SRC_EXT_RGMII (1 << 0) #define EMAC_CLK_SRC_RGMII (2 << 0) /* Burst length of RX and TX DMA transfers */ static int awg_burst_len = BURST_LEN_DEFAULT; TUNABLE_INT("hw.awg.burst_len", &awg_burst_len); /* RX / TX DMA priority. If 1, RX DMA has priority over TX DMA. */ static int awg_rx_tx_pri = RX_TX_PRI_DEFAULT; TUNABLE_INT("hw.awg.rx_tx_pri", &awg_rx_tx_pri); /* Pause time field in the transmitted control frame */ static int awg_pause_time = PAUSE_TIME_DEFAULT; TUNABLE_INT("hw.awg.pause_time", &awg_pause_time); /* Request a TX interrupt every descriptors */ static int awg_tx_interval = TX_INTERVAL_DEFAULT; TUNABLE_INT("hw.awg.tx_interval", &awg_tx_interval); /* Maximum number of mbufs to send to if_input */ static int awg_rx_batch = RX_BATCH_DEFAULT; TUNABLE_INT("hw.awg.rx_batch", &awg_rx_batch); enum awg_type { EMAC_A83T = 1, EMAC_H3, EMAC_A64, }; static struct ofw_compat_data compat_data[] = { { "allwinner,sun8i-a83t-emac", EMAC_A83T }, { "allwinner,sun8i-h3-emac", EMAC_H3 }, { "allwinner,sun50i-a64-emac", EMAC_A64 }, { NULL, 0 } }; struct awg_bufmap { bus_dmamap_t map; struct mbuf *mbuf; }; struct awg_txring { bus_dma_tag_t desc_tag; bus_dmamap_t desc_map; struct emac_desc *desc_ring; bus_addr_t desc_ring_paddr; bus_dma_tag_t buf_tag; struct awg_bufmap buf_map[TX_DESC_COUNT]; u_int cur, next, queued; u_int segs; }; struct awg_rxring { bus_dma_tag_t desc_tag; bus_dmamap_t desc_map; struct emac_desc *desc_ring; bus_addr_t desc_ring_paddr; bus_dma_tag_t buf_tag; struct awg_bufmap buf_map[RX_DESC_COUNT]; bus_dmamap_t buf_spare_map; u_int cur; }; enum { _RES_EMAC, _RES_IRQ, _RES_SYSCON, _RES_NITEMS }; struct awg_softc { struct resource *res[_RES_NITEMS]; struct mtx mtx; if_t ifp; device_t dev; device_t miibus; struct callout stat_ch; void *ih; u_int mdc_div_ratio_m; int link; int if_flags; enum awg_type type; struct syscon *syscon; struct awg_txring tx; struct awg_rxring rx; }; static struct resource_spec awg_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE }, { SYS_RES_MEMORY, 1, RF_ACTIVE | RF_OPTIONAL }, { -1, 0 } }; static void awg_txeof(struct awg_softc *sc); static void awg_start_locked(struct awg_softc *sc); static void awg_tick(void *softc); static int awg_parse_delay(device_t dev, uint32_t *tx_delay, uint32_t *rx_delay); static uint32_t syscon_read_emac_clk_reg(device_t dev); static void syscon_write_emac_clk_reg(device_t dev, uint32_t val); static phandle_t awg_get_phy_node(device_t dev); static bool awg_has_internal_phy(device_t dev); /* * MII functions */ static int awg_miibus_readreg(device_t dev, int phy, int reg) { struct awg_softc *sc; int retry, val; sc = device_get_softc(dev); val = 0; WR4(sc, EMAC_MII_CMD, (sc->mdc_div_ratio_m << MDC_DIV_RATIO_M_SHIFT) | (phy << PHY_ADDR_SHIFT) | (reg << PHY_REG_ADDR_SHIFT) | MII_BUSY); for (retry = MII_BUSY_RETRY; retry > 0; retry--) { if ((RD4(sc, EMAC_MII_CMD) & MII_BUSY) == 0) { val = RD4(sc, EMAC_MII_DATA); break; } DELAY(10); } if (retry == 0) device_printf(dev, "phy read timeout, phy=%d reg=%d\n", phy, reg); return (val); } static int awg_miibus_writereg(device_t dev, int phy, int reg, int val) { struct awg_softc *sc; int retry; sc = device_get_softc(dev); WR4(sc, EMAC_MII_DATA, val); WR4(sc, EMAC_MII_CMD, (sc->mdc_div_ratio_m << MDC_DIV_RATIO_M_SHIFT) | (phy << PHY_ADDR_SHIFT) | (reg << PHY_REG_ADDR_SHIFT) | MII_WR | MII_BUSY); for (retry = MII_BUSY_RETRY; retry > 0; retry--) { if ((RD4(sc, EMAC_MII_CMD) & MII_BUSY) == 0) break; DELAY(10); } if (retry == 0) device_printf(dev, "phy write timeout, phy=%d reg=%d\n", phy, reg); return (0); } static void awg_miibus_statchg(device_t dev) { struct awg_softc *sc; struct mii_data *mii; uint32_t val; sc = device_get_softc(dev); AWG_ASSERT_LOCKED(sc); if ((if_getdrvflags(sc->ifp) & IFF_DRV_RUNNING) == 0) return; mii = device_get_softc(sc->miibus); if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == (IFM_ACTIVE | IFM_AVALID)) { switch (IFM_SUBTYPE(mii->mii_media_active)) { case IFM_1000_T: case IFM_1000_SX: case IFM_100_TX: case IFM_10_T: sc->link = 1; break; default: sc->link = 0; break; } } else sc->link = 0; if (sc->link == 0) return; val = RD4(sc, EMAC_BASIC_CTL_0); val &= ~(BASIC_CTL_SPEED | BASIC_CTL_DUPLEX); if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T || IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) val |= BASIC_CTL_SPEED_1000 << BASIC_CTL_SPEED_SHIFT; else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) val |= BASIC_CTL_SPEED_100 << BASIC_CTL_SPEED_SHIFT; else val |= BASIC_CTL_SPEED_10 << BASIC_CTL_SPEED_SHIFT; if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) val |= BASIC_CTL_DUPLEX; WR4(sc, EMAC_BASIC_CTL_0, val); val = RD4(sc, EMAC_RX_CTL_0); val &= ~RX_FLOW_CTL_EN; if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) val |= RX_FLOW_CTL_EN; WR4(sc, EMAC_RX_CTL_0, val); val = RD4(sc, EMAC_TX_FLOW_CTL); val &= ~(PAUSE_TIME|TX_FLOW_CTL_EN); if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) val |= TX_FLOW_CTL_EN; if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) val |= awg_pause_time << PAUSE_TIME_SHIFT; WR4(sc, EMAC_TX_FLOW_CTL, val); } /* * Media functions */ static void awg_media_status(if_t ifp, struct ifmediareq *ifmr) { struct awg_softc *sc; struct mii_data *mii; sc = if_getsoftc(ifp); mii = device_get_softc(sc->miibus); AWG_LOCK(sc); mii_pollstat(mii); ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; AWG_UNLOCK(sc); } static int awg_media_change(if_t ifp) { struct awg_softc *sc; struct mii_data *mii; int error; sc = if_getsoftc(ifp); mii = device_get_softc(sc->miibus); AWG_LOCK(sc); error = mii_mediachg(mii); AWG_UNLOCK(sc); return (error); } /* * Core functions */ /* Bit Reversal - http://aggregate.org/MAGIC/#Bit%20Reversal */ static uint32_t bitrev32(uint32_t x) { x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8)); return (x >> 16) | (x << 16); } static u_int awg_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) { uint32_t crc, hashreg, hashbit, *hash = arg; crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN) & 0x7f; crc = bitrev32(~crc) >> 26; hashreg = (crc >> 5); hashbit = (crc & 0x1f); hash[hashreg] |= (1 << hashbit); return (1); } static void awg_setup_rxfilter(struct awg_softc *sc) { uint32_t val, hash[2], machi, maclo; uint8_t *eaddr; if_t ifp; AWG_ASSERT_LOCKED(sc); ifp = sc->ifp; val = 0; hash[0] = hash[1] = 0; if (if_getflags(ifp) & IFF_PROMISC) val |= DIS_ADDR_FILTER; else if (if_getflags(ifp) & IFF_ALLMULTI) { val |= RX_ALL_MULTICAST; hash[0] = hash[1] = ~0; } else if (if_foreach_llmaddr(ifp, awg_hash_maddr, hash) > 0) val |= HASH_MULTICAST; /* Write our unicast address */ eaddr = if_getlladdr(ifp); machi = (eaddr[5] << 8) | eaddr[4]; maclo = (eaddr[3] << 24) | (eaddr[2] << 16) | (eaddr[1] << 8) | (eaddr[0] << 0); WR4(sc, EMAC_ADDR_HIGH(0), machi); WR4(sc, EMAC_ADDR_LOW(0), maclo); /* Multicast hash filters */ WR4(sc, EMAC_RX_HASH_0, hash[1]); WR4(sc, EMAC_RX_HASH_1, hash[0]); /* RX frame filter config */ WR4(sc, EMAC_RX_FRM_FLT, val); } static void awg_setup_core(struct awg_softc *sc) { uint32_t val; AWG_ASSERT_LOCKED(sc); /* Configure DMA burst length and priorities */ val = awg_burst_len << BASIC_CTL_BURST_LEN_SHIFT; if (awg_rx_tx_pri) val |= BASIC_CTL_RX_TX_PRI; WR4(sc, EMAC_BASIC_CTL_1, val); } static void awg_enable_mac(struct awg_softc *sc, bool enable) { uint32_t tx, rx; AWG_ASSERT_LOCKED(sc); tx = RD4(sc, EMAC_TX_CTL_0); rx = RD4(sc, EMAC_RX_CTL_0); if (enable) { tx |= TX_EN; rx |= RX_EN | CHECK_CRC; } else { tx &= ~TX_EN; rx &= ~(RX_EN | CHECK_CRC); } WR4(sc, EMAC_TX_CTL_0, tx); WR4(sc, EMAC_RX_CTL_0, rx); } static void awg_get_eaddr(device_t dev, uint8_t *eaddr) { struct awg_softc *sc; uint32_t maclo, machi, rnd; u_char rootkey[16]; uint32_t rootkey_size; sc = device_get_softc(dev); machi = RD4(sc, EMAC_ADDR_HIGH(0)) & 0xffff; maclo = RD4(sc, EMAC_ADDR_LOW(0)); rootkey_size = sizeof(rootkey); if (maclo == 0xffffffff && machi == 0xffff) { /* MAC address in hardware is invalid, create one */ if (aw_sid_get_fuse(AW_SID_FUSE_ROOTKEY, rootkey, &rootkey_size) == 0 && (rootkey[3] | rootkey[12] | rootkey[13] | rootkey[14] | rootkey[15]) != 0) { /* MAC address is derived from the root key in SID */ maclo = (rootkey[13] << 24) | (rootkey[12] << 16) | (rootkey[3] << 8) | 0x02; machi = (rootkey[15] << 8) | rootkey[14]; } else { /* Create one */ rnd = arc4random(); maclo = 0x00f2 | (rnd & 0xffff0000); machi = rnd & 0xffff; } } eaddr[0] = maclo & 0xff; eaddr[1] = (maclo >> 8) & 0xff; eaddr[2] = (maclo >> 16) & 0xff; eaddr[3] = (maclo >> 24) & 0xff; eaddr[4] = machi & 0xff; eaddr[5] = (machi >> 8) & 0xff; } /* * DMA functions */ static void awg_enable_dma_intr(struct awg_softc *sc) { /* Enable interrupts */ WR4(sc, EMAC_INT_EN, RX_INT_EN | TX_INT_EN | TX_BUF_UA_INT_EN); } static void awg_disable_dma_intr(struct awg_softc *sc) { /* Disable interrupts */ WR4(sc, EMAC_INT_EN, 0); } static void awg_init_dma(struct awg_softc *sc) { uint32_t val; AWG_ASSERT_LOCKED(sc); /* Enable interrupts */ #ifdef DEVICE_POLLING if ((if_getcapenable(sc->ifp) & IFCAP_POLLING) == 0) awg_enable_dma_intr(sc); else awg_disable_dma_intr(sc); #else awg_enable_dma_intr(sc); #endif /* Enable transmit DMA */ val = RD4(sc, EMAC_TX_CTL_1); WR4(sc, EMAC_TX_CTL_1, val | TX_DMA_EN | TX_MD | TX_NEXT_FRAME); /* Enable receive DMA */ val = RD4(sc, EMAC_RX_CTL_1); WR4(sc, EMAC_RX_CTL_1, val | RX_DMA_EN | RX_MD); } static void awg_stop_dma(struct awg_softc *sc) { uint32_t val; AWG_ASSERT_LOCKED(sc); /* Stop transmit DMA and flush data in the TX FIFO */ val = RD4(sc, EMAC_TX_CTL_1); val &= ~TX_DMA_EN; val |= FLUSH_TX_FIFO; WR4(sc, EMAC_TX_CTL_1, val); /* Disable interrupts */ awg_disable_dma_intr(sc); /* Disable transmit DMA */ val = RD4(sc, EMAC_TX_CTL_1); WR4(sc, EMAC_TX_CTL_1, val & ~TX_DMA_EN); /* Disable receive DMA */ val = RD4(sc, EMAC_RX_CTL_1); WR4(sc, EMAC_RX_CTL_1, val & ~RX_DMA_EN); } static int awg_encap(struct awg_softc *sc, struct mbuf **mp) { bus_dmamap_t map; bus_dma_segment_t segs[TX_MAX_SEGS]; int error, nsegs, cur, first, last, i; u_int csum_flags; uint32_t flags, status; struct mbuf *m; cur = first = sc->tx.cur; map = sc->tx.buf_map[first].map; m = *mp; error = bus_dmamap_load_mbuf_sg(sc->tx.buf_tag, map, m, segs, &nsegs, BUS_DMA_NOWAIT); if (error == EFBIG) { m = m_collapse(m, M_NOWAIT, TX_MAX_SEGS); if (m == NULL) { device_printf(sc->dev, "awg_encap: m_collapse failed\n"); m_freem(*mp); *mp = NULL; return (ENOMEM); } *mp = m; error = bus_dmamap_load_mbuf_sg(sc->tx.buf_tag, map, m, segs, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { m_freem(*mp); *mp = NULL; } } if (error != 0) { device_printf(sc->dev, "awg_encap: bus_dmamap_load_mbuf_sg failed\n"); return (error); } if (nsegs == 0) { m_freem(*mp); *mp = NULL; return (EIO); } if (sc->tx.queued + nsegs > TX_DESC_COUNT) { bus_dmamap_unload(sc->tx.buf_tag, map); return (ENOBUFS); } bus_dmamap_sync(sc->tx.buf_tag, map, BUS_DMASYNC_PREWRITE); flags = TX_FIR_DESC; status = 0; if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) { if ((m->m_pkthdr.csum_flags & (CSUM_TCP|CSUM_UDP)) != 0) csum_flags = TX_CHECKSUM_CTL_FULL; else csum_flags = TX_CHECKSUM_CTL_IP; flags |= (csum_flags << TX_CHECKSUM_CTL_SHIFT); } for (i = 0; i < nsegs; i++) { sc->tx.segs++; if (i == nsegs - 1) { flags |= TX_LAST_DESC; /* * Can only request TX completion * interrupt on last descriptor. */ if (sc->tx.segs >= awg_tx_interval) { sc->tx.segs = 0; flags |= TX_INT_CTL; } } sc->tx.desc_ring[cur].addr = htole32((uint32_t)segs[i].ds_addr); sc->tx.desc_ring[cur].size = htole32(flags | segs[i].ds_len); sc->tx.desc_ring[cur].status = htole32(status); flags &= ~TX_FIR_DESC; /* * Setting of the valid bit in the first descriptor is * deferred until the whole chain is fully set up. */ status = TX_DESC_CTL; ++sc->tx.queued; cur = TX_NEXT(cur); } sc->tx.cur = cur; /* Store mapping and mbuf in the last segment */ last = TX_SKIP(cur, TX_DESC_COUNT - 1); sc->tx.buf_map[first].map = sc->tx.buf_map[last].map; sc->tx.buf_map[last].map = map; sc->tx.buf_map[last].mbuf = m; /* * The whole mbuf chain has been DMA mapped, * fix the first descriptor. */ sc->tx.desc_ring[first].status = htole32(TX_DESC_CTL); return (0); } static void awg_clean_txbuf(struct awg_softc *sc, int index) { struct awg_bufmap *bmap; --sc->tx.queued; bmap = &sc->tx.buf_map[index]; if (bmap->mbuf != NULL) { bus_dmamap_sync(sc->tx.buf_tag, bmap->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->tx.buf_tag, bmap->map); m_freem(bmap->mbuf); bmap->mbuf = NULL; } } static void awg_setup_rxdesc(struct awg_softc *sc, int index, bus_addr_t paddr) { uint32_t status, size; status = RX_DESC_CTL; size = MCLBYTES - 1; sc->rx.desc_ring[index].addr = htole32((uint32_t)paddr); sc->rx.desc_ring[index].size = htole32(size); sc->rx.desc_ring[index].status = htole32(status); } static void awg_reuse_rxdesc(struct awg_softc *sc, int index) { sc->rx.desc_ring[index].status = htole32(RX_DESC_CTL); } static int awg_newbuf_rx(struct awg_softc *sc, int index) { struct mbuf *m; bus_dma_segment_t seg; bus_dmamap_t map; int nsegs; m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (m == NULL) return (ENOBUFS); m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; m_adj(m, ETHER_ALIGN); if (bus_dmamap_load_mbuf_sg(sc->rx.buf_tag, sc->rx.buf_spare_map, m, &seg, &nsegs, BUS_DMA_NOWAIT) != 0) { m_freem(m); return (ENOBUFS); } if (sc->rx.buf_map[index].mbuf != NULL) { bus_dmamap_sync(sc->rx.buf_tag, sc->rx.buf_map[index].map, BUS_DMASYNC_POSTREAD); bus_dmamap_unload(sc->rx.buf_tag, sc->rx.buf_map[index].map); } map = sc->rx.buf_map[index].map; sc->rx.buf_map[index].map = sc->rx.buf_spare_map; sc->rx.buf_spare_map = map; bus_dmamap_sync(sc->rx.buf_tag, sc->rx.buf_map[index].map, BUS_DMASYNC_PREREAD); sc->rx.buf_map[index].mbuf = m; awg_setup_rxdesc(sc, index, seg.ds_addr); return (0); } static void awg_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) { if (error != 0) return; *(bus_addr_t *)arg = segs[0].ds_addr; } static int awg_setup_dma(device_t dev) { struct awg_softc *sc; int error, i; sc = device_get_softc(dev); /* Setup TX ring */ error = bus_dma_tag_create( bus_get_dma_tag(dev), /* Parent tag */ DESC_ALIGN, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ TX_DESC_SIZE, 1, /* maxsize, nsegs */ TX_DESC_SIZE, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->tx.desc_tag); if (error != 0) { device_printf(dev, "cannot create TX descriptor ring tag\n"); return (error); } error = bus_dmamem_alloc(sc->tx.desc_tag, (void **)&sc->tx.desc_ring, BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->tx.desc_map); if (error != 0) { device_printf(dev, "cannot allocate TX descriptor ring\n"); return (error); } error = bus_dmamap_load(sc->tx.desc_tag, sc->tx.desc_map, sc->tx.desc_ring, TX_DESC_SIZE, awg_dmamap_cb, &sc->tx.desc_ring_paddr, 0); if (error != 0) { device_printf(dev, "cannot load TX descriptor ring\n"); return (error); } for (i = 0; i < TX_DESC_COUNT; i++) sc->tx.desc_ring[i].next = htole32(sc->tx.desc_ring_paddr + DESC_OFF(TX_NEXT(i))); error = bus_dma_tag_create( bus_get_dma_tag(dev), /* Parent tag */ 1, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ MCLBYTES, TX_MAX_SEGS, /* maxsize, nsegs */ MCLBYTES, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->tx.buf_tag); if (error != 0) { device_printf(dev, "cannot create TX buffer tag\n"); return (error); } sc->tx.queued = 0; for (i = 0; i < TX_DESC_COUNT; i++) { error = bus_dmamap_create(sc->tx.buf_tag, 0, &sc->tx.buf_map[i].map); if (error != 0) { device_printf(dev, "cannot create TX buffer map\n"); return (error); } } /* Setup RX ring */ error = bus_dma_tag_create( bus_get_dma_tag(dev), /* Parent tag */ DESC_ALIGN, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ RX_DESC_SIZE, 1, /* maxsize, nsegs */ RX_DESC_SIZE, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->rx.desc_tag); if (error != 0) { device_printf(dev, "cannot create RX descriptor ring tag\n"); return (error); } error = bus_dmamem_alloc(sc->rx.desc_tag, (void **)&sc->rx.desc_ring, BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->rx.desc_map); if (error != 0) { device_printf(dev, "cannot allocate RX descriptor ring\n"); return (error); } error = bus_dmamap_load(sc->rx.desc_tag, sc->rx.desc_map, sc->rx.desc_ring, RX_DESC_SIZE, awg_dmamap_cb, &sc->rx.desc_ring_paddr, 0); if (error != 0) { device_printf(dev, "cannot load RX descriptor ring\n"); return (error); } error = bus_dma_tag_create( bus_get_dma_tag(dev), /* Parent tag */ 1, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ MCLBYTES, 1, /* maxsize, nsegs */ MCLBYTES, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->rx.buf_tag); if (error != 0) { device_printf(dev, "cannot create RX buffer tag\n"); return (error); } error = bus_dmamap_create(sc->rx.buf_tag, 0, &sc->rx.buf_spare_map); if (error != 0) { device_printf(dev, "cannot create RX buffer spare map\n"); return (error); } for (i = 0; i < RX_DESC_COUNT; i++) { sc->rx.desc_ring[i].next = htole32(sc->rx.desc_ring_paddr + DESC_OFF(RX_NEXT(i))); error = bus_dmamap_create(sc->rx.buf_tag, 0, &sc->rx.buf_map[i].map); if (error != 0) { device_printf(dev, "cannot create RX buffer map\n"); return (error); } sc->rx.buf_map[i].mbuf = NULL; error = awg_newbuf_rx(sc, i); if (error != 0) { device_printf(dev, "cannot create RX buffer\n"); return (error); } } bus_dmamap_sync(sc->rx.desc_tag, sc->rx.desc_map, BUS_DMASYNC_PREWRITE); /* Write transmit and receive descriptor base address registers */ WR4(sc, EMAC_TX_DMA_LIST, sc->tx.desc_ring_paddr); WR4(sc, EMAC_RX_DMA_LIST, sc->rx.desc_ring_paddr); return (0); } static void awg_dma_start_tx(struct awg_softc *sc) { uint32_t val; AWG_ASSERT_LOCKED(sc); /* Start and run TX DMA */ val = RD4(sc, EMAC_TX_CTL_1); WR4(sc, EMAC_TX_CTL_1, val | TX_DMA_START); } /* * if_ functions */ static void awg_start_locked(struct awg_softc *sc) { struct mbuf *m; if_t ifp; int cnt, err; AWG_ASSERT_LOCKED(sc); if (!sc->link) return; ifp = sc->ifp; if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING) return; for (cnt = 0; ; cnt++) { m = if_dequeue(ifp); if (m == NULL) break; err = awg_encap(sc, &m); if (err != 0) { if (err == ENOBUFS) if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); if (m != NULL) if_sendq_prepend(ifp, m); break; } bpf_mtap_if(ifp, m); } if (cnt != 0) { bus_dmamap_sync(sc->tx.desc_tag, sc->tx.desc_map, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); awg_dma_start_tx(sc); } } static void awg_start(if_t ifp) { struct awg_softc *sc; sc = if_getsoftc(ifp); AWG_LOCK(sc); awg_start_locked(sc); AWG_UNLOCK(sc); } static void awg_init_locked(struct awg_softc *sc) { struct mii_data *mii; if_t ifp; mii = device_get_softc(sc->miibus); ifp = sc->ifp; AWG_ASSERT_LOCKED(sc); if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) return; awg_setup_rxfilter(sc); awg_setup_core(sc); awg_enable_mac(sc, true); awg_init_dma(sc); if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); mii_mediachg(mii); callout_reset(&sc->stat_ch, hz, awg_tick, sc); } static void awg_init(void *softc) { struct awg_softc *sc; sc = softc; AWG_LOCK(sc); awg_init_locked(sc); AWG_UNLOCK(sc); } static void awg_stop(struct awg_softc *sc) { if_t ifp; uint32_t val; int i; AWG_ASSERT_LOCKED(sc); ifp = sc->ifp; callout_stop(&sc->stat_ch); awg_stop_dma(sc); awg_enable_mac(sc, false); sc->link = 0; /* Finish handling transmitted buffers */ awg_txeof(sc); /* Release any untransmitted buffers. */ for (i = sc->tx.next; sc->tx.queued > 0; i = TX_NEXT(i)) { val = le32toh(sc->tx.desc_ring[i].status); if ((val & TX_DESC_CTL) != 0) break; awg_clean_txbuf(sc, i); } sc->tx.next = i; for (; sc->tx.queued > 0; i = TX_NEXT(i)) { sc->tx.desc_ring[i].status = 0; awg_clean_txbuf(sc, i); } sc->tx.cur = sc->tx.next; bus_dmamap_sync(sc->tx.desc_tag, sc->tx.desc_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* Setup RX buffers for reuse */ bus_dmamap_sync(sc->rx.desc_tag, sc->rx.desc_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); for (i = sc->rx.cur; ; i = RX_NEXT(i)) { val = le32toh(sc->rx.desc_ring[i].status); if ((val & RX_DESC_CTL) != 0) break; awg_reuse_rxdesc(sc, i); } sc->rx.cur = i; bus_dmamap_sync(sc->rx.desc_tag, sc->rx.desc_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING | IFF_DRV_OACTIVE); } static int awg_ioctl(if_t ifp, u_long cmd, caddr_t data) { struct awg_softc *sc; struct mii_data *mii; struct ifreq *ifr; int flags, mask, error; sc = if_getsoftc(ifp); mii = device_get_softc(sc->miibus); ifr = (struct ifreq *)data; error = 0; switch (cmd) { case SIOCSIFFLAGS: AWG_LOCK(sc); if (if_getflags(ifp) & IFF_UP) { if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { flags = if_getflags(ifp) ^ sc->if_flags; if ((flags & (IFF_PROMISC|IFF_ALLMULTI)) != 0) awg_setup_rxfilter(sc); } else awg_init_locked(sc); } else { if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) awg_stop(sc); } sc->if_flags = if_getflags(ifp); AWG_UNLOCK(sc); break; case SIOCADDMULTI: case SIOCDELMULTI: if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { AWG_LOCK(sc); awg_setup_rxfilter(sc); AWG_UNLOCK(sc); } break; case SIOCSIFMEDIA: case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); break; case SIOCSIFCAP: mask = ifr->ifr_reqcap ^ if_getcapenable(ifp); #ifdef DEVICE_POLLING if (mask & IFCAP_POLLING) { if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) { error = ether_poll_register(awg_poll, ifp); if (error != 0) break; AWG_LOCK(sc); awg_disable_dma_intr(sc); if_setcapenablebit(ifp, IFCAP_POLLING, 0); AWG_UNLOCK(sc); } else { error = ether_poll_deregister(ifp); AWG_LOCK(sc); awg_enable_dma_intr(sc); if_setcapenablebit(ifp, 0, IFCAP_POLLING); AWG_UNLOCK(sc); } } #endif if (mask & IFCAP_VLAN_MTU) if_togglecapenable(ifp, IFCAP_VLAN_MTU); if (mask & IFCAP_RXCSUM) if_togglecapenable(ifp, IFCAP_RXCSUM); if (mask & IFCAP_TXCSUM) if_togglecapenable(ifp, IFCAP_TXCSUM); if ((if_getcapenable(ifp) & IFCAP_TXCSUM) != 0) if_sethwassistbits(ifp, CSUM_IP | CSUM_UDP | CSUM_TCP, 0); else if_sethwassistbits(ifp, 0, CSUM_IP | CSUM_UDP | CSUM_TCP); break; default: error = ether_ioctl(ifp, cmd, data); break; } return (error); } /* * Interrupts functions */ static int awg_rxintr(struct awg_softc *sc) { if_t ifp; struct mbuf *m, *mh, *mt; int error, index, len, cnt, npkt; uint32_t status; ifp = sc->ifp; mh = mt = NULL; cnt = 0; npkt = 0; bus_dmamap_sync(sc->rx.desc_tag, sc->rx.desc_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); for (index = sc->rx.cur; ; index = RX_NEXT(index)) { status = le32toh(sc->rx.desc_ring[index].status); if ((status & RX_DESC_CTL) != 0) break; len = (status & RX_FRM_LEN) >> RX_FRM_LEN_SHIFT; if (len == 0) { if ((status & (RX_NO_ENOUGH_BUF_ERR | RX_OVERFLOW_ERR)) != 0) if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); awg_reuse_rxdesc(sc, index); continue; } m = sc->rx.buf_map[index].mbuf; error = awg_newbuf_rx(sc, index); if (error != 0) { if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); awg_reuse_rxdesc(sc, index); continue; } m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = len; m->m_len = len; if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0 && (status & RX_FRM_TYPE) != 0) { m->m_pkthdr.csum_flags = CSUM_IP_CHECKED; if ((status & RX_HEADER_ERR) == 0) m->m_pkthdr.csum_flags |= CSUM_IP_VALID; if ((status & RX_PAYLOAD_ERR) == 0) { m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR; m->m_pkthdr.csum_data = 0xffff; } } m->m_nextpkt = NULL; if (mh == NULL) mh = m; else mt->m_nextpkt = m; mt = m; ++cnt; ++npkt; if (cnt == awg_rx_batch) { AWG_UNLOCK(sc); if_input(ifp, mh); AWG_LOCK(sc); mh = mt = NULL; cnt = 0; } } if (index != sc->rx.cur) { bus_dmamap_sync(sc->rx.desc_tag, sc->rx.desc_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); } if (mh != NULL) { AWG_UNLOCK(sc); if_input(ifp, mh); AWG_LOCK(sc); } sc->rx.cur = index; return (npkt); } static void awg_txeof(struct awg_softc *sc) { struct emac_desc *desc; uint32_t status, size; if_t ifp; int i, prog; AWG_ASSERT_LOCKED(sc); bus_dmamap_sync(sc->tx.desc_tag, sc->tx.desc_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); ifp = sc->ifp; prog = 0; for (i = sc->tx.next; sc->tx.queued > 0; i = TX_NEXT(i)) { desc = &sc->tx.desc_ring[i]; status = le32toh(desc->status); if ((status & TX_DESC_CTL) != 0) break; size = le32toh(desc->size); if (size & TX_LAST_DESC) { if ((status & (TX_HEADER_ERR | TX_PAYLOAD_ERR)) != 0) if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); else if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); } prog++; awg_clean_txbuf(sc, i); } if (prog > 0) { sc->tx.next = i; if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); } } static void awg_intr(void *arg) { struct awg_softc *sc; uint32_t val; sc = arg; AWG_LOCK(sc); val = RD4(sc, EMAC_INT_STA); WR4(sc, EMAC_INT_STA, val); if (val & RX_INT) awg_rxintr(sc); if (val & TX_INT) awg_txeof(sc); if (val & (TX_INT | TX_BUF_UA_INT)) { if (!if_sendq_empty(sc->ifp)) awg_start_locked(sc); } AWG_UNLOCK(sc); } #ifdef DEVICE_POLLING static int awg_poll(if_t ifp, enum poll_cmd cmd, int count) { struct awg_softc *sc; uint32_t val; int rx_npkts; sc = if_getsoftc(ifp); rx_npkts = 0; AWG_LOCK(sc); if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) { AWG_UNLOCK(sc); return (0); } rx_npkts = awg_rxintr(sc); awg_txeof(sc); if (!if_sendq_empty(ifp)) awg_start_locked(sc); if (cmd == POLL_AND_CHECK_STATUS) { val = RD4(sc, EMAC_INT_STA); if (val != 0) WR4(sc, EMAC_INT_STA, val); } AWG_UNLOCK(sc); return (rx_npkts); } #endif /* * syscon functions */ static uint32_t syscon_read_emac_clk_reg(device_t dev) { struct awg_softc *sc; sc = device_get_softc(dev); if (sc->syscon != NULL) return (SYSCON_READ_4(sc->syscon, EMAC_CLK_REG)); else if (sc->res[_RES_SYSCON] != NULL) return (bus_read_4(sc->res[_RES_SYSCON], 0)); return (0); } static void syscon_write_emac_clk_reg(device_t dev, uint32_t val) { struct awg_softc *sc; sc = device_get_softc(dev); if (sc->syscon != NULL) SYSCON_WRITE_4(sc->syscon, EMAC_CLK_REG, val); else if (sc->res[_RES_SYSCON] != NULL) bus_write_4(sc->res[_RES_SYSCON], 0, val); } /* * PHY functions */ static phandle_t awg_get_phy_node(device_t dev) { phandle_t node; pcell_t phy_handle; node = ofw_bus_get_node(dev); if (OF_getencprop(node, "phy-handle", (void *)&phy_handle, sizeof(phy_handle)) <= 0) return (0); return (OF_node_from_xref(phy_handle)); } static bool awg_has_internal_phy(device_t dev) { phandle_t node, phy_node; node = ofw_bus_get_node(dev); /* Legacy binding */ if (OF_hasprop(node, "allwinner,use-internal-phy")) return (true); phy_node = awg_get_phy_node(dev); return (phy_node != 0 && ofw_bus_node_is_compatible(OF_parent(phy_node), "allwinner,sun8i-h3-mdio-internal") != 0); } static int awg_parse_delay(device_t dev, uint32_t *tx_delay, uint32_t *rx_delay) { phandle_t node; uint32_t delay; if (tx_delay == NULL || rx_delay == NULL) return (EINVAL); *tx_delay = *rx_delay = 0; node = ofw_bus_get_node(dev); if (OF_getencprop(node, "tx-delay", &delay, sizeof(delay)) >= 0) *tx_delay = delay; else if (OF_getencprop(node, "allwinner,tx-delay-ps", &delay, sizeof(delay)) >= 0) { if ((delay % 100) != 0) { device_printf(dev, "tx-delay-ps is not a multiple of 100\n"); return (EDOM); } *tx_delay = delay / 100; } if (*tx_delay > 7) { device_printf(dev, "tx-delay out of range\n"); return (ERANGE); } if (OF_getencprop(node, "rx-delay", &delay, sizeof(delay)) >= 0) *rx_delay = delay; else if (OF_getencprop(node, "allwinner,rx-delay-ps", &delay, sizeof(delay)) >= 0) { if ((delay % 100) != 0) { device_printf(dev, "rx-delay-ps is not within documented domain\n"); return (EDOM); } *rx_delay = delay / 100; } if (*rx_delay > 31) { device_printf(dev, "rx-delay out of range\n"); return (ERANGE); } return (0); } static int awg_setup_phy(device_t dev) { struct awg_softc *sc; clk_t clk_tx, clk_tx_parent; const char *tx_parent_name; char *phy_type; phandle_t node; uint32_t reg, tx_delay, rx_delay; int error; bool use_syscon; sc = device_get_softc(dev); node = ofw_bus_get_node(dev); use_syscon = false; if (OF_getprop_alloc(node, "phy-mode", (void **)&phy_type) == 0) return (0); if (sc->syscon != NULL || sc->res[_RES_SYSCON] != NULL) use_syscon = true; if (bootverbose) device_printf(dev, "PHY type: %s, conf mode: %s\n", phy_type, use_syscon ? "reg" : "clk"); if (use_syscon) { /* * Abstract away writing to syscon for devices like the pine64. * For the pine64, we get dtb from U-Boot and it still uses the * legacy setup of specifying syscon register in emac node * rather than as its own node and using an xref in emac. * These abstractions can go away once U-Boot dts is up-to-date. */ reg = syscon_read_emac_clk_reg(dev); reg &= ~(EMAC_CLK_PIT | EMAC_CLK_SRC | EMAC_CLK_RMII_EN); if (strncmp(phy_type, "rgmii", 5) == 0) reg |= EMAC_CLK_PIT_RGMII | EMAC_CLK_SRC_RGMII; else if (strcmp(phy_type, "rmii") == 0) reg |= EMAC_CLK_RMII_EN; else reg |= EMAC_CLK_PIT_MII | EMAC_CLK_SRC_MII; /* * Fail attach if we fail to parse either of the delay * parameters. If we don't have the proper delay to write to * syscon, then awg likely won't function properly anyways. * Lack of delay is not an error! */ error = awg_parse_delay(dev, &tx_delay, &rx_delay); if (error != 0) goto fail; /* Default to 0 and we'll increase it if we need to. */ reg &= ~(EMAC_CLK_ETXDC | EMAC_CLK_ERXDC); if (tx_delay > 0) reg |= (tx_delay << EMAC_CLK_ETXDC_SHIFT); if (rx_delay > 0) reg |= (rx_delay << EMAC_CLK_ERXDC_SHIFT); if (sc->type == EMAC_H3) { if (awg_has_internal_phy(dev)) { reg |= EMAC_CLK_EPHY_SELECT; reg &= ~EMAC_CLK_EPHY_SHUTDOWN; if (OF_hasprop(node, "allwinner,leds-active-low")) reg |= EMAC_CLK_EPHY_LED_POL; else reg &= ~EMAC_CLK_EPHY_LED_POL; /* Set internal PHY addr to 1 */ reg &= ~EMAC_CLK_EPHY_ADDR; reg |= (1 << EMAC_CLK_EPHY_ADDR_SHIFT); } else { reg &= ~EMAC_CLK_EPHY_SELECT; } } if (bootverbose) device_printf(dev, "EMAC clock: 0x%08x\n", reg); syscon_write_emac_clk_reg(dev, reg); } else { if (strncmp(phy_type, "rgmii", 5) == 0) tx_parent_name = "emac_int_tx"; else tx_parent_name = "mii_phy_tx"; /* Get the TX clock */ error = clk_get_by_ofw_name(dev, 0, "tx", &clk_tx); if (error != 0) { device_printf(dev, "cannot get tx clock\n"); goto fail; } /* Find the desired parent clock based on phy-mode property */ error = clk_get_by_name(dev, tx_parent_name, &clk_tx_parent); if (error != 0) { device_printf(dev, "cannot get clock '%s'\n", tx_parent_name); goto fail; } /* Set TX clock parent */ error = clk_set_parent_by_clk(clk_tx, clk_tx_parent); if (error != 0) { device_printf(dev, "cannot set tx clock parent\n"); goto fail; } /* Enable TX clock */ error = clk_enable(clk_tx); if (error != 0) { device_printf(dev, "cannot enable tx clock\n"); goto fail; } } error = 0; fail: OF_prop_free(phy_type); return (error); } static int awg_setup_extres(device_t dev) { struct awg_softc *sc; phandle_t node, phy_node; hwreset_t rst_ahb, rst_ephy; clk_t clk_ahb, clk_ephy; regulator_t reg; uint64_t freq; int error, div; sc = device_get_softc(dev); rst_ahb = rst_ephy = NULL; clk_ahb = clk_ephy = NULL; reg = NULL; node = ofw_bus_get_node(dev); phy_node = awg_get_phy_node(dev); if (phy_node == 0 && OF_hasprop(node, "phy-handle")) { error = ENXIO; device_printf(dev, "cannot get phy handle\n"); goto fail; } /* Get AHB clock and reset resources */ error = hwreset_get_by_ofw_name(dev, 0, "stmmaceth", &rst_ahb); if (error != 0) error = hwreset_get_by_ofw_name(dev, 0, "ahb", &rst_ahb); if (error != 0) { device_printf(dev, "cannot get ahb reset\n"); goto fail; } if (hwreset_get_by_ofw_name(dev, 0, "ephy", &rst_ephy) != 0) if (phy_node == 0 || hwreset_get_by_ofw_idx(dev, phy_node, 0, &rst_ephy) != 0) rst_ephy = NULL; error = clk_get_by_ofw_name(dev, 0, "stmmaceth", &clk_ahb); if (error != 0) error = clk_get_by_ofw_name(dev, 0, "ahb", &clk_ahb); if (error != 0) { device_printf(dev, "cannot get ahb clock\n"); goto fail; } if (clk_get_by_ofw_name(dev, 0, "ephy", &clk_ephy) != 0) if (phy_node == 0 || clk_get_by_ofw_index(dev, phy_node, 0, &clk_ephy) != 0) clk_ephy = NULL; if (OF_hasprop(node, "syscon") && syscon_get_by_ofw_property(dev, node, "syscon", &sc->syscon) != 0) { device_printf(dev, "cannot get syscon driver handle\n"); goto fail; } /* Configure PHY for MII or RGMII mode */ if (awg_setup_phy(dev) != 0) goto fail; /* Enable clocks */ error = clk_enable(clk_ahb); if (error != 0) { device_printf(dev, "cannot enable ahb clock\n"); goto fail; } if (clk_ephy != NULL) { error = clk_enable(clk_ephy); if (error != 0) { device_printf(dev, "cannot enable ephy clock\n"); goto fail; } } /* De-assert reset */ error = hwreset_deassert(rst_ahb); if (error != 0) { device_printf(dev, "cannot de-assert ahb reset\n"); goto fail; } if (rst_ephy != NULL) { /* * The ephy reset is left de-asserted by U-Boot. Assert it * here to make sure that we're in a known good state going * into the PHY reset. */ hwreset_assert(rst_ephy); error = hwreset_deassert(rst_ephy); if (error != 0) { device_printf(dev, "cannot de-assert ephy reset\n"); goto fail; } } /* Enable PHY regulator if applicable */ if (regulator_get_by_ofw_property(dev, 0, "phy-supply", ®) == 0) { error = regulator_enable(reg); if (error != 0) { device_printf(dev, "cannot enable PHY regulator\n"); goto fail; } } /* Determine MDC clock divide ratio based on AHB clock */ error = clk_get_freq(clk_ahb, &freq); if (error != 0) { device_printf(dev, "cannot get AHB clock frequency\n"); goto fail; } div = freq / MDIO_FREQ; if (div <= 16) sc->mdc_div_ratio_m = MDC_DIV_RATIO_M_16; else if (div <= 32) sc->mdc_div_ratio_m = MDC_DIV_RATIO_M_32; else if (div <= 64) sc->mdc_div_ratio_m = MDC_DIV_RATIO_M_64; else if (div <= 128) sc->mdc_div_ratio_m = MDC_DIV_RATIO_M_128; else { device_printf(dev, "cannot determine MDC clock divide ratio\n"); error = ENXIO; goto fail; } if (bootverbose) device_printf(dev, "AHB frequency %ju Hz, MDC div: 0x%x\n", (uintmax_t)freq, sc->mdc_div_ratio_m); return (0); fail: if (reg != NULL) regulator_release(reg); if (clk_ephy != NULL) clk_release(clk_ephy); if (clk_ahb != NULL) clk_release(clk_ahb); if (rst_ephy != NULL) hwreset_release(rst_ephy); if (rst_ahb != NULL) hwreset_release(rst_ahb); return (error); } #ifdef AWG_DEBUG static void awg_dump_regs(device_t dev) { static const struct { const char *name; u_int reg; } regs[] = { { "BASIC_CTL_0", EMAC_BASIC_CTL_0 }, { "BASIC_CTL_1", EMAC_BASIC_CTL_1 }, { "INT_STA", EMAC_INT_STA }, { "INT_EN", EMAC_INT_EN }, { "TX_CTL_0", EMAC_TX_CTL_0 }, { "TX_CTL_1", EMAC_TX_CTL_1 }, { "TX_FLOW_CTL", EMAC_TX_FLOW_CTL }, { "TX_DMA_LIST", EMAC_TX_DMA_LIST }, { "RX_CTL_0", EMAC_RX_CTL_0 }, { "RX_CTL_1", EMAC_RX_CTL_1 }, { "RX_DMA_LIST", EMAC_RX_DMA_LIST }, { "RX_FRM_FLT", EMAC_RX_FRM_FLT }, { "RX_HASH_0", EMAC_RX_HASH_0 }, { "RX_HASH_1", EMAC_RX_HASH_1 }, { "MII_CMD", EMAC_MII_CMD }, { "ADDR_HIGH0", EMAC_ADDR_HIGH(0) }, { "ADDR_LOW0", EMAC_ADDR_LOW(0) }, { "TX_DMA_STA", EMAC_TX_DMA_STA }, { "TX_DMA_CUR_DESC", EMAC_TX_DMA_CUR_DESC }, { "TX_DMA_CUR_BUF", EMAC_TX_DMA_CUR_BUF }, { "RX_DMA_STA", EMAC_RX_DMA_STA }, { "RX_DMA_CUR_DESC", EMAC_RX_DMA_CUR_DESC }, { "RX_DMA_CUR_BUF", EMAC_RX_DMA_CUR_BUF }, { "RGMII_STA", EMAC_RGMII_STA }, }; struct awg_softc *sc; unsigned int n; sc = device_get_softc(dev); for (n = 0; n < nitems(regs); n++) device_printf(dev, " %-20s %08x\n", regs[n].name, RD4(sc, regs[n].reg)); } #endif #define GPIO_ACTIVE_LOW 1 static int awg_phy_reset(device_t dev) { pcell_t gpio_prop[4], delay_prop[3]; phandle_t node, gpio_node; device_t gpio; uint32_t pin, flags; uint32_t pin_value; node = ofw_bus_get_node(dev); if (OF_getencprop(node, "allwinner,reset-gpio", gpio_prop, sizeof(gpio_prop)) <= 0) return (0); if (OF_getencprop(node, "allwinner,reset-delays-us", delay_prop, sizeof(delay_prop)) <= 0) return (ENXIO); gpio_node = OF_node_from_xref(gpio_prop[0]); if ((gpio = OF_device_from_xref(gpio_prop[0])) == NULL) return (ENXIO); if (GPIO_MAP_GPIOS(gpio, node, gpio_node, nitems(gpio_prop) - 1, gpio_prop + 1, &pin, &flags) != 0) return (ENXIO); pin_value = GPIO_PIN_LOW; if (OF_hasprop(node, "allwinner,reset-active-low")) pin_value = GPIO_PIN_HIGH; if (flags & GPIO_ACTIVE_LOW) pin_value = !pin_value; GPIO_PIN_SETFLAGS(gpio, pin, GPIO_PIN_OUTPUT); GPIO_PIN_SET(gpio, pin, pin_value); DELAY(delay_prop[0]); GPIO_PIN_SET(gpio, pin, !pin_value); DELAY(delay_prop[1]); GPIO_PIN_SET(gpio, pin, pin_value); DELAY(delay_prop[2]); return (0); } static int awg_reset(device_t dev) { struct awg_softc *sc; int retry; sc = device_get_softc(dev); /* Reset PHY if necessary */ if (awg_phy_reset(dev) != 0) { device_printf(dev, "failed to reset PHY\n"); return (ENXIO); } /* Soft reset all registers and logic */ WR4(sc, EMAC_BASIC_CTL_1, BASIC_CTL_SOFT_RST); /* Wait for soft reset bit to self-clear */ for (retry = SOFT_RST_RETRY; retry > 0; retry--) { if ((RD4(sc, EMAC_BASIC_CTL_1) & BASIC_CTL_SOFT_RST) == 0) break; DELAY(10); } if (retry == 0) { device_printf(dev, "soft reset timed out\n"); #ifdef AWG_DEBUG awg_dump_regs(dev); #endif return (ETIMEDOUT); } return (0); } /* * Stats */ static void awg_tick(void *softc) { struct awg_softc *sc; struct mii_data *mii; if_t ifp; int link; sc = softc; ifp = sc->ifp; mii = device_get_softc(sc->miibus); AWG_ASSERT_LOCKED(sc); if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) return; link = sc->link; mii_tick(mii); if (sc->link && !link) awg_start_locked(sc); callout_reset(&sc->stat_ch, hz, awg_tick, sc); } /* * Probe/attach functions */ static int awg_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Allwinner Gigabit Ethernet"); return (BUS_PROBE_DEFAULT); } static int awg_attach(device_t dev) { uint8_t eaddr[ETHER_ADDR_LEN]; struct awg_softc *sc; int error; sc = device_get_softc(dev); sc->dev = dev; sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; if (bus_alloc_resources(dev, awg_spec, sc->res) != 0) { device_printf(dev, "cannot allocate resources for device\n"); return (ENXIO); } mtx_init(&sc->mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF); callout_init_mtx(&sc->stat_ch, &sc->mtx, 0); /* Setup clocks and regulators */ error = awg_setup_extres(dev); if (error != 0) return (error); /* Read MAC address before resetting the chip */ awg_get_eaddr(dev, eaddr); /* Soft reset EMAC core */ error = awg_reset(dev); if (error != 0) return (error); /* Setup DMA descriptors */ error = awg_setup_dma(dev); if (error != 0) return (error); /* Install interrupt handler */ error = bus_setup_intr(dev, sc->res[_RES_IRQ], INTR_TYPE_NET | INTR_MPSAFE, NULL, awg_intr, sc, &sc->ih); if (error != 0) { device_printf(dev, "cannot setup interrupt handler\n"); return (error); } /* Setup ethernet interface */ sc->ifp = if_alloc(IFT_ETHER); if_setsoftc(sc->ifp, sc); if_initname(sc->ifp, device_get_name(dev), device_get_unit(dev)); if_setflags(sc->ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); if_setstartfn(sc->ifp, awg_start); if_setioctlfn(sc->ifp, awg_ioctl); if_setinitfn(sc->ifp, awg_init); if_setsendqlen(sc->ifp, TX_DESC_COUNT - 1); if_setsendqready(sc->ifp); if_sethwassist(sc->ifp, CSUM_IP | CSUM_UDP | CSUM_TCP); if_setcapabilities(sc->ifp, IFCAP_VLAN_MTU | IFCAP_HWCSUM); if_setcapenable(sc->ifp, if_getcapabilities(sc->ifp)); #ifdef DEVICE_POLLING if_setcapabilitiesbit(sc->ifp, IFCAP_POLLING, 0); #endif /* Attach MII driver */ error = mii_attach(dev, &sc->miibus, sc->ifp, awg_media_change, awg_media_status, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, MIIF_DOPAUSE); if (error != 0) { device_printf(dev, "cannot attach PHY\n"); return (error); } /* Attach ethernet interface */ ether_ifattach(sc->ifp, eaddr); return (0); } static device_method_t awg_methods[] = { /* Device interface */ DEVMETHOD(device_probe, awg_probe), DEVMETHOD(device_attach, awg_attach), /* MII interface */ DEVMETHOD(miibus_readreg, awg_miibus_readreg), DEVMETHOD(miibus_writereg, awg_miibus_writereg), DEVMETHOD(miibus_statchg, awg_miibus_statchg), DEVMETHOD_END }; static driver_t awg_driver = { "awg", awg_methods, sizeof(struct awg_softc), }; DRIVER_MODULE(awg, simplebus, awg_driver, 0, 0); DRIVER_MODULE(miibus, awg, miibus_driver, 0, 0); MODULE_DEPEND(awg, ether, 1, 1, 1); MODULE_DEPEND(awg, miibus, 1, 1, 1); MODULE_DEPEND(awg, aw_sid, 1, 1, 1); SIMPLEBUS_PNP_INFO(compat_data); diff --git a/sys/arm/nvidia/as3722.c b/sys/arm/nvidia/as3722.c index 537cd4f6e24a..ca5f7372aed1 100644 --- a/sys/arm/nvidia/as3722.c +++ b/sys/arm/nvidia/as3722.c @@ -1,401 +1,401 @@ /*- * Copyright (c) 2016 Michal Meloun * All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ #include /* * AS3722 PMIC driver */ #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #include #include "clock_if.h" #include "regdev_if.h" #include "as3722.h" static struct ofw_compat_data compat_data[] = { {"ams,as3722", 1}, {NULL, 0}, }; #define LOCK(_sc) sx_xlock(&(_sc)->lock) #define UNLOCK(_sc) sx_xunlock(&(_sc)->lock) #define LOCK_INIT(_sc) sx_init(&(_sc)->lock, "as3722") #define LOCK_DESTROY(_sc) sx_destroy(&(_sc)->lock); #define ASSERT_LOCKED(_sc) sx_assert(&(_sc)->lock, SA_XLOCKED); #define ASSERT_UNLOCKED(_sc) sx_assert(&(_sc)->lock, SA_UNLOCKED); #define AS3722_DEVICE_ID 0x0C /* * Raw register access function. */ int as3722_read(struct as3722_softc *sc, uint8_t reg, uint8_t *val) { uint8_t addr; int rv; struct iic_msg msgs[2] = { {0, IIC_M_WR, 1, &addr}, {0, IIC_M_RD, 1, val}, }; msgs[0].slave = sc->bus_addr; msgs[1].slave = sc->bus_addr; addr = reg; rv = iicbus_transfer(sc->dev, msgs, 2); if (rv != 0) { device_printf(sc->dev, "Error when reading reg 0x%02X, rv: %d\n", reg, rv); return (EIO); } return (0); } int as3722_read_buf(struct as3722_softc *sc, uint8_t reg, uint8_t *buf, size_t size) { uint8_t addr; int rv; struct iic_msg msgs[2] = { {0, IIC_M_WR, 1, &addr}, {0, IIC_M_RD, size, buf}, }; msgs[0].slave = sc->bus_addr; msgs[1].slave = sc->bus_addr; addr = reg; rv = iicbus_transfer(sc->dev, msgs, 2); if (rv != 0) { device_printf(sc->dev, "Error when reading reg 0x%02X, rv: %d\n", reg, rv); return (EIO); } return (0); } int as3722_write(struct as3722_softc *sc, uint8_t reg, uint8_t val) { uint8_t data[2]; int rv; struct iic_msg msgs[1] = { {0, IIC_M_WR, 2, data}, }; msgs[0].slave = sc->bus_addr; data[0] = reg; data[1] = val; rv = iicbus_transfer(sc->dev, msgs, 1); if (rv != 0) { device_printf(sc->dev, "Error when writing reg 0x%02X, rv: %d\n", reg, rv); return (EIO); } return (0); } int as3722_write_buf(struct as3722_softc *sc, uint8_t reg, uint8_t *buf, size_t size) { uint8_t data[1]; int rv; struct iic_msg msgs[2] = { {0, IIC_M_WR, 1, data}, {0, IIC_M_WR | IIC_M_NOSTART, size, buf}, }; msgs[0].slave = sc->bus_addr; msgs[1].slave = sc->bus_addr; data[0] = reg; rv = iicbus_transfer(sc->dev, msgs, 2); if (rv != 0) { device_printf(sc->dev, "Error when writing reg 0x%02X, rv: %d\n", reg, rv); return (EIO); } return (0); } int as3722_modify(struct as3722_softc *sc, uint8_t reg, uint8_t clear, uint8_t set) { uint8_t val; int rv; rv = as3722_read(sc, reg, &val); if (rv != 0) return (rv); val &= ~clear; val |= set; rv = as3722_write(sc, reg, val); if (rv != 0) return (rv); return (0); } static int as3722_get_version(struct as3722_softc *sc) { uint8_t reg; int rv; /* Verify AS3722 ID and version. */ rv = RD1(sc, AS3722_ASIC_ID1, ®); if (rv != 0) return (ENXIO); if (reg != AS3722_DEVICE_ID) { device_printf(sc->dev, "Invalid chip ID is 0x%x\n", reg); return (ENXIO); } rv = RD1(sc, AS3722_ASIC_ID2, &sc->chip_rev); if (rv != 0) return (ENXIO); if (bootverbose) device_printf(sc->dev, "AS3722 rev: 0x%x\n", sc->chip_rev); return (0); } static int as3722_init(struct as3722_softc *sc) { uint32_t reg; int rv; reg = 0; if (sc->int_pullup) reg |= AS3722_INT_PULL_UP; if (sc->i2c_pullup) reg |= AS3722_I2C_PULL_UP; rv = RM1(sc, AS3722_IO_VOLTAGE, AS3722_INT_PULL_UP | AS3722_I2C_PULL_UP, reg); if (rv != 0) return (ENXIO); /* mask interrupts */ rv = WR1(sc, AS3722_INTERRUPT_MASK1, 0); if (rv != 0) return (ENXIO); rv = WR1(sc, AS3722_INTERRUPT_MASK2, 0); if (rv != 0) return (ENXIO); rv = WR1(sc, AS3722_INTERRUPT_MASK3, 0); if (rv != 0) return (ENXIO); rv = WR1(sc, AS3722_INTERRUPT_MASK4, 0); if (rv != 0) return (ENXIO); return (0); } static int as3722_parse_fdt(struct as3722_softc *sc, phandle_t node) { sc->int_pullup = OF_hasprop(node, "ams,enable-internal-int-pullup") ? 1 : 0; sc->i2c_pullup = OF_hasprop(node, "ams,enable-internal-i2c-pullup") ? 1 : 0; return 0; } static void as3722_intr(void *arg) { /* XXX Finish temperature alarms. */ } static int as3722_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "AS3722 PMIC"); return (BUS_PROBE_DEFAULT); } static int as3722_attach(device_t dev) { struct as3722_softc *sc; int rv, rid; phandle_t node; sc = device_get_softc(dev); sc->dev = dev; sc->bus_addr = iicbus_get_addr(dev); node = ofw_bus_get_node(sc->dev); rv = 0; LOCK_INIT(sc); rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->irq_res == NULL) { device_printf(dev, "Cannot allocate interrupt.\n"); rv = ENXIO; goto fail; } rv = as3722_parse_fdt(sc, node); if (rv != 0) goto fail; rv = as3722_get_version(sc); if (rv != 0) goto fail; rv = as3722_init(sc); if (rv != 0) goto fail; rv = as3722_regulator_attach(sc, node); if (rv != 0) goto fail; rv = as3722_gpio_attach(sc, node); if (rv != 0) goto fail; rv = as3722_rtc_attach(sc, node); if (rv != 0) goto fail; fdt_pinctrl_register(dev, NULL); fdt_pinctrl_configure_by_name(dev, "default"); /* Setup interrupt. */ rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, as3722_intr, sc, &sc->irq_h); if (rv) { device_printf(dev, "Cannot setup interrupt.\n"); goto fail; } return (bus_generic_attach(dev)); fail: if (sc->irq_h != NULL) bus_teardown_intr(dev, sc->irq_res, sc->irq_h); if (sc->irq_res != NULL) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); LOCK_DESTROY(sc); return (rv); } static int as3722_detach(device_t dev) { struct as3722_softc *sc; sc = device_get_softc(dev); if (sc->irq_h != NULL) bus_teardown_intr(dev, sc->irq_res, sc->irq_h); if (sc->irq_res != NULL) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); LOCK_DESTROY(sc); return (bus_generic_detach(dev)); } static phandle_t as3722_gpio_get_node(device_t bus, device_t dev) { /* We only have one child, the GPIO bus, which needs our own node. */ return (ofw_bus_get_node(bus)); } static device_method_t as3722_methods[] = { /* Device interface */ DEVMETHOD(device_probe, as3722_probe), DEVMETHOD(device_attach, as3722_attach), DEVMETHOD(device_detach, as3722_detach), /* Regdev interface */ DEVMETHOD(regdev_map, as3722_regulator_map), /* RTC interface */ DEVMETHOD(clock_gettime, as3722_rtc_gettime), DEVMETHOD(clock_settime, as3722_rtc_settime), /* GPIO protocol interface */ DEVMETHOD(gpio_get_bus, as3722_gpio_get_bus), DEVMETHOD(gpio_pin_max, as3722_gpio_pin_max), DEVMETHOD(gpio_pin_getname, as3722_gpio_pin_getname), DEVMETHOD(gpio_pin_getflags, as3722_gpio_pin_getflags), DEVMETHOD(gpio_pin_getcaps, as3722_gpio_pin_getcaps), DEVMETHOD(gpio_pin_setflags, as3722_gpio_pin_setflags), DEVMETHOD(gpio_pin_get, as3722_gpio_pin_get), DEVMETHOD(gpio_pin_set, as3722_gpio_pin_set), DEVMETHOD(gpio_pin_toggle, as3722_gpio_pin_toggle), DEVMETHOD(gpio_map_gpios, as3722_gpio_map_gpios), /* fdt_pinctrl interface */ DEVMETHOD(fdt_pinctrl_configure, as3722_pinmux_configure), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_node, as3722_gpio_get_node), DEVMETHOD_END }; static DEFINE_CLASS_0(gpio, as3722_driver, as3722_methods, sizeof(struct as3722_softc)); EARLY_DRIVER_MODULE(as3722, iicbus, as3722_driver, NULL, NULL, 74); diff --git a/sys/arm/nvidia/as3722_regulators.c b/sys/arm/nvidia/as3722_regulators.c index 912c0d964961..331dfb72f4b5 100644 --- a/sys/arm/nvidia/as3722_regulators.c +++ b/sys/arm/nvidia/as3722_regulators.c @@ -1,709 +1,709 @@ /*- * Copyright 2016 Michal Meloun * All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include "as3722.h" MALLOC_DEFINE(M_AS3722_REG, "AS3722 regulator", "AS3722 power regulator"); #define DIV_ROUND_UP(n,d) howmany(n, d) enum as3722_reg_id { AS3722_REG_ID_SD0, AS3722_REG_ID_SD1, AS3722_REG_ID_SD2, AS3722_REG_ID_SD3, AS3722_REG_ID_SD4, AS3722_REG_ID_SD5, AS3722_REG_ID_SD6, AS3722_REG_ID_LDO0, AS3722_REG_ID_LDO1, AS3722_REG_ID_LDO2, AS3722_REG_ID_LDO3, AS3722_REG_ID_LDO4, AS3722_REG_ID_LDO5, AS3722_REG_ID_LDO6, AS3722_REG_ID_LDO7, AS3722_REG_ID_LDO9, AS3722_REG_ID_LDO10, AS3722_REG_ID_LDO11, }; /* Regulator HW definition. */ struct reg_def { intptr_t id; /* ID */ char *name; /* Regulator name */ char *supply_name; /* Source property name */ uint8_t volt_reg; uint8_t volt_vsel_mask; uint8_t enable_reg; uint8_t enable_mask; uint8_t ext_enable_reg; uint8_t ext_enable_mask; struct regulator_range *ranges; int nranges; }; struct as3722_reg_sc { struct regnode *regnode; struct as3722_softc *base_sc; struct reg_def *def; phandle_t xref; struct regnode_std_param *param; int ext_control; int enable_tracking; int enable_usec; }; static struct regulator_range as3722_sd016_ranges[] = { REG_RANGE_INIT(0x00, 0x00, 0, 0), REG_RANGE_INIT(0x01, 0x5A, 610000, 10000), }; static struct regulator_range as3722_sd0_lv_ranges[] = { REG_RANGE_INIT(0x00, 0x00, 0, 0), REG_RANGE_INIT(0x01, 0x6E, 410000, 10000), }; static struct regulator_range as3722_sd_ranges[] = { REG_RANGE_INIT(0x00, 0x00, 0, 0), REG_RANGE_INIT(0x01, 0x40, 612500, 12500), REG_RANGE_INIT(0x41, 0x70, 1425000, 25000), REG_RANGE_INIT(0x71, 0x7F, 2650000, 50000), }; static struct regulator_range as3722_ldo3_ranges[] = { REG_RANGE_INIT(0x00, 0x00, 0, 0), REG_RANGE_INIT(0x01, 0x2D, 620000, 20000), }; static struct regulator_range as3722_ldo_ranges[] = { REG_RANGE_INIT(0x00, 0x00, 0, 0), REG_RANGE_INIT(0x01, 0x24, 825000, 25000), REG_RANGE_INIT(0x40, 0x7F, 1725000, 25000), }; static struct reg_def as3722s_def[] = { { .id = AS3722_REG_ID_SD0, .name = "sd0", .volt_reg = AS3722_SD0_VOLTAGE, .volt_vsel_mask = AS3722_SD_VSEL_MASK, .enable_reg = AS3722_SD_CONTROL, .enable_mask = AS3722_SDN_CTRL(0), .ext_enable_reg = AS3722_ENABLE_CTRL1, .ext_enable_mask = AS3722_SD0_EXT_ENABLE_MASK, .ranges = as3722_sd016_ranges, .nranges = nitems(as3722_sd016_ranges), }, { .id = AS3722_REG_ID_SD1, .name = "sd1", .volt_reg = AS3722_SD1_VOLTAGE, .volt_vsel_mask = AS3722_SD_VSEL_MASK, .enable_reg = AS3722_SD_CONTROL, .enable_mask = AS3722_SDN_CTRL(1), .ext_enable_reg = AS3722_ENABLE_CTRL1, .ext_enable_mask = AS3722_SD1_EXT_ENABLE_MASK, .ranges = as3722_sd_ranges, .nranges = nitems(as3722_sd_ranges), }, { .id = AS3722_REG_ID_SD2, .name = "sd2", .supply_name = "vsup-sd2", .volt_reg = AS3722_SD2_VOLTAGE, .volt_vsel_mask = AS3722_SD_VSEL_MASK, .enable_reg = AS3722_SD_CONTROL, .enable_mask = AS3722_SDN_CTRL(2), .ext_enable_reg = AS3722_ENABLE_CTRL1, .ext_enable_mask = AS3722_SD2_EXT_ENABLE_MASK, .ranges = as3722_sd_ranges, .nranges = nitems(as3722_sd_ranges), }, { .id = AS3722_REG_ID_SD3, .name = "sd3", .supply_name = "vsup-sd3", .volt_reg = AS3722_SD3_VOLTAGE, .volt_vsel_mask = AS3722_SD_VSEL_MASK, .enable_reg = AS3722_SD_CONTROL, .enable_mask = AS3722_SDN_CTRL(3), .ext_enable_reg = AS3722_ENABLE_CTRL1, .ext_enable_mask = AS3722_SD3_EXT_ENABLE_MASK, .ranges = as3722_sd_ranges, .nranges = nitems(as3722_sd_ranges), }, { .id = AS3722_REG_ID_SD4, .name = "sd4", .supply_name = "vsup-sd4", .volt_reg = AS3722_SD4_VOLTAGE, .volt_vsel_mask = AS3722_SD_VSEL_MASK, .enable_reg = AS3722_SD_CONTROL, .enable_mask = AS3722_SDN_CTRL(4), .ext_enable_reg = AS3722_ENABLE_CTRL2, .ext_enable_mask = AS3722_SD4_EXT_ENABLE_MASK, .ranges = as3722_sd_ranges, .nranges = nitems(as3722_sd_ranges), }, { .id = AS3722_REG_ID_SD5, .name = "sd5", .supply_name = "vsup-sd5", .volt_reg = AS3722_SD5_VOLTAGE, .volt_vsel_mask = AS3722_SD_VSEL_MASK, .enable_reg = AS3722_SD_CONTROL, .enable_mask = AS3722_SDN_CTRL(5), .ext_enable_reg = AS3722_ENABLE_CTRL2, .ext_enable_mask = AS3722_SD5_EXT_ENABLE_MASK, .ranges = as3722_sd_ranges, .nranges = nitems(as3722_sd_ranges), }, { .id = AS3722_REG_ID_SD6, .name = "sd6", .volt_reg = AS3722_SD6_VOLTAGE, .volt_vsel_mask = AS3722_SD_VSEL_MASK, .enable_reg = AS3722_SD_CONTROL, .enable_mask = AS3722_SDN_CTRL(6), .ext_enable_reg = AS3722_ENABLE_CTRL2, .ext_enable_mask = AS3722_SD6_EXT_ENABLE_MASK, .ranges = as3722_sd016_ranges, .nranges = nitems(as3722_sd016_ranges), }, { .id = AS3722_REG_ID_LDO0, .name = "ldo0", .supply_name = "vin-ldo0", .volt_reg = AS3722_LDO0_VOLTAGE, .volt_vsel_mask = AS3722_LDO0_VSEL_MASK, .enable_reg = AS3722_LDO_CONTROL0, .enable_mask = AS3722_LDO0_CTRL, .ext_enable_reg = AS3722_ENABLE_CTRL3, .ext_enable_mask = AS3722_LDO0_EXT_ENABLE_MASK, .ranges = as3722_ldo_ranges, .nranges = nitems(as3722_ldo_ranges), }, { .id = AS3722_REG_ID_LDO1, .name = "ldo1", .supply_name = "vin-ldo1-6", .volt_reg = AS3722_LDO1_VOLTAGE, .volt_vsel_mask = AS3722_LDO_VSEL_MASK, .enable_reg = AS3722_LDO_CONTROL0, .enable_mask = AS3722_LDO1_CTRL, .ext_enable_reg = AS3722_ENABLE_CTRL3, .ext_enable_mask = AS3722_LDO1_EXT_ENABLE_MASK, .ranges = as3722_ldo_ranges, .nranges = nitems(as3722_ldo_ranges), }, { .id = AS3722_REG_ID_LDO2, .name = "ldo2", .supply_name = "vin-ldo2-5-7", .volt_reg = AS3722_LDO2_VOLTAGE, .volt_vsel_mask = AS3722_LDO_VSEL_MASK, .enable_reg = AS3722_LDO_CONTROL0, .enable_mask = AS3722_LDO2_CTRL, .ext_enable_reg = AS3722_ENABLE_CTRL3, .ext_enable_mask = AS3722_LDO2_EXT_ENABLE_MASK, .ranges = as3722_ldo_ranges, .nranges = nitems(as3722_ldo_ranges), }, { .id = AS3722_REG_ID_LDO3, .name = "ldo3", .supply_name = "vin-ldo3-4", .volt_reg = AS3722_LDO3_VOLTAGE, .volt_vsel_mask = AS3722_LDO3_VSEL_MASK, .enable_reg = AS3722_LDO_CONTROL0, .enable_mask = AS3722_LDO3_CTRL, .ext_enable_reg = AS3722_ENABLE_CTRL3, .ext_enable_mask = AS3722_LDO3_EXT_ENABLE_MASK, .ranges = as3722_ldo3_ranges, .nranges = nitems(as3722_ldo3_ranges), }, { .id = AS3722_REG_ID_LDO4, .name = "ldo4", .supply_name = "vin-ldo3-4", .volt_reg = AS3722_LDO4_VOLTAGE, .volt_vsel_mask = AS3722_LDO_VSEL_MASK, .enable_reg = AS3722_LDO_CONTROL0, .enable_mask = AS3722_LDO4_CTRL, .ext_enable_reg = AS3722_ENABLE_CTRL4, .ext_enable_mask = AS3722_LDO4_EXT_ENABLE_MASK, .ranges = as3722_ldo_ranges, .nranges = nitems(as3722_ldo_ranges), }, { .id = AS3722_REG_ID_LDO5, .name = "ldo5", .supply_name = "vin-ldo2-5-7", .volt_reg = AS3722_LDO5_VOLTAGE, .volt_vsel_mask = AS3722_LDO_VSEL_MASK, .enable_reg = AS3722_LDO_CONTROL0, .enable_mask = AS3722_LDO5_CTRL, .ext_enable_reg = AS3722_ENABLE_CTRL4, .ext_enable_mask = AS3722_LDO5_EXT_ENABLE_MASK, .ranges = as3722_ldo_ranges, .nranges = nitems(as3722_ldo_ranges), }, { .id = AS3722_REG_ID_LDO6, .name = "ldo6", .supply_name = "vin-ldo1-6", .volt_reg = AS3722_LDO6_VOLTAGE, .volt_vsel_mask = AS3722_LDO_VSEL_MASK, .enable_reg = AS3722_LDO_CONTROL0, .enable_mask = AS3722_LDO6_CTRL, .ext_enable_reg = AS3722_ENABLE_CTRL4, .ext_enable_mask = AS3722_LDO6_EXT_ENABLE_MASK, .ranges = as3722_ldo_ranges, .nranges = nitems(as3722_ldo_ranges), }, { .id = AS3722_REG_ID_LDO7, .name = "ldo7", .supply_name = "vin-ldo2-5-7", .volt_reg = AS3722_LDO7_VOLTAGE, .volt_vsel_mask = AS3722_LDO_VSEL_MASK, .enable_reg = AS3722_LDO_CONTROL0, .enable_mask = AS3722_LDO7_CTRL, .ext_enable_reg = AS3722_ENABLE_CTRL4, .ext_enable_mask = AS3722_LDO7_EXT_ENABLE_MASK, .ranges = as3722_ldo_ranges, .nranges = nitems(as3722_ldo_ranges), }, { .id = AS3722_REG_ID_LDO9, .name = "ldo9", .supply_name = "vin-ldo9-10", .volt_reg = AS3722_LDO9_VOLTAGE, .volt_vsel_mask = AS3722_LDO_VSEL_MASK, .enable_reg = AS3722_LDO_CONTROL1, .enable_mask = AS3722_LDO9_CTRL, .ext_enable_reg = AS3722_ENABLE_CTRL5, .ext_enable_mask = AS3722_LDO9_EXT_ENABLE_MASK, .ranges = as3722_ldo_ranges, .nranges = nitems(as3722_ldo_ranges), }, { .id = AS3722_REG_ID_LDO10, .name = "ldo10", .supply_name = "vin-ldo9-10", .volt_reg = AS3722_LDO10_VOLTAGE, .volt_vsel_mask = AS3722_LDO_VSEL_MASK, .enable_reg = AS3722_LDO_CONTROL1, .enable_mask = AS3722_LDO10_CTRL, .ext_enable_reg = AS3722_ENABLE_CTRL5, .ext_enable_mask = AS3722_LDO10_EXT_ENABLE_MASK, .ranges = as3722_ldo_ranges, .nranges = nitems(as3722_ldo_ranges), }, { .id = AS3722_REG_ID_LDO11, .name = "ldo11", .supply_name = "vin-ldo11", .volt_reg = AS3722_LDO11_VOLTAGE, .volt_vsel_mask = AS3722_LDO_VSEL_MASK, .enable_reg = AS3722_LDO_CONTROL1, .enable_mask = AS3722_LDO11_CTRL, .ext_enable_reg = AS3722_ENABLE_CTRL5, .ext_enable_mask = AS3722_LDO11_EXT_ENABLE_MASK, .ranges = as3722_ldo_ranges, .nranges = nitems(as3722_ldo_ranges), }, }; struct as3722_regnode_init_def { struct regnode_init_def reg_init_def; int ext_control; int enable_tracking; }; static int as3722_regnode_init(struct regnode *regnode); static int as3722_regnode_enable(struct regnode *regnode, bool enable, int *udelay); static int as3722_regnode_set_volt(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay); static int as3722_regnode_get_volt(struct regnode *regnode, int *uvolt); static regnode_method_t as3722_regnode_methods[] = { /* Regulator interface */ REGNODEMETHOD(regnode_init, as3722_regnode_init), REGNODEMETHOD(regnode_enable, as3722_regnode_enable), REGNODEMETHOD(regnode_set_voltage, as3722_regnode_set_volt), REGNODEMETHOD(regnode_get_voltage, as3722_regnode_get_volt), REGNODEMETHOD_END }; DEFINE_CLASS_1(as3722_regnode, as3722_regnode_class, as3722_regnode_methods, sizeof(struct as3722_reg_sc), regnode_class); static int as3722_read_sel(struct as3722_reg_sc *sc, uint8_t *sel) { int rv; rv = RD1(sc->base_sc, sc->def->volt_reg, sel); if (rv != 0) return (rv); *sel &= sc->def->volt_vsel_mask; *sel >>= ffs(sc->def->volt_vsel_mask) - 1; return (0); } static int as3722_write_sel(struct as3722_reg_sc *sc, uint8_t sel) { int rv; sel <<= ffs(sc->def->volt_vsel_mask) - 1; sel &= sc->def->volt_vsel_mask; rv = RM1(sc->base_sc, sc->def->volt_reg, sc->def->volt_vsel_mask, sel); if (rv != 0) return (rv); return (rv); } static bool as3722_sd0_is_low_voltage(struct as3722_reg_sc *sc) { uint8_t val; int rv; rv = RD1(sc->base_sc, AS3722_FUSE7, &val); if (rv != 0) return (rv); return (val & AS3722_FUSE7_SD0_LOW_VOLTAGE ? true : false); } static int as3722_reg_extreg_setup(struct as3722_reg_sc *sc, int ext_pwr_ctrl) { uint8_t val; int rv; val = ext_pwr_ctrl << (ffs(sc->def->ext_enable_mask) - 1); rv = RM1(sc->base_sc, sc->def->ext_enable_reg, sc->def->ext_enable_mask, val); return (rv); } static int as3722_reg_enable(struct as3722_reg_sc *sc) { int rv; rv = RM1(sc->base_sc, sc->def->enable_reg, sc->def->enable_mask, sc->def->enable_mask); return (rv); } static int as3722_reg_disable(struct as3722_reg_sc *sc) { int rv; rv = RM1(sc->base_sc, sc->def->enable_reg, sc->def->enable_mask, 0); return (rv); } static int as3722_regnode_init(struct regnode *regnode) { struct as3722_reg_sc *sc; int rv; sc = regnode_get_softc(regnode); sc->enable_usec = 500; if (sc->def->id == AS3722_REG_ID_SD0) { if (as3722_sd0_is_low_voltage(sc)) { sc->def->ranges = as3722_sd0_lv_ranges; sc->def->nranges = nitems(as3722_sd0_lv_ranges); } sc->enable_usec = 600; } else if (sc->def->id == AS3722_REG_ID_LDO3) { if (sc->enable_tracking) { rv = RM1(sc->base_sc, sc->def->volt_reg, AS3722_LDO3_MODE_MASK, AS3722_LDO3_MODE_PMOS_TRACKING); if (rv < 0) { device_printf(sc->base_sc->dev, "LDO3 tracking failed: %d\n", rv); return (rv); } } } if (sc->ext_control) { rv = as3722_reg_enable(sc); if (rv < 0) { device_printf(sc->base_sc->dev, "Failed to enable %s regulator: %d\n", sc->def->name, rv); return (rv); } rv = as3722_reg_extreg_setup(sc, sc->ext_control); if (rv < 0) { device_printf(sc->base_sc->dev, "%s ext control failed: %d", sc->def->name, rv); return (rv); } } return (0); } static void as3722_fdt_parse(struct as3722_softc *sc, phandle_t node, struct reg_def *def, struct as3722_regnode_init_def *init_def) { int rv; phandle_t parent, supply_node; char prop_name[64]; /* Maximum OFW property name length. */ rv = regulator_parse_ofw_stdparam(sc->dev, node, &init_def->reg_init_def); rv = OF_getencprop(node, "ams,ext-control", &init_def->ext_control, sizeof(init_def->ext_control)); if (rv <= 0) init_def->ext_control = 0; if (init_def->ext_control > 3) { device_printf(sc->dev, "Invalid value for ams,ext-control property: %d\n", init_def->ext_control); init_def->ext_control = 0; } if (OF_hasprop(node, "ams,enable-tracking")) init_def->enable_tracking = 1; /* Get parent supply. */ if (def->supply_name == NULL) return; parent = OF_parent(node); snprintf(prop_name, sizeof(prop_name), "%s-supply", def->supply_name); rv = OF_getencprop(parent, prop_name, &supply_node, sizeof(supply_node)); if (rv <= 0) return; supply_node = OF_node_from_xref(supply_node); rv = OF_getprop_alloc(supply_node, "regulator-name", (void **)&init_def->reg_init_def.parent_name); if (rv <= 0) init_def->reg_init_def.parent_name = NULL; } static struct as3722_reg_sc * as3722_attach(struct as3722_softc *sc, phandle_t node, struct reg_def *def) { struct as3722_reg_sc *reg_sc; struct as3722_regnode_init_def init_def; struct regnode *regnode; bzero(&init_def, sizeof(init_def)); as3722_fdt_parse(sc, node, def, &init_def); init_def.reg_init_def.id = def->id; init_def.reg_init_def.ofw_node = node; regnode = regnode_create(sc->dev, &as3722_regnode_class, &init_def.reg_init_def); if (regnode == NULL) { device_printf(sc->dev, "Cannot create regulator.\n"); return (NULL); } reg_sc = regnode_get_softc(regnode); /* Init regulator softc. */ reg_sc->regnode = regnode; reg_sc->base_sc = sc; reg_sc->def = def; reg_sc->xref = OF_xref_from_node(node); reg_sc->param = regnode_get_stdparam(regnode); reg_sc->ext_control = init_def.ext_control; reg_sc->enable_tracking = init_def.enable_tracking; regnode_register(regnode); if (bootverbose) { int volt, rv; regnode_topo_slock(); rv = regnode_get_voltage(regnode, &volt); if (rv == ENODEV) { device_printf(sc->dev, " Regulator %s: parent doesn't exist yet.\n", regnode_get_name(regnode)); } else if (rv != 0) { device_printf(sc->dev, " Regulator %s: voltage: INVALID!!!\n", regnode_get_name(regnode)); } else { device_printf(sc->dev, " Regulator %s: voltage: %d uV\n", regnode_get_name(regnode), volt); } regnode_topo_unlock(); } return (reg_sc); } int as3722_regulator_attach(struct as3722_softc *sc, phandle_t node) { struct as3722_reg_sc *reg; phandle_t child, rnode; int i; rnode = ofw_bus_find_child(node, "regulators"); if (rnode <= 0) { device_printf(sc->dev, " Cannot find regulators subnode\n"); return (ENXIO); } sc->nregs = nitems(as3722s_def); sc->regs = malloc(sizeof(struct as3722_reg_sc *) * sc->nregs, M_AS3722_REG, M_WAITOK | M_ZERO); /* Attach all known regulators if exist in DT. */ for (i = 0; i < sc->nregs; i++) { child = ofw_bus_find_child(rnode, as3722s_def[i].name); if (child == 0) { if (bootverbose) device_printf(sc->dev, "Regulator %s missing in DT\n", as3722s_def[i].name); continue; } reg = as3722_attach(sc, child, as3722s_def + i); if (reg == NULL) { device_printf(sc->dev, "Cannot attach regulator: %s\n", as3722s_def[i].name); return (ENXIO); } sc->regs[i] = reg; } return (0); } int as3722_regulator_map(device_t dev, phandle_t xref, int ncells, pcell_t *cells, int *num) { struct as3722_softc *sc; int i; sc = device_get_softc(dev); for (i = 0; i < sc->nregs; i++) { if (sc->regs[i] == NULL) continue; if (sc->regs[i]->xref == xref) { *num = sc->regs[i]->def->id; return (0); } } return (ENXIO); } static int as3722_regnode_enable(struct regnode *regnode, bool val, int *udelay) { struct as3722_reg_sc *sc; int rv; sc = regnode_get_softc(regnode); if (val) rv = as3722_reg_enable(sc); else rv = as3722_reg_disable(sc); *udelay = sc->enable_usec; return (rv); } static int as3722_regnode_set_volt(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay) { struct as3722_reg_sc *sc; uint8_t sel; int rv; sc = regnode_get_softc(regnode); *udelay = 0; rv = regulator_range_volt_to_sel8(sc->def->ranges, sc->def->nranges, min_uvolt, max_uvolt, &sel); if (rv != 0) return (rv); rv = as3722_write_sel(sc, sel); return (rv); } static int as3722_regnode_get_volt(struct regnode *regnode, int *uvolt) { struct as3722_reg_sc *sc; uint8_t sel; int rv; sc = regnode_get_softc(regnode); rv = as3722_read_sel(sc, &sel); if (rv != 0) return (rv); /* LDO6 have bypass. */ if (sc->def->id == AS3722_REG_ID_LDO6 && sel == AS3722_LDO6_SEL_BYPASS) return (ENOENT); rv = regulator_range_sel8_to_volt(sc->def->ranges, sc->def->nranges, sel, uvolt); return (rv); } diff --git a/sys/arm/nvidia/drm2/tegra_hdmi.c b/sys/arm/nvidia/drm2/tegra_hdmi.c index 174a9718bbfa..e5ce30ac2eb3 100644 --- a/sys/arm/nvidia/drm2/tegra_hdmi.c +++ b/sys/arm/nvidia/drm2/tegra_hdmi.c @@ -1,1315 +1,1315 @@ /*- * Copyright (c) 2015 Michal Meloun * All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #include #include #include #include #include #include "tegra_dc_if.h" #include "tegra_drm_if.h" #define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, 4 * (_r), (_v)) #define RD4(_sc, _r) bus_read_4((_sc)->mem_res, 4 * (_r)) /* HDA stream format verb. */ #define AC_FMT_CHAN_GET(x) (((x) >> 0) & 0xf) #define AC_FMT_CHAN_BITS_GET(x) (((x) >> 4) & 0x7) #define AC_FMT_DIV_GET(x) (((x) >> 8) & 0x7) #define AC_FMT_MUL_GET(x) (((x) >> 11) & 0x7) #define AC_FMT_BASE_44K (1 << 14) #define AC_FMT_TYPE_NON_PCM (1 << 15) #define HDMI_REKEY_DEFAULT 56 #define HDMI_ELD_BUFFER_SIZE 96 #define HDMI_DC_CLOCK_MULTIPIER 2 struct audio_reg { uint32_t audio_clk; bus_size_t acr_reg; bus_size_t nval_reg; bus_size_t aval_reg; }; static const struct audio_reg audio_regs[] = { { .audio_clk = 32000, .acr_reg = HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_LOW, .nval_reg = HDMI_NV_PDISP_SOR_AUDIO_NVAL_0320, .aval_reg = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0320, }, { .audio_clk = 44100, .acr_reg = HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW, .nval_reg = HDMI_NV_PDISP_SOR_AUDIO_NVAL_0441, .aval_reg = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0441, }, { .audio_clk = 88200, .acr_reg = HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_LOW, .nval_reg = HDMI_NV_PDISP_SOR_AUDIO_NVAL_0882, .aval_reg = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0882, }, { .audio_clk = 176400, .acr_reg = HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_LOW, .nval_reg = HDMI_NV_PDISP_SOR_AUDIO_NVAL_1764, .aval_reg = HDMI_NV_PDISP_SOR_AUDIO_AVAL_1764, }, { .audio_clk = 48000, .acr_reg = HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_LOW, .nval_reg = HDMI_NV_PDISP_SOR_AUDIO_NVAL_0480, .aval_reg = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0480, }, { .audio_clk = 96000, .acr_reg = HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_LOW, .nval_reg = HDMI_NV_PDISP_SOR_AUDIO_NVAL_0960, .aval_reg = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0960, }, { .audio_clk = 192000, .acr_reg = HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_LOW, .nval_reg = HDMI_NV_PDISP_SOR_AUDIO_NVAL_1920, .aval_reg = HDMI_NV_PDISP_SOR_AUDIO_AVAL_1920, }, }; struct tmds_config { uint32_t pclk; uint32_t pll0; uint32_t pll1; uint32_t drive_c; uint32_t pe_c; uint32_t peak_c; uint32_t pad_ctls; }; static const struct tmds_config tegra124_tmds_config[] = { { /* 480p/576p / 25.2MHz/27MHz */ .pclk = 27000000, .pll0 = 0x01003010, .pll1 = 0x00301B00, .drive_c = 0x1F1F1F1F, .pe_c = 0x00000000, .peak_c = 0x03030303, .pad_ctls = 0x800034BB, }, { /* 720p/1080i / 74.25MHz */ .pclk = 74250000, .pll0 = 0x01003110, .pll1 = 0x00301500, .drive_c = 0x2C2C2C2C, .pe_c = 0x00000000, .peak_c = 0x07070707, .pad_ctls = 0x800034BB, }, { /* 1080p / 148.5MHz */ .pclk = 148500000, .pll0 = 0x01003310, .pll1 = 0x00301500, .drive_c = 0x33333333, .pe_c = 0x00000000, .peak_c = 0x0C0C0C0C, .pad_ctls = 0x800034BB, }, { /* 2216p / 297MHz */ .pclk = UINT_MAX, .pll0 = 0x01003F10, .pll1 = 0x00300F00, .drive_c = 0x37373737, .pe_c = 0x00000000, .peak_c = 0x17171717, .pad_ctls = 0x800036BB, }, }; struct hdmi_softc { device_t dev; struct resource *mem_res; struct resource *irq_res; void *irq_ih; clk_t clk_parent; clk_t clk_hdmi; hwreset_t hwreset_hdmi; regulator_t supply_hdmi; regulator_t supply_pll; regulator_t supply_vdd; uint64_t pclk; boolean_t hdmi_mode; int audio_src_type; int audio_freq; int audio_chans; struct tegra_drm *drm; struct tegra_drm_encoder output; const struct tmds_config *tmds_config; int n_tmds_configs; }; static struct ofw_compat_data compat_data[] = { {"nvidia,tegra124-hdmi", 1}, {NULL, 0}, }; /* These functions have been copied from newer version of drm_edid.c */ /* ELD Header Block */ #define DRM_ELD_HEADER_BLOCK_SIZE 4 #define DRM_ELD_BASELINE_ELD_LEN 2 /* in dwords! */ static int drm_eld_size(const uint8_t *eld) { return DRM_ELD_HEADER_BLOCK_SIZE + eld[DRM_ELD_BASELINE_ELD_LEN] * 4; } static int drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, struct drm_display_mode *mode) { int rv; if (!frame || !mode) return -EINVAL; rv = hdmi_avi_infoframe_init(frame); if (rv < 0) return rv; if (mode->flags & DRM_MODE_FLAG_DBLCLK) frame->pixel_repeat = 1; frame->video_code = drm_match_cea_mode(mode); frame->picture_aspect = HDMI_PICTURE_ASPECT_NONE; #ifdef FREEBSD_NOTYET /* * Populate picture aspect ratio from either * user input (if specified) or from the CEA mode list. */ if (mode->picture_aspect_ratio == HDMI_PICTURE_ASPECT_4_3 || mode->picture_aspect_ratio == HDMI_PICTURE_ASPECT_16_9) frame->picture_aspect = mode->picture_aspect_ratio; else if (frame->video_code > 0) frame->picture_aspect = drm_get_cea_aspect_ratio( frame->video_code); #endif frame->active_aspect = HDMI_ACTIVE_ASPECT_PICTURE; frame->scan_mode = HDMI_SCAN_MODE_UNDERSCAN; return 0; } /* --------------------------------------------------------------------- */ static int hdmi_setup_clock(struct tegra_drm_encoder *output, clk_t clk, uint64_t pclk) { struct hdmi_softc *sc; uint64_t freq; int rv; sc = device_get_softc(output->dev); /* Disable consumers clock for while. */ rv = clk_disable(sc->clk_hdmi); if (rv != 0) { device_printf(sc->dev, "Cannot disable 'hdmi' clock\n"); return (rv); } rv = clk_disable(clk); if (rv != 0) { device_printf(sc->dev, "Cannot disable display clock\n"); return (rv); } /* Set frequency for Display Controller PLL. */ freq = HDMI_DC_CLOCK_MULTIPIER * pclk; rv = clk_set_freq(sc->clk_parent, freq, 0); if (rv != 0) { device_printf(output->dev, "Cannot set display pixel frequency\n"); return (rv); } /* Reparent display controller */ rv = clk_set_parent_by_clk(clk, sc->clk_parent); if (rv != 0) { device_printf(output->dev, "Cannot set parent clock\n"); return (rv); } rv = clk_set_freq(clk, freq, 0); if (rv != 0) { device_printf(output->dev, "Cannot set display controller frequency\n"); return (rv); } rv = clk_set_freq(sc->clk_hdmi, pclk, 0); if (rv != 0) { device_printf(output->dev, "Cannot set display controller frequency\n"); return (rv); } /* And reenable consumers clock. */ rv = clk_enable(clk); if (rv != 0) { device_printf(sc->dev, "Cannot enable display clock\n"); return (rv); } rv = clk_enable(sc->clk_hdmi); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'hdmi' clock\n"); return (rv); } rv = clk_get_freq(clk, &freq); if (rv != 0) { device_printf(output->dev, "Cannot get display controller frequency\n"); return (rv); } DRM_DEBUG_KMS("DC frequency: %llu\n", freq); return (0); } /* ------------------------------------------------------------------- * * Infoframes. * */ static void avi_setup_infoframe(struct hdmi_softc *sc, struct drm_display_mode *mode) { struct hdmi_avi_infoframe frame; uint8_t buf[17], *hdr, *pb; ssize_t rv; rv = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); if (rv < 0) { device_printf(sc->dev, "Cannot setup AVI infoframe: %zd\n", rv); return; } rv = hdmi_avi_infoframe_pack(&frame, buf, sizeof(buf)); if (rv < 0) { device_printf(sc->dev, "Cannot pack AVI infoframe: %zd\n", rv); return; } hdr = buf + 0; pb = buf + 3; WR4(sc, HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_HEADER, (hdr[2] << 16) | (hdr[1] << 8) | (hdr[0] << 0)); WR4(sc, HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_LOW, (pb[3] << 24) |(pb[2] << 16) | (pb[1] << 8) | (pb[0] << 0)); WR4(sc, HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_HIGH, (pb[6] << 16) | (pb[5] << 8) | (pb[4] << 0)); WR4(sc, HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_LOW, (pb[10] << 24) |(pb[9] << 16) | (pb[8] << 8) | (pb[7] << 0)); WR4(sc, HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_HIGH, (pb[13] << 16) | (pb[12] << 8) | (pb[11] << 0)); WR4(sc, HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL, AVI_INFOFRAME_CTRL_ENABLE); } static void audio_setup_infoframe(struct hdmi_softc *sc) { struct hdmi_audio_infoframe frame; uint8_t buf[14], *hdr, *pb; ssize_t rv; rv = hdmi_audio_infoframe_init(&frame); frame.channels = sc->audio_chans; rv = hdmi_audio_infoframe_pack(&frame, buf, sizeof(buf)); if (rv < 0) { device_printf(sc->dev, "Cannot pack audio infoframe\n"); return; } hdr = buf + 0; pb = buf + 3; WR4(sc, HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER, (hdr[2] << 16) | (hdr[1] << 8) | (hdr[0] << 0)); WR4(sc, HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_LOW, (pb[3] << 24) |(pb[2] << 16) | (pb[1] << 8) | (pb[0] << 0)); WR4(sc, HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_HIGH, (pb[5] << 8) | (pb[4] << 0)); WR4(sc, HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL, AUDIO_INFOFRAME_CTRL_ENABLE); } /* ------------------------------------------------------------------- * * Audio * */ static void init_hda_eld(struct hdmi_softc *sc) { size_t size; int i ; uint32_t val; size = drm_eld_size(sc->output.connector.eld); for (i = 0; i < HDMI_ELD_BUFFER_SIZE; i++) { val = i << 8; if (i < size) val |= sc->output.connector.eld[i]; WR4(sc, HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR, val); } WR4(sc,HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE, SOR_AUDIO_HDA_PRESENSE_VALID | SOR_AUDIO_HDA_PRESENSE_PRESENT); } static int get_audio_regs(int freq, bus_size_t *acr_reg, bus_size_t *nval_reg, bus_size_t *aval_reg) { int i; const struct audio_reg *reg; for (i = 0; i < nitems(audio_regs) ; i++) { reg = audio_regs + i; if (reg->audio_clk == freq) { if (acr_reg != NULL) *acr_reg = reg->acr_reg; if (nval_reg != NULL) *nval_reg = reg->nval_reg; if (aval_reg != NULL) *aval_reg = reg->aval_reg; return (0); } } return (ERANGE); } #define FR_BITS 16 #define TO_FFP(x) (((int64_t)(x)) << FR_BITS) #define TO_INT(x) ((int)((x) >> FR_BITS)) static int get_hda_cts_n(uint32_t audio_freq_hz, uint32_t pixclk_freq_hz, uint32_t *best_cts, uint32_t *best_n, uint32_t *best_a) { int min_n; int max_n; int ideal_n; int n; int cts; int aval; int64_t err_f; int64_t min_err_f; int64_t cts_f; int64_t aval_f; int64_t half_f; /* constant 0.5 */ bool better_n; /* * All floats are in fixed I48.16 format. * * Ideal ACR interval is 1000 hz (1 ms); * acceptable is 300 hz .. 1500 hz */ min_n = 128 * audio_freq_hz / 1500; max_n = 128 * audio_freq_hz / 300; ideal_n = 128 * audio_freq_hz / 1000; min_err_f = TO_FFP(100); half_f = TO_FFP(1) / 2; *best_n = 0; *best_cts = 0; *best_a = 0; for (n = min_n; n <= max_n; n++) { cts_f = TO_FFP(pixclk_freq_hz); cts_f *= n; cts_f /= 128 * audio_freq_hz; cts = TO_INT(cts_f + half_f); /* round */ err_f = cts_f - TO_FFP(cts); if (err_f < 0) err_f = -err_f; aval_f = TO_FFP(24000000); aval_f *= n; aval_f /= 128 * audio_freq_hz; aval = TO_INT(aval_f); /* truncate */ better_n = abs(n - ideal_n) < abs((int)(*best_n) - ideal_n); if (TO_FFP(aval) == aval_f && (err_f < min_err_f || (err_f == min_err_f && better_n))) { min_err_f = err_f; *best_n = (uint32_t)n; *best_cts = (uint32_t)cts; *best_a = (uint32_t)aval; if (err_f == 0 && n == ideal_n) break; } } return (0); } #undef FR_BITS #undef TO_FFP #undef TO_INT static int audio_setup(struct hdmi_softc *sc) { uint32_t val; uint32_t audio_n; uint32_t audio_cts; uint32_t audio_aval; uint64_t hdmi_freq; bus_size_t aval_reg; int rv; if (!sc->hdmi_mode) return (ENOTSUP); rv = get_audio_regs(sc->audio_freq, NULL, NULL, &aval_reg); if (rv != 0) { device_printf(sc->dev, "Unsupported audio frequency.\n"); return (rv); } rv = clk_get_freq(sc->clk_hdmi, &hdmi_freq); if (rv != 0) { device_printf(sc->dev, "Cannot get hdmi frequency: %d\n", rv); return (rv); } rv = get_hda_cts_n(sc->audio_freq, hdmi_freq, &audio_cts, &audio_n, &audio_aval); if (rv != 0) { device_printf(sc->dev, "Cannot compute audio coefs: %d\n", rv); return (rv); } /* Audio infoframe. */ audio_setup_infoframe(sc); /* Setup audio source */ WR4(sc, HDMI_NV_PDISP_SOR_AUDIO_CNTRL0, SOR_AUDIO_CNTRL0_SOURCE_SELECT(sc->audio_src_type) | SOR_AUDIO_CNTRL0_INJECT_NULLSMPL); val = RD4(sc, HDMI_NV_PDISP_SOR_AUDIO_SPARE0); val |= SOR_AUDIO_SPARE0_HBR_ENABLE; WR4(sc, HDMI_NV_PDISP_SOR_AUDIO_SPARE0, val); WR4(sc, HDMI_NV_PDISP_HDMI_ACR_CTRL, 0); WR4(sc, HDMI_NV_PDISP_AUDIO_N, AUDIO_N_RESETF | AUDIO_N_GENERATE_ALTERNATE | AUDIO_N_VALUE(audio_n - 1)); WR4(sc, HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH, ACR_SUBPACK_N(audio_n) | ACR_ENABLE); WR4(sc, HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW, ACR_SUBPACK_CTS(audio_cts)); WR4(sc, HDMI_NV_PDISP_HDMI_SPARE, SPARE_HW_CTS | SPARE_FORCE_SW_CTS | SPARE_CTS_RESET_VAL(1)); val = RD4(sc, HDMI_NV_PDISP_AUDIO_N); val &= ~AUDIO_N_RESETF; WR4(sc, HDMI_NV_PDISP_AUDIO_N, val); WR4(sc, aval_reg, audio_aval); return (0); } static void audio_disable(struct hdmi_softc *sc) { uint32_t val; /* Disable audio */ val = RD4(sc, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); val &= ~GENERIC_CTRL_AUDIO; WR4(sc, HDMI_NV_PDISP_HDMI_GENERIC_CTRL, val); /* Disable audio infoframes */ val = RD4(sc, HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); val &= ~AUDIO_INFOFRAME_CTRL_ENABLE; WR4(sc, HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL, val); } static void audio_enable(struct hdmi_softc *sc) { uint32_t val; if (!sc->hdmi_mode) audio_disable(sc); /* Enable audio infoframes */ val = RD4(sc, HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); val |= AUDIO_INFOFRAME_CTRL_ENABLE; WR4(sc, HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL, val); /* Enable audio */ val = RD4(sc, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); val |= GENERIC_CTRL_AUDIO; WR4(sc, HDMI_NV_PDISP_HDMI_GENERIC_CTRL, val); } /* ------------------------------------------------------------------- * * HDMI. * */ /* Process format change notification from HDA */ static void hda_intr(struct hdmi_softc *sc) { uint32_t val; int rv; if (!sc->hdmi_mode) return; val = RD4(sc, HDMI_NV_PDISP_SOR_AUDIO_HDA_CODEC_SCRATCH0); if ((val & (1 << 30)) == 0) { audio_disable(sc); return; } /* XXX Move this to any header */ /* Keep in sync with HDA */ sc->audio_freq = val & 0x00FFFFFF; sc->audio_chans = (val >> 24) & 0x0f; DRM_DEBUG_KMS("%d channel(s) at %dHz\n", sc->audio_chans, sc->audio_freq); rv = audio_setup(sc); if (rv != 0) { audio_disable(sc); return; } audio_enable(sc); } static void tmds_init(struct hdmi_softc *sc, const struct tmds_config *tmds) { WR4(sc, HDMI_NV_PDISP_SOR_PLL0, tmds->pll0); WR4(sc, HDMI_NV_PDISP_SOR_PLL1, tmds->pll1); WR4(sc, HDMI_NV_PDISP_PE_CURRENT, tmds->pe_c); WR4(sc, HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT, tmds->drive_c); WR4(sc, HDMI_NV_PDISP_SOR_IO_PEAK_CURRENT, tmds->peak_c); WR4(sc, HDMI_NV_PDISP_SOR_PAD_CTLS0, tmds->pad_ctls); } static int hdmi_sor_start(struct hdmi_softc *sc, struct drm_display_mode *mode) { int i; uint32_t val; /* Enable TMDS macro */ val = RD4(sc, HDMI_NV_PDISP_SOR_PLL0); val &= ~SOR_PLL0_PWR; val &= ~SOR_PLL0_VCOPD; val &= ~SOR_PLL0_PULLDOWN; WR4(sc, HDMI_NV_PDISP_SOR_PLL0, val); DELAY(10); val = RD4(sc, HDMI_NV_PDISP_SOR_PLL0); val &= ~SOR_PLL0_PDBG; WR4(sc, HDMI_NV_PDISP_SOR_PLL0, val); WR4(sc, HDMI_NV_PDISP_SOR_PWR, SOR_PWR_SETTING_NEW); WR4(sc, HDMI_NV_PDISP_SOR_PWR, 0); /* Wait until SOR is ready */ for (i = 1000; i > 0; i--) { val = RD4(sc, HDMI_NV_PDISP_SOR_PWR); if ((val & SOR_PWR_SETTING_NEW) == 0) break; DELAY(10); } if (i <= 0) { device_printf(sc->dev, "Timeouted while enabling SOR power.\n"); return (ETIMEDOUT); } val = SOR_STATE2_ASY_OWNER(ASY_OWNER_HEAD0) | SOR_STATE2_ASY_SUBOWNER(SUBOWNER_BOTH) | SOR_STATE2_ASY_CRCMODE(ASY_CRCMODE_COMPLETE) | SOR_STATE2_ASY_PROTOCOL(ASY_PROTOCOL_SINGLE_TMDS_A); if (mode->flags & DRM_MODE_FLAG_NHSYNC) val |= SOR_STATE2_ASY_HSYNCPOL_NEG; if (mode->flags & DRM_MODE_FLAG_NVSYNC) val |= SOR_STATE2_ASY_VSYNCPOL_NEG; WR4(sc, HDMI_NV_PDISP_SOR_STATE2, val); WR4(sc, HDMI_NV_PDISP_SOR_STATE1, SOR_STATE1_ASY_ORMODE_NORMAL | SOR_STATE1_ASY_HEAD_OPMODE(ASY_HEAD_OPMODE_AWAKE)); WR4(sc, HDMI_NV_PDISP_SOR_STATE0, 0); WR4(sc, HDMI_NV_PDISP_SOR_STATE0, SOR_STATE0_UPDATE); val = RD4(sc, HDMI_NV_PDISP_SOR_STATE1); val |= SOR_STATE1_ATTACHED; WR4(sc, HDMI_NV_PDISP_SOR_STATE1, val); WR4(sc, HDMI_NV_PDISP_SOR_STATE0, 0); return 0; } static int hdmi_disable(struct hdmi_softc *sc) { struct tegra_crtc *crtc; device_t dc; uint32_t val; dc = NULL; if (sc->output.encoder.crtc != NULL) { crtc = container_of(sc->output.encoder.crtc, struct tegra_crtc, drm_crtc); dc = crtc->dev; } if (dc != NULL) { TEGRA_DC_HDMI_ENABLE(dc, false); TEGRA_DC_DISPLAY_ENABLE(dc, false); } audio_disable(sc); val = RD4(sc, HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL); val &= ~AVI_INFOFRAME_CTRL_ENABLE; WR4(sc, HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL, val); /* Disable interrupts */ WR4(sc, HDMI_NV_PDISP_INT_ENABLE, 0); WR4(sc, HDMI_NV_PDISP_INT_MASK, 0); return (0); } static int hdmi_enable(struct hdmi_softc *sc) { uint64_t freq; struct drm_display_mode *mode; struct tegra_crtc *crtc; uint32_t val, h_sync_width, h_back_porch, h_front_porch, h_pulse_start; uint32_t h_max_ac_packet, div8_2; device_t dc; int i, rv; mode = &sc->output.encoder.crtc->mode; crtc = container_of(sc->output.encoder.crtc, struct tegra_crtc, drm_crtc); dc = crtc->dev; /* Compute all timings first. */ sc->pclk = mode->clock * 1000; h_sync_width = mode->hsync_end - mode->hsync_start; h_back_porch = mode->htotal - mode->hsync_end; h_front_porch = mode->hsync_start - mode->hdisplay; h_pulse_start = 1 + h_sync_width + h_back_porch - 10; h_max_ac_packet = (h_sync_width + h_back_porch + h_front_porch - HDMI_REKEY_DEFAULT - 18) / 32; /* Check if HDMI device is connected and detected. */ if (sc->output.connector.edid_blob_ptr == NULL) { sc->hdmi_mode = false; } else { sc->hdmi_mode = drm_detect_hdmi_monitor( (struct edid *)sc->output.connector.edid_blob_ptr->data); } /* Get exact HDMI pixel frequency. */ rv = clk_get_freq(sc->clk_hdmi, &freq); if (rv != 0) { device_printf(sc->dev, "Cannot get 'hdmi' clock frequency\n"); return (rv); } DRM_DEBUG_KMS("HDMI frequency: %llu Hz\n", freq); /* Wakeup SOR power */ val = RD4(sc, HDMI_NV_PDISP_SOR_PLL0); val &= ~SOR_PLL0_PDBG; WR4(sc, HDMI_NV_PDISP_SOR_PLL0, val); DELAY(10); val = RD4(sc, HDMI_NV_PDISP_SOR_PLL0); val &= ~SOR_PLL0_PWR; WR4(sc, HDMI_NV_PDISP_SOR_PLL0, val); /* Setup timings */ TEGRA_DC_SETUP_TIMING(dc, h_pulse_start); WR4(sc, HDMI_NV_PDISP_HDMI_VSYNC_WINDOW, VSYNC_WINDOW_START(0x200) | VSYNC_WINDOW_END(0x210) | VSYNC_WINDOW_ENABLE); /* Setup video source and adjust video range */ val = 0; if (crtc->nvidia_head != 0) HDMI_SRC_DISPLAYB; if ((mode->hdisplay != 640) || (mode->vdisplay != 480)) val |= ARM_VIDEO_RANGE_LIMITED; WR4(sc, HDMI_NV_PDISP_INPUT_CONTROL, val); /* Program SOR reference clock - it uses 8.2 fractional divisor */ div8_2 = (freq * 4) / 1000000; val = SOR_REFCLK_DIV_INT(div8_2 >> 2) | SOR_REFCLK_DIV_FRAC(div8_2); WR4(sc, HDMI_NV_PDISP_SOR_REFCLK, val); /* Setup audio */ if (sc->hdmi_mode) { rv = audio_setup(sc); if (rv != 0) sc->hdmi_mode = false; } /* Init HDA ELD */ init_hda_eld(sc); val = HDMI_CTRL_REKEY(HDMI_REKEY_DEFAULT); val |= HDMI_CTRL_MAX_AC_PACKET(h_max_ac_packet); if (sc->hdmi_mode) val |= HDMI_CTRL_ENABLE; WR4(sc, HDMI_NV_PDISP_HDMI_CTRL, val); /* Setup TMDS */ for (i = 0; i < sc->n_tmds_configs; i++) { if (sc->pclk <= sc->tmds_config[i].pclk) { tmds_init(sc, sc->tmds_config + i); break; } } /* Program sequencer. */ WR4(sc, HDMI_NV_PDISP_SOR_SEQ_CTL, SOR_SEQ_PU_PC(0) | SOR_SEQ_PU_PC_ALT(0) | SOR_SEQ_PD_PC(8) | SOR_SEQ_PD_PC_ALT(8)); val = SOR_SEQ_INST_WAIT_TIME(1) | SOR_SEQ_INST_WAIT_UNITS(WAIT_UNITS_VSYNC) | SOR_SEQ_INST_HALT | SOR_SEQ_INST_DRIVE_PWM_OUT_LO; WR4(sc, HDMI_NV_PDISP_SOR_SEQ_INST(0), val); WR4(sc, HDMI_NV_PDISP_SOR_SEQ_INST(8), val); val = RD4(sc,HDMI_NV_PDISP_SOR_CSTM); val &= ~SOR_CSTM_LVDS_ENABLE; val &= ~SOR_CSTM_ROTCLK(~0); val |= SOR_CSTM_ROTCLK(2); val &= ~SOR_CSTM_MODE(~0); val |= SOR_CSTM_MODE(CSTM_MODE_TMDS); val |= SOR_CSTM_PLLDIV; WR4(sc, HDMI_NV_PDISP_SOR_CSTM, val); TEGRA_DC_DISPLAY_ENABLE(dc, false); rv = hdmi_sor_start(sc, mode); if (rv != 0) return (rv); TEGRA_DC_HDMI_ENABLE(dc, true); TEGRA_DC_DISPLAY_ENABLE(dc, true); /* Enable HDA codec interrupt */ WR4(sc, HDMI_NV_PDISP_INT_MASK, INT_CODEC_SCRATCH0); WR4(sc, HDMI_NV_PDISP_INT_ENABLE, INT_CODEC_SCRATCH0); if (sc->hdmi_mode) { avi_setup_infoframe(sc, mode); audio_enable(sc); } return (0); } /* ------------------------------------------------------------------- * * DRM Interface. * */ static enum drm_mode_status hdmi_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct tegra_drm_encoder *output; struct hdmi_softc *sc; int rv; uint64_t freq; output = container_of(connector, struct tegra_drm_encoder, connector); sc = device_get_softc(output->dev); freq = HDMI_DC_CLOCK_MULTIPIER * mode->clock * 1000; rv = clk_test_freq(sc->clk_parent, freq, 0); DRM_DEBUG_KMS("Test HDMI frequency: %u kHz, rv: %d\n", mode->clock, rv); if (rv != 0) return (MODE_NOCLOCK); return (MODE_OK); } static const struct drm_connector_helper_funcs hdmi_connector_helper_funcs = { .get_modes = tegra_drm_connector_get_modes, .mode_valid = hdmi_connector_mode_valid, .best_encoder = tegra_drm_connector_best_encoder, }; static const struct drm_connector_funcs hdmi_connector_funcs = { .dpms = drm_helper_connector_dpms, .detect = tegra_drm_connector_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = drm_connector_cleanup, }; static const struct drm_encoder_funcs hdmi_encoder_funcs = { .destroy = drm_encoder_cleanup, }; static void hdmi_encoder_dpms(struct drm_encoder *encoder, int mode) { /* Empty function. */ } static bool hdmi_encoder_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted) { return (true); } static void hdmi_encoder_prepare(struct drm_encoder *encoder) { /* Empty function. */ } static void hdmi_encoder_commit(struct drm_encoder *encoder) { /* Empty function. */ } static void hdmi_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted) { struct tegra_drm_encoder *output; struct hdmi_softc *sc; int rv; output = container_of(encoder, struct tegra_drm_encoder, encoder); sc = device_get_softc(output->dev); rv = hdmi_enable(sc); if (rv != 0) device_printf(sc->dev, "Cannot enable HDMI port\n"); } static void hdmi_encoder_disable(struct drm_encoder *encoder) { struct tegra_drm_encoder *output; struct hdmi_softc *sc; int rv; output = container_of(encoder, struct tegra_drm_encoder, encoder); sc = device_get_softc(output->dev); if (sc == NULL) return; rv = hdmi_disable(sc); if (rv != 0) device_printf(sc->dev, "Cannot disable HDMI port\n"); } static const struct drm_encoder_helper_funcs hdmi_encoder_helper_funcs = { .dpms = hdmi_encoder_dpms, .mode_fixup = hdmi_encoder_mode_fixup, .prepare = hdmi_encoder_prepare, .commit = hdmi_encoder_commit, .mode_set = hdmi_encoder_mode_set, .disable = hdmi_encoder_disable, }; /* ------------------------------------------------------------------- * * Bus and infrastructure. * */ static int hdmi_init_client(device_t dev, device_t host1x, struct tegra_drm *drm) { struct hdmi_softc *sc; phandle_t node; int rv; sc = device_get_softc(dev); node = ofw_bus_get_node(sc->dev); sc->drm = drm; sc->output.setup_clock = &hdmi_setup_clock; rv = tegra_drm_encoder_attach(&sc->output, node); if (rv != 0) { device_printf(dev, "Cannot attach output connector\n"); return(ENXIO); } /* Connect this encoder + connector to DRM. */ drm_connector_init(&drm->drm_dev, &sc->output.connector, &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); drm_connector_helper_add(&sc->output.connector, &hdmi_connector_helper_funcs); sc->output.connector.dpms = DRM_MODE_DPMS_OFF; drm_encoder_init(&drm->drm_dev, &sc->output.encoder, &hdmi_encoder_funcs, DRM_MODE_ENCODER_TMDS); drm_encoder_helper_add(&sc->output.encoder, &hdmi_encoder_helper_funcs); drm_mode_connector_attach_encoder(&sc->output.connector, &sc->output.encoder); rv = tegra_drm_encoder_init(&sc->output, drm); if (rv < 0) { device_printf(sc->dev, "Unable to init HDMI output\n"); return (rv); } sc->output.encoder.possible_crtcs = 0x3; return (0); } static int hdmi_exit_client(device_t dev, device_t host1x, struct tegra_drm *drm) { struct hdmi_softc *sc; sc = device_get_softc(dev); tegra_drm_encoder_exit(&sc->output, drm); return (0); } static int get_fdt_resources(struct hdmi_softc *sc, phandle_t node) { int rv; rv = regulator_get_by_ofw_property(sc->dev, 0, "hdmi-supply", &sc->supply_hdmi); if (rv != 0) { device_printf(sc->dev, "Cannot get 'hdmi' regulator\n"); return (ENXIO); } rv = regulator_get_by_ofw_property(sc->dev,0, "pll-supply", &sc->supply_pll); if (rv != 0) { device_printf(sc->dev, "Cannot get 'pll' regulator\n"); return (ENXIO); } rv = regulator_get_by_ofw_property(sc->dev, 0, "vdd-supply", &sc->supply_vdd); if (rv != 0) { device_printf(sc->dev, "Cannot get 'vdd' regulator\n"); return (ENXIO); } rv = hwreset_get_by_ofw_name(sc->dev, 0, "hdmi", &sc->hwreset_hdmi); if (rv != 0) { device_printf(sc->dev, "Cannot get 'hdmi' reset\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, 0, "parent", &sc->clk_parent); if (rv != 0) { device_printf(sc->dev, "Cannot get 'parent' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, 0, "hdmi", &sc->clk_hdmi); if (rv != 0) { device_printf(sc->dev, "Cannot get 'hdmi' clock\n"); return (ENXIO); } return (0); } static int enable_fdt_resources(struct hdmi_softc *sc) { int rv; rv = clk_set_parent_by_clk(sc->clk_hdmi, sc->clk_parent); if (rv != 0) { device_printf(sc->dev, "Cannot set parent for 'hdmi' clock\n"); return (rv); } /* 594 MHz is arbitrarily selected value */ rv = clk_set_freq(sc->clk_parent, 594000000, 0); if (rv != 0) { device_printf(sc->dev, "Cannot set frequency for 'hdmi' parent clock\n"); return (rv); } rv = clk_set_freq(sc->clk_hdmi, 594000000 / 4, 0); if (rv != 0) { device_printf(sc->dev, "Cannot set frequency for 'hdmi' parent clock\n"); return (rv); } rv = regulator_enable(sc->supply_hdmi); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'hdmi' regulator\n"); return (rv); } rv = regulator_enable(sc->supply_pll); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'pll' regulator\n"); return (rv); } rv = regulator_enable(sc->supply_vdd); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'vdd' regulator\n"); return (rv); } rv = clk_enable(sc->clk_hdmi); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'hdmi' clock\n"); return (rv); } rv = hwreset_deassert(sc->hwreset_hdmi); if (rv != 0) { device_printf(sc->dev, "Cannot unreset 'hdmi' reset\n"); return (rv); } return (0); } static void hdmi_intr(void *arg) { struct hdmi_softc *sc; uint32_t status; sc = arg; /* Confirm interrupt */ status = RD4(sc, HDMI_NV_PDISP_INT_STATUS); WR4(sc, HDMI_NV_PDISP_INT_STATUS, status); /* process audio verb from HDA */ if (status & INT_CODEC_SCRATCH0) hda_intr(sc); } static int hdmi_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Tegra HDMI"); return (BUS_PROBE_DEFAULT); } static int hdmi_attach(device_t dev) { struct hdmi_softc *sc; phandle_t node; int rid, rv; sc = device_get_softc(dev); sc->dev = dev; sc->output.dev = sc->dev; node = ofw_bus_get_node(sc->dev); sc->audio_src_type = SOURCE_SELECT_AUTO; sc->audio_freq = 44100; sc->audio_chans = 2; sc->hdmi_mode = false; sc->tmds_config = tegra124_tmds_config; sc->n_tmds_configs = nitems(tegra124_tmds_config); rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) { device_printf(dev, "Cannot allocate memory resources\n"); goto fail; } rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->irq_res == NULL) { device_printf(dev, "Cannot allocate IRQ resources\n"); goto fail; } rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, hdmi_intr, sc, &sc->irq_ih); if (rv != 0) { device_printf(dev, "WARNING: unable to register interrupt handler\n"); goto fail; } rv = get_fdt_resources(sc, node); if (rv != 0) { device_printf(dev, "Cannot parse FDT resources\n"); goto fail; } rv = enable_fdt_resources(sc); if (rv != 0) { device_printf(dev, "Cannot enable FDT resources\n"); goto fail; } rv = TEGRA_DRM_REGISTER_CLIENT(device_get_parent(sc->dev), sc->dev); if (rv != 0) { device_printf(dev, "Cannot register DRM device\n"); goto fail; } return (bus_generic_attach(dev)); fail: TEGRA_DRM_DEREGISTER_CLIENT(device_get_parent(sc->dev), sc->dev); if (sc->irq_ih != NULL) bus_teardown_intr(dev, sc->irq_res, sc->irq_ih); if (sc->clk_parent != NULL) clk_release(sc->clk_parent); if (sc->clk_hdmi != NULL) clk_release(sc->clk_hdmi); if (sc->hwreset_hdmi != NULL) hwreset_release(sc->hwreset_hdmi); if (sc->supply_hdmi != NULL) regulator_release(sc->supply_hdmi); if (sc->supply_pll != NULL) regulator_release(sc->supply_pll); if (sc->supply_vdd != NULL) regulator_release(sc->supply_vdd); if (sc->irq_res != NULL) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); if (sc->mem_res != NULL) bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); return (ENXIO); } static int hdmi_detach(device_t dev) { struct hdmi_softc *sc; sc = device_get_softc(dev); TEGRA_DRM_DEREGISTER_CLIENT(device_get_parent(sc->dev), sc->dev); if (sc->irq_ih != NULL) bus_teardown_intr(dev, sc->irq_res, sc->irq_ih); if (sc->clk_parent != NULL) clk_release(sc->clk_parent); if (sc->clk_hdmi != NULL) clk_release(sc->clk_hdmi); if (sc->hwreset_hdmi != NULL) hwreset_release(sc->hwreset_hdmi); if (sc->supply_hdmi != NULL) regulator_release(sc->supply_hdmi); if (sc->supply_pll != NULL) regulator_release(sc->supply_pll); if (sc->supply_vdd != NULL) regulator_release(sc->supply_vdd); if (sc->irq_res != NULL) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); if (sc->mem_res != NULL) bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); return (bus_generic_detach(dev)); } static device_method_t tegra_hdmi_methods[] = { /* Device interface */ DEVMETHOD(device_probe, hdmi_probe), DEVMETHOD(device_attach, hdmi_attach), DEVMETHOD(device_detach, hdmi_detach), /* tegra drm interface */ DEVMETHOD(tegra_drm_init_client, hdmi_init_client), DEVMETHOD(tegra_drm_exit_client, hdmi_exit_client), DEVMETHOD_END }; DEFINE_CLASS_0(tegra_hdmi, tegra_hdmi_driver, tegra_hdmi_methods, sizeof(struct hdmi_softc)); DRIVER_MODULE(tegra_hdmi, host1x, tegra_hdmi_driver, 0, 0); diff --git a/sys/arm/nvidia/tegra124/tegra124_cpufreq.c b/sys/arm/nvidia/tegra124/tegra124_cpufreq.c index 7cf83978557e..a537d9397722 100644 --- a/sys/arm/nvidia/tegra124/tegra124_cpufreq.c +++ b/sys/arm/nvidia/tegra124/tegra124_cpufreq.c @@ -1,588 +1,588 @@ /*- * Copyright (c) 2016 Michal Meloun * All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include "cpufreq_if.h" #define XXX /* CPU voltage table entry */ struct speedo_entry { uint64_t freq; /* Frequency point */ int c0; /* Coeeficient values for */ int c1; /* quadratic equation: */ int c2; /* c2 * speedo^2 + c1 * speedo + c0 */ }; struct cpu_volt_def { int min_uvolt; /* Min allowed CPU voltage */ int max_uvolt; /* Max allowed CPU voltage */ int step_uvolt; /* Step of CPU voltage */ int speedo_scale; /* Scaling factor for cvt */ int speedo_nitems; /* Size of speedo table */ struct speedo_entry *speedo_tbl; /* CPU voltage table */ }; struct cpu_speed_point { uint64_t freq; /* Frequecy */ int uvolt; /* Requested voltage */ }; static struct speedo_entry tegra124_speedo_dpll_tbl[] = { { 204000000ULL, 1112619, -29295, 402}, { 306000000ULL, 1150460, -30585, 402}, { 408000000ULL, 1190122, -31865, 402}, { 510000000ULL, 1231606, -33155, 402}, { 612000000ULL, 1274912, -34435, 402}, { 714000000ULL, 1320040, -35725, 402}, { 816000000ULL, 1366990, -37005, 402}, { 918000000ULL, 1415762, -38295, 402}, {1020000000ULL, 1466355, -39575, 402}, {1122000000ULL, 1518771, -40865, 402}, {1224000000ULL, 1573009, -42145, 402}, {1326000000ULL, 1629068, -43435, 402}, {1428000000ULL, 1686950, -44715, 402}, {1530000000ULL, 1746653, -46005, 402}, {1632000000ULL, 1808179, -47285, 402}, {1734000000ULL, 1871526, -48575, 402}, {1836000000ULL, 1936696, -49855, 402}, {1938000000ULL, 2003687, -51145, 402}, {2014500000ULL, 2054787, -52095, 402}, {2116500000ULL, 2124957, -53385, 402}, {2218500000ULL, 2196950, -54665, 402}, {2320500000ULL, 2270765, -55955, 402}, {2320500000ULL, 2270765, -55955, 402}, {2422500000ULL, 2346401, -57235, 402}, {2524500000ULL, 2437299, -58535, 402}, }; static struct cpu_volt_def tegra124_cpu_volt_dpll_def = { .min_uvolt = 900000, /* 0.9 V */ .max_uvolt = 1260000, /* 1.26 */ .step_uvolt = 10000, /* 10 mV */ .speedo_scale = 100, .speedo_nitems = nitems(tegra124_speedo_dpll_tbl), .speedo_tbl = tegra124_speedo_dpll_tbl, }; static struct speedo_entry tegra124_speedo_pllx_tbl[] = { { 204000000ULL, 800000, 0, 0}, { 306000000ULL, 800000, 0, 0}, { 408000000ULL, 800000, 0, 0}, { 510000000ULL, 800000, 0, 0}, { 612000000ULL, 800000, 0, 0}, { 714000000ULL, 800000, 0, 0}, { 816000000ULL, 820000, 0, 0}, { 918000000ULL, 840000, 0, 0}, {1020000000ULL, 880000, 0, 0}, {1122000000ULL, 900000, 0, 0}, {1224000000ULL, 930000, 0, 0}, {1326000000ULL, 960000, 0, 0}, {1428000000ULL, 990000, 0, 0}, {1530000000ULL, 1020000, 0, 0}, {1632000000ULL, 1070000, 0, 0}, {1734000000ULL, 1100000, 0, 0}, {1836000000ULL, 1140000, 0, 0}, {1938000000ULL, 1180000, 0, 0}, {2014500000ULL, 1220000, 0, 0}, {2116500000ULL, 1260000, 0, 0}, {2218500000ULL, 1310000, 0, 0}, {2320500000ULL, 1360000, 0, 0}, {2397000000ULL, 1400000, 0, 0}, {2499000000ULL, 1400000, 0, 0}, }; static struct cpu_volt_def tegra124_cpu_volt_pllx_def = { .min_uvolt = 1000000, /* XXX 0.9 V doesn't work on all boards */ .max_uvolt = 1260000, /* 1.26 */ .step_uvolt = 10000, /* 10 mV */ .speedo_scale = 100, .speedo_nitems = nitems(tegra124_speedo_pllx_tbl), .speedo_tbl = tegra124_speedo_pllx_tbl, }; static uint64_t cpu_freq_tbl[] = { 204000000ULL, 306000000ULL, 408000000ULL, 510000000ULL, 612000000ULL, 714000000ULL, 816000000ULL, 918000000ULL, 1020000000ULL, 1122000000ULL, 1224000000ULL, 1326000000ULL, 1428000000ULL, 1530000000ULL, 1632000000ULL, 1734000000ULL, 1836000000ULL, 1938000000ULL, 2014000000ULL, 2116000000ULL, 2218000000ULL, 2320000000ULL, 2422000000ULL, 2524000000ULL, }; static uint64_t cpu_max_freq[] = { 2014500000ULL, 2320500000ULL, 2116500000ULL, 2524500000ULL, }; struct tegra124_cpufreq_softc { device_t dev; phandle_t node; regulator_t supply_vdd_cpu; clk_t clk_cpu_g; clk_t clk_cpu_lp; clk_t clk_pll_x; clk_t clk_pll_p; clk_t clk_dfll; int process_id; int speedo_id; int speedo_value; uint64_t cpu_max_freq; struct cpu_volt_def *cpu_def; struct cpu_speed_point *speed_points; int nspeed_points; struct cpu_speed_point *act_speed_point; int latency; }; static int cpufreq_lowest_freq = 1; TUNABLE_INT("hw.tegra124.cpufreq.lowest_freq", &cpufreq_lowest_freq); #define DIV_ROUND_CLOSEST(val, div) (((val) + ((div) / 2)) / (div)) #define ROUND_UP(val, div) roundup(val, div) #define ROUND_DOWN(val, div) rounddown(val, div) /* * Compute requesetd voltage for given frequency and SoC process variations, * - compute base voltage from speedo value using speedo table * - round up voltage to next regulator step * - clamp it to regulator limits */ static int freq_to_voltage(struct tegra124_cpufreq_softc *sc, uint64_t freq) { int uv, scale, min_uvolt, max_uvolt, step_uvolt; struct speedo_entry *ent; int i; /* Get speedo entry with higher frequency */ ent = NULL; for (i = 0; i < sc->cpu_def->speedo_nitems; i++) { if (sc->cpu_def->speedo_tbl[i].freq >= freq) { ent = &sc->cpu_def->speedo_tbl[i]; break; } } if (ent == NULL) ent = &sc->cpu_def->speedo_tbl[sc->cpu_def->speedo_nitems - 1]; scale = sc->cpu_def->speedo_scale; /* uV = (c2 * speedo / scale + c1) * speedo / scale + c0) */ uv = DIV_ROUND_CLOSEST(ent->c2 * sc->speedo_value, scale); uv = DIV_ROUND_CLOSEST((uv + ent->c1) * sc->speedo_value, scale) + ent->c0; step_uvolt = sc->cpu_def->step_uvolt; /* Round up it to next regulator step */ uv = ROUND_UP(uv, step_uvolt); /* Clamp result */ min_uvolt = ROUND_UP(sc->cpu_def->min_uvolt, step_uvolt); max_uvolt = ROUND_DOWN(sc->cpu_def->max_uvolt, step_uvolt); if (uv < min_uvolt) uv = min_uvolt; if (uv > max_uvolt) uv = max_uvolt; return (uv); } static void build_speed_points(struct tegra124_cpufreq_softc *sc) { int i; sc->nspeed_points = nitems(cpu_freq_tbl); sc->speed_points = malloc(sizeof(struct cpu_speed_point) * sc->nspeed_points, M_DEVBUF, M_NOWAIT); for (i = 0; i < sc->nspeed_points; i++) { sc->speed_points[i].freq = cpu_freq_tbl[i]; sc->speed_points[i].uvolt = freq_to_voltage(sc, cpu_freq_tbl[i]); } } static struct cpu_speed_point * get_speed_point(struct tegra124_cpufreq_softc *sc, uint64_t freq) { int i; if (sc->speed_points[0].freq >= freq) return (sc->speed_points + 0); for (i = 0; i < sc->nspeed_points - 1; i++) { if (sc->speed_points[i + 1].freq > freq) return (sc->speed_points + i); } return (sc->speed_points + sc->nspeed_points - 1); } static int tegra124_cpufreq_settings(device_t dev, struct cf_setting *sets, int *count) { struct tegra124_cpufreq_softc *sc; int i, j; if (sets == NULL || count == NULL) return (EINVAL); sc = device_get_softc(dev); memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * (*count)); for (i = 0, j = sc->nspeed_points - 1; j >= 0; j--) { if (sc->cpu_max_freq < sc->speed_points[j].freq) continue; sets[i].freq = sc->speed_points[j].freq / 1000000; sets[i].volts = sc->speed_points[j].uvolt / 1000; sets[i].lat = sc->latency; sets[i].dev = dev; i++; } *count = i; return (0); } static int set_cpu_freq(struct tegra124_cpufreq_softc *sc, uint64_t freq) { struct cpu_speed_point *point; int rv; point = get_speed_point(sc, freq); if (sc->act_speed_point->uvolt < point->uvolt) { /* set cpu voltage */ rv = regulator_set_voltage(sc->supply_vdd_cpu, point->uvolt, point->uvolt); DELAY(10000); if (rv != 0) return (rv); } /* Switch supermux to PLLP first */ rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_p); if (rv != 0) { device_printf(sc->dev, "Can't set parent to PLLP\n"); return (rv); } /* Set PLLX frequency */ rv = clk_set_freq(sc->clk_pll_x, point->freq, CLK_SET_ROUND_DOWN); if (rv != 0) { device_printf(sc->dev, "Can't set CPU clock frequency\n"); return (rv); } rv = clk_set_parent_by_clk(sc->clk_cpu_g, sc->clk_pll_x); if (rv != 0) { device_printf(sc->dev, "Can't set parent to PLLX\n"); return (rv); } if (sc->act_speed_point->uvolt > point->uvolt) { /* set cpu voltage */ rv = regulator_set_voltage(sc->supply_vdd_cpu, point->uvolt, point->uvolt); if (rv != 0) return (rv); } sc->act_speed_point = point; return (0); } static int tegra124_cpufreq_set(device_t dev, const struct cf_setting *cf) { struct tegra124_cpufreq_softc *sc; uint64_t freq; int rv; if (cf == NULL || cf->freq < 0) return (EINVAL); sc = device_get_softc(dev); freq = cf->freq; if (freq < cpufreq_lowest_freq) freq = cpufreq_lowest_freq; freq *= 1000000; if (freq >= sc->cpu_max_freq) freq = sc->cpu_max_freq; rv = set_cpu_freq(sc, freq); return (rv); } static int tegra124_cpufreq_get(device_t dev, struct cf_setting *cf) { struct tegra124_cpufreq_softc *sc; if (cf == NULL) return (EINVAL); sc = device_get_softc(dev); memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf)); cf->dev = NULL; cf->freq = sc->act_speed_point->freq / 1000000; cf->volts = sc->act_speed_point->uvolt / 1000; /* Transition latency in us. */ cf->lat = sc->latency; /* Driver providing this setting. */ cf->dev = dev; return (0); } static int tegra124_cpufreq_type(device_t dev, int *type) { if (type == NULL) return (EINVAL); *type = CPUFREQ_TYPE_ABSOLUTE; return (0); } static int get_fdt_resources(struct tegra124_cpufreq_softc *sc, phandle_t node) { int rv; device_t parent_dev; parent_dev = device_get_parent(sc->dev); rv = regulator_get_by_ofw_property(parent_dev, 0, "vdd-cpu-supply", &sc->supply_vdd_cpu); if (rv != 0) { device_printf(sc->dev, "Cannot get 'vdd-cpu' regulator\n"); return (rv); } rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_g", &sc->clk_cpu_g); if (rv != 0) { device_printf(sc->dev, "Cannot get 'cpu_g' clock: %d\n", rv); return (ENXIO); } rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_lp", &sc->clk_cpu_lp); if (rv != 0) { device_printf(sc->dev, "Cannot get 'cpu_lp' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(parent_dev, 0, "pll_x", &sc->clk_pll_x); if (rv != 0) { device_printf(sc->dev, "Cannot get 'pll_x' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(parent_dev, 0, "pll_p", &sc->clk_pll_p); if (rv != 0) { device_printf(parent_dev, "Cannot get 'pll_p' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(parent_dev, 0, "dfll", &sc->clk_dfll); if (rv != 0) { /* XXX DPLL is not implemented yet */ /* device_printf(sc->dev, "Cannot get 'dfll' clock\n"); return (ENXIO); */ } return (0); } static void tegra124_cpufreq_identify(driver_t *driver, device_t parent) { phandle_t root; root = OF_finddevice("/"); if (!ofw_bus_node_is_compatible(root, "nvidia,tegra124")) return; if (device_get_unit(parent) != 0) return; if (device_find_child(parent, "tegra124_cpufreq", -1) != NULL) return; if (BUS_ADD_CHILD(parent, 0, "tegra124_cpufreq", -1) == NULL) device_printf(parent, "add child failed\n"); } static int tegra124_cpufreq_probe(device_t dev) { device_set_desc(dev, "CPU Frequency Control"); return (0); } static int tegra124_cpufreq_attach(device_t dev) { struct tegra124_cpufreq_softc *sc; uint64_t freq; int rv; sc = device_get_softc(dev); sc->dev = dev; sc->node = ofw_bus_get_node(device_get_parent(dev)); sc->process_id = tegra_sku_info.cpu_process_id; sc->speedo_id = tegra_sku_info.cpu_speedo_id; sc->speedo_value = tegra_sku_info.cpu_speedo_value; /* Tegra 124 */ /* XXX DPLL is not implemented yet */ if (1) sc->cpu_def = &tegra124_cpu_volt_pllx_def; else sc->cpu_def = &tegra124_cpu_volt_dpll_def; rv = get_fdt_resources(sc, sc->node); if (rv != 0) { return (rv); } build_speed_points(sc); rv = clk_get_freq(sc->clk_cpu_g, &freq); if (rv != 0) { device_printf(dev, "Can't get CPU clock frequency\n"); return (rv); } if (sc->speedo_id < nitems(cpu_max_freq)) sc->cpu_max_freq = cpu_max_freq[sc->speedo_id]; else sc->cpu_max_freq = cpu_max_freq[0]; sc->act_speed_point = get_speed_point(sc, freq); /* Set safe startup CPU frequency. */ rv = set_cpu_freq(sc, 1632000000); if (rv != 0) { device_printf(dev, "Can't set initial CPU clock frequency\n"); return (rv); } /* This device is controlled by cpufreq(4). */ cpufreq_register(dev); return (0); } static int tegra124_cpufreq_detach(device_t dev) { struct tegra124_cpufreq_softc *sc; sc = device_get_softc(dev); cpufreq_unregister(dev); if (sc->supply_vdd_cpu != NULL) regulator_release(sc->supply_vdd_cpu); if (sc->clk_cpu_g != NULL) clk_release(sc->clk_cpu_g); if (sc->clk_cpu_lp != NULL) clk_release(sc->clk_cpu_lp); if (sc->clk_pll_x != NULL) clk_release(sc->clk_pll_x); if (sc->clk_pll_p != NULL) clk_release(sc->clk_pll_p); if (sc->clk_dfll != NULL) clk_release(sc->clk_dfll); return (0); } static device_method_t tegra124_cpufreq_methods[] = { /* Device interface */ DEVMETHOD(device_identify, tegra124_cpufreq_identify), DEVMETHOD(device_probe, tegra124_cpufreq_probe), DEVMETHOD(device_attach, tegra124_cpufreq_attach), DEVMETHOD(device_detach, tegra124_cpufreq_detach), /* cpufreq interface */ DEVMETHOD(cpufreq_drv_set, tegra124_cpufreq_set), DEVMETHOD(cpufreq_drv_get, tegra124_cpufreq_get), DEVMETHOD(cpufreq_drv_settings, tegra124_cpufreq_settings), DEVMETHOD(cpufreq_drv_type, tegra124_cpufreq_type), DEVMETHOD_END }; static DEFINE_CLASS_0(tegra124_cpufreq, tegra124_cpufreq_driver, tegra124_cpufreq_methods, sizeof(struct tegra124_cpufreq_softc)); DRIVER_MODULE(tegra124_cpufreq, cpu, tegra124_cpufreq_driver, NULL, NULL); diff --git a/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c b/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c index 0b611abc39cb..43c7e345d12c 100644 --- a/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c +++ b/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c @@ -1,1202 +1,1202 @@ /*- * Copyright (c) 2016 Michal Meloun * All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #include #include "phydev_if.h" /* FUSE calibration data. */ #define FUSE_XUSB_CALIB 0x0F0 #define FUSE_XUSB_CALIB_HS_CURR_LEVEL_123(x) (((x) >> 15) & 0x3F); #define FUSE_XUSB_CALIB_HS_IREF_CAP(x) (((x) >> 13) & 0x03); #define FUSE_XUSB_CALIB_HS_SQUELCH_LEVEL(x) (((x) >> 11) & 0x03); #define FUSE_XUSB_CALIB_HS_TERM_RANGE_ADJ(x) (((x) >> 7) & 0x0F); #define FUSE_XUSB_CALIB_HS_CURR_LEVEL_0(x) (((x) >> 0) & 0x3F); /* Registers. */ #define XUSB_PADCTL_USB2_PAD_MUX 0x004 #define XUSB_PADCTL_USB2_PORT_CAP 0x008 #define USB2_PORT_CAP_ULPI_PORT_INTERNAL (1 << 25) #define USB2_PORT_CAP_ULPI_PORT_CAP (1 << 24) #define USB2_PORT_CAP_PORT_REVERSE_ID(p) (1 << (3 + (p) * 4)) #define USB2_PORT_CAP_PORT_INTERNAL(p) (1 << (2 + (p) * 4)) #define USB2_PORT_CAP_PORT_CAP(p, x) (((x) & 3) << ((p) * 4)) #define USB2_PORT_CAP_PORT_CAP_OTG 0x3 #define USB2_PORT_CAP_PORT_CAP_DEVICE 0x2 #define USB2_PORT_CAP_PORT_CAP_HOST 0x1 #define USB2_PORT_CAP_PORT_CAP_DISABLED 0x0 #define XUSB_PADCTL_SS_PORT_MAP 0x014 #define SS_PORT_MAP_PORT_INTERNAL(p) (1 << (3 + (p) * 4)) #define SS_PORT_MAP_PORT_MAP(p, x) (((x) & 7) << ((p) * 4)) #define XUSB_PADCTL_ELPG_PROGRAM 0x01C #define ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26) #define ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25) #define ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24) #define ELPG_PROGRAM_SSP_ELPG_VCORE_DOWN(x) (1 << (18 + (x) * 4)) #define ELPG_PROGRAM_SSP_ELPG_CLAMP_EN_EARLY(x) (1 << (17 + (x) * 4)) #define ELPG_PROGRAM_SSP_ELPG_CLAMP_EN(x) (1 << (16 + (x) * 4)) #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040 #define IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19) #define IOPHY_PLL_P0_CTL1_REFCLK_SEL(x) (((x) & 0xF) << 12) #define IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1) #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044 #define IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6) #define IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5) #define IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4) #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2(x) (0x058 + (x) * 4) #define IOPHY_USB3_PAD_CTL2_CDR_CNTL(x) (((x) & 0x00FF) << 4) #define IOPHY_USB3_PAD_CTL2_RX_EQ(x) (((x) & 0xFFFF) << 8) #define IOPHY_USB3_PAD_CTL2_RX_WANDER(x) (((x) & 0x000F) << 4) #define IOPHY_USB3_PAD_CTL2_RX_TERM_CNTL(x) (((x) & 0x0003) << 2) #define IOPHY_USB3_PAD_CTL2_TX_TERM_CNTL(x) (((x) & 0x0003) << 0) #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4(x) (0x068 + (x) * 4) #define XUSB_PADCTL_USB2_OTG_PAD_CTL0(x) (0x0A0 + (x) * 4) #define USB2_OTG_PAD_CTL0_LSBIAS_SEL (1 << 23) #define USB2_OTG_PAD_CTL0_DISCON_DETECT_METHOD (1 << 22) #define USB2_OTG_PAD_CTL0_PD_ZI (1 << 21) #define USB2_OTG_PAD_CTL0_PD2 (1 << 20) #define USB2_OTG_PAD_CTL0_PD (1 << 19) #define USB2_OTG_PAD_CTL0_TERM_EN (1 << 18) #define USB2_OTG_PAD_CTL0_LS_LS_FSLEW(x) (((x) & 0x03) << 16) #define USB2_OTG_PAD_CTL0_LS_RSLEW(x) (((x) & 0x03) << 14) #define USB2_OTG_PAD_CTL0_FS_SLEW(x) (((x) & 0x03) << 12) #define USB2_OTG_PAD_CTL0_HS_SLEW(x) (((x) & 0x3F) << 6) #define USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(x) (((x) & 0x3F) << 0) #define XUSB_PADCTL_USB2_OTG_PAD_CTL1(x) (0x0AC + (x) * 4) #define USB2_OTG_PAD_CTL1_RPU_RANGE_ADJ(x) (((x) & 0x3) << 11) #define USB2_OTG_PAD_CTL1_HS_IREF_CAP(x) (((x) & 0x3) << 9) #define USB2_OTG_PAD_CTL1_SPARE(x) (((x) & 0x3) << 7) #define USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ(x) (((x) & 0xF) << 3) #define USB2_OTG_PAD_CTL1_PD_DR (1 << 2) #define USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP (1 << 1) #define USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP (1 << 0) #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x0B8 #define USB2_BIAS_PAD_CTL0_ADJRPU(x) (((x) & 0x7) << 14) #define USB2_BIAS_PAD_CTL0_PD_TRK (1 << 13) #define USB2_BIAS_PAD_CTL0_PD (1 << 12) #define USB2_BIAS_PAD_CTL0_TERM_OFFSETL(x) (((x) & 0x3) << 9) #define USB2_BIAS_PAD_CTL0_VBUS_LEVEL(x) (((x) & 0x3) << 7) #define USB2_BIAS_PAD_CTL0_HS_CHIRP_LEVEL(x) (((x) & 0x3) << 5) #define USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL(x) (((x) & 0x7) << 2) #define USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL(x) (((x) & 0x3) << 0) #define XUSB_PADCTL_HSIC_PAD0_CTL0 0x0C8 #define HSIC_PAD0_CTL0_HSIC_OPT(x) (((x) & 0xF) << 16) #define HSIC_PAD0_CTL0_TX_SLEWN(x) (((x) & 0xF) << 12) #define HSIC_PAD0_CTL0_TX_SLEWP(x) (((x) & 0xF) << 8) #define HSIC_PAD0_CTL0_TX_RTUNEN(x) (((x) & 0xF) << 4) #define HSIC_PAD0_CTL0_TX_RTUNEP(x) (((x) & 0xF) << 0) #define XUSB_PADCTL_USB3_PAD_MUX 0x134 #define USB3_PAD_MUX_PCIE_IDDQ_DISABLE(x) (1 << (1 + (x))) #define USB3_PAD_MUX_SATA_IDDQ_DISABLE (1 << 6) #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138 #define IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27) #define IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24) #define IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3) #define IOPHY_PLL_S0_CTL1_PLL_RST_L (1 << 1) #define IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0) #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2 0x13C #define XUSB_PADCTL_IOPHY_PLL_S0_CTL3 0x140 #define XUSB_PADCTL_IOPHY_PLL_S0_CTL4 0x144 #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148 #define IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1) #define IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0) #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2 0x14C #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL3 0x150 #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL4 0x154 #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5 0x158 #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6 0x15C #define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v)) #define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r)) struct padctl_softc { device_t dev; struct resource *mem_res; hwreset_t rst; int phy_ena_cnt; /* Fuses calibration data */ uint32_t hs_curr_level_0; uint32_t hs_curr_level_123; uint32_t hs_iref_cap; uint32_t hs_term_range_adj; uint32_t hs_squelch_level; uint32_t hs_curr_level_offset; }; static struct ofw_compat_data compat_data[] = { {"nvidia,tegra124-xusb-padctl", 1}, {NULL, 0}, }; /* Ports. */ enum padctl_port_type { PADCTL_PORT_USB2, PADCTL_PORT_ULPI, PADCTL_PORT_HSIC, PADCTL_PORT_USB3, }; struct padctl_lane; struct padctl_port { enum padctl_port_type type; const char *name; const char *base_name; int idx; int (*init)(struct padctl_softc *sc, struct padctl_port *port); /* Runtime data. */ bool enabled; regulator_t supply_vbus; /* USB2, USB3 */ bool internal; /* ULPI, USB2, USB3 */ uint32_t companion; /* USB3 */ struct padctl_lane *lane; }; static int usb3_port_init(struct padctl_softc *sc, struct padctl_port *port); #define PORT(t, n, p, i) { \ .type = t, \ .name = n "-" #p, \ .base_name = n, \ .idx = p, \ .init = i, \ } static struct padctl_port ports_tbl[] = { PORT(PADCTL_PORT_USB2, "usb2", 0, NULL), PORT(PADCTL_PORT_USB2, "usb2", 1, NULL), PORT(PADCTL_PORT_USB2, "usb2", 2, NULL), PORT(PADCTL_PORT_ULPI, "ulpi", 0, NULL), PORT(PADCTL_PORT_HSIC, "hsic", 0, NULL), PORT(PADCTL_PORT_HSIC, "hsic", 1, NULL), PORT(PADCTL_PORT_USB3, "usb3", 0, usb3_port_init), PORT(PADCTL_PORT_USB3, "usb3", 1, usb3_port_init), }; /* Pads - a group of lannes. */ enum padctl_pad_type { PADCTL_PAD_USB2, PADCTL_PAD_ULPI, PADCTL_PAD_HSIC, PADCTL_PAD_PCIE, PADCTL_PAD_SATA, }; struct padctl_lane; struct padctl_pad { const char *name; enum padctl_pad_type type; int (*powerup)(struct padctl_softc *sc, struct padctl_lane *lane); int (*powerdown)(struct padctl_softc *sc, struct padctl_lane *lane); /* Runtime data. */ bool enabled; struct padctl_lane *lanes[8]; /* Safe maximum value. */ int nlanes; }; static int usb2_powerup(struct padctl_softc *sc, struct padctl_lane *lane); static int usb2_powerdown(struct padctl_softc *sc, struct padctl_lane *lane); static int pcie_powerup(struct padctl_softc *sc, struct padctl_lane *lane); static int pcie_powerdown(struct padctl_softc *sc, struct padctl_lane *lane); static int sata_powerup(struct padctl_softc *sc, struct padctl_lane *lane); static int sata_powerdown(struct padctl_softc *sc, struct padctl_lane *lane); #define PAD(n, t, u, d) { \ .name = n, \ .type = t, \ .powerup = u, \ .powerdown = d, \ } static struct padctl_pad pads_tbl[] = { PAD("usb2", PADCTL_PAD_USB2, usb2_powerup, usb2_powerdown), PAD("ulpi", PADCTL_PAD_ULPI, NULL, NULL), PAD("hsic", PADCTL_PAD_HSIC, NULL, NULL), PAD("pcie", PADCTL_PAD_PCIE, pcie_powerup, pcie_powerdown), PAD("sata", PADCTL_PAD_SATA, sata_powerup, sata_powerdown), }; /* Lanes. */ static char *otg_mux[] = {"snps", "xusb", "uart", "rsvd"}; static char *usb_mux[] = {"snps", "xusb"}; static char *pci_mux[] = {"pcie", "usb3-ss", "sata", "rsvd"}; struct padctl_lane { const char *name; int idx; bus_size_t reg; uint32_t shift; uint32_t mask; char **mux; int nmux; /* Runtime data. */ bool enabled; struct padctl_pad *pad; struct padctl_port *port; int mux_idx; }; #define LANE(n, p, r, s, m, mx) { \ .name = n "-" #p, \ .idx = p, \ .reg = r, \ .shift = s, \ .mask = m, \ .mux = mx, \ .nmux = nitems(mx), \ } static struct padctl_lane lanes_tbl[] = { LANE("usb2", 0, XUSB_PADCTL_USB2_PAD_MUX, 0, 0x3, otg_mux), LANE("usb2", 1, XUSB_PADCTL_USB2_PAD_MUX, 2, 0x3, otg_mux), LANE("usb2", 2, XUSB_PADCTL_USB2_PAD_MUX, 4, 0x3, otg_mux), LANE("ulpi", 0, XUSB_PADCTL_USB2_PAD_MUX, 12, 0x1, usb_mux), LANE("hsic", 0, XUSB_PADCTL_USB2_PAD_MUX, 14, 0x1, usb_mux), LANE("hsic", 1, XUSB_PADCTL_USB2_PAD_MUX, 15, 0x1, usb_mux), LANE("pcie", 0, XUSB_PADCTL_USB3_PAD_MUX, 16, 0x3, pci_mux), LANE("pcie", 1, XUSB_PADCTL_USB3_PAD_MUX, 18, 0x3, pci_mux), LANE("pcie", 2, XUSB_PADCTL_USB3_PAD_MUX, 20, 0x3, pci_mux), LANE("pcie", 3, XUSB_PADCTL_USB3_PAD_MUX, 22, 0x3, pci_mux), LANE("pcie", 4, XUSB_PADCTL_USB3_PAD_MUX, 24, 0x3, pci_mux), LANE("sata", 0, XUSB_PADCTL_USB3_PAD_MUX, 26, 0x3, pci_mux), }; /* Define all possible mappings for USB3 port lanes */ struct padctl_lane_map { int port_idx; enum padctl_pad_type pad_type; int lane_idx; }; #define LANE_MAP(pi, pt, li) { \ .port_idx = pi, \ .pad_type = pt, \ .lane_idx = li, \ } static struct padctl_lane_map lane_map_tbl[] = { LANE_MAP(0, PADCTL_PAD_PCIE, 0), /* port USB3-0 -> lane PCIE-0 */ LANE_MAP(1, PADCTL_PAD_PCIE, 1), /* port USB3-1 -> lane PCIE-1 */ /* -- or -- */ LANE_MAP(1, PADCTL_PAD_SATA, 0), /* port USB3-1 -> lane SATA-0 */ }; /* Phy class and methods. */ static int xusbpadctl_phy_enable(struct phynode *phy, bool enable); static phynode_method_t xusbpadctl_phynode_methods[] = { PHYNODEMETHOD(phynode_enable, xusbpadctl_phy_enable), PHYNODEMETHOD_END }; DEFINE_CLASS_1(xusbpadctl_phynode, xusbpadctl_phynode_class, xusbpadctl_phynode_methods, 0, phynode_class); static struct padctl_port *search_lane_port(struct padctl_softc *sc, struct padctl_lane *lane); /* ------------------------------------------------------------------------- * * PHY functions */ static int usb3_port_init(struct padctl_softc *sc, struct padctl_port *port) { uint32_t reg; reg = RD4(sc, XUSB_PADCTL_SS_PORT_MAP); if (port->internal) reg &= ~SS_PORT_MAP_PORT_INTERNAL(port->idx); else reg |= SS_PORT_MAP_PORT_INTERNAL(port->idx); reg &= ~SS_PORT_MAP_PORT_MAP(port->idx, ~0); reg |= SS_PORT_MAP_PORT_MAP(port->idx, port->companion); WR4(sc, XUSB_PADCTL_SS_PORT_MAP, reg); reg = RD4(sc, XUSB_PADCTL_IOPHY_USB3_PAD_CTL2(port->idx)); reg &= ~IOPHY_USB3_PAD_CTL2_CDR_CNTL(~0); reg &= ~IOPHY_USB3_PAD_CTL2_RX_EQ(~0); reg &= ~IOPHY_USB3_PAD_CTL2_RX_WANDER(~0); reg |= IOPHY_USB3_PAD_CTL2_CDR_CNTL(0x24); reg |= IOPHY_USB3_PAD_CTL2_RX_EQ(0xF070); reg |= IOPHY_USB3_PAD_CTL2_RX_WANDER(0xF); WR4(sc, XUSB_PADCTL_IOPHY_USB3_PAD_CTL2(port->idx), reg); WR4(sc, XUSB_PADCTL_IOPHY_USB3_PAD_CTL4(port->idx), 0x002008EE); reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); reg &= ~ELPG_PROGRAM_SSP_ELPG_VCORE_DOWN(port->idx); WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); DELAY(100); reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); reg &= ~ELPG_PROGRAM_SSP_ELPG_CLAMP_EN_EARLY(port->idx); WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); DELAY(100); reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); reg &= ~ELPG_PROGRAM_SSP_ELPG_CLAMP_EN(port->idx); WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); DELAY(100); return (0); } static int pcie_powerup(struct padctl_softc *sc, struct padctl_lane *lane) { uint32_t reg; int i; reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); reg &= ~IOPHY_PLL_P0_CTL1_REFCLK_SEL(~0); WR4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg); DELAY(100); reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL2); reg |= IOPHY_PLL_P0_CTL2_REFCLKBUF_EN; reg |= IOPHY_PLL_P0_CTL2_TXCLKREF_EN; reg |= IOPHY_PLL_P0_CTL2_TXCLKREF_SEL; WR4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL2, reg); DELAY(100); reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); reg |= IOPHY_PLL_P0_CTL1_PLL_RST; WR4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg); DELAY(100); for (i = 100; i > 0; i--) { reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); if (reg & IOPHY_PLL_P0_CTL1_PLL0_LOCKDET) break; DELAY(10); } if (i <= 0) { device_printf(sc->dev, "Failed to power up PCIe phy\n"); return (ETIMEDOUT); } reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); reg |= USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->idx); WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); return (0); } static int pcie_powerdown(struct padctl_softc *sc, struct padctl_lane *lane) { uint32_t reg; reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); reg &= ~USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->idx); WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); reg &= ~IOPHY_PLL_P0_CTL1_PLL_RST; WR4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg); DELAY(100); return (0); } static int sata_powerup(struct padctl_softc *sc, struct padctl_lane *lane) { uint32_t reg; int i; reg = RD4(sc, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); reg &= ~IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; reg &= ~IOPHY_MISC_PAD_S0_CTL1_IDDQ; WR4(sc, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1, reg); reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); reg &= ~IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; reg &= ~IOPHY_PLL_S0_CTL1_PLL_IDDQ; WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); reg |= IOPHY_PLL_S0_CTL1_PLL1_MODE; WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); reg |= IOPHY_PLL_S0_CTL1_PLL_RST_L; WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); for (i = 100; i >= 0; i--) { reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); if (reg & IOPHY_PLL_S0_CTL1_PLL1_LOCKDET) break; DELAY(100); } if (i <= 0) { device_printf(sc->dev, "Failed to power up SATA phy\n"); return (ETIMEDOUT); } reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); reg |= IOPHY_PLL_S0_CTL1_PLL_RST_L; WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); reg |= USB3_PAD_MUX_SATA_IDDQ_DISABLE; WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); return (0); } static int sata_powerdown(struct padctl_softc *sc, struct padctl_lane *lane) { uint32_t reg; reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); reg &= ~USB3_PAD_MUX_SATA_IDDQ_DISABLE; WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); reg &= ~IOPHY_PLL_S0_CTL1_PLL_RST_L; WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); DELAY(100); reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); reg &= ~IOPHY_PLL_S0_CTL1_PLL1_MODE; WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); DELAY(100); reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); reg |= IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; reg |= IOPHY_PLL_S0_CTL1_PLL_IDDQ; WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); DELAY(100); reg = RD4(sc, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); reg |= IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; reg |= IOPHY_MISC_PAD_S0_CTL1_IDDQ; WR4(sc, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1, reg); DELAY(100); return (0); } static int usb2_powerup(struct padctl_softc *sc, struct padctl_lane *lane) { uint32_t reg; struct padctl_port *port; int rv; port = search_lane_port(sc, lane); if (port == NULL) { device_printf(sc->dev, "Cannot find port for lane: %s\n", lane->name); } reg = RD4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); reg &= ~USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL(~0); reg &= ~USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL(~0); reg |= USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL(sc->hs_squelch_level); reg |= USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL(5); WR4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0, reg); reg = RD4(sc, XUSB_PADCTL_USB2_PORT_CAP); reg &= ~USB2_PORT_CAP_PORT_CAP(lane->idx, ~0); reg |= USB2_PORT_CAP_PORT_CAP(lane->idx, USB2_PORT_CAP_PORT_CAP_HOST); WR4(sc, XUSB_PADCTL_USB2_PORT_CAP, reg); reg = RD4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL0(lane->idx)); reg &= ~USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(~0); reg &= ~USB2_OTG_PAD_CTL0_HS_SLEW(~0); reg &= ~USB2_OTG_PAD_CTL0_LS_RSLEW(~0); reg &= ~USB2_OTG_PAD_CTL0_PD; reg &= ~USB2_OTG_PAD_CTL0_PD2; reg &= ~USB2_OTG_PAD_CTL0_PD_ZI; reg |= USB2_OTG_PAD_CTL0_HS_SLEW(14); if (lane->idx == 0) { reg |= USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(sc->hs_curr_level_0); reg |= USB2_OTG_PAD_CTL0_LS_RSLEW(3); } else { reg |= USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(sc->hs_curr_level_123); reg |= USB2_OTG_PAD_CTL0_LS_RSLEW(0); } WR4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL0(lane->idx), reg); reg = RD4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL1(lane->idx)); reg &= ~USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ(~0); reg &= ~USB2_OTG_PAD_CTL1_HS_IREF_CAP(~0); reg &= ~USB2_OTG_PAD_CTL1_PD_DR; reg &= ~USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP; reg &= ~USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP; reg |= USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ(sc->hs_term_range_adj); reg |= USB2_OTG_PAD_CTL1_HS_IREF_CAP(sc->hs_iref_cap); WR4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL1(lane->idx), reg); if (port != NULL && port->supply_vbus != NULL) { rv = regulator_enable(port->supply_vbus); if (rv != 0) { device_printf(sc->dev, "Cannot enable vbus regulator\n"); return (rv); } } reg = RD4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); reg &= ~USB2_BIAS_PAD_CTL0_PD; WR4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0, reg); return (0); } static int usb2_powerdown(struct padctl_softc *sc, struct padctl_lane *lane) { uint32_t reg; struct padctl_port *port; int rv; port = search_lane_port(sc, lane); if (port == NULL) { device_printf(sc->dev, "Cannot find port for lane: %s\n", lane->name); } reg = RD4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); reg |= USB2_BIAS_PAD_CTL0_PD; WR4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0, reg); if (port != NULL && port->supply_vbus != NULL) { rv = regulator_enable(port->supply_vbus); if (rv != 0) { device_printf(sc->dev, "Cannot disable vbus regulator\n"); return (rv); } } return (0); } static int phy_powerup(struct padctl_softc *sc) { uint32_t reg; reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); DELAY(100); reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); DELAY(100); reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); DELAY(100); return (0); } static int phy_powerdown(struct padctl_softc *sc) { uint32_t reg; reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); reg |= ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); DELAY(100); reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); reg |= ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); DELAY(100); reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); reg |= ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); DELAY(100); return (0); } static int xusbpadctl_phy_enable(struct phynode *phy, bool enable) { device_t dev; intptr_t id; struct padctl_softc *sc; struct padctl_lane *lane; struct padctl_pad *pad; int rv; dev = phynode_get_device(phy); id = phynode_get_id(phy); sc = device_get_softc(dev); if (id < 0 || id >= nitems(lanes_tbl)) { device_printf(dev, "Unknown phy: %d\n", id); return (ENXIO); } lane = lanes_tbl + id; if (!lane->enabled) { device_printf(dev, "Lane is not enabled/configured: %s\n", lane->name); return (ENXIO); } pad = lane->pad; if (enable) { if (sc->phy_ena_cnt == 0) { rv = phy_powerup(sc); if (rv != 0) return (rv); } sc->phy_ena_cnt++; } if (enable) rv = pad->powerup(sc, lane); else rv = pad->powerdown(sc, lane); if (rv != 0) return (rv); if (!enable) { if (sc->phy_ena_cnt == 1) { rv = phy_powerdown(sc); if (rv != 0) return (rv); } sc->phy_ena_cnt--; } return (0); } /* ------------------------------------------------------------------------- * * FDT processing */ static struct padctl_port * search_port(struct padctl_softc *sc, char *port_name) { int i; for (i = 0; i < nitems(ports_tbl); i++) { if (strcmp(port_name, ports_tbl[i].name) == 0) return (&ports_tbl[i]); } return (NULL); } static struct padctl_port * search_lane_port(struct padctl_softc *sc, struct padctl_lane *lane) { int i; for (i = 0; i < nitems(ports_tbl); i++) { if (!ports_tbl[i].enabled) continue; if (ports_tbl[i].lane == lane) return (ports_tbl + i); } return (NULL); } static struct padctl_lane * search_lane(struct padctl_softc *sc, char *lane_name) { int i; for (i = 0; i < nitems(lanes_tbl); i++) { if (strcmp(lane_name, lanes_tbl[i].name) == 0) return (lanes_tbl + i); } return (NULL); } static struct padctl_lane * search_pad_lane(struct padctl_softc *sc, enum padctl_pad_type type, int idx) { int i; for (i = 0; i < nitems(lanes_tbl); i++) { if (!lanes_tbl[i].enabled) continue; if (type == lanes_tbl[i].pad->type && idx == lanes_tbl[i].idx) return (lanes_tbl + i); } return (NULL); } static struct padctl_lane * search_usb3_pad_lane(struct padctl_softc *sc, int idx) { int i; struct padctl_lane *lane, *tmp; lane = NULL; for (i = 0; i < nitems(lane_map_tbl); i++) { if (idx != lane_map_tbl[i].port_idx) continue; tmp = search_pad_lane(sc, lane_map_tbl[i].pad_type, lane_map_tbl[i].lane_idx); if (tmp == NULL) continue; if (strcmp(tmp->mux[tmp->mux_idx], "usb3-ss") != 0) continue; if (lane != NULL) { device_printf(sc->dev, "Duplicated mappings found for" " lanes: %s and %s\n", lane->name, tmp->name); return (NULL); } lane = tmp; } return (lane); } static struct padctl_pad * search_pad(struct padctl_softc *sc, char *pad_name) { int i; for (i = 0; i < nitems(pads_tbl); i++) { if (strcmp(pad_name, pads_tbl[i].name) == 0) return (pads_tbl + i); } return (NULL); } static int search_mux(struct padctl_softc *sc, struct padctl_lane *lane, char *fnc_name) { int i; for (i = 0; i < lane->nmux; i++) { if (strcmp(fnc_name, lane->mux[i]) == 0) return (i); } return (-1); } static int config_lane(struct padctl_softc *sc, struct padctl_lane *lane) { uint32_t reg; reg = RD4(sc, lane->reg); reg &= ~(lane->mask << lane->shift); reg |= (lane->mux_idx & lane->mask) << lane->shift; WR4(sc, lane->reg, reg); return (0); } static int process_lane(struct padctl_softc *sc, phandle_t node, struct padctl_pad *pad) { struct padctl_lane *lane; struct phynode *phynode; struct phynode_init_def phy_init; char *name; char *function; int rv; name = NULL; function = NULL; rv = OF_getprop_alloc(node, "name", (void **)&name); if (rv <= 0) { device_printf(sc->dev, "Cannot read lane name.\n"); return (ENXIO); } lane = search_lane(sc, name); if (lane == NULL) { device_printf(sc->dev, "Unknown lane: %s\n", name); rv = ENXIO; goto end; } /* Read function (mux) settings. */ rv = OF_getprop_alloc(node, "nvidia,function", (void **)&function); if (rv <= 0) { device_printf(sc->dev, "Cannot read lane function.\n"); rv = ENXIO; goto end; } lane->mux_idx = search_mux(sc, lane, function); if (lane->mux_idx == ~0) { device_printf(sc->dev, "Unknown function %s for lane %s\n", function, name); rv = ENXIO; goto end; } rv = config_lane(sc, lane); if (rv != 0) { device_printf(sc->dev, "Cannot configure lane: %s: %d\n", name, rv); rv = ENXIO; goto end; } lane->pad = pad; lane->enabled = true; pad->lanes[pad->nlanes++] = lane; /* Create and register phy. */ bzero(&phy_init, sizeof(phy_init)); phy_init.id = lane - lanes_tbl; phy_init.ofw_node = node; phynode = phynode_create(sc->dev, &xusbpadctl_phynode_class, &phy_init); if (phynode == NULL) { device_printf(sc->dev, "Cannot create phy\n"); rv = ENXIO; goto end; } if (phynode_register(phynode) == NULL) { device_printf(sc->dev, "Cannot create phy\n"); return (ENXIO); } rv = 0; end: if (name != NULL) OF_prop_free(name); if (function != NULL) OF_prop_free(function); return (rv); } static int process_pad(struct padctl_softc *sc, phandle_t node) { struct padctl_pad *pad; char *name; int rv; name = NULL; rv = OF_getprop_alloc(node, "name", (void **)&name); if (rv <= 0) { device_printf(sc->dev, "Cannot read pad name.\n"); return (ENXIO); } pad = search_pad(sc, name); if (pad == NULL) { device_printf(sc->dev, "Unknown pad: %s\n", name); rv = ENXIO; goto end; } /* Read and process associated lanes. */ node = ofw_bus_find_child(node, "lanes"); if (node <= 0) { device_printf(sc->dev, "Cannot find regulators subnode\n"); rv = ENXIO; goto end; } for (node = OF_child(node); node != 0; node = OF_peer(node)) { if (!ofw_bus_node_status_okay(node)) continue; rv = process_lane(sc, node, pad); if (rv != 0) goto end; } pad->enabled = true; rv = 0; end: if (name != NULL) OF_prop_free(name); return (rv); } static int process_port(struct padctl_softc *sc, phandle_t node) { struct padctl_port *port; char *name; int rv; name = NULL; rv = OF_getprop_alloc(node, "name", (void **)&name); if (rv <= 0) { device_printf(sc->dev, "Cannot read port name.\n"); return (ENXIO); } port = search_port(sc, name); if (port == NULL) { device_printf(sc->dev, "Unknown port: %s\n", name); rv = ENXIO; goto end; } if (port->type == PADCTL_PORT_USB3) { rv = OF_getencprop(node, "nvidia,usb2-companion", &(port->companion), sizeof(port->companion)); if (rv <= 0) { device_printf(sc->dev, "Missing 'nvidia,usb2-companion' property " "for port: %s\n", name); rv = ENXIO; goto end; } } if (OF_hasprop(node, "vbus-supply")) { rv = regulator_get_by_ofw_property(sc->dev, 0, "vbus-supply", &port->supply_vbus); if (rv <= 0) { device_printf(sc->dev, "Cannot get 'vbus-supply' regulator " "for port: %s\n", name); rv = ENXIO; goto end; } } if (OF_hasprop(node, "nvidia,internal")) port->internal = true; /* Find assigned lane */ if (port->lane == NULL) { switch(port->type) { /* Routing is fixed for USB2, ULPI AND HSIC. */ case PADCTL_PORT_USB2: port->lane = search_pad_lane(sc, PADCTL_PAD_USB2, port->idx); break; case PADCTL_PORT_ULPI: port->lane = search_pad_lane(sc, PADCTL_PAD_ULPI, port->idx); break; case PADCTL_PORT_HSIC: port->lane = search_pad_lane(sc, PADCTL_PAD_HSIC, port->idx); break; case PADCTL_PORT_USB3: port->lane = search_usb3_pad_lane(sc, port->idx); break; } } if (port->lane == NULL) { device_printf(sc->dev, "Cannot find lane for port: %s\n", name); rv = ENXIO; goto end; } port->enabled = true; rv = 0; end: if (name != NULL) OF_prop_free(name); return (rv); } static int parse_fdt(struct padctl_softc *sc, phandle_t base_node) { phandle_t node; int rv; rv = 0; node = ofw_bus_find_child(base_node, "pads"); if (node <= 0) { device_printf(sc->dev, "Cannot find pads subnode.\n"); return (ENXIO); } for (node = OF_child(node); node != 0; node = OF_peer(node)) { if (!ofw_bus_node_status_okay(node)) continue; rv = process_pad(sc, node); if (rv != 0) return (rv); } node = ofw_bus_find_child(base_node, "ports"); if (node <= 0) { device_printf(sc->dev, "Cannot find ports subnode.\n"); return (ENXIO); } for (node = OF_child(node); node != 0; node = OF_peer(node)) { if (!ofw_bus_node_status_okay(node)) continue; rv = process_port(sc, node); if (rv != 0) return (rv); } return (0); } static void load_calibration(struct padctl_softc *sc) { uint32_t reg; /* All XUSB pad calibrations are packed into single dword.*/ reg = tegra_fuse_read_4(FUSE_XUSB_CALIB); sc->hs_curr_level_0 = FUSE_XUSB_CALIB_HS_CURR_LEVEL_0(reg); sc->hs_curr_level_123 = FUSE_XUSB_CALIB_HS_CURR_LEVEL_123(reg); sc->hs_iref_cap = FUSE_XUSB_CALIB_HS_IREF_CAP(reg); sc->hs_squelch_level = FUSE_XUSB_CALIB_HS_SQUELCH_LEVEL(reg); sc->hs_term_range_adj = FUSE_XUSB_CALIB_HS_TERM_RANGE_ADJ(reg); } /* ------------------------------------------------------------------------- * * BUS functions */ static int xusbpadctl_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "Tegra XUSB phy"); return (BUS_PROBE_DEFAULT); } static int xusbpadctl_detach(device_t dev) { /* This device is always present. */ return (EBUSY); } static int xusbpadctl_attach(device_t dev) { struct padctl_softc * sc; int i, rid, rv; struct padctl_port *port; phandle_t node; sc = device_get_softc(dev); sc->dev = dev; node = ofw_bus_get_node(dev); rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) { device_printf(dev, "Cannot allocate memory resources\n"); return (ENXIO); } rv = hwreset_get_by_ofw_name(dev, 0, "padctl", &sc->rst); if (rv != 0) { device_printf(dev, "Cannot get 'padctl' reset: %d\n", rv); return (rv); } rv = hwreset_deassert(sc->rst); if (rv != 0) { device_printf(dev, "Cannot unreset 'padctl' reset: %d\n", rv); return (rv); } load_calibration(sc); rv = parse_fdt(sc, node); if (rv != 0) { device_printf(dev, "Cannot parse fdt configuration: %d\n", rv); return (rv); } for (i = 0; i < nitems(ports_tbl); i++) { port = ports_tbl + i; if (!port->enabled) continue; if (port->init == NULL) continue; rv = port->init(sc, port); if (rv != 0) { device_printf(dev, "Cannot init port '%s'\n", port->name); return (rv); } } return (0); } static device_method_t tegra_xusbpadctl_methods[] = { /* Device interface */ DEVMETHOD(device_probe, xusbpadctl_probe), DEVMETHOD(device_attach, xusbpadctl_attach), DEVMETHOD(device_detach, xusbpadctl_detach), DEVMETHOD_END }; static DEFINE_CLASS_0(xusbpadctl, tegra_xusbpadctl_driver, tegra_xusbpadctl_methods, sizeof(struct padctl_softc)); EARLY_DRIVER_MODULE(tegra_xusbpadctl, simplebus, tegra_xusbpadctl_driver, NULL, NULL, 73); diff --git a/sys/arm/nvidia/tegra_ahci.c b/sys/arm/nvidia/tegra_ahci.c index de60f02e97ea..bf60971e2b7c 100644 --- a/sys/arm/nvidia/tegra_ahci.c +++ b/sys/arm/nvidia/tegra_ahci.c @@ -1,781 +1,781 @@ /*- * Copyright (c) 2016 Michal Meloun * All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ #include /* * AHCI driver for Tegra SoCs. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #define SATA_CONFIGURATION 0x180 #define SATA_CONFIGURATION_CLK_OVERRIDE (1U << 31) #define SATA_CONFIGURATION_EN_FPCI (1 << 0) #define SATA_FPCI_BAR5 0x94 #define SATA_FPCI_BAR_START(x) (((x) & 0xFFFFFFF) << 4) #define SATA_FPCI_BAR_ACCESS_TYPE (1 << 0) #define SATA_INTR_MASK 0x188 #define SATA_INTR_MASK_IP_INT_MASK (1 << 16) #define SCFG_OFFSET 0x1000 #define T_SATA0_CFG_1 0x04 #define T_SATA0_CFG_1_IO_SPACE (1 << 0) #define T_SATA0_CFG_1_MEMORY_SPACE (1 << 1) #define T_SATA0_CFG_1_BUS_MASTER (1 << 2) #define T_SATA0_CFG_1_SERR (1 << 8) #define T_SATA0_CFG_9 0x24 #define T_SATA0_CFG_9_BASE_ADDRESS_SHIFT 13 #define T_SATA0_CFG_35 0x94 #define T_SATA0_CFG_35_IDP_INDEX_MASK (0x7ff << 2) #define T_SATA0_CFG_35_IDP_INDEX (0x2a << 2) #define T_SATA0_AHCI_IDP1 0x98 #define T_SATA0_AHCI_IDP1_DATA 0x400040 #define T_SATA0_CFG_PHY_1 0x12c #define T_SATA0_CFG_PHY_1_PADS_IDDQ_EN (1 << 23) #define T_SATA0_CFG_PHY_1_PAD_PLL_IDDQ_EN (1 << 22) #define T_SATA0_NVOOB 0x114 #define T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH_MASK (0x3 << 26) #define T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH (0x3 << 26) #define T_SATA0_NVOOB_SQUELCH_FILTER_MODE_MASK (0x3 << 24) #define T_SATA0_NVOOB_SQUELCH_FILTER_MODE (0x1 << 24) #define T_SATA0_NVOOB_COMMA_CNT_MASK (0xff << 16) #define T_SATA0_NVOOB_COMMA_CNT (0x07 << 16) #define T_SATA0_CFG_PHY 0x120 #define T_SATA0_CFG_PHY_MASK_SQUELCH (1 << 24) #define T_SATA0_CFG_PHY_USE_7BIT_ALIGN_DET_FOR_SPD (1 << 11) #define T_SATA0_CFG2NVOOB_2 0x134 #define T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW_MASK (0x1ff << 18) #define T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW (0xc << 18) #define T_SATA0_AHCI_HBA_CAP_BKDR 0x300 #define T_SATA0_AHCI_HBA_CAP_BKDR_SNCQ (1 << 30) #define T_SATA0_AHCI_HBA_CAP_BKDR_SUPP_PM (1 << 17) #define T_SATA0_AHCI_HBA_CAP_BKDR_SALP (1 << 26) #define T_SATA0_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP (1 << 14) #define T_SATA0_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP (1 << 13) #define T_SATA0_BKDOOR_CC 0x4a4 #define T_SATA0_BKDOOR_CC_CLASS_CODE_MASK (0xffff << 16) #define T_SATA0_BKDOOR_CC_CLASS_CODE (0x0106 << 16) #define T_SATA0_BKDOOR_CC_PROG_IF_MASK (0xff << 8) #define T_SATA0_BKDOOR_CC_PROG_IF (0x01 << 8) #define T_SATA0_CFG_SATA 0x54c #define T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN (1 << 12) #define T_SATA0_CFG_MISC 0x550 #define T_SATA0_INDEX 0x680 #define T_SATA0_CHX_PHY_CTRL1_GEN1 0x690 #define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK 0xff #define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT 8 #define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK 0xff #define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT 0 #define T_SATA0_CHX_PHY_CTRL1_GEN2 0x694 #define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK 0xff #define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_SHIFT 12 #define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK 0xff #define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_SHIFT 0 #define T_SATA0_CHX_PHY_CTRL2 0x69c #define T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1 0x23 #define T_SATA0_CHX_PHY_CTRL11 0x6d0 #define T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ (0x2800 << 16) #define T_SATA0_CHX_PHY_CTRL17 0x6e8 #define T_SATA0_CHX_PHY_CTRL18 0x6ec #define T_SATA0_CHX_PHY_CTRL20 0x6f4 #define T_SATA0_CHX_PHY_CTRL21 0x6f8 #define FUSE_SATA_CALIB 0x124 #define FUSE_SATA_CALIB_MASK 0x3 #define SATA_AUX_MISC_CNTL 0x1108 #define SATA_AUX_PAD_PLL_CTRL_0 0x1120 #define SATA_AUX_PAD_PLL_CTRL_1 0x1124 #define SATA_AUX_PAD_PLL_CTRL_2 0x1128 #define SATA_AUX_PAD_PLL_CTRL_3 0x112c #define T_AHCI_HBA_CCC_PORTS 0x0018 #define T_AHCI_HBA_CAP_BKDR 0x00A0 #define T_AHCI_HBA_CAP_BKDR_S64A (1 << 31) #define T_AHCI_HBA_CAP_BKDR_SNCQ (1 << 30) #define T_AHCI_HBA_CAP_BKDR_SSNTF (1 << 29) #define T_AHCI_HBA_CAP_BKDR_SMPS (1 << 28) #define T_AHCI_HBA_CAP_BKDR_SUPP_STG_SPUP (1 << 27) #define T_AHCI_HBA_CAP_BKDR_SALP (1 << 26) #define T_AHCI_HBA_CAP_BKDR_SAL (1 << 25) #define T_AHCI_HBA_CAP_BKDR_SUPP_CLO (1 << 24) #define T_AHCI_HBA_CAP_BKDR_INTF_SPD_SUPP(x) (((x) & 0xF) << 20) #define T_AHCI_HBA_CAP_BKDR_SUPP_NONZERO_OFFSET (1 << 19) #define T_AHCI_HBA_CAP_BKDR_SUPP_AHCI_ONLY (1 << 18) #define T_AHCI_HBA_CAP_BKDR_SUPP_PM (1 << 17) #define T_AHCI_HBA_CAP_BKDR_FIS_SWITCHING (1 << 16) #define T_AHCI_HBA_CAP_BKDR_PIO_MULT_DRQ_BLK (1 << 15) #define T_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP (1 << 14) #define T_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP (1 << 13) #define T_AHCI_HBA_CAP_BKDR_NUM_CMD_SLOTS(x) (((x) & 0x1F) << 8) #define T_AHCI_HBA_CAP_BKDR_CMD_CMPL_COALESING (1 << 7) #define T_AHCI_HBA_CAP_BKDR_ENCL_MGMT_SUPP (1 << 6) #define T_AHCI_HBA_CAP_BKDR_EXT_SATA (1 << 5) #define T_AHCI_HBA_CAP_BKDR_NUM_PORTS(x) (((x) & 0xF) << 0) #define T_AHCI_PORT_BKDR 0x0170 #define T_AHCI_PORT_BKDR_PXDEVSLP_DETO_OVERRIDE_VAL(x) (((x) & 0xFF) << 24) #define T_AHCI_PORT_BKDR_PXDEVSLP_MDAT_OVERRIDE_VAL(x) (((x) & 0x1F) << 16) #define T_AHCI_PORT_BKDR_PXDEVSLP_DETO_OVERRIDE (1 << 15) #define T_AHCI_PORT_BKDR_PXDEVSLP_MDAT_OVERRIDE (1 << 14) #define T_AHCI_PORT_BKDR_PXDEVSLP_DM(x) (((x) & 0xF) << 10) #define T_AHCI_PORT_BKDR_PORT_UNCONNECTED (1 << 9) #define T_AHCI_PORT_BKDR_CLK_CLAMP_CTRL_CLAMP_THIS_CH (1 << 8) #define T_AHCI_PORT_BKDR_CLK_CLAMP_CTRL_TXRXCLK_UNCLAMP (1 << 7) #define T_AHCI_PORT_BKDR_CLK_CLAMP_CTRL_TXRXCLK_CLAMP (1 << 6) #define T_AHCI_PORT_BKDR_CLK_CLAMP_CTRL_DEVCLK_UNCLAMP (1 << 5) #define T_AHCI_PORT_BKDR_CLK_CLAMP_CTRL_DEVCLK_CLAMP (1 << 4) #define T_AHCI_PORT_BKDR_HOTPLUG_CAP (1 << 3) #define T_AHCI_PORT_BKDR_MECH_SWITCH (1 << 2) #define T_AHCI_PORT_BKDR_COLD_PRSN_DET (1 << 1) #define T_AHCI_PORT_BKDR_EXT_SATA_SUPP (1 << 0) /* AUX registers */ #define SATA_AUX_MISC_CNTL_1 0x008 #define SATA_AUX_MISC_CNTL_1_DEVSLP_OVERRIDE (1 << 17) #define SATA_AUX_MISC_CNTL_1_SDS_SUPPORT (1 << 13) #define SATA_AUX_MISC_CNTL_1_DESO_SUPPORT (1 << 15) #define AHCI_WR4(_sc, _r, _v) bus_write_4((_sc)->ctlr.r_mem, (_r), (_v)) #define AHCI_RD4(_sc, _r) bus_read_4((_sc)->ctlr.r_mem, (_r)) #define SATA_WR4(_sc, _r, _v) bus_write_4((_sc)->sata_mem, (_r), (_v)) #define SATA_RD4(_sc, _r) bus_read_4((_sc)->sata_mem, (_r)) struct sata_pad_calibration { uint32_t gen1_tx_amp; uint32_t gen1_tx_peak; uint32_t gen2_tx_amp; uint32_t gen2_tx_peak; }; static const struct sata_pad_calibration tegra124_pad_calibration[] = { {0x18, 0x04, 0x18, 0x0a}, {0x0e, 0x04, 0x14, 0x0a}, {0x0e, 0x07, 0x1a, 0x0e}, {0x14, 0x0e, 0x1a, 0x0e}, }; struct ahci_soc; struct tegra_ahci_sc { struct ahci_controller ctlr; /* Must be first */ device_t dev; struct ahci_soc *soc; struct resource *sata_mem; struct resource *aux_mem; clk_t clk_sata; clk_t clk_sata_oob; clk_t clk_pll_e; clk_t clk_cml; hwreset_t hwreset_sata; hwreset_t hwreset_sata_oob; hwreset_t hwreset_sata_cold; regulator_t regulators[16]; /* Safe maximum */ phy_t phy; }; struct ahci_soc { char **regulator_names; int (*init)(struct tegra_ahci_sc *sc); }; /* Tegra 124 config. */ static char *tegra124_reg_names[] = { "hvdd-supply", "vddio-supply", "avdd-supply", "target-5v-supply", "target-12v-supply", NULL }; static int tegra124_ahci_init(struct tegra_ahci_sc *sc); static struct ahci_soc tegra124_soc = { .regulator_names = tegra124_reg_names, .init = tegra124_ahci_init, }; /* Tegra 210 config. */ static char *tegra210_reg_names[] = { NULL }; static struct ahci_soc tegra210_soc = { .regulator_names = tegra210_reg_names, }; static struct ofw_compat_data compat_data[] = { {"nvidia,tegra124-ahci", (uintptr_t)&tegra124_soc}, {"nvidia,tegra210-ahci", (uintptr_t)&tegra210_soc}, {NULL, 0} }; static int get_fdt_resources(struct tegra_ahci_sc *sc, phandle_t node) { int i, rv; /* Regulators. */ for (i = 0; sc->soc->regulator_names[i] != NULL; i++) { if (i >= nitems(sc->regulators)) { device_printf(sc->dev, "Too many regulators present in DT.\n"); return (EOVERFLOW); } rv = regulator_get_by_ofw_property(sc->dev, 0, sc->soc->regulator_names[i], sc->regulators + i); if (rv != 0) { device_printf(sc->dev, "Cannot get '%s' regulator\n", sc->soc->regulator_names[i]); return (ENXIO); } } /* Resets. */ rv = hwreset_get_by_ofw_name(sc->dev, 0, "sata", &sc->hwreset_sata ); if (rv != 0) { device_printf(sc->dev, "Cannot get 'sata' reset\n"); return (ENXIO); } rv = hwreset_get_by_ofw_name(sc->dev, 0, "sata-oob", &sc->hwreset_sata_oob); if (rv != 0) { device_printf(sc->dev, "Cannot get 'sata oob' reset\n"); return (ENXIO); } rv = hwreset_get_by_ofw_name(sc->dev, 0, "sata-cold", &sc->hwreset_sata_cold); if (rv != 0) { device_printf(sc->dev, "Cannot get 'sata cold' reset\n"); return (ENXIO); } /* Phy */ rv = phy_get_by_ofw_name(sc->dev, 0, "sata-0", &sc->phy); if (rv != 0) { rv = phy_get_by_ofw_idx(sc->dev, 0, 0, &sc->phy); if (rv != 0) { device_printf(sc->dev, "Cannot get 'sata' phy\n"); return (ENXIO); } } /* Clocks. */ rv = clk_get_by_ofw_name(sc->dev, 0, "sata", &sc->clk_sata); if (rv != 0) { device_printf(sc->dev, "Cannot get 'sata' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, 0, "sata-oob", &sc->clk_sata_oob); if (rv != 0) { device_printf(sc->dev, "Cannot get 'sata oob' clock\n"); return (ENXIO); } /* These are optional */ rv = clk_get_by_ofw_name(sc->dev, 0, "cml1", &sc->clk_cml); if (rv != 0) sc->clk_cml = NULL; rv = clk_get_by_ofw_name(sc->dev, 0, "pll_e", &sc->clk_pll_e); if (rv != 0) sc->clk_pll_e = NULL; return (0); } static int enable_fdt_resources(struct tegra_ahci_sc *sc) { int i, rv; /* Enable regulators. */ for (i = 0; i < nitems(sc->regulators); i++) { if (sc->regulators[i] == NULL) continue; rv = regulator_enable(sc->regulators[i]); if (rv != 0) { device_printf(sc->dev, "Cannot enable '%s' regulator\n", sc->soc->regulator_names[i]); return (rv); } } /* Stop clocks */ clk_stop(sc->clk_sata); clk_stop(sc->clk_sata_oob); tegra_powergate_power_off(TEGRA_POWERGATE_SAX); rv = hwreset_assert(sc->hwreset_sata); if (rv != 0) { device_printf(sc->dev, "Cannot assert 'sata' reset\n"); return (rv); } rv = hwreset_assert(sc->hwreset_sata_oob); if (rv != 0) { device_printf(sc->dev, "Cannot assert 'sata oob' reset\n"); return (rv); } rv = hwreset_assert(sc->hwreset_sata_cold); if (rv != 0) { device_printf(sc->dev, "Cannot assert 'sata cold' reset\n"); return (rv); } rv = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_SAX, sc->clk_sata, sc->hwreset_sata); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'SAX' powergate\n"); return (rv); } rv = clk_enable(sc->clk_sata_oob); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'sata oob' clock\n"); return (rv); } if (sc->clk_cml != NULL) { rv = clk_enable(sc->clk_cml); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'cml' clock\n"); return (rv); } } if (sc->clk_pll_e != NULL) { rv = clk_enable(sc->clk_pll_e); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'pll e' clock\n"); return (rv); } } rv = hwreset_deassert(sc->hwreset_sata_cold); if (rv != 0) { device_printf(sc->dev, "Cannot unreset 'sata cold' reset\n"); return (rv); } rv = hwreset_deassert(sc->hwreset_sata_oob); if (rv != 0) { device_printf(sc->dev, "Cannot unreset 'sata oob' reset\n"); return (rv); } rv = phy_enable(sc->phy); if (rv != 0) { device_printf(sc->dev, "Cannot enable SATA phy\n"); return (rv); } return (0); } static int tegra124_ahci_init(struct tegra_ahci_sc *sc) { uint32_t val; const struct sata_pad_calibration *calib; /* Pad calibration. */ val = tegra_fuse_read_4(FUSE_SATA_CALIB); calib = tegra124_pad_calibration + (val & FUSE_SATA_CALIB_MASK); SATA_WR4(sc, SCFG_OFFSET + T_SATA0_INDEX, 1); val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN1); val &= ~(T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT); val &= ~(T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT); val |= calib->gen1_tx_amp << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT; val |= calib->gen1_tx_peak << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT; SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN1, val); val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN2); val &= ~(T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK << T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_SHIFT); val &= ~(T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK << T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_SHIFT); val |= calib->gen2_tx_amp << T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_SHIFT; val |= calib->gen2_tx_peak << T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_SHIFT; SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN2, val); SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL11, T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ); SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL2, T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1); SATA_WR4(sc, SCFG_OFFSET + T_SATA0_INDEX, 0); return (0); } static int tegra_ahci_ctrl_init(struct tegra_ahci_sc *sc) { uint32_t val; int rv; /* Enable SATA MMIO. */ val = SATA_RD4(sc, SATA_FPCI_BAR5); val &= ~SATA_FPCI_BAR_START(~0); val |= SATA_FPCI_BAR_START(0x10000); val |= SATA_FPCI_BAR_ACCESS_TYPE; SATA_WR4(sc, SATA_FPCI_BAR5, val); /* Enable FPCI access */ val = SATA_RD4(sc, SATA_CONFIGURATION); val |= SATA_CONFIGURATION_EN_FPCI; SATA_WR4(sc, SATA_CONFIGURATION, val); /* Recommended electrical settings for phy */ SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL17, 0x55010000); SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL18, 0x55010000); SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL20, 0x1); SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL21, 0x1); /* SQUELCH and Gen3 */ val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CFG_PHY); val |= T_SATA0_CFG_PHY_MASK_SQUELCH; val &= ~T_SATA0_CFG_PHY_USE_7BIT_ALIGN_DET_FOR_SPD; SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_PHY, val); val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_NVOOB); val &= ~T_SATA0_NVOOB_COMMA_CNT_MASK; val &= ~T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH_MASK; val &= ~T_SATA0_NVOOB_SQUELCH_FILTER_MODE_MASK; val |= T_SATA0_NVOOB_COMMA_CNT; val |= T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH; val |= T_SATA0_NVOOB_SQUELCH_FILTER_MODE; SATA_WR4(sc, SCFG_OFFSET + T_SATA0_NVOOB, val); /* Setup COMWAKE_IDLE_CNT */ val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CFG2NVOOB_2); val &= ~T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW_MASK; val |= T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW; SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG2NVOOB_2, val); if (sc->soc->init != NULL) { rv = sc->soc->init(sc); if (rv != 0) { device_printf(sc->dev, "SOC specific intialization failed: %d\n", rv); return (rv); } } /* Enable backdoor programming. */ val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CFG_SATA); val |= T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN; SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_SATA, val); /* Set device class and interface */ val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_BKDOOR_CC); val &= ~T_SATA0_BKDOOR_CC_CLASS_CODE_MASK; val &= ~T_SATA0_BKDOOR_CC_PROG_IF_MASK; val |= T_SATA0_BKDOOR_CC_CLASS_CODE; val |= T_SATA0_BKDOOR_CC_PROG_IF; SATA_WR4(sc, SCFG_OFFSET + T_SATA0_BKDOOR_CC, val); /* Enable LPM capabilities */ val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_AHCI_HBA_CAP_BKDR); val |= T_SATA0_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP; val |= T_SATA0_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP; val |= T_SATA0_AHCI_HBA_CAP_BKDR_SALP; val |= T_SATA0_AHCI_HBA_CAP_BKDR_SUPP_PM; SATA_WR4(sc, SCFG_OFFSET + T_SATA0_AHCI_HBA_CAP_BKDR, val); /* Disable backdoor programming. */ val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CFG_SATA); val &= ~T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN; SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_SATA, val); /* SATA Second Level Clock Gating */ val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CFG_35); val &= ~T_SATA0_CFG_35_IDP_INDEX_MASK; val |= T_SATA0_CFG_35_IDP_INDEX; SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_35, val); SATA_WR4(sc, SCFG_OFFSET + T_SATA0_AHCI_IDP1, 0x400040); val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CFG_PHY_1); val |= T_SATA0_CFG_PHY_1_PADS_IDDQ_EN; val |= T_SATA0_CFG_PHY_1_PAD_PLL_IDDQ_EN; SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_PHY_1, val); /* * Indicate Sata only has the capability to enter DevSleep * from slumber link. */ if (sc->aux_mem != NULL) { val = bus_read_4(sc->aux_mem, SATA_AUX_MISC_CNTL_1); val |= SATA_AUX_MISC_CNTL_1_DESO_SUPPORT; bus_write_4(sc->aux_mem, SATA_AUX_MISC_CNTL_1, val); } /* Enable IPFS Clock Gating */ val = SATA_RD4(sc, SCFG_OFFSET + SATA_CONFIGURATION); val &= ~SATA_CONFIGURATION_CLK_OVERRIDE; SATA_WR4(sc, SCFG_OFFSET + SATA_CONFIGURATION, val); /* Enable IO & memory access, bus master mode */ val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CFG_1); val |= T_SATA0_CFG_1_IO_SPACE; val |= T_SATA0_CFG_1_MEMORY_SPACE; val |= T_SATA0_CFG_1_BUS_MASTER; val |= T_SATA0_CFG_1_SERR; SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_1, val); /* AHCI bar */ SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_9, 0x08000 << T_SATA0_CFG_9_BASE_ADDRESS_SHIFT); /* Unmask interrupts. */ val = SATA_RD4(sc, SATA_INTR_MASK); val |= SATA_INTR_MASK_IP_INT_MASK; SATA_WR4(sc, SATA_INTR_MASK, val); return (0); } static int tegra_ahci_ctlr_reset(device_t dev) { struct tegra_ahci_sc *sc; int rv; uint32_t reg; sc = device_get_softc(dev); rv = ahci_ctlr_reset(dev); if (rv != 0) return (0); AHCI_WR4(sc, T_AHCI_HBA_CCC_PORTS, 1); /* Overwrite AHCI capabilites. */ reg = AHCI_RD4(sc, T_AHCI_HBA_CAP_BKDR); reg &= ~T_AHCI_HBA_CAP_BKDR_NUM_PORTS(~0); reg |= T_AHCI_HBA_CAP_BKDR_NUM_PORTS(0); reg |= T_AHCI_HBA_CAP_BKDR_EXT_SATA; reg |= T_AHCI_HBA_CAP_BKDR_CMD_CMPL_COALESING; reg |= T_AHCI_HBA_CAP_BKDR_FIS_SWITCHING; reg |= T_AHCI_HBA_CAP_BKDR_SUPP_PM; reg |= T_AHCI_HBA_CAP_BKDR_SUPP_CLO; reg |= T_AHCI_HBA_CAP_BKDR_SUPP_STG_SPUP; AHCI_WR4(sc, T_AHCI_HBA_CAP_BKDR, reg); /* Overwrite AHCI portcapabilites. */ reg = AHCI_RD4(sc, T_AHCI_PORT_BKDR); reg |= T_AHCI_PORT_BKDR_COLD_PRSN_DET; reg |= T_AHCI_PORT_BKDR_HOTPLUG_CAP; reg |= T_AHCI_PORT_BKDR_EXT_SATA_SUPP; AHCI_WR4(sc, T_AHCI_PORT_BKDR, reg); return (0); } static int tegra_ahci_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc_copy(dev, "AHCI SATA controller"); return (BUS_PROBE_DEFAULT); } static int tegra_ahci_attach(device_t dev) { struct tegra_ahci_sc *sc; struct ahci_controller *ctlr; phandle_t node; int rv, rid; sc = device_get_softc(dev); sc->dev = dev; ctlr = &sc->ctlr; node = ofw_bus_get_node(dev); sc->soc = (struct ahci_soc *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; ctlr->r_rid = 0; ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &ctlr->r_rid, RF_ACTIVE); if (ctlr->r_mem == NULL) return (ENXIO); rid = 1; sc->sata_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->sata_mem == NULL) { rv = ENXIO; goto fail; } /* Aux is optionall */ rid = 2; sc->aux_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); rv = get_fdt_resources(sc, node); if (rv != 0) { device_printf(sc->dev, "Failed to allocate FDT resource(s)\n"); goto fail; } rv = enable_fdt_resources(sc); if (rv != 0) { device_printf(sc->dev, "Failed to enable FDT resource(s)\n"); goto fail; } rv = tegra_ahci_ctrl_init(sc); if (rv != 0) { device_printf(sc->dev, "Failed to initialize controller)\n"); goto fail; } /* Setup controller defaults. */ ctlr->msi = 0; ctlr->numirqs = 1; ctlr->ccc = 0; /* Reset controller. */ rv = tegra_ahci_ctlr_reset(dev); if (rv != 0) goto fail; rv = ahci_attach(dev); return (rv); fail: /* XXX FDT stuff */ if (sc->sata_mem != NULL) bus_release_resource(dev, SYS_RES_MEMORY, 1, sc->sata_mem); if (ctlr->r_mem != NULL) bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem); return (rv); } static int tegra_ahci_detach(device_t dev) { ahci_detach(dev); return (0); } static int tegra_ahci_suspend(device_t dev) { struct tegra_ahci_sc *sc = device_get_softc(dev); bus_generic_suspend(dev); /* Disable interupts, so the state change(s) doesn't trigger. */ ATA_OUTL(sc->ctlr.r_mem, AHCI_GHC, ATA_INL(sc->ctlr.r_mem, AHCI_GHC) & (~AHCI_GHC_IE)); return (0); } static int tegra_ahci_resume(device_t dev) { int res; if ((res = tegra_ahci_ctlr_reset(dev)) != 0) return (res); ahci_ctlr_setup(dev); return (bus_generic_resume(dev)); } static device_method_t tegra_ahci_methods[] = { DEVMETHOD(device_probe, tegra_ahci_probe), DEVMETHOD(device_attach, tegra_ahci_attach), DEVMETHOD(device_detach, tegra_ahci_detach), DEVMETHOD(device_suspend, tegra_ahci_suspend), DEVMETHOD(device_resume, tegra_ahci_resume), DEVMETHOD(bus_print_child, ahci_print_child), DEVMETHOD(bus_alloc_resource, ahci_alloc_resource), DEVMETHOD(bus_release_resource, ahci_release_resource), DEVMETHOD(bus_setup_intr, ahci_setup_intr), DEVMETHOD(bus_teardown_intr, ahci_teardown_intr), DEVMETHOD(bus_child_location, ahci_child_location), DEVMETHOD(bus_get_dma_tag, ahci_get_dma_tag), DEVMETHOD_END }; static DEFINE_CLASS_0(ahci, tegra_ahci_driver, tegra_ahci_methods, sizeof(struct tegra_ahci_sc)); DRIVER_MODULE(tegra_ahci, simplebus, tegra_ahci_driver, NULL, NULL); diff --git a/sys/arm/nvidia/tegra_pcie.c b/sys/arm/nvidia/tegra_pcie.c index a22ae02ce4bc..c9b5f46c4e30 100644 --- a/sys/arm/nvidia/tegra_pcie.c +++ b/sys/arm/nvidia/tegra_pcie.c @@ -1,1624 +1,1624 @@ /*- * Copyright (c) 2016 Michal Meloun * All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ #include /* * Nvidia Integrated PCI/PCI-Express controller driver. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #include #include #include #include #include "ofw_bus_if.h" #include "msi_if.h" #include "pcib_if.h" #include "pic_if.h" #define AFI_AXI_BAR0_SZ 0x000 #define AFI_AXI_BAR1_SZ 0x004 #define AFI_AXI_BAR2_SZ 0x008 #define AFI_AXI_BAR3_SZ 0x00c #define AFI_AXI_BAR4_SZ 0x010 #define AFI_AXI_BAR5_SZ 0x014 #define AFI_AXI_BAR0_START 0x018 #define AFI_AXI_BAR1_START 0x01c #define AFI_AXI_BAR2_START 0x020 #define AFI_AXI_BAR3_START 0x024 #define AFI_AXI_BAR4_START 0x028 #define AFI_AXI_BAR5_START 0x02c #define AFI_FPCI_BAR0 0x030 #define AFI_FPCI_BAR1 0x034 #define AFI_FPCI_BAR2 0x038 #define AFI_FPCI_BAR3 0x03c #define AFI_FPCI_BAR4 0x040 #define AFI_FPCI_BAR5 0x044 #define AFI_MSI_BAR_SZ 0x060 #define AFI_MSI_FPCI_BAR_ST 0x064 #define AFI_MSI_AXI_BAR_ST 0x068 #define AFI_MSI_VEC(x) (0x06c + 4 * (x)) #define AFI_MSI_EN_VEC(x) (0x08c + 4 * (x)) #define AFI_MSI_INTR_IN_REG 32 #define AFI_MSI_REGS 8 #define AFI_CONFIGURATION 0x0ac #define AFI_CONFIGURATION_EN_FPCI (1 << 0) #define AFI_FPCI_ERROR_MASKS 0x0b0 #define AFI_INTR_MASK 0x0b4 #define AFI_INTR_MASK_MSI_MASK (1 << 8) #define AFI_INTR_MASK_INT_MASK (1 << 0) #define AFI_INTR_CODE 0x0b8 #define AFI_INTR_CODE_MASK 0xf #define AFI_INTR_CODE_INT_CODE_INI_SLVERR 1 #define AFI_INTR_CODE_INT_CODE_INI_DECERR 2 #define AFI_INTR_CODE_INT_CODE_TGT_SLVERR 3 #define AFI_INTR_CODE_INT_CODE_TGT_DECERR 4 #define AFI_INTR_CODE_INT_CODE_TGT_WRERR 5 #define AFI_INTR_CODE_INT_CODE_SM_MSG 6 #define AFI_INTR_CODE_INT_CODE_DFPCI_DECERR 7 #define AFI_INTR_CODE_INT_CODE_AXI_DECERR 8 #define AFI_INTR_CODE_INT_CODE_FPCI_TIMEOUT 9 #define AFI_INTR_CODE_INT_CODE_PE_PRSNT_SENSE 10 #define AFI_INTR_CODE_INT_CODE_PE_CLKREQ_SENSE 11 #define AFI_INTR_CODE_INT_CODE_CLKCLAMP_SENSE 12 #define AFI_INTR_CODE_INT_CODE_RDY4PD_SENSE 13 #define AFI_INTR_CODE_INT_CODE_P2P_ERROR 14 #define AFI_INTR_SIGNATURE 0x0bc #define AFI_UPPER_FPCI_ADDRESS 0x0c0 #define AFI_SM_INTR_ENABLE 0x0c4 #define AFI_SM_INTR_RP_DEASSERT (1 << 14) #define AFI_SM_INTR_RP_ASSERT (1 << 13) #define AFI_SM_INTR_HOTPLUG (1 << 12) #define AFI_SM_INTR_PME (1 << 11) #define AFI_SM_INTR_FATAL_ERROR (1 << 10) #define AFI_SM_INTR_UNCORR_ERROR (1 << 9) #define AFI_SM_INTR_CORR_ERROR (1 << 8) #define AFI_SM_INTR_INTD_DEASSERT (1 << 7) #define AFI_SM_INTR_INTC_DEASSERT (1 << 6) #define AFI_SM_INTR_INTB_DEASSERT (1 << 5) #define AFI_SM_INTR_INTA_DEASSERT (1 << 4) #define AFI_SM_INTR_INTD_ASSERT (1 << 3) #define AFI_SM_INTR_INTC_ASSERT (1 << 2) #define AFI_SM_INTR_INTB_ASSERT (1 << 1) #define AFI_SM_INTR_INTA_ASSERT (1 << 0) #define AFI_AFI_INTR_ENABLE 0x0c8 #define AFI_AFI_INTR_ENABLE_CODE(code) (1 << (code)) #define AFI_PCIE_CONFIG 0x0f8 #define AFI_PCIE_CONFIG_PCIE_DISABLE(x) (1 << ((x) + 1)) #define AFI_PCIE_CONFIG_PCIE_DISABLE_ALL 0x6 #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK (0xf << 20) #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR2_1 (0x0 << 20) #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR4_1 (0x1 << 20) #define AFI_FUSE 0x104 #define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2) #define AFI_PEX0_CTRL 0x110 #define AFI_PEX1_CTRL 0x118 #define AFI_PEX2_CTRL 0x128 #define AFI_PEX_CTRL_OVERRIDE_EN (1 << 4) #define AFI_PEX_CTRL_REFCLK_EN (1 << 3) #define AFI_PEX_CTRL_CLKREQ_EN (1 << 1) #define AFI_PEX_CTRL_RST_L (1 << 0) #define AFI_AXI_BAR6_SZ 0x134 #define AFI_AXI_BAR7_SZ 0x138 #define AFI_AXI_BAR8_SZ 0x13c #define AFI_AXI_BAR6_START 0x140 #define AFI_AXI_BAR7_START 0x144 #define AFI_AXI_BAR8_START 0x148 #define AFI_FPCI_BAR6 0x14c #define AFI_FPCI_BAR7 0x150 #define AFI_FPCI_BAR8 0x154 #define AFI_PLLE_CONTROL 0x160 #define AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL (1 << 9) #define AFI_PLLE_CONTROL_BYPASS_PCIE2PLLE_CONTROL (1 << 8) #define AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN (1 << 1) #define AFI_PLLE_CONTROL_PCIE2PLLE_CONTROL_EN (1 << 0) #define AFI_PEXBIAS_CTRL 0x168 /* Configuration space */ #define RP_VEND_XP 0x0F00 #define RP_VEND_XP_DL_UP (1 << 30) #define RP_VEND_CTL2 0x0fa8 #define RP_VEND_CTL2_PCA_ENABLE (1 << 7) #define RP_PRIV_MISC 0x0FE0 #define RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0) #define RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0) #define RP_LINK_CONTROL_STATUS 0x0090 #define RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000 #define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000 /* PADS space */ #define PADS_REFCLK_CFG0 0x000c8 #define PADS_REFCLK_CFG1 0x000cc /* Wait 50 ms (per port) for link. */ #define TEGRA_PCIE_LINKUP_TIMEOUT 50000 /* FPCI Address space */ #define FPCI_MAP_IO 0xFDFC000000ULL #define FPCI_MAP_TYPE0_CONFIG 0xFDFC000000ULL #define FPCI_MAP_TYPE1_CONFIG 0xFDFF000000ULL #define FPCI_MAP_EXT_TYPE0_CONFIG 0xFE00000000ULL #define FPCI_MAP_EXT_TYPE1_CONFIG 0xFE10000000ULL #define TEGRA_PCIB_MSI_ENABLE #define DEBUG #ifdef DEBUG #define debugf(fmt, args...) do { printf(fmt,##args); } while (0) #else #define debugf(fmt, args...) #endif /* * Configuration space format: * [27:24] extended register * [23:16] bus * [15:11] slot (device) * [10: 8] function * [ 7: 0] register */ #define PCI_CFG_EXT_REG(reg) ((((reg) >> 8) & 0x0f) << 24) #define PCI_CFG_BUS(bus) (((bus) & 0xff) << 16) #define PCI_CFG_DEV(dev) (((dev) & 0x1f) << 11) #define PCI_CFG_FUN(fun) (((fun) & 0x07) << 8) #define PCI_CFG_BASE_REG(reg) ((reg) & 0xff) #define PADS_WR4(_sc, _r, _v) bus_write_4((_sc)->pads_mem_res, (_r), (_v)) #define PADS_RD4(_sc, _r) bus_read_4((_sc)->pads_mem_res, (_r)) #define AFI_WR4(_sc, _r, _v) bus_write_4((_sc)->afi_mem_res, (_r), (_v)) #define AFI_RD4(_sc, _r) bus_read_4((_sc)->afi_mem_res, (_r)) static struct { bus_size_t axi_start; bus_size_t fpci_start; bus_size_t size; } bars[] = { {AFI_AXI_BAR0_START, AFI_FPCI_BAR0, AFI_AXI_BAR0_SZ}, /* BAR 0 */ {AFI_AXI_BAR1_START, AFI_FPCI_BAR1, AFI_AXI_BAR1_SZ}, /* BAR 1 */ {AFI_AXI_BAR2_START, AFI_FPCI_BAR2, AFI_AXI_BAR2_SZ}, /* BAR 2 */ {AFI_AXI_BAR3_START, AFI_FPCI_BAR3, AFI_AXI_BAR3_SZ}, /* BAR 3 */ {AFI_AXI_BAR4_START, AFI_FPCI_BAR4, AFI_AXI_BAR4_SZ}, /* BAR 4 */ {AFI_AXI_BAR5_START, AFI_FPCI_BAR5, AFI_AXI_BAR5_SZ}, /* BAR 5 */ {AFI_AXI_BAR6_START, AFI_FPCI_BAR6, AFI_AXI_BAR6_SZ}, /* BAR 6 */ {AFI_AXI_BAR7_START, AFI_FPCI_BAR7, AFI_AXI_BAR7_SZ}, /* BAR 7 */ {AFI_AXI_BAR8_START, AFI_FPCI_BAR8, AFI_AXI_BAR8_SZ}, /* BAR 8 */ {AFI_MSI_AXI_BAR_ST, AFI_MSI_FPCI_BAR_ST, AFI_MSI_BAR_SZ}, /* MSI 9 */ }; struct pcie_soc { char **regulator_names; bool cml_clk; bool pca_enable; uint32_t pads_refclk_cfg0; uint32_t pads_refclk_cfg1; }; /* Tegra 124 config. */ static char *tegra124_reg_names[] = { "avddio-pex-supply", "dvddio-pex-supply", "avdd-pex-pll-supply", "hvdd-pex-supply", "hvdd-pex-pll-e-supply", "vddio-pex-ctl-supply", "avdd-pll-erefe-supply", NULL }; static struct pcie_soc tegra124_soc = { .regulator_names = tegra124_reg_names, .cml_clk = true, .pca_enable = false, .pads_refclk_cfg0 = 0x44ac44ac, }; /* Tegra 210 config. */ static char *tegra210_reg_names[] = { "avdd-pll-uerefe-supply", "hvddio-pex-supply", "dvddio-pex-supply", "dvdd-pex-pll-supply", "hvdd-pex-pll-e-supply", "vddio-pex-ctl-supply", NULL }; static struct pcie_soc tegra210_soc = { .regulator_names = tegra210_reg_names, .cml_clk = true, .pca_enable = true, .pads_refclk_cfg0 = 0x90b890b8, }; /* Compatible devices. */ static struct ofw_compat_data compat_data[] = { {"nvidia,tegra124-pcie", (uintptr_t)&tegra124_soc}, {"nvidia,tegra210-pcie", (uintptr_t)&tegra210_soc}, {NULL, 0}, }; #define TEGRA_FLAG_MSI_USED 0x0001 struct tegra_pcib_irqsrc { struct intr_irqsrc isrc; u_int irq; u_int flags; }; struct tegra_pcib_port { int enabled; int port_idx; /* chip port index */ int num_lanes; /* number of lanes */ bus_size_t afi_pex_ctrl; /* offset of afi_pex_ctrl */ phy_t phy; /* port phy */ /* Config space properties. */ bus_addr_t rp_base_addr; /* PA of config window */ bus_size_t rp_size; /* size of config window */ bus_space_handle_t cfg_handle; /* handle of config window */ }; #define TEGRA_PCIB_MAX_PORTS 3 #define TEGRA_PCIB_MAX_MSI AFI_MSI_INTR_IN_REG * AFI_MSI_REGS struct tegra_pcib_softc { struct ofw_pci_softc ofw_pci; device_t dev; struct pcie_soc *soc; struct mtx mtx; struct resource *pads_mem_res; struct resource *afi_mem_res; struct resource *cfg_mem_res; struct resource *irq_res; struct resource *msi_irq_res; void *intr_cookie; void *msi_intr_cookie; struct ofw_pci_range mem_range; struct ofw_pci_range pref_mem_range; struct ofw_pci_range io_range; clk_t clk_pex; clk_t clk_afi; clk_t clk_pll_e; clk_t clk_cml; hwreset_t hwreset_pex; hwreset_t hwreset_afi; hwreset_t hwreset_pcie_x; regulator_t regulators[16]; /* Safe maximum */ vm_offset_t msi_page; /* VA of MSI page */ bus_addr_t cfg_base_addr; /* base address of config */ bus_size_t cfg_cur_offs; /* currently mapped window */ bus_space_handle_t cfg_handle; /* handle of config window */ bus_space_tag_t bus_tag; /* tag of config window */ int lanes_cfg; int num_ports; struct tegra_pcib_port *ports[TEGRA_PCIB_MAX_PORTS]; struct tegra_pcib_irqsrc *isrcs; }; static int tegra_pcib_maxslots(device_t dev) { return (16); } static int tegra_pcib_route_interrupt(device_t bus, device_t dev, int pin) { struct tegra_pcib_softc *sc; u_int irq; sc = device_get_softc(bus); irq = intr_map_clone_irq(rman_get_start(sc->irq_res)); device_printf(bus, "route pin %d for device %d.%d to %u\n", pin, pci_get_slot(dev), pci_get_function(dev), irq); return (irq); } static int tegra_pcbib_map_cfg(struct tegra_pcib_softc *sc, u_int bus, u_int slot, u_int func, u_int reg) { bus_size_t offs; int flags, rv; offs = sc->cfg_base_addr; offs |= PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) | PCI_CFG_FUN(func) | PCI_CFG_EXT_REG(reg); if ((sc->cfg_handle != 0) && (sc->cfg_cur_offs == offs)) return (0); if (sc->cfg_handle != 0) bus_space_unmap(sc->bus_tag, sc->cfg_handle, 0x800); #if defined(BUS_SPACE_MAP_NONPOSTED) flags = BUS_SPACE_MAP_NONPOSTED; #else flags = 0; #endif rv = bus_space_map(sc->bus_tag, offs, 0x800, flags, &sc->cfg_handle); if (rv != 0) device_printf(sc->dev, "Cannot map config space\n"); else sc->cfg_cur_offs = offs; return (rv); } static uint32_t tegra_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { struct tegra_pcib_softc *sc; bus_space_handle_t hndl; uint32_t off; uint32_t val; int rv, i; sc = device_get_softc(dev); if (bus == 0) { if (func != 0) return (0xFFFFFFFF); for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { if ((sc->ports[i] != NULL) && (sc->ports[i]->port_idx == slot)) { hndl = sc->ports[i]->cfg_handle; off = reg & 0xFFF; break; } } if (i >= TEGRA_PCIB_MAX_PORTS) return (0xFFFFFFFF); } else { rv = tegra_pcbib_map_cfg(sc, bus, slot, func, reg); if (rv != 0) return (0xFFFFFFFF); hndl = sc->cfg_handle; off = PCI_CFG_BASE_REG(reg); } val = bus_space_read_4(sc->bus_tag, hndl, off & ~3); switch (bytes) { case 4: break; case 2: if (off & 3) val >>= 16; val &= 0xffff; break; case 1: val >>= ((off & 3) << 3); val &= 0xff; break; } return val; } static void tegra_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int bytes) { struct tegra_pcib_softc *sc; bus_space_handle_t hndl; uint32_t off; uint32_t val2; int rv, i; sc = device_get_softc(dev); if (bus == 0) { if (func != 0) return; for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { if ((sc->ports[i] != NULL) && (sc->ports[i]->port_idx == slot)) { hndl = sc->ports[i]->cfg_handle; off = reg & 0xFFF; break; } } if (i >= TEGRA_PCIB_MAX_PORTS) return; } else { rv = tegra_pcbib_map_cfg(sc, bus, slot, func, reg); if (rv != 0) return; hndl = sc->cfg_handle; off = PCI_CFG_BASE_REG(reg); } switch (bytes) { case 4: bus_space_write_4(sc->bus_tag, hndl, off, val); break; case 2: val2 = bus_space_read_4(sc->bus_tag, hndl, off & ~3); val2 &= ~(0xffff << ((off & 3) << 3)); val2 |= ((val & 0xffff) << ((off & 3) << 3)); bus_space_write_4(sc->bus_tag, hndl, off & ~3, val2); break; case 1: val2 = bus_space_read_4(sc->bus_tag, hndl, off & ~3); val2 &= ~(0xff << ((off & 3) << 3)); val2 |= ((val & 0xff) << ((off & 3) << 3)); bus_space_write_4(sc->bus_tag, hndl, off & ~3, val2); break; } } static int tegra_pci_intr(void *arg) { struct tegra_pcib_softc *sc = arg; uint32_t code, signature; code = bus_read_4(sc->afi_mem_res, AFI_INTR_CODE) & AFI_INTR_CODE_MASK; signature = bus_read_4(sc->afi_mem_res, AFI_INTR_SIGNATURE); bus_write_4(sc->afi_mem_res, AFI_INTR_CODE, 0); if (code == AFI_INTR_CODE_INT_CODE_SM_MSG) return(FILTER_STRAY); printf("tegra_pci_intr: code %x sig %x\n", code, signature); return (FILTER_HANDLED); } /* ----------------------------------------------------------------------- * * PCI MSI interface */ static int tegra_pcib_alloc_msi(device_t pci, device_t child, int count, int maxcount, int *irqs) { phandle_t msi_parent; /* XXXX ofw_bus_msimap() don't works for Tegra DT. ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, NULL); */ msi_parent = OF_xref_from_node(ofw_bus_get_node(pci)); return (intr_alloc_msi(pci, child, msi_parent, count, maxcount, irqs)); } static int tegra_pcib_release_msi(device_t pci, device_t child, int count, int *irqs) { phandle_t msi_parent; /* XXXX ofw_bus_msimap() don't works for Tegra DT. ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, NULL); */ msi_parent = OF_xref_from_node(ofw_bus_get_node(pci)); return (intr_release_msi(pci, child, msi_parent, count, irqs)); } static int tegra_pcib_map_msi(device_t pci, device_t child, int irq, uint64_t *addr, uint32_t *data) { phandle_t msi_parent; /* XXXX ofw_bus_msimap() don't works for Tegra DT. ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, NULL); */ msi_parent = OF_xref_from_node(ofw_bus_get_node(pci)); return (intr_map_msi(pci, child, msi_parent, irq, addr, data)); } #ifdef TEGRA_PCIB_MSI_ENABLE /* -------------------------------------------------------------------------- * * Interrupts * */ static inline void tegra_pcib_isrc_mask(struct tegra_pcib_softc *sc, struct tegra_pcib_irqsrc *tgi, uint32_t val) { uint32_t reg; int offs, bit; offs = tgi->irq / AFI_MSI_INTR_IN_REG; bit = 1 << (tgi->irq % AFI_MSI_INTR_IN_REG); if (val != 0) AFI_WR4(sc, AFI_MSI_VEC(offs), bit); reg = AFI_RD4(sc, AFI_MSI_EN_VEC(offs)); if (val != 0) reg |= bit; else reg &= ~bit; AFI_WR4(sc, AFI_MSI_EN_VEC(offs), reg); } static int tegra_pcib_msi_intr(void *arg) { u_int irq, i, bit, reg; struct tegra_pcib_softc *sc; struct trapframe *tf; struct tegra_pcib_irqsrc *tgi; sc = (struct tegra_pcib_softc *)arg; tf = curthread->td_intr_frame; for (i = 0; i < AFI_MSI_REGS; i++) { reg = AFI_RD4(sc, AFI_MSI_VEC(i)); /* Handle one vector. */ while (reg != 0) { bit = ffs(reg) - 1; /* Send EOI */ AFI_WR4(sc, AFI_MSI_VEC(i), 1 << bit); irq = i * AFI_MSI_INTR_IN_REG + bit; tgi = &sc->isrcs[irq]; if (intr_isrc_dispatch(&tgi->isrc, tf) != 0) { /* Disable stray. */ tegra_pcib_isrc_mask(sc, tgi, 0); device_printf(sc->dev, "Stray irq %u disabled\n", irq); } reg = AFI_RD4(sc, AFI_MSI_VEC(i)); } } return (FILTER_HANDLED); } static int tegra_pcib_msi_attach(struct tegra_pcib_softc *sc) { int error; uint32_t irq; const char *name; sc->isrcs = malloc(sizeof(*sc->isrcs) * TEGRA_PCIB_MAX_MSI, M_DEVBUF, M_WAITOK | M_ZERO); name = device_get_nameunit(sc->dev); for (irq = 0; irq < TEGRA_PCIB_MAX_MSI; irq++) { sc->isrcs[irq].irq = irq; error = intr_isrc_register(&sc->isrcs[irq].isrc, sc->dev, 0, "%s,%u", name, irq); if (error != 0) return (error); /* XXX deregister ISRCs */ } if (intr_msi_register(sc->dev, OF_xref_from_node(ofw_bus_get_node(sc->dev))) != 0) return (ENXIO); return (0); } static int tegra_pcib_msi_detach(struct tegra_pcib_softc *sc) { /* * There has not been established any procedure yet * how to detach PIC from living system correctly. */ device_printf(sc->dev, "%s: not implemented yet\n", __func__); return (EBUSY); } static void tegra_pcib_msi_disable_intr(device_t dev, struct intr_irqsrc *isrc) { struct tegra_pcib_softc *sc; struct tegra_pcib_irqsrc *tgi; sc = device_get_softc(dev); tgi = (struct tegra_pcib_irqsrc *)isrc; tegra_pcib_isrc_mask(sc, tgi, 0); } static void tegra_pcib_msi_enable_intr(device_t dev, struct intr_irqsrc *isrc) { struct tegra_pcib_softc *sc; struct tegra_pcib_irqsrc *tgi; sc = device_get_softc(dev); tgi = (struct tegra_pcib_irqsrc *)isrc; tegra_pcib_isrc_mask(sc, tgi, 1); } /* MSI interrupts are edge trigered -> do nothing */ static void tegra_pcib_msi_post_filter(device_t dev, struct intr_irqsrc *isrc) { } static void tegra_pcib_msi_post_ithread(device_t dev, struct intr_irqsrc *isrc) { } static void tegra_pcib_msi_pre_ithread(device_t dev, struct intr_irqsrc *isrc) { } static int tegra_pcib_msi_setup_intr(device_t dev, struct intr_irqsrc *isrc, struct resource *res, struct intr_map_data *data) { if (data == NULL || data->type != INTR_MAP_DATA_MSI) return (ENOTSUP); if (isrc->isrc_handlers == 0) tegra_pcib_msi_enable_intr(dev, isrc); return (0); } static int tegra_pcib_msi_teardown_intr(device_t dev, struct intr_irqsrc *isrc, struct resource *res, struct intr_map_data *data) { struct tegra_pcib_softc *sc; struct tegra_pcib_irqsrc *tgi; sc = device_get_softc(dev); tgi = (struct tegra_pcib_irqsrc *)isrc; if (isrc->isrc_handlers == 0) tegra_pcib_isrc_mask(sc, tgi, 0); return (0); } static int tegra_pcib_msi_alloc_msi(device_t dev, device_t child, int count, int maxcount, device_t *pic, struct intr_irqsrc **srcs) { struct tegra_pcib_softc *sc; int i, irq, end_irq; bool found; KASSERT(powerof2(count), ("%s: bad count", __func__)); KASSERT(powerof2(maxcount), ("%s: bad maxcount", __func__)); sc = device_get_softc(dev); mtx_lock(&sc->mtx); found = false; for (irq = 0; (irq + count - 1) < TEGRA_PCIB_MAX_MSI; irq++) { /* Start on an aligned interrupt */ if ((irq & (maxcount - 1)) != 0) continue; /* Assume we found a valid range until shown otherwise */ found = true; /* Check this range is valid */ for (end_irq = irq; end_irq < irq + count; end_irq++) { /* This is already used */ if ((sc->isrcs[end_irq].flags & TEGRA_FLAG_MSI_USED) == TEGRA_FLAG_MSI_USED) { found = false; break; } } if (found) break; } /* Not enough interrupts were found */ if (!found || irq == (TEGRA_PCIB_MAX_MSI - 1)) { mtx_unlock(&sc->mtx); return (ENXIO); } for (i = 0; i < count; i++) { /* Mark the interrupt as used */ sc->isrcs[irq + i].flags |= TEGRA_FLAG_MSI_USED; } mtx_unlock(&sc->mtx); for (i = 0; i < count; i++) srcs[i] = (struct intr_irqsrc *)&sc->isrcs[irq + i]; *pic = device_get_parent(dev); return (0); } static int tegra_pcib_msi_release_msi(device_t dev, device_t child, int count, struct intr_irqsrc **isrc) { struct tegra_pcib_softc *sc; struct tegra_pcib_irqsrc *ti; int i; sc = device_get_softc(dev); mtx_lock(&sc->mtx); for (i = 0; i < count; i++) { ti = (struct tegra_pcib_irqsrc *)isrc[i]; KASSERT((ti->flags & TEGRA_FLAG_MSI_USED) == TEGRA_FLAG_MSI_USED, ("%s: Trying to release an unused MSI-X interrupt", __func__)); ti->flags &= ~TEGRA_FLAG_MSI_USED; } mtx_unlock(&sc->mtx); return (0); } static int tegra_pcib_msi_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc, uint64_t *addr, uint32_t *data) { struct tegra_pcib_softc *sc = device_get_softc(dev); struct tegra_pcib_irqsrc *ti = (struct tegra_pcib_irqsrc *)isrc; *addr = vtophys(sc->msi_page); *data = ti->irq; return (0); } #endif /* ------------------------------------------------------------------- */ static bus_size_t tegra_pcib_pex_ctrl(struct tegra_pcib_softc *sc, int port) { switch (port) { case 0: return (AFI_PEX0_CTRL); case 1: return (AFI_PEX1_CTRL); case 2: return (AFI_PEX2_CTRL); default: panic("invalid port number: %d\n", port); } } static int tegra_pcib_enable_fdt_resources(struct tegra_pcib_softc *sc) { int i, rv; rv = hwreset_assert(sc->hwreset_pcie_x); if (rv != 0) { device_printf(sc->dev, "Cannot assert 'pcie_x' reset\n"); return (rv); } rv = hwreset_assert(sc->hwreset_afi); if (rv != 0) { device_printf(sc->dev, "Cannot assert 'afi' reset\n"); return (rv); } rv = hwreset_assert(sc->hwreset_pex); if (rv != 0) { device_printf(sc->dev, "Cannot assert 'pex' reset\n"); return (rv); } tegra_powergate_power_off(TEGRA_POWERGATE_PCX); /* Regulators. */ for (i = 0; i < nitems(sc->regulators); i++) { if (sc->regulators[i] == NULL) continue; rv = regulator_enable(sc->regulators[i]); if (rv != 0) { device_printf(sc->dev, "Cannot enable '%s' regulator\n", sc->soc->regulator_names[i]); return (rv); } } rv = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCX, sc->clk_pex, sc->hwreset_pex); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'PCX' powergate\n"); return (rv); } rv = hwreset_deassert(sc->hwreset_afi); if (rv != 0) { device_printf(sc->dev, "Cannot unreset 'afi' reset\n"); return (rv); } rv = clk_enable(sc->clk_afi); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'afi' clock\n"); return (rv); } if (sc->soc->cml_clk) { rv = clk_enable(sc->clk_cml); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'cml' clock\n"); return (rv); } } rv = clk_enable(sc->clk_pll_e); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'pll_e' clock\n"); return (rv); } return (0); } static struct tegra_pcib_port * tegra_pcib_parse_port(struct tegra_pcib_softc *sc, phandle_t node) { struct tegra_pcib_port *port; uint32_t tmp[5]; char tmpstr[6]; int rv; port = malloc(sizeof(struct tegra_pcib_port), M_DEVBUF, M_WAITOK); rv = OF_getprop(node, "status", tmpstr, sizeof(tmpstr)); if (rv <= 0 || strcmp(tmpstr, "okay") == 0 || strcmp(tmpstr, "ok") == 0) port->enabled = 1; else port->enabled = 0; rv = OF_getencprop(node, "assigned-addresses", tmp, sizeof(tmp)); if (rv != sizeof(tmp)) { device_printf(sc->dev, "Cannot parse assigned-address: %d\n", rv); goto fail; } port->rp_base_addr = tmp[2]; port->rp_size = tmp[4]; port->port_idx = OFW_PCI_PHYS_HI_DEVICE(tmp[0]) - 1; if (port->port_idx >= TEGRA_PCIB_MAX_PORTS) { device_printf(sc->dev, "Invalid port index: %d\n", port->port_idx); goto fail; } /* XXX - TODO: * Implement proper function for parsing pci "reg" property: * - it have PCI bus format * - its relative to matching "assigned-addresses" */ rv = OF_getencprop(node, "reg", tmp, sizeof(tmp)); if (rv != sizeof(tmp)) { device_printf(sc->dev, "Cannot parse reg: %d\n", rv); goto fail; } port->rp_base_addr += tmp[2]; rv = OF_getencprop(node, "nvidia,num-lanes", &port->num_lanes, sizeof(port->num_lanes)); if (rv != sizeof(port->num_lanes)) { device_printf(sc->dev, "Cannot parse nvidia,num-lanes: %d\n", rv); goto fail; } if (port->num_lanes > 4) { device_printf(sc->dev, "Invalid nvidia,num-lanes: %d\n", port->num_lanes); goto fail; } port->afi_pex_ctrl = tegra_pcib_pex_ctrl(sc, port->port_idx); sc->lanes_cfg |= port->num_lanes << (4 * port->port_idx); /* Phy. */ rv = phy_get_by_ofw_name(sc->dev, node, "pcie-0", &port->phy); if (rv != 0) { device_printf(sc->dev, "Cannot get 'pcie-0' phy for port %d\n", port->port_idx); goto fail; } return (port); fail: free(port, M_DEVBUF); return (NULL); } static int tegra_pcib_parse_fdt_resources(struct tegra_pcib_softc *sc, phandle_t node) { phandle_t child; struct tegra_pcib_port *port; int i, rv; /* Regulators. */ for (i = 0; sc->soc->regulator_names[i] != NULL; i++) { if (i >= nitems(sc->regulators)) { device_printf(sc->dev, "Too many regulators present in DT.\n"); return (EOVERFLOW); } rv = regulator_get_by_ofw_property(sc->dev, 0, sc->soc->regulator_names[i], sc->regulators + i); if (rv != 0) { device_printf(sc->dev, "Cannot get '%s' regulator\n", sc->soc->regulator_names[i]); return (ENXIO); } } /* Resets. */ rv = hwreset_get_by_ofw_name(sc->dev, 0, "pex", &sc->hwreset_pex); if (rv != 0) { device_printf(sc->dev, "Cannot get 'pex' reset\n"); return (ENXIO); } rv = hwreset_get_by_ofw_name(sc->dev, 0, "afi", &sc->hwreset_afi); if (rv != 0) { device_printf(sc->dev, "Cannot get 'afi' reset\n"); return (ENXIO); } rv = hwreset_get_by_ofw_name(sc->dev, 0, "pcie_x", &sc->hwreset_pcie_x); if (rv != 0) { device_printf(sc->dev, "Cannot get 'pcie_x' reset\n"); return (ENXIO); } /* Clocks. */ rv = clk_get_by_ofw_name(sc->dev, 0, "pex", &sc->clk_pex); if (rv != 0) { device_printf(sc->dev, "Cannot get 'pex' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, 0, "afi", &sc->clk_afi); if (rv != 0) { device_printf(sc->dev, "Cannot get 'afi' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, 0, "pll_e", &sc->clk_pll_e); if (rv != 0) { device_printf(sc->dev, "Cannot get 'pll_e' clock\n"); return (ENXIO); } if (sc->soc->cml_clk) { rv = clk_get_by_ofw_name(sc->dev, 0, "cml", &sc->clk_cml); if (rv != 0) { device_printf(sc->dev, "Cannot get 'cml' clock\n"); return (ENXIO); } } /* Ports */ sc->num_ports = 0; for (child = OF_child(node); child != 0; child = OF_peer(child)) { port = tegra_pcib_parse_port(sc, child); if (port == NULL) { device_printf(sc->dev, "Cannot parse PCIe port node\n"); return (ENXIO); } sc->ports[sc->num_ports++] = port; } return (0); } static int tegra_pcib_decode_ranges(struct tegra_pcib_softc *sc, struct ofw_pci_range *ranges, int nranges) { int i; for (i = 2; i < nranges; i++) { if ((ranges[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) == OFW_PCI_PHYS_HI_SPACE_IO) { if (sc->io_range.size != 0) { device_printf(sc->dev, "Duplicated IO range found in DT\n"); return (ENXIO); } sc->io_range = ranges[i]; } if (((ranges[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) == OFW_PCI_PHYS_HI_SPACE_MEM32)) { if (ranges[i].pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) { if (sc->pref_mem_range.size != 0) { device_printf(sc->dev, "Duplicated memory range found " "in DT\n"); return (ENXIO); } sc->pref_mem_range = ranges[i]; } else { if (sc->mem_range.size != 0) { device_printf(sc->dev, "Duplicated memory range found " "in DT\n"); return (ENXIO); } sc->mem_range = ranges[i]; } } } if ((sc->io_range.size == 0) || (sc->mem_range.size == 0) || (sc->pref_mem_range.size == 0)) { device_printf(sc->dev, " Not all required ranges are found in DT\n"); return (ENXIO); } return (0); } /* * Hardware config. */ static int tegra_pcib_wait_for_link(struct tegra_pcib_softc *sc, struct tegra_pcib_port *port) { uint32_t reg; int i; /* Setup link detection. */ reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0, RP_PRIV_MISC, 4); reg &= ~RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT; reg |= RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT; tegra_pcib_write_config(sc->dev, 0, port->port_idx, 0, RP_PRIV_MISC, reg, 4); for (i = TEGRA_PCIE_LINKUP_TIMEOUT; i > 0; i--) { reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0, RP_VEND_XP, 4); if (reg & RP_VEND_XP_DL_UP) break; DELAY(1); } if (i <= 0) return (ETIMEDOUT); for (i = TEGRA_PCIE_LINKUP_TIMEOUT; i > 0; i--) { reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0, RP_LINK_CONTROL_STATUS, 4); if (reg & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE) break; DELAY(1); } if (i <= 0) return (ETIMEDOUT); return (0); } static void tegra_pcib_port_enable(struct tegra_pcib_softc *sc, int port_num) { struct tegra_pcib_port *port; uint32_t reg; int rv; port = sc->ports[port_num]; /* Put port to reset. */ reg = AFI_RD4(sc, port->afi_pex_ctrl); reg &= ~AFI_PEX_CTRL_RST_L; AFI_WR4(sc, port->afi_pex_ctrl, reg); AFI_RD4(sc, port->afi_pex_ctrl); DELAY(10); /* Enable clocks. */ reg |= AFI_PEX_CTRL_REFCLK_EN; reg |= AFI_PEX_CTRL_CLKREQ_EN; reg |= AFI_PEX_CTRL_OVERRIDE_EN; AFI_WR4(sc, port->afi_pex_ctrl, reg); AFI_RD4(sc, port->afi_pex_ctrl); DELAY(100); /* Release reset. */ reg |= AFI_PEX_CTRL_RST_L; AFI_WR4(sc, port->afi_pex_ctrl, reg); if (sc->soc->pca_enable) { reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0, RP_VEND_CTL2, 4); reg |= RP_VEND_CTL2_PCA_ENABLE; tegra_pcib_write_config(sc->dev, 0, port->port_idx, 0, RP_VEND_CTL2, reg, 4); } rv = tegra_pcib_wait_for_link(sc, port); if (bootverbose) device_printf(sc->dev, " port %d (%d lane%s): Link is %s\n", port->port_idx, port->num_lanes, port->num_lanes > 1 ? "s": "", rv == 0 ? "up": "down"); } static void tegra_pcib_port_disable(struct tegra_pcib_softc *sc, uint32_t port_num) { struct tegra_pcib_port *port; uint32_t reg; port = sc->ports[port_num]; /* Put port to reset. */ reg = AFI_RD4(sc, port->afi_pex_ctrl); reg &= ~AFI_PEX_CTRL_RST_L; AFI_WR4(sc, port->afi_pex_ctrl, reg); AFI_RD4(sc, port->afi_pex_ctrl); DELAY(10); /* Disable clocks. */ reg &= ~AFI_PEX_CTRL_CLKREQ_EN; reg &= ~AFI_PEX_CTRL_REFCLK_EN; AFI_WR4(sc, port->afi_pex_ctrl, reg); if (bootverbose) device_printf(sc->dev, " port %d (%d lane%s): Disabled\n", port->port_idx, port->num_lanes, port->num_lanes > 1 ? "s": ""); } static void tegra_pcib_set_bar(struct tegra_pcib_softc *sc, int bar, uint32_t axi, uint64_t fpci, uint32_t size, int is_memory) { uint32_t fpci_reg; uint32_t axi_reg; uint32_t size_reg; axi_reg = axi & ~0xFFF; size_reg = size >> 12; fpci_reg = (uint32_t)(fpci >> 8) & ~0xF; fpci_reg |= is_memory ? 0x1 : 0x0; AFI_WR4(sc, bars[bar].axi_start, axi_reg); AFI_WR4(sc, bars[bar].size, size_reg); AFI_WR4(sc, bars[bar].fpci_start, fpci_reg); } static int tegra_pcib_enable(struct tegra_pcib_softc *sc) { int rv; int i; uint32_t reg; rv = tegra_pcib_enable_fdt_resources(sc); if (rv != 0) { device_printf(sc->dev, "Cannot enable FDT resources\n"); return (rv); } /* Enable PLLE control. */ reg = AFI_RD4(sc, AFI_PLLE_CONTROL); reg &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL; reg |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN; AFI_WR4(sc, AFI_PLLE_CONTROL, reg); /* Set bias pad. */ AFI_WR4(sc, AFI_PEXBIAS_CTRL, 0); /* Configure mode and ports. */ reg = AFI_RD4(sc, AFI_PCIE_CONFIG); reg &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK; if (sc->lanes_cfg == 0x14) { if (bootverbose) device_printf(sc->dev, "Using x1,x4 configuration\n"); reg |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR4_1; } else if (sc->lanes_cfg == 0x12) { if (bootverbose) device_printf(sc->dev, "Using x1,x2 configuration\n"); reg |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR2_1; } else { device_printf(sc->dev, "Unsupported lanes configuration: 0x%X\n", sc->lanes_cfg); } reg |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL; for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { if ((sc->ports[i] != NULL)) reg &= ~AFI_PCIE_CONFIG_PCIE_DISABLE(sc->ports[i]->port_idx); } AFI_WR4(sc, AFI_PCIE_CONFIG, reg); /* Enable Gen2 support. */ reg = AFI_RD4(sc, AFI_FUSE); reg &= ~AFI_FUSE_PCIE_T0_GEN2_DIS; AFI_WR4(sc, AFI_FUSE, reg); for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { if (sc->ports[i] != NULL) { rv = phy_enable(sc->ports[i]->phy); if (rv != 0) { device_printf(sc->dev, "Cannot enable phy for port %d\n", sc->ports[i]->port_idx); return (rv); } } } /* Configure PCIe reference clock */ PADS_WR4(sc, PADS_REFCLK_CFG0, sc->soc->pads_refclk_cfg0); if (sc->num_ports > 2) PADS_WR4(sc, PADS_REFCLK_CFG1, sc->soc->pads_refclk_cfg1); rv = hwreset_deassert(sc->hwreset_pcie_x); if (rv != 0) { device_printf(sc->dev, "Cannot unreset 'pci_x' reset\n"); return (rv); } /* Enable config space. */ reg = AFI_RD4(sc, AFI_CONFIGURATION); reg |= AFI_CONFIGURATION_EN_FPCI; AFI_WR4(sc, AFI_CONFIGURATION, reg); /* Enable AFI errors. */ reg = 0; reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_INI_SLVERR); reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_INI_DECERR); reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_TGT_SLVERR); reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_TGT_DECERR); reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_TGT_WRERR); reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_SM_MSG); reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_DFPCI_DECERR); reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_AXI_DECERR); reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_FPCI_TIMEOUT); reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_PE_PRSNT_SENSE); reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_PE_CLKREQ_SENSE); reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_CLKCLAMP_SENSE); reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_RDY4PD_SENSE); reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_P2P_ERROR); AFI_WR4(sc, AFI_AFI_INTR_ENABLE, reg); AFI_WR4(sc, AFI_SM_INTR_ENABLE, 0xffffffff); /* Enable INT, disable MSI. */ AFI_WR4(sc, AFI_INTR_MASK, AFI_INTR_MASK_INT_MASK); /* Mask all FPCI errors. */ AFI_WR4(sc, AFI_FPCI_ERROR_MASKS, 0); /* Setup AFI translation windows. */ /* BAR 0 - type 1 extended configuration. */ tegra_pcib_set_bar(sc, 0, rman_get_start(sc->cfg_mem_res), FPCI_MAP_EXT_TYPE1_CONFIG, rman_get_size(sc->cfg_mem_res), 0); /* BAR 1 - downstream I/O. */ tegra_pcib_set_bar(sc, 1, sc->io_range.host, FPCI_MAP_IO, sc->io_range.size, 0); /* BAR 2 - downstream prefetchable memory 1:1. */ tegra_pcib_set_bar(sc, 2, sc->pref_mem_range.host, sc->pref_mem_range.host, sc->pref_mem_range.size, 1); /* BAR 3 - downstream not prefetchable memory 1:1 .*/ tegra_pcib_set_bar(sc, 3, sc->mem_range.host, sc->mem_range.host, sc->mem_range.size, 1); /* BAR 3-8 clear. */ tegra_pcib_set_bar(sc, 4, 0, 0, 0, 0); tegra_pcib_set_bar(sc, 5, 0, 0, 0, 0); tegra_pcib_set_bar(sc, 6, 0, 0, 0, 0); tegra_pcib_set_bar(sc, 7, 0, 0, 0, 0); tegra_pcib_set_bar(sc, 8, 0, 0, 0, 0); /* MSI BAR - clear. */ tegra_pcib_set_bar(sc, 9, 0, 0, 0, 0); return(0); } #ifdef TEGRA_PCIB_MSI_ENABLE static int tegra_pcib_attach_msi(device_t dev) { struct tegra_pcib_softc *sc; uint32_t reg; int i, rv; sc = device_get_softc(dev); sc->msi_page = (uintptr_t)kmem_alloc_contig(PAGE_SIZE, M_WAITOK, 0, BUS_SPACE_MAXADDR, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT); /* MSI BAR */ tegra_pcib_set_bar(sc, 9, vtophys(sc->msi_page), vtophys(sc->msi_page), PAGE_SIZE, 0); /* Disable and clear all interrupts. */ for (i = 0; i < AFI_MSI_REGS; i++) { AFI_WR4(sc, AFI_MSI_EN_VEC(i), 0); AFI_WR4(sc, AFI_MSI_VEC(i), 0xFFFFFFFF); } rv = bus_setup_intr(dev, sc->msi_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, tegra_pcib_msi_intr, NULL, sc, &sc->msi_intr_cookie); if (rv != 0) { device_printf(dev, "cannot setup MSI interrupt handler\n"); rv = ENXIO; goto out; } if (tegra_pcib_msi_attach(sc) != 0) { device_printf(dev, "WARNING: unable to attach PIC\n"); tegra_pcib_msi_detach(sc); goto out; } /* Unmask MSI interrupt. */ reg = AFI_RD4(sc, AFI_INTR_MASK); reg |= AFI_INTR_MASK_MSI_MASK; AFI_WR4(sc, AFI_INTR_MASK, reg); out: return (rv); } #endif static int tegra_pcib_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) { device_set_desc(dev, "Nvidia Integrated PCI/PCI-E Controller"); return (BUS_PROBE_DEFAULT); } return (ENXIO); } static int tegra_pcib_attach(device_t dev) { struct tegra_pcib_softc *sc; phandle_t node; int rv; int rid; struct tegra_pcib_port *port; int i; sc = device_get_softc(dev); sc->dev = dev; mtx_init(&sc->mtx, "msi_mtx", NULL, MTX_DEF); node = ofw_bus_get_node(dev); sc->soc = (struct pcie_soc *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; rv = tegra_pcib_parse_fdt_resources(sc, node); if (rv != 0) { device_printf(dev, "Cannot get FDT resources\n"); return (rv); } /* Allocate bus_space resources. */ rid = 0; sc->pads_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->pads_mem_res == NULL) { device_printf(dev, "Cannot allocate PADS register\n"); rv = ENXIO; goto out; } /* * XXX - FIXME * tag for config space is not filled when RF_ALLOCATED flag is used. */ sc->bus_tag = rman_get_bustag(sc->pads_mem_res); rid = 1; sc->afi_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->afi_mem_res == NULL) { device_printf(dev, "Cannot allocate AFI register\n"); rv = ENXIO; goto out; } rid = 2; sc->cfg_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ALLOCATED); if (sc->cfg_mem_res == NULL) { device_printf(dev, "Cannot allocate config space memory\n"); rv = ENXIO; goto out; } sc->cfg_base_addr = rman_get_start(sc->cfg_mem_res); /* Map RP slots */ for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { if (sc->ports[i] == NULL) continue; port = sc->ports[i]; rv = bus_space_map(sc->bus_tag, port->rp_base_addr, port->rp_size, 0, &port->cfg_handle); if (rv != 0) { device_printf(sc->dev, "Cannot allocate memory for " "port: %d\n", i); rv = ENXIO; goto out; } } /* * Get PCI interrupt */ rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | RF_SHAREABLE); if (sc->irq_res == NULL) { device_printf(dev, "Cannot allocate IRQ resources\n"); rv = ENXIO; goto out; } rid = 1; sc->msi_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->irq_res == NULL) { device_printf(dev, "Cannot allocate MSI IRQ resources\n"); rv = ENXIO; goto out; } sc->ofw_pci.sc_range_mask = 0x3; rv = ofw_pcib_init(dev); if (rv != 0) goto out; rv = tegra_pcib_decode_ranges(sc, sc->ofw_pci.sc_range, sc->ofw_pci.sc_nrange); if (rv != 0) goto out; if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_BIO | INTR_MPSAFE, tegra_pci_intr, NULL, sc, &sc->intr_cookie)) { device_printf(dev, "cannot setup interrupt handler\n"); rv = ENXIO; goto out; } /* * Enable PCIE device. */ rv = tegra_pcib_enable(sc); if (rv != 0) goto out; for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) { if (sc->ports[i] == NULL) continue; if (sc->ports[i]->enabled) tegra_pcib_port_enable(sc, i); else tegra_pcib_port_disable(sc, i); } #ifdef TEGRA_PCIB_MSI_ENABLE rv = tegra_pcib_attach_msi(dev); if (rv != 0) goto out; #endif device_add_child(dev, "pci", -1); return (bus_generic_attach(dev)); out: return (rv); } static device_method_t tegra_pcib_methods[] = { /* Device interface */ DEVMETHOD(device_probe, tegra_pcib_probe), DEVMETHOD(device_attach, tegra_pcib_attach), /* Bus interface */ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), /* pcib interface */ DEVMETHOD(pcib_maxslots, tegra_pcib_maxslots), DEVMETHOD(pcib_read_config, tegra_pcib_read_config), DEVMETHOD(pcib_write_config, tegra_pcib_write_config), DEVMETHOD(pcib_route_interrupt, tegra_pcib_route_interrupt), DEVMETHOD(pcib_alloc_msi, tegra_pcib_alloc_msi), DEVMETHOD(pcib_release_msi, tegra_pcib_release_msi), DEVMETHOD(pcib_map_msi, tegra_pcib_map_msi), DEVMETHOD(pcib_request_feature, pcib_request_feature_allow), #ifdef TEGRA_PCIB_MSI_ENABLE /* MSI/MSI-X */ DEVMETHOD(msi_alloc_msi, tegra_pcib_msi_alloc_msi), DEVMETHOD(msi_release_msi, tegra_pcib_msi_release_msi), DEVMETHOD(msi_map_msi, tegra_pcib_msi_map_msi), /* Interrupt controller interface */ DEVMETHOD(pic_disable_intr, tegra_pcib_msi_disable_intr), DEVMETHOD(pic_enable_intr, tegra_pcib_msi_enable_intr), DEVMETHOD(pic_setup_intr, tegra_pcib_msi_setup_intr), DEVMETHOD(pic_teardown_intr, tegra_pcib_msi_teardown_intr), DEVMETHOD(pic_post_filter, tegra_pcib_msi_post_filter), DEVMETHOD(pic_post_ithread, tegra_pcib_msi_post_ithread), DEVMETHOD(pic_pre_ithread, tegra_pcib_msi_pre_ithread), #endif /* OFW bus interface */ DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), DEVMETHOD_END }; DEFINE_CLASS_1(pcib, tegra_pcib_driver, tegra_pcib_methods, sizeof(struct tegra_pcib_softc), ofw_pcib_driver); DRIVER_MODULE(tegra_pcib, simplebus, tegra_pcib_driver, NULL, NULL); diff --git a/sys/arm/nvidia/tegra_usbphy.c b/sys/arm/nvidia/tegra_usbphy.c index 2499a568fe4c..eeaca9fcc07c 100644 --- a/sys/arm/nvidia/tegra_usbphy.c +++ b/sys/arm/nvidia/tegra_usbphy.c @@ -1,848 +1,848 @@ /*- * Copyright (c) 2016 Michal Meloun * All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ #include /* * USB phy driver for Tegra SoCs. */ #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include "phynode_if.h" #define CTRL_ICUSB_CTRL 0x15c #define ICUSB_CTR_IC_ENB1 (1 << 3) #define CTRL_USB_USBMODE 0x1f8 #define USB_USBMODE_MASK (3 << 0) #define USB_USBMODE_HOST (3 << 0) #define USB_USBMODE_DEVICE (2 << 0) #define CTRL_USB_HOSTPC1_DEVLC 0x1b4 #define USB_HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29) #define USB_HOSTPC1_DEVLC_STS (1 << 28) #define USB_HOSTPC1_DEVLC_PHCD (1 << 22) #define IF_USB_SUSP_CTRL 0x400 #define FAST_WAKEUP_RESP (1 << 26) #define UTMIP_SUSPL1_SET (1 << 25) #define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16) #define USB_SUSP_SET (1 << 14) #define UTMIP_PHY_ENB (1 << 12) #define UTMIP_RESET (1 << 11) #define USB_SUSP_POL (1 << 10) #define USB_PHY_CLK_VALID_INT_ENB (1 << 9) #define USB_PHY_CLK_VALID_INT_STS (1 << 8) #define USB_PHY_CLK_VALID (1 << 7) #define USB_CLKEN (1 << 6) #define USB_SUSP_CLR (1 << 5) #define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) #define USB_WAKE_ON_CNNT_EN_DEV (1 << 3) #define USB_WAKE_ON_RESUME_EN (1 << 2) #define USB_WAKEUP_INT_ENB (1 << 1) #define USB_WAKEUP_INT_STS (1 << 0) #define IF_USB_PHY_VBUS_SENSORS 0x404 #define B_SESS_END_SW_VALUE (1 << 4) #define B_SESS_END_SW_EN (1 << 3) #define UTMIP_XCVR_CFG0 0x808 #define UTMIP_XCVR_HSSLEW_MSB(x) ((((x) & 0x1fc) >> 2) << 25) #define UTMIP_XCVR_SETUP_MSB(x) ((((x) & 0x70) >> 4) << 22) #define UTMIP_XCVR_LSBIAS_SEL (1 << 21) #define UTMIP_XCVR_DISCON_METHOD (1 << 20) #define UTMIP_FORCE_PDZI_POWERUP (1 << 19) #define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18) #define UTMIP_FORCE_PD2_POWERUP (1 << 17) #define UTMIP_FORCE_PD2_POWERDOWN (1 << 16) #define UTMIP_FORCE_PD_POWERUP (1 << 15) #define UTMIP_FORCE_PD_POWERDOWN (1 << 14) #define UTMIP_XCVR_TERMEN (1 << 13) #define UTMIP_XCVR_HSLOOPBACK (1 << 12) #define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10) #define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8) #define UTMIP_XCVR_FSSLEW(x) (((x) & 0x3) << 6) #define UTMIP_XCVR_HSSLEW(x) (((x) & 0x3) << 4) #define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0) #define UTMIP_BIAS_CFG0 0x80C #define UTMIP_IDDIG_C_VAL (1 << 30) #define UTMIP_IDDIG_C_SEL (1 << 29) #define UTMIP_IDDIG_B_VAL (1 << 28) #define UTMIP_IDDIG_B_SEL (1 << 27) #define UTMIP_IDDIG_A_VAL (1 << 26) #define UTMIP_IDDIG_A_SEL (1 << 25) #define UTMIP_HSDISCON_LEVEL_MSB(x) ((((x) & 0x4) >> 2) << 24) #define UTMIP_IDPD_VAL (1 << 23) #define UTMIP_IDPD_SEL (1 << 22) #define UTMIP_IDDIG_VAL (1 << 21) #define UTMIP_IDDIG_SEL (1 << 20) #define UTMIP_GPI_VAL (1 << 19) #define UTMIP_GPI_SEL (1 << 18) #define UTMIP_ACTIVE_TERM_OFFSET(x) (((x) & 0x7) << 15) #define UTMIP_ACTIVE_PULLUP_OFFSET(x) (((x) & 0x7) << 12) #define UTMIP_OTGPD (1 << 11) #define UTMIP_BIASPD (1 << 10) #define UTMIP_VBUS_LEVEL_LEVEL(x) (((x) & 0x3) << 8) #define UTMIP_SESS_LEVEL_LEVEL(x) (((x) & 0x3) << 6) #define UTMIP_HSCHIRP_LEVEL(x) (((x) & 0x3) << 4) #define UTMIP_HSDISCON_LEVEL(x) (((x) & 0x3) << 2) #define UTMIP_HSSQUELCH_LEVEL(x) (((x) & 0x3) << 0) #define UTMIP_HSRX_CFG0 0x810 #define UTMIP_KEEP_PATT_ON_ACTIVE(x) (((x) & 0x3) << 30) #define UTMIP_ALLOW_CONSEC_UPDN (1 << 29) #define UTMIP_REALIGN_ON_NEW_PKT (1 << 28) #define UTMIP_PCOUNT_UPDN_DIV(x) (((x) & 0xf) << 24) #define UTMIP_SQUELCH_EOP_DLY(x) (((x) & 0x7) << 21) #define UTMIP_NO_STRIPPING (1 << 20) #define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15) #define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10) #define UTMIP_ELASTIC_OVERRUN_DISABLE (1 << 9) #define UTMIP_ELASTIC_UNDERRUN_DISABLE (1 << 8) #define UTMIP_PASS_CHIRP (1 << 7) #define UTMIP_PASS_FEEDBACK (1 << 6) #define UTMIP_PCOUNT_INERTIA(x) (((x) & 0x3) << 4) #define UTMIP_PHASE_ADJUST(x) (((x) & 0x3) << 2) #define UTMIP_THREE_SYNCBITS (1 << 1) #define UTMIP_USE4SYNC_TRAN (1 << 0) #define UTMIP_HSRX_CFG1 0x814 #define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1F) << 1) #define UTMIP_HS_ALLOW_KEEP_ALIVE (1 << 0) #define UTMIP_TX_CFG0 0x820 #define UTMIP_FS_PREAMBLE_J (1 << 19) #define UTMIP_FS_POSTAMBLE_OUTPUT_ENABLE (1 << 18) #define UTMIP_FS_PREAMBLE_OUTPUT_ENABLE (1 << 17) #define UTMIP_FSLS_ALLOW_SOP_TX_STUFF_ERR (1 << 16) #define UTMIP_HS_READY_WAIT_FOR_VALID (1 << 15) #define UTMIP_HS_TX_IPG_DLY(x) (((x) & 0x1f) << 10) #define UTMIP_HS_DISCON_EOP_ONLY (1 << 9) #define UTMIP_HS_DISCON_DISABLE (1 << 8) #define UTMIP_HS_POSTAMBLE_OUTPUT_ENABLE (1 << 7) #define UTMIP_HS_PREAMBLE_OUTPUT_ENABLE (1 << 6) #define UTMIP_SIE_RESUME_ON_LINESTATE (1 << 5) #define UTMIP_SOF_ON_NO_STUFF (1 << 4) #define UTMIP_SOF_ON_NO_ENCODE (1 << 3) #define UTMIP_NO_STUFFING (1 << 2) #define UTMIP_NO_ENCODING (1 << 1) #define UTMIP_NO_SYNC_NO_EOP (1 << 0) #define UTMIP_MISC_CFG0 0x824 #define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27) #define UTMIP_DPDM_OBSERVE (1 << 26) #define UTMIP_KEEP_XCVR_PD_ON_SOFT_DISCON (1 << 25) #define UTMIP_ALLOW_LS_ON_SOFT_DISCON (1 << 24) #define UTMIP_FORCE_FS_DISABLE_ON_DEV_CHIRP (1 << 23) #define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22) #define UTMIP_LS_TO_FS_SKIP_4MS (1 << 21) #define UTMIP_INJECT_ERROR_TYPE(x) (((x) & 0x3) << 19) #define UTMIP_FORCE_HS_CLOCK_ON (1 << 18) #define UTMIP_DISABLE_HS_TERM (1 << 17) #define UTMIP_FORCE_HS_TERM (1 << 16) #define UTMIP_DISABLE_PULLUP_DP (1 << 15) #define UTMIP_DISABLE_PULLUP_DM (1 << 14) #define UTMIP_DISABLE_PULLDN_DP (1 << 13) #define UTMIP_DISABLE_PULLDN_DM (1 << 12) #define UTMIP_FORCE_PULLUP_DP (1 << 11) #define UTMIP_FORCE_PULLUP_DM (1 << 10) #define UTMIP_FORCE_PULLDN_DP (1 << 9) #define UTMIP_FORCE_PULLDN_DM (1 << 8) #define UTMIP_STABLE_COUNT(x) (((x) & 0x7) << 5) #define UTMIP_STABLE_ALL (1 << 4) #define UTMIP_NO_FREE_ON_SUSPEND (1 << 3) #define UTMIP_NEVER_FREE_RUNNING_TERMS (1 << 2) #define UTMIP_ALWAYS_FREE_RUNNING_TERMS (1 << 1) #define UTMIP_COMB_TERMS (1 << 0) #define UTMIP_MISC_CFG1 0x828 #define UTMIP_PHY_XTAL_CLOCKEN (1 << 30) #define UTMIP_DEBOUNCE_CFG0 0x82C #define UTMIP_BIAS_DEBOUNCE_B(x) (((x) & 0xffff) << 16) #define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0) #define UTMIP_BAT_CHRG_CFG0 0x830 #define UTMIP_CHRG_DEBOUNCE_TIMESCALE(x) (((x) & 0x1f) << 8) #define UTMIP_OP_I_SRC_ENG (1 << 5) #define UTMIP_ON_SRC_ENG (1 << 4) #define UTMIP_OP_SRC_ENG (1 << 3) #define UTMIP_ON_SINK_ENG (1 << 2) #define UTMIP_OP_SINK_ENG (1 << 1) #define UTMIP_PD_CHRG (1 << 0) #define UTMIP_SPARE_CFG0 0x834 #define FUSE_HS_IREF_CAP_CFG (1 << 7) #define FUSE_HS_SQUELCH_LEVEL (1 << 6) #define FUSE_SPARE (1 << 5) #define FUSE_TERM_RANGE_ADJ_SEL (1 << 4) #define FUSE_SETUP_SEL (1 << 3) #define HS_RX_LATE_SQUELCH (1 << 2) #define HS_RX_FLUSH_ALAP (1 << 1) #define HS_RX_IPG_ERROR_ENABLE (1 << 0) #define UTMIP_XCVR_CFG1 0x838 #define UTMIP_XCVR_RPU_RANGE_ADJ(x) (((x) & 0x3) << 26) #define UTMIP_XCVR_HS_IREF_CAP(x) (((x) & 0x3) << 24) #define UTMIP_XCVR_SPARE(x) (((x) & 0x3) << 22) #define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18) #define UTMIP_RCTRL_SW_SET (1 << 17) #define UTMIP_RCTRL_SW_VAL(x) (((x) & 0x1f) << 12) #define UTMIP_TCTRL_SW_SET (1 << 11) #define UTMIP_TCTRL_SW_VAL(x) (((x) & 0x1f) << 6) #define UTMIP_FORCE_PDDR_POWERUP (1 << 5) #define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4) #define UTMIP_FORCE_PDCHRP_POWERUP (1 << 3) #define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2) #define UTMIP_FORCE_PDDISC_POWERUP (1 << 1) #define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0) #define UTMIP_BIAS_CFG1 0x83c #define UTMIP_BIAS_DEBOUNCE_TIMESCALE(x) (((x) & 0x3f) << 8) #define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3) #define UTMIP_VBUS_WAKEUP_POWERDOWN (1 << 2) #define UTMIP_FORCE_PDTRK_POWERUP (1 << 1) #define UTMIP_FORCE_PDTRK_POWERDOWN (1 << 0) static int usbpby_enable_cnt; enum usb_ifc_type { USB_IFC_TYPE_UNKNOWN = 0, USB_IFC_TYPE_UTMI, USB_IFC_TYPE_ULPI }; enum usb_dr_mode { USB_DR_MODE_UNKNOWN = 0, USB_DR_MODE_DEVICE, USB_DR_MODE_HOST, USB_DR_MODE_OTG }; struct usbphy_softc { device_t dev; struct resource *mem_res; struct resource *pads_res; clk_t clk_reg; clk_t clk_pads; clk_t clk_pllu; regulator_t supply_vbus; hwreset_t reset_usb; hwreset_t reset_pads; enum usb_ifc_type ifc_type; enum usb_dr_mode dr_mode; bool have_utmi_regs; /* UTMI params */ int hssync_start_delay; int elastic_limit; int idle_wait_delay; int term_range_adj; int xcvr_lsfslew; int xcvr_lsrslew; int xcvr_hsslew; int hssquelch_level; int hsdiscon_level; int xcvr_setup; int xcvr_setup_use_fuses; }; static struct ofw_compat_data compat_data[] = { {"nvidia,tegra210-usb-phy", 1}, {"nvidia,tegra30-usb-phy", 1}, {NULL, 0}, }; /* Phy controller class and methods. */ static int usbphy_phy_enable(struct phynode *phy, bool enable); static phynode_method_t usbphy_phynode_methods[] = { PHYNODEMETHOD(phynode_enable, usbphy_phy_enable), PHYNODEMETHOD_END }; DEFINE_CLASS_1(usbphy_phynode, usbphy_phynode_class, usbphy_phynode_methods, 0, phynode_class); #define RD4(sc, offs) \ bus_read_4(sc->mem_res, offs) #define WR4(sc, offs, val) \ bus_write_4(sc->mem_res, offs, val) static int reg_wait(struct usbphy_softc *sc, uint32_t reg, uint32_t mask, uint32_t val) { int i; for (i = 0; i < 1000; i++) { if ((RD4(sc, reg) & mask) == val) return (0); DELAY(10); } return (ETIMEDOUT); } static int usbphy_utmi_phy_clk(struct usbphy_softc *sc, bool enable) { uint32_t val; int rv; val = RD4(sc, CTRL_USB_HOSTPC1_DEVLC); if (enable) val &= ~USB_HOSTPC1_DEVLC_PHCD; else val |= USB_HOSTPC1_DEVLC_PHCD; WR4(sc, CTRL_USB_HOSTPC1_DEVLC, val); rv = reg_wait(sc, IF_USB_SUSP_CTRL, USB_PHY_CLK_VALID, enable ? USB_PHY_CLK_VALID: 0); if (rv != 0) { device_printf(sc->dev, "USB phy clock timeout.\n"); return (ETIMEDOUT); } return (0); } static int usbphy_utmi_enable(struct usbphy_softc *sc) { int rv; uint32_t val; /* Reset phy */ val = RD4(sc, IF_USB_SUSP_CTRL); val |= UTMIP_RESET; WR4(sc, IF_USB_SUSP_CTRL, val); val = RD4(sc, UTMIP_TX_CFG0); val |= UTMIP_FS_PREAMBLE_J; WR4(sc, UTMIP_TX_CFG0, val); val = RD4(sc, UTMIP_HSRX_CFG0); val &= ~UTMIP_IDLE_WAIT(~0); val &= ~UTMIP_ELASTIC_LIMIT(~0); val |= UTMIP_IDLE_WAIT(sc->idle_wait_delay); val |= UTMIP_ELASTIC_LIMIT(sc->elastic_limit); WR4(sc, UTMIP_HSRX_CFG0, val); val = RD4(sc, UTMIP_HSRX_CFG1); val &= ~UTMIP_HS_SYNC_START_DLY(~0); val |= UTMIP_HS_SYNC_START_DLY(sc->hssync_start_delay); WR4(sc, UTMIP_HSRX_CFG1, val); val = RD4(sc, UTMIP_DEBOUNCE_CFG0); val &= ~UTMIP_BIAS_DEBOUNCE_A(~0); val |= UTMIP_BIAS_DEBOUNCE_A(0x7530); /* For 12MHz */ WR4(sc, UTMIP_DEBOUNCE_CFG0, val); val = RD4(sc, UTMIP_MISC_CFG0); val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE; WR4(sc, UTMIP_MISC_CFG0, val); if (sc->dr_mode == USB_DR_MODE_DEVICE) { val = RD4(sc,IF_USB_SUSP_CTRL); val &= ~USB_WAKE_ON_CNNT_EN_DEV; val &= ~USB_WAKE_ON_DISCON_EN_DEV; WR4(sc, IF_USB_SUSP_CTRL, val); val = RD4(sc, UTMIP_BAT_CHRG_CFG0); val &= ~UTMIP_PD_CHRG; WR4(sc, UTMIP_BAT_CHRG_CFG0, val); } else { val = RD4(sc, UTMIP_BAT_CHRG_CFG0); val |= UTMIP_PD_CHRG; WR4(sc, UTMIP_BAT_CHRG_CFG0, val); } usbpby_enable_cnt++; if (usbpby_enable_cnt == 1) { rv = hwreset_deassert(sc->reset_pads); if (rv != 0) { device_printf(sc->dev, "Cannot unreset 'utmi-pads' reset\n"); return (rv); } rv = clk_enable(sc->clk_pads); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'utmi-pads' clock\n"); return (rv); } val = bus_read_4(sc->pads_res, UTMIP_BIAS_CFG0); val &= ~UTMIP_OTGPD; val &= ~UTMIP_BIASPD; val &= ~UTMIP_HSSQUELCH_LEVEL(~0); val &= ~UTMIP_HSDISCON_LEVEL(~0); val &= ~UTMIP_HSDISCON_LEVEL_MSB(~0); val |= UTMIP_HSSQUELCH_LEVEL(sc->hssquelch_level); val |= UTMIP_HSDISCON_LEVEL(sc->hsdiscon_level); val |= UTMIP_HSDISCON_LEVEL_MSB(sc->hsdiscon_level); bus_write_4(sc->pads_res, UTMIP_BIAS_CFG0, val); rv = clk_disable(sc->clk_pads); if (rv != 0) { device_printf(sc->dev, "Cannot disable 'utmi-pads' clock\n"); return (rv); } } val = RD4(sc, UTMIP_XCVR_CFG0); val &= ~UTMIP_FORCE_PD_POWERDOWN; val &= ~UTMIP_FORCE_PD2_POWERDOWN ; val &= ~UTMIP_FORCE_PDZI_POWERDOWN; val &= ~UTMIP_XCVR_LSBIAS_SEL; val &= ~UTMIP_XCVR_LSFSLEW(~0); val &= ~UTMIP_XCVR_LSRSLEW(~0); val &= ~UTMIP_XCVR_HSSLEW(~0); val &= ~UTMIP_XCVR_HSSLEW_MSB(~0); val |= UTMIP_XCVR_LSFSLEW(sc->xcvr_lsfslew); val |= UTMIP_XCVR_LSRSLEW(sc->xcvr_lsrslew); val |= UTMIP_XCVR_HSSLEW(sc->xcvr_hsslew); val |= UTMIP_XCVR_HSSLEW_MSB(sc->xcvr_hsslew); if (!sc->xcvr_setup_use_fuses) { val &= ~UTMIP_XCVR_SETUP(~0); val &= ~UTMIP_XCVR_SETUP_MSB(~0); val |= UTMIP_XCVR_SETUP(sc->xcvr_setup); val |= UTMIP_XCVR_SETUP_MSB(sc->xcvr_setup); } WR4(sc, UTMIP_XCVR_CFG0, val); val = RD4(sc, UTMIP_XCVR_CFG1); val &= ~UTMIP_FORCE_PDDISC_POWERDOWN; val &= ~UTMIP_FORCE_PDCHRP_POWERDOWN; val &= ~UTMIP_FORCE_PDDR_POWERDOWN; val &= ~UTMIP_XCVR_TERM_RANGE_ADJ(~0); val |= UTMIP_XCVR_TERM_RANGE_ADJ(sc->term_range_adj); WR4(sc, UTMIP_XCVR_CFG1, val); val = RD4(sc, UTMIP_BIAS_CFG1); val &= ~UTMIP_BIAS_PDTRK_COUNT(~0); val |= UTMIP_BIAS_PDTRK_COUNT(0x5); WR4(sc, UTMIP_BIAS_CFG1, val); val = RD4(sc, UTMIP_SPARE_CFG0); if (sc->xcvr_setup_use_fuses) val |= FUSE_SETUP_SEL; else val &= ~FUSE_SETUP_SEL; WR4(sc, UTMIP_SPARE_CFG0, val); val = RD4(sc, IF_USB_SUSP_CTRL); val |= UTMIP_PHY_ENB; WR4(sc, IF_USB_SUSP_CTRL, val); val = RD4(sc, IF_USB_SUSP_CTRL); val &= ~UTMIP_RESET; WR4(sc, IF_USB_SUSP_CTRL, val); usbphy_utmi_phy_clk(sc, true); val = RD4(sc, CTRL_USB_USBMODE); val &= ~USB_USBMODE_MASK; if (sc->dr_mode == USB_DR_MODE_HOST) val |= USB_USBMODE_HOST; else val |= USB_USBMODE_DEVICE; WR4(sc, CTRL_USB_USBMODE, val); val = RD4(sc, CTRL_USB_HOSTPC1_DEVLC); val &= ~USB_HOSTPC1_DEVLC_PTS(~0); val |= USB_HOSTPC1_DEVLC_PTS(0); WR4(sc, CTRL_USB_HOSTPC1_DEVLC, val); return (0); } static int usbphy_utmi_disable(struct usbphy_softc *sc) { int rv; uint32_t val; usbphy_utmi_phy_clk(sc, false); if (sc->dr_mode == USB_DR_MODE_DEVICE) { val = RD4(sc, IF_USB_SUSP_CTRL); val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0); val |= USB_WAKE_ON_CNNT_EN_DEV; val |= USB_WAKEUP_DEBOUNCE_COUNT(5); WR4(sc, IF_USB_SUSP_CTRL, val); } val = RD4(sc, IF_USB_SUSP_CTRL); val |= UTMIP_RESET; WR4(sc, IF_USB_SUSP_CTRL, val); val = RD4(sc, UTMIP_BAT_CHRG_CFG0); val |= UTMIP_PD_CHRG; WR4(sc, UTMIP_BAT_CHRG_CFG0, val); val = RD4(sc, UTMIP_XCVR_CFG0); val |= UTMIP_FORCE_PD_POWERDOWN; val |= UTMIP_FORCE_PD2_POWERDOWN; val |= UTMIP_FORCE_PDZI_POWERDOWN; WR4(sc, UTMIP_XCVR_CFG0, val); val = RD4(sc, UTMIP_XCVR_CFG1); val |= UTMIP_FORCE_PDDISC_POWERDOWN; val |= UTMIP_FORCE_PDCHRP_POWERDOWN; val |= UTMIP_FORCE_PDDR_POWERDOWN; WR4(sc, UTMIP_XCVR_CFG1, val); usbpby_enable_cnt--; if (usbpby_enable_cnt <= 0) { rv = clk_enable(sc->clk_pads); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'utmi-pads' clock\n"); return (rv); } val =bus_read_4(sc->pads_res, UTMIP_BIAS_CFG0); val |= UTMIP_OTGPD; val |= UTMIP_BIASPD; bus_write_4(sc->pads_res, UTMIP_BIAS_CFG0, val); rv = clk_disable(sc->clk_pads); if (rv != 0) { device_printf(sc->dev, "Cannot disable 'utmi-pads' clock\n"); return (rv); } } return (0); } static int usbphy_phy_enable(struct phynode *phy, bool enable) { device_t dev; struct usbphy_softc *sc; int rv = 0; dev = phynode_get_device(phy); sc = device_get_softc(dev); if (sc->ifc_type != USB_IFC_TYPE_UTMI) { device_printf(sc->dev, "Only UTMI interface is supported.\n"); return (ENXIO); } if (enable) rv = usbphy_utmi_enable(sc); else rv = usbphy_utmi_disable(sc); return (rv); } static enum usb_ifc_type usb_get_ifc_mode(device_t dev, phandle_t node, char *name) { char *tmpstr; int rv; enum usb_ifc_type ret; rv = OF_getprop_alloc(node, name, (void **)&tmpstr); if (rv <= 0) return (USB_IFC_TYPE_UNKNOWN); ret = USB_IFC_TYPE_UNKNOWN; if (strcmp(tmpstr, "utmi") == 0) ret = USB_IFC_TYPE_UTMI; else if (strcmp(tmpstr, "ulpi") == 0) ret = USB_IFC_TYPE_ULPI; else device_printf(dev, "Unsupported phy type: %s\n", tmpstr); OF_prop_free(tmpstr); return (ret); } static enum usb_dr_mode usb_get_dr_mode(device_t dev, phandle_t node, char *name) { char *tmpstr; int rv; enum usb_dr_mode ret; rv = OF_getprop_alloc(node, name, (void **)&tmpstr); if (rv <= 0) return (USB_DR_MODE_UNKNOWN); ret = USB_DR_MODE_UNKNOWN; if (strcmp(tmpstr, "device") == 0) ret = USB_DR_MODE_DEVICE; else if (strcmp(tmpstr, "host") == 0) ret = USB_DR_MODE_HOST; else if (strcmp(tmpstr, "otg") == 0) ret = USB_DR_MODE_OTG; else device_printf(dev, "Unknown dr mode: %s\n", tmpstr); OF_prop_free(tmpstr); return (ret); } static int usbphy_utmi_read_params(struct usbphy_softc *sc, phandle_t node) { int rv; rv = OF_getencprop(node, "nvidia,hssync-start-delay", &sc->hssync_start_delay, sizeof (sc->hssync_start_delay)); if (rv <= 0) return (ENXIO); rv = OF_getencprop(node, "nvidia,elastic-limit", &sc->elastic_limit, sizeof (sc->elastic_limit)); if (rv <= 0) return (ENXIO); rv = OF_getencprop(node, "nvidia,idle-wait-delay", &sc->idle_wait_delay, sizeof (sc->idle_wait_delay)); if (rv <= 0) return (ENXIO); rv = OF_getencprop(node, "nvidia,term-range-adj", &sc->term_range_adj, sizeof (sc->term_range_adj)); if (rv <= 0) return (ENXIO); rv = OF_getencprop(node, "nvidia,xcvr-lsfslew", &sc->xcvr_lsfslew, sizeof (sc->xcvr_lsfslew)); if (rv <= 0) return (ENXIO); rv = OF_getencprop(node, "nvidia,xcvr-lsrslew", &sc->xcvr_lsrslew, sizeof (sc->xcvr_lsrslew)); if (rv <= 0) return (ENXIO); rv = OF_getencprop(node, "nvidia,xcvr-hsslew", &sc->xcvr_hsslew, sizeof (sc->xcvr_hsslew)); if (rv <= 0) return (ENXIO); rv = OF_getencprop(node, "nvidia,hssquelch-level", &sc->hssquelch_level, sizeof (sc->hssquelch_level)); if (rv <= 0) return (ENXIO); rv = OF_getencprop(node, "nvidia,hsdiscon-level", &sc->hsdiscon_level, sizeof (sc->hsdiscon_level)); if (rv <= 0) return (ENXIO); rv = OF_getproplen(node, "nvidia,xcvr-setup-use-fuses"); if (rv >= 1) { sc->xcvr_setup_use_fuses = 1; } else { rv = OF_getencprop(node, "nvidia,xcvr-setup", &sc->xcvr_setup, sizeof (sc->xcvr_setup)); if (rv <= 0) return (ENXIO); } return (0); } static int usbphy_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "Tegra USB phy"); return (BUS_PROBE_DEFAULT); } static int usbphy_attach(device_t dev) { struct usbphy_softc *sc; int rid, rv; phandle_t node; struct phynode *phynode; struct phynode_init_def phy_init; sc = device_get_softc(dev); sc->dev = dev; rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE | RF_SHAREABLE); if (sc->mem_res == NULL) { device_printf(dev, "Cannot allocate memory resources\n"); return (ENXIO); } rid = 1; sc->pads_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE | RF_SHAREABLE); if (sc->mem_res == NULL) { device_printf(dev, "Cannot allocate memory resources\n"); return (ENXIO); } node = ofw_bus_get_node(dev); rv = hwreset_get_by_ofw_name(sc->dev, 0, "usb", &sc->reset_usb); if (rv != 0) { device_printf(dev, "Cannot get 'usb' reset\n"); return (ENXIO); } rv = hwreset_get_by_ofw_name(sc->dev, 0, "utmi-pads", &sc->reset_pads); if (rv != 0) { device_printf(dev, "Cannot get 'utmi-pads' reset\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, 0, "reg", &sc->clk_reg); if (rv != 0) { device_printf(sc->dev, "Cannot get 'reg' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, 0, "pll_u", &sc->clk_pllu); if (rv != 0) { device_printf(sc->dev, "Cannot get 'pll_u' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, 0, "utmi-pads", &sc->clk_pads); if (rv != 0) { device_printf(sc->dev, "Cannot get 'utmi-pads' clock\n"); return (ENXIO); } rv = hwreset_deassert(sc->reset_usb); if (rv != 0) { device_printf(dev, "Cannot unreset 'usb' reset\n"); return (ENXIO); } rv = clk_enable(sc->clk_pllu); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'pllu' clock\n"); return (ENXIO); } rv = clk_enable(sc->clk_reg); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'reg' clock\n"); return (ENXIO); } if (OF_hasprop(node, "nvidia,has-utmi-pad-registers")) sc->have_utmi_regs = true; sc->dr_mode = usb_get_dr_mode(dev, node, "dr_mode"); if (sc->dr_mode == USB_DR_MODE_UNKNOWN) sc->dr_mode = USB_DR_MODE_HOST; sc->ifc_type = usb_get_ifc_mode(dev, node, "phy_type"); /* We supports only utmi phy mode for now .... */ if (sc->ifc_type != USB_IFC_TYPE_UTMI) { device_printf(dev, "Unsupported phy type\n"); return (ENXIO); } rv = usbphy_utmi_read_params(sc, node); if (rv < 0) return rv; if (OF_hasprop(node, "vbus-supply")) { rv = regulator_get_by_ofw_property(sc->dev, 0, "vbus-supply", &sc->supply_vbus); if (rv != 0) { device_printf(sc->dev, "Cannot get \"vbus\" regulator\n"); return (ENXIO); } rv = regulator_enable(sc->supply_vbus); if (rv != 0) { device_printf(sc->dev, "Cannot enable \"vbus\" regulator\n"); return (rv); } } /* Create and register phy. */ bzero(&phy_init, sizeof(phy_init)); phy_init.id = 1; phy_init.ofw_node = node; phynode = phynode_create(dev, &usbphy_phynode_class, &phy_init); if (phynode == NULL) { device_printf(sc->dev, "Cannot create phy\n"); return (ENXIO); } if (phynode_register(phynode) == NULL) { device_printf(sc->dev, "Cannot create phy\n"); return (ENXIO); } return (0); } static int usbphy_detach(device_t dev) { /* This device is always present. */ return (EBUSY); } static device_method_t tegra_usbphy_methods[] = { /* Device interface */ DEVMETHOD(device_probe, usbphy_probe), DEVMETHOD(device_attach, usbphy_attach), DEVMETHOD(device_detach, usbphy_detach), DEVMETHOD_END }; static DEFINE_CLASS_0(usbphy, tegra_usbphy_driver, tegra_usbphy_methods, sizeof(struct usbphy_softc)); EARLY_DRIVER_MODULE(tegra_usbphy, simplebus, tegra_usbphy_driver, NULL, NULL, 79); diff --git a/sys/arm/nvidia/tegra_xhci.c b/sys/arm/nvidia/tegra_xhci.c index 21ce4dc0540d..5bd7e6b7736e 100644 --- a/sys/arm/nvidia/tegra_xhci.c +++ b/sys/arm/nvidia/tegra_xhci.c @@ -1,1122 +1,1122 @@ /*- * Copyright (c) 2016 Michal Meloun * All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ #include /* * XHCI driver for Tegra SoCs. */ #include "opt_bus.h" #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #include #include #include #include #include #include "usbdevs.h" /* FPCI address space */ #define T_XUSB_CFG_0 0x000 #define T_XUSB_CFG_1 0x004 #define CFG_1_BUS_MASTER (1 << 2) #define CFG_1_MEMORY_SPACE (1 << 1) #define CFG_1_IO_SPACE (1 << 0) #define T_XUSB_CFG_2 0x008 #define T_XUSB_CFG_3 0x00C #define T_XUSB_CFG_4 0x010 #define CFG_4_BASE_ADDRESS(x) (((x) & 0x1FFFF) << 15) #define T_XUSB_CFG_5 0x014 #define T_XUSB_CFG_ARU_MAILBOX_CMD 0x0E4 #define ARU_MAILBOX_CMD_INT_EN (1U << 31) #define ARU_MAILBOX_CMD_DEST_XHCI (1 << 30) #define ARU_MAILBOX_CMD_DEST_SMI (1 << 29) #define ARU_MAILBOX_CMD_DEST_PME (1 << 28) #define ARU_MAILBOX_CMD_DEST_FALC (1 << 27) #define T_XUSB_CFG_ARU_MAILBOX_DATA_IN 0x0E8 #define ARU_MAILBOX_DATA_IN_DATA(x) (((x) & 0xFFFFFF) << 0) #define ARU_MAILBOX_DATA_IN_TYPE(x) (((x) & 0x0000FF) << 24) #define T_XUSB_CFG_ARU_MAILBOX_DATA_OUT 0x0EC #define ARU_MAILBOX_DATA_OUT_DATA(x) (((x) >> 0) & 0xFFFFFF) #define ARU_MAILBOX_DATA_OUT_TYPE(x) (((x) >> 24) & 0x0000FF) #define T_XUSB_CFG_ARU_MAILBOX_OWNER 0x0F0 #define ARU_MAILBOX_OWNER_SW 2 #define ARU_MAILBOX_OWNER_FW 1 #define ARU_MAILBOX_OWNER_NONE 0 #define XUSB_CFG_ARU_C11_CSBRANGE 0x41C /* ! UNDOCUMENTED ! */ #define ARU_C11_CSBRANGE_PAGE(x) ((x) >> 9) #define ARU_C11_CSBRANGE_ADDR(x) (0x800 + ((x) & 0x1FF)) #define XUSB_CFG_ARU_SMI_INTR 0x428 /* ! UNDOCUMENTED ! */ #define ARU_SMI_INTR_EN (1 << 3) #define ARU_SMI_INTR_FW_HANG (1 << 1) #define XUSB_CFG_ARU_RST 0x42C /* ! UNDOCUMENTED ! */ #define ARU_RST_RESET (1 << 0) #define XUSB_HOST_CONFIGURATION 0x180 #define CONFIGURATION_CLKEN_OVERRIDE (1U<< 31) #define CONFIGURATION_PW_NO_DEVSEL_ERR_CYA (1 << 19) #define CONFIGURATION_INITIATOR_READ_IDLE (1 << 18) #define CONFIGURATION_INITIATOR_WRITE_IDLE (1 << 17) #define CONFIGURATION_WDATA_LEAD_CYA (1 << 15) #define CONFIGURATION_WR_INTRLV_CYA (1 << 14) #define CONFIGURATION_TARGET_READ_IDLE (1 << 11) #define CONFIGURATION_TARGET_WRITE_IDLE (1 << 10) #define CONFIGURATION_MSI_VEC_EMPTY (1 << 9) #define CONFIGURATION_UFPCI_MSIAW (1 << 7) #define CONFIGURATION_UFPCI_PWPASSPW (1 << 6) #define CONFIGURATION_UFPCI_PASSPW (1 << 5) #define CONFIGURATION_UFPCI_PWPASSNPW (1 << 4) #define CONFIGURATION_DFPCI_PWPASSNPW (1 << 3) #define CONFIGURATION_DFPCI_RSPPASSPW (1 << 2) #define CONFIGURATION_DFPCI_PASSPW (1 << 1) #define CONFIGURATION_EN_FPCI (1 << 0) /* IPFS address space */ #define XUSB_HOST_FPCI_ERROR_MASKS 0x184 #define FPCI_ERROR_MASTER_ABORT (1 << 2) #define FPCI_ERRORI_DATA_ERROR (1 << 1) #define FPCI_ERROR_TARGET_ABORT (1 << 0) #define XUSB_HOST_INTR_MASK 0x188 #define INTR_IP_INT_MASK (1 << 16) #define INTR_MSI_MASK (1 << 8) #define INTR_INT_MASK (1 << 0) #define XUSB_HOST_CLKGATE_HYSTERESIS 0x1BC /* CSB Falcon CPU */ #define XUSB_FALCON_CPUCTL 0x100 #define CPUCTL_STOPPED (1 << 5) #define CPUCTL_HALTED (1 << 4) #define CPUCTL_HRESET (1 << 3) #define CPUCTL_SRESET (1 << 2) #define CPUCTL_STARTCPU (1 << 1) #define CPUCTL_IINVAL (1 << 0) #define XUSB_FALCON_BOOTVEC 0x104 #define XUSB_FALCON_DMACTL 0x10C #define XUSB_FALCON_IMFILLRNG1 0x154 #define IMFILLRNG1_TAG_HI(x) (((x) & 0xFFF) << 16) #define IMFILLRNG1_TAG_LO(x) (((x) & 0xFFF) << 0) #define XUSB_FALCON_IMFILLCTL 0x158 /* CSB mempool */ #define XUSB_CSB_MEMPOOL_APMAP 0x10181C #define APMAP_BOOTPATH (1U << 31) #define XUSB_CSB_MEMPOOL_ILOAD_ATTR 0x101A00 #define XUSB_CSB_MEMPOOL_ILOAD_BASE_LO 0x101A04 #define XUSB_CSB_MEMPOOL_ILOAD_BASE_HI 0x101A08 #define XUSB_CSB_MEMPOOL_L2IMEMOP_SIZE 0x101A10 #define L2IMEMOP_SIZE_OFFSET(x) (((x) & 0x3FF) << 8) #define L2IMEMOP_SIZE_SIZE(x) (((x) & 0x0FF) << 24) #define XUSB_CSB_MEMPOOL_L2IMEMOP_TRIG 0x101A14 #define L2IMEMOP_INVALIDATE_ALL (0x40 << 24) #define L2IMEMOP_LOAD_LOCKED_RESULT (0x11 << 24) #define XUSB_CSB_MEMPOOL_L2IMEMOP_RESULT 0x101A18 #define L2IMEMOP_RESULT_VLD (1U << 31) #define XUSB_CSB_IMEM_BLOCK_SIZE 256 #define TEGRA_XHCI_SS_HIGH_SPEED 120000000 #define TEGRA_XHCI_SS_LOW_SPEED 12000000 /* MBOX commands. */ #define MBOX_CMD_MSG_ENABLED 1 #define MBOX_CMD_INC_FALC_CLOCK 2 #define MBOX_CMD_DEC_FALC_CLOCK 3 #define MBOX_CMD_INC_SSPI_CLOCK 4 #define MBOX_CMD_DEC_SSPI_CLOCK 5 #define MBOX_CMD_SET_BW 6 #define MBOX_CMD_SET_SS_PWR_GATING 7 #define MBOX_CMD_SET_SS_PWR_UNGATING 8 #define MBOX_CMD_SAVE_DFE_CTLE_CTX 9 #define MBOX_CMD_AIRPLANE_MODE_ENABLED 10 #define MBOX_CMD_AIRPLANE_MODE_DISABLED 11 #define MBOX_CMD_START_HSIC_IDLE 12 #define MBOX_CMD_STOP_HSIC_IDLE 13 #define MBOX_CMD_DBC_WAKE_STACK 14 #define MBOX_CMD_HSIC_PRETEND_CONNECT 15 #define MBOX_CMD_RESET_SSPI 16 #define MBOX_CMD_DISABLE_SS_LFPS_DETECTION 17 #define MBOX_CMD_ENABLE_SS_LFPS_DETECTION 18 /* MBOX responses. */ #define MBOX_CMD_ACK (0x80 + 0) #define MBOX_CMD_NAK (0x80 + 1) #define IPFS_WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res_ipfs, (_r), (_v)) #define IPFS_RD4(_sc, _r) bus_read_4((_sc)->mem_res_ipfs, (_r)) #define FPCI_WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res_fpci, (_r), (_v)) #define FPCI_RD4(_sc, _r) bus_read_4((_sc)->mem_res_fpci, (_r)) #define LOCK(_sc) mtx_lock(&(_sc)->mtx) #define UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) #define SLEEP(_sc, timeout) \ mtx_sleep(sc, &sc->mtx, 0, "tegra_xhci", timeout); #define LOCK_INIT(_sc) \ mtx_init(&_sc->mtx, device_get_nameunit(_sc->dev), "tegra_xhci", MTX_DEF) #define LOCK_DESTROY(_sc) mtx_destroy(&_sc->mtx) #define ASSERT_LOCKED(_sc) mtx_assert(&_sc->mtx, MA_OWNED) #define ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->mtx, MA_NOTOWNED) struct tegra_xusb_fw_hdr { uint32_t boot_loadaddr_in_imem; uint32_t boot_codedfi_offset; uint32_t boot_codetag; uint32_t boot_codesize; uint32_t phys_memaddr; uint16_t reqphys_memsize; uint16_t alloc_phys_memsize; uint32_t rodata_img_offset; uint32_t rodata_section_start; uint32_t rodata_section_end; uint32_t main_fnaddr; uint32_t fwimg_cksum; uint32_t fwimg_created_time; uint32_t imem_resident_start; uint32_t imem_resident_end; uint32_t idirect_start; uint32_t idirect_end; uint32_t l2_imem_start; uint32_t l2_imem_end; uint32_t version_id; uint8_t init_ddirect; uint8_t reserved[3]; uint32_t phys_addr_log_buffer; uint32_t total_log_entries; uint32_t dequeue_ptr; uint32_t dummy[2]; uint32_t fwimg_len; uint8_t magic[8]; uint32_t ss_low_power_entry_timeout; uint8_t num_hsic_port; uint8_t ss_portmap; uint8_t build; uint8_t padding[137]; /* Pad to 256 bytes */ }; struct xhci_soc; struct tegra_xhci_softc { struct xhci_softc xhci_softc; device_t dev; struct xhci_soc *soc; struct mtx mtx; struct resource *mem_res_fpci; struct resource *mem_res_ipfs; struct resource *irq_res_mbox; void *irq_hdl_mbox; clk_t clk_xusb_host; clk_t clk_xusb_gate; clk_t clk_xusb_falcon_src; clk_t clk_xusb_ss; clk_t clk_xusb_hs_src; clk_t clk_xusb_fs_src; hwreset_t hwreset_xusb_host; hwreset_t hwreset_xusb_ss; regulator_t regulators[16]; /* Safe maximum */ phy_t phys[8]; /* Safe maximum */ struct intr_config_hook irq_hook; bool xhci_inited; void *fw_vaddr; vm_size_t fw_size; }; struct xhci_soc { char *fw_name; char **regulator_names; char **phy_names; }; /* Tegra 124 config */ static char *tegra124_reg_names[] = { "avddio-pex-supply", "dvddio-pex-supply", "avdd-usb-supply", "avdd-pll-utmip-supply", "avdd-pll-erefe-supply", "avdd-usb-ss-pll-supply", "hvdd-usb-ss-supply", "hvdd-usb-ss-pll-e-supply", NULL }; static char *tegra124_phy_names[] = { "usb2-0", "usb2-1", "usb2-2", "usb3-0", NULL }; static struct xhci_soc tegra124_soc = { .fw_name = "tegra124_xusb_fw", .regulator_names = tegra124_reg_names, .phy_names = tegra124_phy_names, }; /* Tegra 210 config */ static char *tegra210_reg_names[] = { "dvddio-pex-supply", "hvddio-pex-supply", "avdd-usb-supply", "avdd-pll-utmip-supply", "avdd-pll-uerefe-supply", "dvdd-usb-ss-pll-supply", "hvdd-usb-ss-pll-e-supply", NULL }; static char *tegra210_phy_names[] = { "usb2-0", "usb2-1", "usb2-2", "usb2-3", "usb3-0", "usb3-1", NULL }; static struct xhci_soc tegra210_soc = { .fw_name = "tegra210_xusb_fw", .regulator_names = tegra210_reg_names, .phy_names = tegra210_phy_names, }; /* Compatible devices. */ static struct ofw_compat_data compat_data[] = { {"nvidia,tegra124-xusb", (uintptr_t)&tegra124_soc}, {"nvidia,tegra210-xusb", (uintptr_t)&tegra210_soc}, {NULL, 0} }; static uint32_t CSB_RD4(struct tegra_xhci_softc *sc, uint32_t addr) { FPCI_WR4(sc, XUSB_CFG_ARU_C11_CSBRANGE, ARU_C11_CSBRANGE_PAGE(addr)); return (FPCI_RD4(sc, ARU_C11_CSBRANGE_ADDR(addr))); } static void CSB_WR4(struct tegra_xhci_softc *sc, uint32_t addr, uint32_t val) { FPCI_WR4(sc, XUSB_CFG_ARU_C11_CSBRANGE, ARU_C11_CSBRANGE_PAGE(addr)); FPCI_WR4(sc, ARU_C11_CSBRANGE_ADDR(addr), val); } static int get_fdt_resources(struct tegra_xhci_softc *sc, phandle_t node) { int i, rv; /* Regulators. */ for (i = 0; sc->soc->regulator_names[i] != NULL; i++) { if (i >= nitems(sc->regulators)) { device_printf(sc->dev, "Too many regulators present in DT.\n"); return (EOVERFLOW); } rv = regulator_get_by_ofw_property(sc->dev, 0, sc->soc->regulator_names[i], sc->regulators + i); if (rv != 0) { device_printf(sc->dev, "Cannot get '%s' regulator\n", sc->soc->regulator_names[i]); return (ENXIO); } } rv = hwreset_get_by_ofw_name(sc->dev, 0, "xusb_host", &sc->hwreset_xusb_host); if (rv != 0) { device_printf(sc->dev, "Cannot get 'xusb_host' reset\n"); return (ENXIO); } rv = hwreset_get_by_ofw_name(sc->dev, 0, "xusb_ss", &sc->hwreset_xusb_ss); if (rv != 0) { device_printf(sc->dev, "Cannot get 'xusb_ss' reset\n"); return (ENXIO); } /* Phys. */ for (i = 0; sc->soc->phy_names[i] != NULL; i++) { if (i >= nitems(sc->phys)) { device_printf(sc->dev, "Too many phys present in DT.\n"); return (EOVERFLOW); } rv = phy_get_by_ofw_name(sc->dev, 0, sc->soc->phy_names[i], sc->phys + i); if (rv != 0 && rv != ENOENT) { device_printf(sc->dev, "Cannot get '%s' phy.\n", sc->soc->phy_names[i]); return (ENXIO); } } rv = clk_get_by_ofw_name(sc->dev, 0, "xusb_host", &sc->clk_xusb_host); if (rv != 0) { device_printf(sc->dev, "Cannot get 'xusb_host' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, 0, "xusb_falcon_src", &sc->clk_xusb_falcon_src); if (rv != 0) { device_printf(sc->dev, "Cannot get 'xusb_falcon_src' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, 0, "xusb_ss", &sc->clk_xusb_ss); if (rv != 0) { device_printf(sc->dev, "Cannot get 'xusb_ss' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, 0, "xusb_hs_src", &sc->clk_xusb_hs_src); if (rv != 0) { device_printf(sc->dev, "Cannot get 'xusb_hs_src' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, 0, "xusb_fs_src", &sc->clk_xusb_fs_src); if (rv != 0) { device_printf(sc->dev, "Cannot get 'xusb_fs_src' clock\n"); return (ENXIO); } /* Clock xusb_gate is missing in mainstream DT */ rv = clk_get_by_name(sc->dev, "xusb_gate", &sc->clk_xusb_gate); if (rv != 0) { device_printf(sc->dev, "Cannot get 'xusb_gate' clock\n"); return (ENXIO); } return (0); } static int enable_fdt_resources(struct tegra_xhci_softc *sc) { int i, rv; rv = hwreset_assert(sc->hwreset_xusb_host); if (rv != 0) { device_printf(sc->dev, "Cannot reset 'xusb_host' reset\n"); return (rv); } rv = hwreset_assert(sc->hwreset_xusb_ss); if (rv != 0) { device_printf(sc->dev, "Cannot reset 'xusb_ss' reset\n"); return (rv); } /* Regulators. */ for (i = 0; i < nitems(sc->regulators); i++) { if (sc->regulators[i] == NULL) continue; rv = regulator_enable(sc->regulators[i]); if (rv != 0) { device_printf(sc->dev, "Cannot enable '%s' regulator\n", sc->soc->regulator_names[i]); return (rv); } } /* Power off XUSB host and XUSB SS domains. */ rv = tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA); if (rv != 0) { device_printf(sc->dev, "Cannot powerdown 'xusba' domain\n"); return (rv); } rv = tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC); if (rv != 0) { device_printf(sc->dev, "Cannot powerdown 'xusbc' domain\n"); return (rv); } /* Setup XUSB ss_src clock first */ clk_set_freq(sc->clk_xusb_ss, TEGRA_XHCI_SS_HIGH_SPEED, 0); if (rv != 0) return (rv); /* The XUSB gate clock must be enabled before XUSBA can be powered. */ rv = clk_enable(sc->clk_xusb_gate); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'xusb_gate' clock\n"); return (rv); } /* Power on XUSB host and XUSB SS domains. */ rv = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBC, sc->clk_xusb_host, sc->hwreset_xusb_host); if (rv != 0) { device_printf(sc->dev, "Cannot powerup 'xusbc' domain\n"); return (rv); } rv = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBA, sc->clk_xusb_ss, sc->hwreset_xusb_ss); if (rv != 0) { device_printf(sc->dev, "Cannot powerup 'xusba' domain\n"); return (rv); } /* Enable rest of clocks */ rv = clk_enable(sc->clk_xusb_falcon_src); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'xusb_falcon_src' clock\n"); return (rv); } rv = clk_enable(sc->clk_xusb_fs_src); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'xusb_fs_src' clock\n"); return (rv); } rv = clk_enable(sc->clk_xusb_hs_src); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'xusb_hs_src' clock\n"); return (rv); } /* Phys. */ for (i = 0; i < nitems(sc->phys); i++) { if (sc->phys[i] == NULL) continue; rv = phy_enable(sc->phys[i]); if (rv != 0) { device_printf(sc->dev, "Cannot enable '%s' phy\n", sc->soc->phy_names[i]); return (rv); } } return (0); } /* Respond by ACK/NAK back to FW */ static void mbox_send_ack(struct tegra_xhci_softc *sc, uint32_t cmd, uint32_t data) { uint32_t reg; reg = ARU_MAILBOX_DATA_IN_TYPE(cmd) | ARU_MAILBOX_DATA_IN_DATA(data); FPCI_WR4(sc, T_XUSB_CFG_ARU_MAILBOX_DATA_IN, reg); reg = FPCI_RD4(sc, T_XUSB_CFG_ARU_MAILBOX_CMD); reg |= ARU_MAILBOX_CMD_DEST_FALC | ARU_MAILBOX_CMD_INT_EN; FPCI_WR4(sc, T_XUSB_CFG_ARU_MAILBOX_CMD, reg); } /* Sent command to FW */ static int mbox_send_cmd(struct tegra_xhci_softc *sc, uint32_t cmd, uint32_t data) { uint32_t reg; int i; reg = FPCI_RD4(sc, T_XUSB_CFG_ARU_MAILBOX_OWNER); if (reg != ARU_MAILBOX_OWNER_NONE) { device_printf(sc->dev, "CPU mailbox is busy: 0x%08X\n", reg); return (EBUSY); } /* XXX Is this right? Retry loop? Wait before send? */ FPCI_WR4(sc, T_XUSB_CFG_ARU_MAILBOX_OWNER, ARU_MAILBOX_OWNER_SW); reg = FPCI_RD4(sc, T_XUSB_CFG_ARU_MAILBOX_OWNER); if (reg != ARU_MAILBOX_OWNER_SW) { device_printf(sc->dev, "Cannot acquire CPU mailbox: 0x%08X\n", reg); return (EBUSY); } reg = ARU_MAILBOX_DATA_IN_TYPE(cmd) | ARU_MAILBOX_DATA_IN_DATA(data); FPCI_WR4(sc, T_XUSB_CFG_ARU_MAILBOX_DATA_IN, reg); reg = FPCI_RD4(sc, T_XUSB_CFG_ARU_MAILBOX_CMD); reg |= ARU_MAILBOX_CMD_DEST_FALC | ARU_MAILBOX_CMD_INT_EN; FPCI_WR4(sc, T_XUSB_CFG_ARU_MAILBOX_CMD, reg); for (i = 250; i > 0; i--) { reg = FPCI_RD4(sc, T_XUSB_CFG_ARU_MAILBOX_OWNER); if (reg == ARU_MAILBOX_OWNER_NONE) break; DELAY(100); } if (i <= 0) { device_printf(sc->dev, "Command response timeout: 0x%08X\n", reg); return (ETIMEDOUT); } return(0); } static void process_msg(struct tegra_xhci_softc *sc, uint32_t req_cmd, uint32_t req_data, uint32_t *resp_cmd, uint32_t *resp_data) { uint64_t freq; int rv; /* In most cases, data are echoed back. */ *resp_data = req_data; switch (req_cmd) { case MBOX_CMD_INC_FALC_CLOCK: case MBOX_CMD_DEC_FALC_CLOCK: rv = clk_set_freq(sc->clk_xusb_falcon_src, req_data * 1000ULL, 0); if (rv == 0) { rv = clk_get_freq(sc->clk_xusb_falcon_src, &freq); *resp_data = (uint32_t)(freq / 1000); } *resp_cmd = rv == 0 ? MBOX_CMD_ACK: MBOX_CMD_NAK; break; case MBOX_CMD_INC_SSPI_CLOCK: case MBOX_CMD_DEC_SSPI_CLOCK: rv = clk_set_freq(sc->clk_xusb_ss, req_data * 1000ULL, 0); if (rv == 0) { rv = clk_get_freq(sc->clk_xusb_ss, &freq); *resp_data = (uint32_t)(freq / 1000); } *resp_cmd = rv == 0 ? MBOX_CMD_ACK: MBOX_CMD_NAK; break; case MBOX_CMD_SET_BW: /* No respense is expected. */ *resp_cmd = 0; break; case MBOX_CMD_SET_SS_PWR_GATING: case MBOX_CMD_SET_SS_PWR_UNGATING: *resp_cmd = MBOX_CMD_NAK; break; case MBOX_CMD_SAVE_DFE_CTLE_CTX: /* Not implemented yet. */ *resp_cmd = MBOX_CMD_ACK; break; case MBOX_CMD_START_HSIC_IDLE: case MBOX_CMD_STOP_HSIC_IDLE: /* Not implemented yet. */ *resp_cmd = MBOX_CMD_NAK; break; case MBOX_CMD_DISABLE_SS_LFPS_DETECTION: case MBOX_CMD_ENABLE_SS_LFPS_DETECTION: /* Not implemented yet. */ *resp_cmd = MBOX_CMD_NAK; break; case MBOX_CMD_AIRPLANE_MODE_ENABLED: case MBOX_CMD_AIRPLANE_MODE_DISABLED: case MBOX_CMD_DBC_WAKE_STACK: case MBOX_CMD_HSIC_PRETEND_CONNECT: case MBOX_CMD_RESET_SSPI: device_printf(sc->dev, "Received unused/unexpected command: %u\n", req_cmd); *resp_cmd = 0; break; default: device_printf(sc->dev, "Received unknown command: %u\n", req_cmd); } } static void intr_mbox(void *arg) { struct tegra_xhci_softc *sc; uint32_t reg, msg, resp_cmd, resp_data; sc = (struct tegra_xhci_softc *)arg; /* Clear interrupt first */ reg = FPCI_RD4(sc, XUSB_CFG_ARU_SMI_INTR); FPCI_WR4(sc, XUSB_CFG_ARU_SMI_INTR, reg); if (reg & ARU_SMI_INTR_FW_HANG) { device_printf(sc->dev, "XUSB CPU firmware hang!!! CPUCTL: 0x%08X\n", CSB_RD4(sc, XUSB_FALCON_CPUCTL)); } msg = FPCI_RD4(sc, T_XUSB_CFG_ARU_MAILBOX_DATA_OUT); resp_cmd = 0; process_msg(sc, ARU_MAILBOX_DATA_OUT_TYPE(msg), ARU_MAILBOX_DATA_OUT_DATA(msg), &resp_cmd, &resp_data); if (resp_cmd != 0) mbox_send_ack(sc, resp_cmd, resp_data); else FPCI_WR4(sc, T_XUSB_CFG_ARU_MAILBOX_OWNER, ARU_MAILBOX_OWNER_NONE); reg = FPCI_RD4(sc, T_XUSB_CFG_ARU_MAILBOX_CMD); reg &= ~ARU_MAILBOX_CMD_DEST_SMI; FPCI_WR4(sc, T_XUSB_CFG_ARU_MAILBOX_CMD, reg); } static int load_fw(struct tegra_xhci_softc *sc) { const struct firmware *fw; const struct tegra_xusb_fw_hdr *fw_hdr; vm_paddr_t fw_paddr, fw_base; void *fw_vaddr; vm_size_t fw_size; uint32_t code_tags, code_size; struct clocktime fw_clock; struct timespec fw_timespec; int i; /* Reset ARU */ FPCI_WR4(sc, XUSB_CFG_ARU_RST, ARU_RST_RESET); DELAY(3000); /* Check if FALCON already runs */ if (CSB_RD4(sc, XUSB_CSB_MEMPOOL_ILOAD_BASE_LO) != 0) { device_printf(sc->dev, "XUSB CPU is already loaded, CPUCTL: 0x%08X\n", CSB_RD4(sc, XUSB_FALCON_CPUCTL)); return (0); } fw = firmware_get(sc->soc->fw_name); if (fw == NULL) { device_printf(sc->dev, "Cannot read xusb firmware\n"); return (ENOENT); } /* Allocate uncached memory and copy firmware into. */ fw_hdr = (const struct tegra_xusb_fw_hdr *)fw->data; fw_size = fw_hdr->fwimg_len; fw_vaddr = kmem_alloc_contig(fw_size, M_WAITOK, 0, -1UL, PAGE_SIZE, 0, VM_MEMATTR_UNCACHEABLE); fw_paddr = vtophys((uintptr_t)fw_vaddr); fw_hdr = (const struct tegra_xusb_fw_hdr *)fw_vaddr; memcpy(fw_vaddr, fw->data, fw_size); firmware_put(fw, FIRMWARE_UNLOAD); sc->fw_vaddr = fw_vaddr; sc->fw_size = fw_size; /* Setup firmware physical address and size. */ fw_base = fw_paddr + sizeof(*fw_hdr); CSB_WR4(sc, XUSB_CSB_MEMPOOL_ILOAD_ATTR, fw_size); CSB_WR4(sc, XUSB_CSB_MEMPOOL_ILOAD_BASE_LO, fw_base & 0xFFFFFFFF); CSB_WR4(sc, XUSB_CSB_MEMPOOL_ILOAD_BASE_HI, (uint64_t)fw_base >> 32); CSB_WR4(sc, XUSB_CSB_MEMPOOL_APMAP, APMAP_BOOTPATH); /* Invalidate full L2IMEM context. */ CSB_WR4(sc, XUSB_CSB_MEMPOOL_L2IMEMOP_TRIG, L2IMEMOP_INVALIDATE_ALL); /* Program load of L2IMEM by boot code. */ code_tags = howmany(fw_hdr->boot_codetag, XUSB_CSB_IMEM_BLOCK_SIZE); code_size = howmany(fw_hdr->boot_codesize, XUSB_CSB_IMEM_BLOCK_SIZE); CSB_WR4(sc, XUSB_CSB_MEMPOOL_L2IMEMOP_SIZE, L2IMEMOP_SIZE_OFFSET(code_tags) | L2IMEMOP_SIZE_SIZE(code_size)); /* Execute L2IMEM boot code fetch. */ CSB_WR4(sc, XUSB_CSB_MEMPOOL_L2IMEMOP_TRIG, L2IMEMOP_LOAD_LOCKED_RESULT); /* Program FALCON auto-fill range and block count */ CSB_WR4(sc, XUSB_FALCON_IMFILLCTL, code_size); CSB_WR4(sc, XUSB_FALCON_IMFILLRNG1, IMFILLRNG1_TAG_LO(code_tags) | IMFILLRNG1_TAG_HI(code_tags + code_size)); CSB_WR4(sc, XUSB_FALCON_DMACTL, 0); /* Wait for CPU */ for (i = 500; i > 0; i--) { if (CSB_RD4(sc, XUSB_CSB_MEMPOOL_L2IMEMOP_RESULT) & L2IMEMOP_RESULT_VLD) break; DELAY(100); } if (i <= 0) { device_printf(sc->dev, "Timedout while wating for DMA, " "state: 0x%08X\n", CSB_RD4(sc, XUSB_CSB_MEMPOOL_L2IMEMOP_RESULT)); return (ETIMEDOUT); } /* Boot FALCON cpu */ CSB_WR4(sc, XUSB_FALCON_BOOTVEC, fw_hdr->boot_codetag); CSB_WR4(sc, XUSB_FALCON_CPUCTL, CPUCTL_STARTCPU); /* Wait for CPU */ for (i = 50; i > 0; i--) { if (CSB_RD4(sc, XUSB_FALCON_CPUCTL) == CPUCTL_STOPPED) break; DELAY(100); } if (i <= 0) { device_printf(sc->dev, "Timedout while wating for FALCON cpu, " "state: 0x%08X\n", CSB_RD4(sc, XUSB_FALCON_CPUCTL)); return (ETIMEDOUT); } fw_timespec.tv_sec = fw_hdr->fwimg_created_time; fw_timespec.tv_nsec = 0; clock_ts_to_ct(&fw_timespec, &fw_clock); device_printf(sc->dev, " Falcon firmware version: %02X.%02X.%04X," " (%d/%d/%d %d:%02d:%02d UTC)\n", (fw_hdr->version_id >> 24) & 0xFF,(fw_hdr->version_id >> 15) & 0xFF, fw_hdr->version_id & 0xFFFF, fw_clock.day, fw_clock.mon, fw_clock.year, fw_clock.hour, fw_clock.min, fw_clock.sec); return (0); } static int init_hw(struct tegra_xhci_softc *sc) { int rv; uint32_t reg; rman_res_t base_addr; base_addr = rman_get_start(sc->xhci_softc.sc_io_res); /* Enable FPCI access */ reg = IPFS_RD4(sc, XUSB_HOST_CONFIGURATION); reg |= CONFIGURATION_EN_FPCI; IPFS_WR4(sc, XUSB_HOST_CONFIGURATION, reg); IPFS_RD4(sc, XUSB_HOST_CONFIGURATION); /* Program bar for XHCI base address */ reg = FPCI_RD4(sc, T_XUSB_CFG_4); reg &= ~CFG_4_BASE_ADDRESS(~0); reg |= CFG_4_BASE_ADDRESS((uint32_t)base_addr >> 15); FPCI_WR4(sc, T_XUSB_CFG_4, reg); FPCI_WR4(sc, T_XUSB_CFG_5, (uint32_t)((uint64_t)(base_addr) >> 32)); /* Enable bus master */ reg = FPCI_RD4(sc, T_XUSB_CFG_1); reg |= CFG_1_IO_SPACE; reg |= CFG_1_MEMORY_SPACE; reg |= CFG_1_BUS_MASTER; FPCI_WR4(sc, T_XUSB_CFG_1, reg); /* Enable Interrupts */ reg = IPFS_RD4(sc, XUSB_HOST_INTR_MASK); reg |= INTR_IP_INT_MASK; IPFS_WR4(sc, XUSB_HOST_INTR_MASK, reg); /* Set hysteresis */ IPFS_WR4(sc, XUSB_HOST_CLKGATE_HYSTERESIS, 128); rv = load_fw(sc); if (rv != 0) return rv; return (0); } static int tegra_xhci_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) { device_set_desc(dev, "Nvidia Tegra XHCI controller"); return (BUS_PROBE_DEFAULT); } return (ENXIO); } static int tegra_xhci_detach(device_t dev) { struct tegra_xhci_softc *sc; struct xhci_softc *xsc; sc = device_get_softc(dev); xsc = &sc->xhci_softc; /* during module unload there are lots of children leftover */ device_delete_children(dev); if (sc->xhci_inited) { usb_callout_drain(&xsc->sc_callout); xhci_halt_controller(xsc); } if (xsc->sc_irq_res && xsc->sc_intr_hdl) { bus_teardown_intr(dev, xsc->sc_irq_res, xsc->sc_intr_hdl); xsc->sc_intr_hdl = NULL; } if (xsc->sc_irq_res) { bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(xsc->sc_irq_res), xsc->sc_irq_res); xsc->sc_irq_res = NULL; } if (xsc->sc_io_res != NULL) { bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(xsc->sc_io_res), xsc->sc_io_res); xsc->sc_io_res = NULL; } if (sc->xhci_inited) xhci_uninit(xsc); if (sc->irq_hdl_mbox != NULL) bus_teardown_intr(dev, sc->irq_res_mbox, sc->irq_hdl_mbox); if (sc->fw_vaddr != NULL) kmem_free(sc->fw_vaddr, sc->fw_size); LOCK_DESTROY(sc); return (0); } static int tegra_xhci_attach(device_t dev) { struct tegra_xhci_softc *sc; struct xhci_softc *xsc; int rv, rid; phandle_t node; sc = device_get_softc(dev); sc->dev = dev; sc->soc = (struct xhci_soc *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; node = ofw_bus_get_node(dev); xsc = &sc->xhci_softc; LOCK_INIT(sc); rv = get_fdt_resources(sc, node); if (rv != 0) { rv = ENXIO; goto error; } rv = enable_fdt_resources(sc); if (rv != 0) { rv = ENXIO; goto error; } /* Allocate resources. */ rid = 0; xsc->sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (xsc->sc_io_res == NULL) { device_printf(dev, "Could not allocate HCD memory resources\n"); rv = ENXIO; goto error; } rid = 1; sc->mem_res_fpci = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res_fpci == NULL) { device_printf(dev, "Could not allocate FPCI memory resources\n"); rv = ENXIO; goto error; } rid = 2; sc->mem_res_ipfs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res_ipfs == NULL) { device_printf(dev, "Could not allocate IPFS memory resources\n"); rv = ENXIO; goto error; } rid = 0; xsc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (xsc->sc_irq_res == NULL) { device_printf(dev, "Could not allocate HCD IRQ resources\n"); rv = ENXIO; goto error; } rid = 1; sc->irq_res_mbox = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->irq_res_mbox == NULL) { device_printf(dev, "Could not allocate MBOX IRQ resources\n"); rv = ENXIO; goto error; } rv = init_hw(sc); if (rv != 0) { device_printf(dev, "Could not initialize XUSB hardware\n"); goto error; } /* Wakeup and enable firmaware */ rv = mbox_send_cmd(sc, MBOX_CMD_MSG_ENABLED, 0); if (rv != 0) { device_printf(sc->dev, "Could not enable XUSB firmware\n"); goto error; } /* Fill data for XHCI driver. */ xsc->sc_bus.parent = dev; xsc->sc_bus.devices = xsc->sc_devices; xsc->sc_bus.devices_max = XHCI_MAX_DEVICES; xsc->sc_io_tag = rman_get_bustag(xsc->sc_io_res); xsc->sc_io_hdl = rman_get_bushandle(xsc->sc_io_res); xsc->sc_io_size = rman_get_size(xsc->sc_io_res); strlcpy(xsc->sc_vendor, "Nvidia", sizeof(xsc->sc_vendor)); /* Add USB bus device. */ xsc->sc_bus.bdev = device_add_child(sc->dev, "usbus", -1); if (xsc->sc_bus.bdev == NULL) { device_printf(sc->dev, "Could not add USB device\n"); rv = ENXIO; goto error; } device_set_ivars(xsc->sc_bus.bdev, &xsc->sc_bus); device_set_desc(xsc->sc_bus.bdev, "Nvidia USB 3.0 controller"); rv = xhci_init(xsc, sc->dev, 1); if (rv != 0) { device_printf(sc->dev, "USB init failed: %d\n", rv); goto error; } sc->xhci_inited = true; rv = xhci_start_controller(xsc); if (rv != 0) { device_printf(sc->dev, "Could not start XHCI controller: %d\n", rv); goto error; } rv = bus_setup_intr(dev, sc->irq_res_mbox, INTR_TYPE_MISC | INTR_MPSAFE, NULL, intr_mbox, sc, &sc->irq_hdl_mbox); if (rv != 0) { device_printf(dev, "Could not setup error IRQ: %d\n",rv); xsc->sc_intr_hdl = NULL; goto error; } rv = bus_setup_intr(dev, xsc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, NULL, (driver_intr_t *)xhci_interrupt, xsc, &xsc->sc_intr_hdl); if (rv != 0) { device_printf(dev, "Could not setup error IRQ: %d\n",rv); xsc->sc_intr_hdl = NULL; goto error; } /* Probe the bus. */ rv = device_probe_and_attach(xsc->sc_bus.bdev); if (rv != 0) { device_printf(sc->dev, "Could not initialize USB: %d\n", rv); goto error; } return (0); error: panic("XXXXX"); tegra_xhci_detach(dev); return (rv); } static device_method_t xhci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, tegra_xhci_probe), DEVMETHOD(device_attach, tegra_xhci_attach), DEVMETHOD(device_detach, tegra_xhci_detach), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(device_shutdown, bus_generic_shutdown), /* Bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), DEVMETHOD_END }; static DEFINE_CLASS_0(xhci, xhci_driver, xhci_methods, sizeof(struct tegra_xhci_softc)); DRIVER_MODULE(tegra_xhci, simplebus, xhci_driver, NULL, NULL); MODULE_DEPEND(tegra_xhci, usb, 1, 1, 1); diff --git a/sys/arm/qualcomm/ipq4018_usb_hs_phy.c b/sys/arm/qualcomm/ipq4018_usb_hs_phy.c index 618911fef640..953887ad9906 100644 --- a/sys/arm/qualcomm/ipq4018_usb_hs_phy.c +++ b/sys/arm/qualcomm/ipq4018_usb_hs_phy.c @@ -1,229 +1,229 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2019 Michal Meloun * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include "phynode_if.h" #include "phynode_usb_if.h" static struct ofw_compat_data compat_data[] = { {"qcom,usb-hs-ipq4019-phy", 1}, {NULL, 0}, }; struct ipq4018_usb_hs_phy_softc { device_t dev; }; struct ipq4018_usb_hs_phynode_sc { struct phynode_usb_sc usb_sc; int mode; hwreset_t por_rst; hwreset_t srif_rst; }; static int ipq4018_usb_hs_phynode_phy_enable(struct phynode *phynode, bool enable) { struct ipq4018_usb_hs_phynode_sc *sc; device_t dev; int rv; dev = phynode_get_device(phynode); sc = phynode_get_softc(phynode); /* * * For power-off - assert por, sleep for 10ms, assert srif, * sleep for 10ms */ rv = hwreset_assert(sc->por_rst); if (rv != 0) goto done; DELAY(10*1000); rv = hwreset_assert(sc->srif_rst); if (rv != 0) goto done; DELAY(10*1000); /* * For power-on - power off first, then deassert srif, then * sleep for 10ms, then deassert por. */ if (enable) { rv = hwreset_deassert(sc->srif_rst); if (rv != 0) goto done; DELAY(10*1000); rv = hwreset_deassert(sc->por_rst); if (rv != 0) goto done; DELAY(10*1000); } done: if (rv != 0) { device_printf(dev, "%s: failed, rv=%d\n", __func__, rv); } return (rv); } /* Phy controller class and methods. */ static phynode_method_t ipq4018_usb_hs_phynode_methods[] = { PHYNODEUSBMETHOD(phynode_enable, ipq4018_usb_hs_phynode_phy_enable), PHYNODEUSBMETHOD_END }; DEFINE_CLASS_1(ipq4018_usb_hs_phynode, ipq4018_usb_hs_phynode_class, ipq4018_usb_hs_phynode_methods, sizeof(struct ipq4018_usb_hs_phynode_sc), phynode_usb_class); static int ipq4018_usb_hs_usbphy_init_phy(struct ipq4018_usb_hs_phy_softc *sc, phandle_t node) { struct phynode *phynode; struct phynode_init_def phy_init; struct ipq4018_usb_hs_phynode_sc *phy_sc; int rv; hwreset_t por_rst = NULL, srif_rst = NULL; /* FDT resources */ rv = hwreset_get_by_ofw_name(sc->dev, node, "por_rst", &por_rst); if (rv != 0 && rv != ENOENT) { device_printf(sc->dev, "Cannot get 'por_rst' reset\n"); goto fail; } rv = hwreset_get_by_ofw_name(sc->dev, node, "srif_rst", &srif_rst); if (rv != 0 && rv != ENOENT) { device_printf(sc->dev, "Cannot get 'srif_rst' reset\n"); goto fail; } /* Create and register phy. */ bzero(&phy_init, sizeof(phy_init)); phy_init.id = 1; phy_init.ofw_node = node; phynode = phynode_create(sc->dev, &ipq4018_usb_hs_phynode_class, &phy_init); if (phynode == NULL) { device_printf(sc->dev, "Cannot create phy.\n"); return (ENXIO); } phy_sc = phynode_get_softc(phynode); phy_sc->por_rst = por_rst; phy_sc->srif_rst = srif_rst; if (phynode_register(phynode) == NULL) { device_printf(sc->dev, "Cannot register phy.\n"); return (ENXIO); } (void) ipq4018_usb_hs_phynode_phy_enable(phynode, true); return (0); fail: if (por_rst != NULL) hwreset_release(por_rst); if (srif_rst != NULL) hwreset_release(srif_rst); return (ENXIO); } static int ipq4018_usb_hs_usbphy_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "IPQ4018/IPQ4019 USB HS PHY"); return (BUS_PROBE_DEFAULT); } static int ipq4018_usb_hs_usbphy_attach(device_t dev) { struct ipq4018_usb_hs_phy_softc *sc; phandle_t node; int rv; sc = device_get_softc(dev); sc->dev = dev; node = ofw_bus_get_node(sc->dev); rv = ipq4018_usb_hs_usbphy_init_phy(sc, node); if (rv != 0) goto fail; return (bus_generic_attach(dev)); fail: return (ENXIO); } static int ipq4018_usb_hs_usbphy_detach(device_t dev) { return (0); } static device_method_t ipq4018_usb_hs_usbphy_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ipq4018_usb_hs_usbphy_probe), DEVMETHOD(device_attach, ipq4018_usb_hs_usbphy_attach), DEVMETHOD(device_detach, ipq4018_usb_hs_usbphy_detach), DEVMETHOD_END }; static DEFINE_CLASS_0(ipq4018_usb_hs_usbphy, ipq4018_usb_hs_usbphy_driver, ipq4018_usb_hs_usbphy_methods, sizeof(struct ipq4018_usb_hs_phy_softc)); EARLY_DRIVER_MODULE(ipq4018_usb_hs_usbphy, simplebus, ipq4018_usb_hs_usbphy_driver, NULL, NULL, BUS_PASS_TIMER + BUS_PASS_ORDER_LAST); diff --git a/sys/arm/qualcomm/ipq4018_usb_ss_phy.c b/sys/arm/qualcomm/ipq4018_usb_ss_phy.c index 66ef4c9fe732..b60be5896595 100644 --- a/sys/arm/qualcomm/ipq4018_usb_ss_phy.c +++ b/sys/arm/qualcomm/ipq4018_usb_ss_phy.c @@ -1,209 +1,209 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2019 Michal Meloun * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include "phynode_if.h" #include "phynode_usb_if.h" static struct ofw_compat_data compat_data[] = { {"qcom,usb-ss-ipq4019-phy", 1}, {NULL, 0}, }; struct ipq4018_usb_ss_phy_softc { device_t dev; }; struct ipq4018_usb_ss_phynode_sc { struct phynode_usb_sc usb_sc; int mode; hwreset_t por_rst; }; static int ipq4018_usb_ss_phynode_phy_enable(struct phynode *phynode, bool enable) { struct ipq4018_usb_ss_phynode_sc *sc; device_t dev; int rv; dev = phynode_get_device(phynode); sc = phynode_get_softc(phynode); /* * For power-off - assert por, sleep for 10ms */ rv = hwreset_assert(sc->por_rst); if (rv != 0) goto done; DELAY(10*1000); /* * For power-on - power off first, then deassert por. */ if (enable) { rv = hwreset_deassert(sc->por_rst); if (rv != 0) goto done; DELAY(10*1000); } done: if (rv != 0) { device_printf(dev, "%s: failed, rv=%d\n", __func__, rv); } return (rv); } /* Phy controller class and methods. */ static phynode_method_t ipq4018_usb_ss_phynode_methods[] = { PHYNODEUSBMETHOD(phynode_enable, ipq4018_usb_ss_phynode_phy_enable), PHYNODEUSBMETHOD_END }; DEFINE_CLASS_1(ipq4018_usb_ss_phynode, ipq4018_usb_ss_phynode_class, ipq4018_usb_ss_phynode_methods, sizeof(struct ipq4018_usb_ss_phynode_sc), phynode_usb_class); static int ipq4018_usb_ss_usbphy_init_phy(struct ipq4018_usb_ss_phy_softc *sc, phandle_t node) { struct phynode *phynode; struct phynode_init_def phy_init; struct ipq4018_usb_ss_phynode_sc *phy_sc; int rv; hwreset_t por_rst = NULL; /* FDT resources */ rv = hwreset_get_by_ofw_name(sc->dev, node, "por_rst", &por_rst); if (rv != 0 && rv != ENOENT) { device_printf(sc->dev, "Cannot get 'por_rst' reset\n"); goto fail; } /* Create and register phy. */ bzero(&phy_init, sizeof(phy_init)); phy_init.id = 1; phy_init.ofw_node = node; phynode = phynode_create(sc->dev, &ipq4018_usb_ss_phynode_class, &phy_init); if (phynode == NULL) { device_printf(sc->dev, "Cannot create phy.\n"); return (ENXIO); } phy_sc = phynode_get_softc(phynode); phy_sc->por_rst = por_rst; if (phynode_register(phynode) == NULL) { device_printf(sc->dev, "Cannot register phy.\n"); return (ENXIO); } (void) ipq4018_usb_ss_phynode_phy_enable(phynode, true); return (0); fail: if (por_rst != NULL) hwreset_release(por_rst); return (ENXIO); } static int ipq4018_usb_ss_usbphy_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "IPQ4018/IPQ4019 USB SS PHY"); return (BUS_PROBE_DEFAULT); } static int ipq4018_usb_ss_usbphy_attach(device_t dev) { struct ipq4018_usb_ss_phy_softc *sc; phandle_t node; int rv; sc = device_get_softc(dev); sc->dev = dev; node = ofw_bus_get_node(sc->dev); rv = ipq4018_usb_ss_usbphy_init_phy(sc, node); if (rv != 0) goto fail; return (bus_generic_attach(dev)); fail: return (ENXIO); } static int ipq4018_usb_ss_usbphy_detach(device_t dev) { return (0); } static device_method_t ipq4018_usb_ss_usbphy_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ipq4018_usb_ss_usbphy_probe), DEVMETHOD(device_attach, ipq4018_usb_ss_usbphy_attach), DEVMETHOD(device_detach, ipq4018_usb_ss_usbphy_detach), DEVMETHOD_END }; static DEFINE_CLASS_0(ipq4018_usb_ss_usbphy, ipq4018_usb_ss_usbphy_driver, ipq4018_usb_ss_usbphy_methods, sizeof(struct ipq4018_usb_ss_phy_softc)); EARLY_DRIVER_MODULE(ipq4018_usb_ss_usbphy, simplebus, ipq4018_usb_ss_usbphy_driver, NULL, NULL, BUS_PASS_TIMER + BUS_PASS_ORDER_LAST); diff --git a/sys/arm64/nvidia/tegra210/max77620.c b/sys/arm64/nvidia/tegra210/max77620.c index a27edf01889d..b33d73e71f90 100644 --- a/sys/arm64/nvidia/tegra210/max77620.c +++ b/sys/arm64/nvidia/tegra210/max77620.c @@ -1,504 +1,504 @@ /*- * Copyright (c) 2019 Michal Meloun * * 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 AND CONTRIBUTORS ``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 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 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. */ #include /* * MAX77620 PMIC driver */ #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #include #include "clock_if.h" #include "regdev_if.h" #include "max77620.h" static struct ofw_compat_data compat_data[] = { {"maxim,max77620", 1}, {NULL, 0}, }; #define LOCK(_sc) sx_xlock(&(_sc)->lock) #define UNLOCK(_sc) sx_xunlock(&(_sc)->lock) #define LOCK_INIT(_sc) sx_init(&(_sc)->lock, "max77620") #define LOCK_DESTROY(_sc) sx_destroy(&(_sc)->lock); #define ASSERT_LOCKED(_sc) sx_assert(&(_sc)->lock, SA_XLOCKED); #define ASSERT_UNLOCKED(_sc) sx_assert(&(_sc)->lock, SA_UNLOCKED); #define MAX77620_DEVICE_ID 0x0C /* * Raw register access function. */ int max77620_read(struct max77620_softc *sc, uint8_t reg, uint8_t *val) { uint8_t addr; int rv; struct iic_msg msgs[2] = { {0, IIC_M_WR, 1, &addr}, {0, IIC_M_RD, 1, val}, }; msgs[0].slave = sc->bus_addr; msgs[1].slave = sc->bus_addr; addr = reg; rv = iicbus_transfer(sc->dev, msgs, 2); if (rv != 0) { device_printf(sc->dev, "Error when reading reg 0x%02X, rv: %d\n", reg, rv); return (EIO); } return (0); } int max77620_read_buf(struct max77620_softc *sc, uint8_t reg, uint8_t *buf, size_t size) { uint8_t addr; int rv; struct iic_msg msgs[2] = { {0, IIC_M_WR, 1, &addr}, {0, IIC_M_RD, size, buf}, }; msgs[0].slave = sc->bus_addr; msgs[1].slave = sc->bus_addr; addr = reg; rv = iicbus_transfer(sc->dev, msgs, 2); if (rv != 0) { device_printf(sc->dev, "Error when reading reg 0x%02X, rv: %d\n", reg, rv); return (EIO); } return (0); } int max77620_write(struct max77620_softc *sc, uint8_t reg, uint8_t val) { uint8_t data[2]; int rv; struct iic_msg msgs[1] = { {0, IIC_M_WR, 2, data}, }; msgs[0].slave = sc->bus_addr; data[0] = reg; data[1] = val; rv = iicbus_transfer(sc->dev, msgs, 1); if (rv != 0) { device_printf(sc->dev, "Error when writing reg 0x%02X, rv: %d\n", reg, rv); return (EIO); } return (0); } int max77620_write_buf(struct max77620_softc *sc, uint8_t reg, uint8_t *buf, size_t size) { uint8_t data[1]; int rv; struct iic_msg msgs[2] = { {0, IIC_M_WR, 1, data}, {0, IIC_M_WR | IIC_M_NOSTART, size, buf}, }; msgs[0].slave = sc->bus_addr; msgs[1].slave = sc->bus_addr; data[0] = reg; rv = iicbus_transfer(sc->dev, msgs, 2); if (rv != 0) { device_printf(sc->dev, "Error when writing reg 0x%02X, rv: %d\n", reg, rv); return (EIO); } return (0); } int max77620_modify(struct max77620_softc *sc, uint8_t reg, uint8_t clear, uint8_t set) { uint8_t val; int rv; rv = max77620_read(sc, reg, &val); if (rv != 0) return (rv); val &= ~clear; val |= set; rv = max77620_write(sc, reg, val); if (rv != 0) return (rv); return (0); } static int max77620_parse_fps(struct max77620_softc *sc, int id, phandle_t node) { int val; if (OF_getencprop(node, "maxim,shutdown-fps-time-period-us", &val, sizeof(val)) >= 0) { val = min(val, MAX77620_FPS_PERIOD_MAX_US); val = max(val, MAX77620_FPS_PERIOD_MIN_US); sc->shutdown_fps[id] = val; } if (OF_getencprop(node, "maxim,suspend-fps-time-period-us", &val, sizeof(val)) >= 0) { val = min(val, MAX77620_FPS_PERIOD_MAX_US); val = max(val, MAX77620_FPS_PERIOD_MIN_US); sc->suspend_fps[id] = val; } if (OF_getencprop(node, "maxim,fps-event-source", &val, sizeof(val)) >= 0) { if (val > 2) { device_printf(sc->dev, "Invalid 'fps-event-source' " "value: %d\n", val); return (EINVAL); } sc->event_source[id] = val; } return (0); } static int max77620_parse_fdt(struct max77620_softc *sc, phandle_t node) { phandle_t fpsnode; char fps_name[6]; int i, rv; for (i = 0; i < MAX77620_FPS_COUNT; i++) { sc->shutdown_fps[i] = -1; sc->suspend_fps[i] = -1; sc->event_source[i] = -1; } fpsnode = ofw_bus_find_child(node, "fps"); if (fpsnode > 0) { for (i = 0; i < MAX77620_FPS_COUNT; i++) { sprintf(fps_name, "fps%d", i); node = ofw_bus_find_child(node, fps_name); if (node <= 0) continue; rv = max77620_parse_fps(sc, i, node); if (rv != 0) return (rv); } } return (0); } static int max77620_get_version(struct max77620_softc *sc) { uint8_t buf[6]; int i; int rv; /* Verify ID string (5 bytes ). */ for (i = 0; i <= 6; i++) { rv = RD1(sc, MAX77620_REG_CID0 + i , buf + i); if (rv != 0) { device_printf(sc->dev, "Cannot read chip ID: %d\n", rv); return (ENXIO); } } if (bootverbose) { device_printf(sc->dev, " ID: [0x%02X, 0x%02X, 0x%02X, 0x%02X]\n", buf[0], buf[1], buf[2], buf[3]); } device_printf(sc->dev, " MAX77620 version - OTP: 0x%02X, ES: 0x%02X\n", buf[4], buf[5]); return (0); } static uint8_t max77620_encode_fps_period(struct max77620_softc *sc, int val) { uint8_t i; int period; period = MAX77620_FPS_PERIOD_MIN_US; for (i = 0; i < 7; i++) { if (period >= val) return (i); period *= 2; } return (i); } static int max77620_init(struct max77620_softc *sc) { uint8_t mask, val, tmp; int i, rv; mask = 0; val = 0; for (i = 0; i < MAX77620_FPS_COUNT; i++) { if (sc->shutdown_fps[i] != -1) { mask |= MAX77620_FPS_TIME_PERIOD_MASK; tmp = max77620_encode_fps_period(sc, sc->shutdown_fps[i]); val |= (tmp << MAX77620_FPS_TIME_PERIOD_SHIFT) & MAX77620_FPS_TIME_PERIOD_MASK; } if (sc->event_source[i] != -1) { mask |= MAX77620_FPS_EN_SRC_MASK; tmp = sc->event_source[i]; val |= (tmp << MAX77620_FPS_EN_SRC_SHIFT) & MAX77620_FPS_EN_SRC_MASK; if (sc->event_source[i] == 2) { mask |= MAX77620_FPS_ENFPS_SW_MASK; val |= MAX77620_FPS_ENFPS_SW; } } rv = RM1(sc, MAX77620_REG_FPS_CFG0 + i, mask, val); if (rv != 0) { device_printf(sc->dev, "I/O error: %d\n", rv); return (ENXIO); } } /* Global mask interrupts */ rv = RM1(sc, MAX77620_REG_INTENLBT, 0x81, 0x81); rv = RM1(sc, MAX77620_REG_IRQTOPM, 0x81, 0x81); if (rv != 0) return (ENXIO); return (0); } #ifdef notyet static void max77620_intr(void *arg) { struct max77620_softc *sc; uint8_t intenlbt, intlbt, irqtop, irqtopm, irqsd, irqmasksd; uint8_t irq_lvl2_l0_7, irq_lvl2_l8, irq_lvl2_gpio, irq_msk_l0_7, irq_msk_l8; uint8_t onoffirq, onoffirqm; sc = (struct max77620_softc *)arg; /* XXX Finish temperature alarms. */ RD1(sc, MAX77620_REG_INTENLBT, &intenlbt); RD1(sc, MAX77620_REG_INTLBT, &intlbt); RD1(sc, MAX77620_REG_IRQTOP, &irqtop); RD1(sc, MAX77620_REG_IRQTOPM, &irqtopm); RD1(sc, MAX77620_REG_IRQSD, &irqsd); RD1(sc, MAX77620_REG_IRQMASKSD, &irqmasksd); RD1(sc, MAX77620_REG_IRQ_LVL2_L0_7, &irq_lvl2_l0_7); RD1(sc, MAX77620_REG_IRQ_MSK_L0_7, &irq_msk_l0_7); RD1(sc, MAX77620_REG_IRQ_LVL2_L8, &irq_lvl2_l8); RD1(sc, MAX77620_REG_IRQ_MSK_L8, &irq_msk_l8); RD1(sc, MAX77620_REG_IRQ_LVL2_GPIO, &irq_lvl2_gpio); RD1(sc, MAX77620_REG_ONOFFIRQ, &onoffirq); RD1(sc, MAX77620_REG_ONOFFIRQM, &onoffirqm); printf("%s: intlbt: 0x%02X, intenlbt: 0x%02X\n", __func__, intlbt, intenlbt); printf("%s: irqtop: 0x%02X, irqtopm: 0x%02X\n", __func__, irqtop, irqtopm); printf("%s: irqsd: 0x%02X, irqmasksd: 0x%02X\n", __func__, irqsd, irqmasksd); printf("%s: onoffirq: 0x%02X, onoffirqm: 0x%02X\n", __func__, onoffirq, onoffirqm); printf("%s: irq_lvl2_l0_7: 0x%02X, irq_msk_l0_7: 0x%02X\n", __func__, irq_lvl2_l0_7, irq_msk_l0_7); printf("%s: irq_lvl2_l8: 0x%02X, irq_msk_l8: 0x%02X\n", __func__, irq_lvl2_l8, irq_msk_l8); printf("%s: irq_lvl2_gpio: 0x%02X\n", __func__, irq_lvl2_gpio); } #endif static int max77620_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "MAX77620 PMIC"); return (BUS_PROBE_DEFAULT); } static int max77620_attach(device_t dev) { struct max77620_softc *sc; int rv, rid; phandle_t node; sc = device_get_softc(dev); sc->dev = dev; sc->bus_addr = iicbus_get_addr(dev); node = ofw_bus_get_node(sc->dev); rv = 0; LOCK_INIT(sc); rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); #ifdef notyet /* Interrupt parent is not implemented */ if (sc->irq_res == NULL) { device_printf(dev, "Cannot allocate interrupt.\n"); rv = ENXIO; goto fail; } #endif rv = max77620_parse_fdt(sc, node); if (rv != 0) goto fail; rv = max77620_get_version(sc); if (rv != 0) goto fail; rv = max77620_init(sc); if (rv != 0) goto fail; rv = max77620_regulator_attach(sc, node); if (rv != 0) goto fail; rv = max77620_gpio_attach(sc, node); if (rv != 0) goto fail; rv = max77620_rtc_create(sc, node); if (rv != 0) goto fail; fdt_pinctrl_register(dev, NULL); fdt_pinctrl_configure_by_name(dev, "default"); /* Setup interrupt. */ #ifdef notyet rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, max77620_intr, sc, &sc->irq_h); if (rv) { device_printf(dev, "Cannot setup interrupt.\n"); goto fail; } #endif return (bus_generic_attach(dev)); fail: if (sc->irq_h != NULL) bus_teardown_intr(dev, sc->irq_res, sc->irq_h); if (sc->irq_res != NULL) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); LOCK_DESTROY(sc); return (rv); } static int max77620_detach(device_t dev) { struct max77620_softc *sc; sc = device_get_softc(dev); if (sc->irq_h != NULL) bus_teardown_intr(dev, sc->irq_res, sc->irq_h); if (sc->irq_res != NULL) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); LOCK_DESTROY(sc); return (bus_generic_detach(dev)); } static phandle_t max77620_gpio_get_node(device_t bus, device_t dev) { /* We only have one child, the GPIO bus, which needs our own node. */ return (ofw_bus_get_node(bus)); } static device_method_t max77620_methods[] = { /* Device interface */ DEVMETHOD(device_probe, max77620_probe), DEVMETHOD(device_attach, max77620_attach), DEVMETHOD(device_detach, max77620_detach), /* Regdev interface */ DEVMETHOD(regdev_map, max77620_regulator_map), /* GPIO protocol interface */ DEVMETHOD(gpio_get_bus, max77620_gpio_get_bus), DEVMETHOD(gpio_pin_max, max77620_gpio_pin_max), DEVMETHOD(gpio_pin_getname, max77620_gpio_pin_getname), DEVMETHOD(gpio_pin_getflags, max77620_gpio_pin_getflags), DEVMETHOD(gpio_pin_getcaps, max77620_gpio_pin_getcaps), DEVMETHOD(gpio_pin_setflags, max77620_gpio_pin_setflags), DEVMETHOD(gpio_pin_get, max77620_gpio_pin_get), DEVMETHOD(gpio_pin_set, max77620_gpio_pin_set), DEVMETHOD(gpio_pin_toggle, max77620_gpio_pin_toggle), DEVMETHOD(gpio_map_gpios, max77620_gpio_map_gpios), /* fdt_pinctrl interface */ DEVMETHOD(fdt_pinctrl_configure, max77620_pinmux_configure), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_node, max77620_gpio_get_node), DEVMETHOD_END }; static DEFINE_CLASS_0(gpio, max77620_driver, max77620_methods, sizeof(struct max77620_softc)); EARLY_DRIVER_MODULE(max77620, iicbus, max77620_driver, NULL, NULL, 74); diff --git a/sys/arm64/nvidia/tegra210/max77620_regulators.c b/sys/arm64/nvidia/tegra210/max77620_regulators.c index 3bfed6815711..af1a5af20ec3 100644 --- a/sys/arm64/nvidia/tegra210/max77620_regulators.c +++ b/sys/arm64/nvidia/tegra210/max77620_regulators.c @@ -1,885 +1,885 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright 2020 Michal Meloun * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include "max77620.h" MALLOC_DEFINE(M_MAX77620_REG, "MAX77620 regulator", "MAX77620 power regulator"); #define DIV_ROUND_UP(n,d) howmany(n, d) enum max77620_reg_id { MAX77620_REG_ID_SD0, MAX77620_REG_ID_SD1, MAX77620_REG_ID_SD2, MAX77620_REG_ID_SD3, MAX77620_REG_ID_LDO0, MAX77620_REG_ID_LDO1, MAX77620_REG_ID_LDO2, MAX77620_REG_ID_LDO3, MAX77620_REG_ID_LDO4, MAX77620_REG_ID_LDO5, MAX77620_REG_ID_LDO6, MAX77620_REG_ID_LDO7, MAX77620_REG_ID_LDO8, }; /* Initial configuration. */ struct max77620_regnode_init_def { struct regnode_init_def reg_init_def; int active_fps_src; int active_fps_pu_slot; int active_fps_pd_slot; int suspend_fps_src; int suspend_fps_pu_slot; int suspend_fps_pd_slot; int ramp_rate_setting; }; /* Regulator HW definition. */ struct reg_def { intptr_t id; /* ID */ char *name; /* Regulator name */ char *supply_name; /* Source property name */ bool is_sd_reg; /* SD or LDO regulator? */ uint8_t volt_reg; uint8_t volt_vsel_mask; uint8_t cfg_reg; uint8_t fps_reg; uint8_t pwr_mode_reg; uint8_t pwr_mode_mask; uint8_t pwr_mode_shift; struct regulator_range *ranges; int nranges; }; struct max77620_reg_sc { struct regnode *regnode; struct max77620_softc *base_sc; struct reg_def *def; phandle_t xref; struct regnode_std_param *param; /* Configured values */ int active_fps_src; int active_fps_pu_slot; int active_fps_pd_slot; int suspend_fps_src; int suspend_fps_pu_slot; int suspend_fps_pd_slot; int ramp_rate_setting; int enable_usec; uint8_t enable_pwr_mode; /* Cached values */ uint8_t fps_src; uint8_t pwr_mode; int pwr_ramp_delay; }; static struct regulator_range max77620_sd0_ranges[] = { REG_RANGE_INIT(0, 64, 600000, 12500), /* 0.6V - 1.4V / 12.5mV */ }; static struct regulator_range max77620_sd1_ranges[] = { REG_RANGE_INIT(0, 76, 600000, 12500), /* 0.6V - 1.55V / 12.5mV */ }; static struct regulator_range max77620_sdx_ranges[] = { REG_RANGE_INIT(0, 255, 600000, 12500), /* 0.6V - 3.7875V / 12.5mV */ }; static struct regulator_range max77620_ldo0_1_ranges[] = { REG_RANGE_INIT(0, 63, 800000, 25000), /* 0.8V - 2.375V / 25mV */ }; static struct regulator_range max77620_ldo4_ranges[] = { REG_RANGE_INIT(0, 63, 800000, 12500), /* 0.8V - 1.5875V / 12.5mV */ }; static struct regulator_range max77620_ldox_ranges[] = { REG_RANGE_INIT(0, 63, 800000, 50000), /* 0.8V - 3.95V / 50mV */ }; static struct reg_def max77620s_def[] = { { .id = MAX77620_REG_ID_SD0, .name = "sd0", .supply_name = "in-sd0", .is_sd_reg = true, .volt_reg = MAX77620_REG_SD0, .volt_vsel_mask = MAX77620_SD0_VSEL_MASK, .cfg_reg = MAX77620_REG_CFG_SD0, .fps_reg = MAX77620_REG_FPS_SD0, .pwr_mode_reg = MAX77620_REG_CFG_SD0, .pwr_mode_mask = MAX77620_SD_POWER_MODE_MASK, .pwr_mode_shift = MAX77620_SD_POWER_MODE_SHIFT, .ranges = max77620_sd0_ranges, .nranges = nitems(max77620_sd0_ranges), }, { .id = MAX77620_REG_ID_SD1, .name = "sd1", .supply_name = "in-sd1", .is_sd_reg = true, .volt_reg = MAX77620_REG_SD1, .volt_vsel_mask = MAX77620_SD1_VSEL_MASK, .cfg_reg = MAX77620_REG_CFG_SD1, .fps_reg = MAX77620_REG_FPS_SD1, .pwr_mode_reg = MAX77620_REG_CFG_SD1, .pwr_mode_mask = MAX77620_SD_POWER_MODE_MASK, .pwr_mode_shift = MAX77620_SD_POWER_MODE_SHIFT, .ranges = max77620_sd1_ranges, .nranges = nitems(max77620_sd1_ranges), }, { .id = MAX77620_REG_ID_SD2, .name = "sd2", .supply_name = "in-sd2", .is_sd_reg = true, .volt_reg = MAX77620_REG_SD2, .volt_vsel_mask = MAX77620_SDX_VSEL_MASK, .cfg_reg = MAX77620_REG_CFG_SD2, .fps_reg = MAX77620_REG_FPS_SD2, .pwr_mode_reg = MAX77620_REG_CFG_SD2, .pwr_mode_mask = MAX77620_SD_POWER_MODE_MASK, .pwr_mode_shift = MAX77620_SD_POWER_MODE_SHIFT, .ranges = max77620_sdx_ranges, .nranges = nitems(max77620_sdx_ranges), }, { .id = MAX77620_REG_ID_SD3, .name = "sd3", .supply_name = "in-sd3", .is_sd_reg = true, .volt_reg = MAX77620_REG_SD3, .volt_vsel_mask = MAX77620_SDX_VSEL_MASK, .cfg_reg = MAX77620_REG_CFG_SD3, .fps_reg = MAX77620_REG_FPS_SD3, .pwr_mode_reg = MAX77620_REG_CFG_SD3, .pwr_mode_mask = MAX77620_SD_POWER_MODE_MASK, .pwr_mode_shift = MAX77620_SD_POWER_MODE_SHIFT, .ranges = max77620_sdx_ranges, .nranges = nitems(max77620_sdx_ranges), }, { .id = MAX77620_REG_ID_LDO0, .name = "ldo0", .supply_name = "vin-ldo0-1", .volt_reg = MAX77620_REG_CFG_LDO0, .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, .is_sd_reg = false, .cfg_reg = MAX77620_REG_CFG2_LDO0, .fps_reg = MAX77620_REG_FPS_LDO0, .pwr_mode_reg = MAX77620_REG_CFG_LDO0, .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, .ranges = max77620_ldo0_1_ranges, .nranges = nitems(max77620_ldo0_1_ranges), }, { .id = MAX77620_REG_ID_LDO1, .name = "ldo1", .supply_name = "in-ldo0-1", .is_sd_reg = false, .volt_reg = MAX77620_REG_CFG_LDO1, .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, .cfg_reg = MAX77620_REG_CFG2_LDO1, .fps_reg = MAX77620_REG_FPS_LDO1, .pwr_mode_reg = MAX77620_REG_CFG_LDO1, .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, .ranges = max77620_ldo0_1_ranges, .nranges = nitems(max77620_ldo0_1_ranges), }, { .id = MAX77620_REG_ID_LDO2, .name = "ldo2", .supply_name = "in-ldo2", .is_sd_reg = false, .volt_reg = MAX77620_REG_CFG_LDO2, .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, .cfg_reg = MAX77620_REG_CFG2_LDO2, .fps_reg = MAX77620_REG_FPS_LDO2, .pwr_mode_reg = MAX77620_REG_CFG_LDO2, .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, .ranges = max77620_ldox_ranges, .nranges = nitems(max77620_ldox_ranges), }, { .id = MAX77620_REG_ID_LDO3, .name = "ldo3", .supply_name = "in-ldo3-5", .is_sd_reg = false, .volt_reg = MAX77620_REG_CFG_LDO3, .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, .cfg_reg = MAX77620_REG_CFG2_LDO3, .fps_reg = MAX77620_REG_FPS_LDO3, .pwr_mode_reg = MAX77620_REG_CFG_LDO3, .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, .ranges = max77620_ldox_ranges, .nranges = nitems(max77620_ldox_ranges), }, { .id = MAX77620_REG_ID_LDO4, .name = "ldo4", .supply_name = "in-ldo4-6", .is_sd_reg = false, .volt_reg = MAX77620_REG_CFG_LDO4, .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, .cfg_reg = MAX77620_REG_CFG2_LDO4, .fps_reg = MAX77620_REG_FPS_LDO4, .pwr_mode_reg = MAX77620_REG_CFG_LDO4, .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, .ranges = max77620_ldo4_ranges, .nranges = nitems(max77620_ldo4_ranges), }, { .id = MAX77620_REG_ID_LDO5, .name = "ldo5", .supply_name = "in-ldo3-5", .is_sd_reg = false, .volt_reg = MAX77620_REG_CFG_LDO5, .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, .cfg_reg = MAX77620_REG_CFG2_LDO5, .fps_reg = MAX77620_REG_FPS_LDO5, .pwr_mode_reg = MAX77620_REG_CFG_LDO5, .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, .ranges = max77620_ldox_ranges, .nranges = nitems(max77620_ldox_ranges), }, { .id = MAX77620_REG_ID_LDO6, .name = "ldo6", .supply_name = "in-ldo4-6", .is_sd_reg = false, .volt_reg = MAX77620_REG_CFG_LDO6, .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, .cfg_reg = MAX77620_REG_CFG2_LDO6, .fps_reg = MAX77620_REG_FPS_LDO6, .pwr_mode_reg = MAX77620_REG_CFG_LDO6, .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, .ranges = max77620_ldox_ranges, .nranges = nitems(max77620_ldox_ranges), }, { .id = MAX77620_REG_ID_LDO7, .name = "ldo7", .supply_name = "in-ldo7-8", .is_sd_reg = false, .volt_reg = MAX77620_REG_CFG_LDO7, .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, .cfg_reg = MAX77620_REG_CFG2_LDO7, .fps_reg = MAX77620_REG_FPS_LDO7, .pwr_mode_reg = MAX77620_REG_CFG_LDO7, .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, .ranges = max77620_ldox_ranges, .nranges = nitems(max77620_ldox_ranges), }, { .id = MAX77620_REG_ID_LDO8, .name = "ldo8", .supply_name = "in-ldo7-8", .is_sd_reg = false, .volt_reg = MAX77620_REG_CFG_LDO8, .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, .cfg_reg = MAX77620_REG_CFG2_LDO8, .fps_reg = MAX77620_REG_FPS_LDO8, .pwr_mode_reg = MAX77620_REG_CFG_LDO8, .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, .ranges = max77620_ldox_ranges, .nranges = nitems(max77620_ldox_ranges), }, }; static int max77620_regnode_init(struct regnode *regnode); static int max77620_regnode_enable(struct regnode *regnode, bool enable, int *udelay); static int max77620_regnode_set_volt(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay); static int max77620_regnode_get_volt(struct regnode *regnode, int *uvolt); static regnode_method_t max77620_regnode_methods[] = { /* Regulator interface */ REGNODEMETHOD(regnode_init, max77620_regnode_init), REGNODEMETHOD(regnode_enable, max77620_regnode_enable), REGNODEMETHOD(regnode_set_voltage, max77620_regnode_set_volt), REGNODEMETHOD(regnode_get_voltage, max77620_regnode_get_volt), REGNODEMETHOD_END }; DEFINE_CLASS_1(max77620_regnode, max77620_regnode_class, max77620_regnode_methods, sizeof(struct max77620_reg_sc), regnode_class); static int max77620_get_sel(struct max77620_reg_sc *sc, uint8_t *sel) { int rv; rv = RD1(sc->base_sc, sc->def->volt_reg, sel); if (rv != 0) { printf("%s: cannot read volatge selector: %d\n", regnode_get_name(sc->regnode), rv); return (rv); } *sel &= sc->def->volt_vsel_mask; *sel >>= ffs(sc->def->volt_vsel_mask) - 1; return (0); } static int max77620_set_sel(struct max77620_reg_sc *sc, uint8_t sel) { int rv; sel <<= ffs(sc->def->volt_vsel_mask) - 1; sel &= sc->def->volt_vsel_mask; rv = RM1(sc->base_sc, sc->def->volt_reg, sc->def->volt_vsel_mask, sel); if (rv != 0) { printf("%s: cannot set volatge selector: %d\n", regnode_get_name(sc->regnode), rv); return (rv); } return (rv); } static int max77620_get_fps_src(struct max77620_reg_sc *sc, uint8_t *fps_src) { uint8_t val; int rv; rv = RD1(sc->base_sc, sc->def->fps_reg, &val); if (rv != 0) return (rv); *fps_src = (val & MAX77620_FPS_SRC_MASK) >> MAX77620_FPS_SRC_SHIFT; return (0); } static int max77620_set_fps_src(struct max77620_reg_sc *sc, uint8_t fps_src) { int rv; rv = RM1(sc->base_sc, sc->def->fps_reg, MAX77620_FPS_SRC_MASK, fps_src << MAX77620_FPS_SRC_SHIFT); if (rv != 0) return (rv); sc->fps_src = fps_src; return (0); } static int max77620_set_fps_slots(struct max77620_reg_sc *sc, bool suspend) { uint8_t mask, val; int pu_slot, pd_slot, rv; if (suspend) { pu_slot = sc->suspend_fps_pu_slot; pd_slot = sc->suspend_fps_pd_slot; } else { pu_slot = sc->active_fps_pu_slot; pd_slot = sc->active_fps_pd_slot; } mask = 0; val = 0; if (pu_slot >= 0) { mask |= MAX77620_FPS_PU_PERIOD_MASK; val |= ((uint8_t)pu_slot << MAX77620_FPS_PU_PERIOD_SHIFT) & MAX77620_FPS_PU_PERIOD_MASK; } if (pd_slot >= 0) { mask |= MAX77620_FPS_PD_PERIOD_MASK; val |= ((uint8_t)pd_slot << MAX77620_FPS_PD_PERIOD_SHIFT) & MAX77620_FPS_PD_PERIOD_MASK; } rv = RM1(sc->base_sc, sc->def->fps_reg, mask, val); if (rv != 0) return (rv); return (0); } static int max77620_get_pwr_mode(struct max77620_reg_sc *sc, uint8_t *pwr_mode) { uint8_t val; int rv; rv = RD1(sc->base_sc, sc->def->pwr_mode_reg, &val); if (rv != 0) return (rv); *pwr_mode = (val & sc->def->pwr_mode_mask) >> sc->def->pwr_mode_shift; return (0); } static int max77620_set_pwr_mode(struct max77620_reg_sc *sc, uint8_t pwr_mode) { int rv; rv = RM1(sc->base_sc, sc->def->pwr_mode_reg, sc->def->pwr_mode_shift, pwr_mode << sc->def->pwr_mode_shift); if (rv != 0) return (rv); sc->pwr_mode = pwr_mode; return (0); } static int max77620_get_pwr_ramp_delay(struct max77620_reg_sc *sc, int *rate) { uint8_t val; int rv; rv = RD1(sc->base_sc, sc->def->cfg_reg, &val); if (rv != 0) return (rv); if (sc->def->is_sd_reg) { val = (val & MAX77620_SD_SR_MASK) >> MAX77620_SD_SR_SHIFT; if (val == 0) *rate = 13750; else if (val == 1) *rate = 27500; else if (val == 2) *rate = 55000; else *rate = 100000; } else { val = (val & MAX77620_LDO_SLEW_RATE_MASK) >> MAX77620_LDO_SLEW_RATE_SHIFT; if (val == 0) *rate = 100000; else *rate = 5000; } sc->pwr_ramp_delay = *rate; return (0); } static int max77620_set_pwr_ramp_delay(struct max77620_reg_sc *sc, int rate) { uint8_t val, mask; int rv; if (sc->def->is_sd_reg) { if (rate <= 13750) val = 0; else if (rate <= 27500) val = 1; else if (rate <= 55000) val = 2; else val = 3; val <<= MAX77620_SD_SR_SHIFT; mask = MAX77620_SD_SR_MASK; } else { if (rate <= 5000) val = 1; else val = 0; val <<= MAX77620_LDO_SLEW_RATE_SHIFT; mask = MAX77620_LDO_SLEW_RATE_MASK; } rv = RM1(sc->base_sc, sc->def->cfg_reg, mask, val); if (rv != 0) return (rv); return (0); } static int max77620_regnode_init(struct regnode *regnode) { struct max77620_reg_sc *sc; uint8_t val; int intval, rv; sc = regnode_get_softc(regnode); sc->enable_usec = 500; sc->enable_pwr_mode = MAX77620_POWER_MODE_NORMAL; #if 0 { uint8_t val1, val2, val3; RD1(sc->base_sc, sc->def->volt_reg, &val1); RD1(sc->base_sc, sc->def->cfg_reg, &val2); RD1(sc->base_sc, sc->def->fps_reg, &val3); printf("%s: Volt: 0x%02X, CFG: 0x%02X, FPS: 0x%02X\n", regnode_get_name(sc->regnode), val1, val2, val3); } #endif /* Get current power mode */ rv = max77620_get_pwr_mode(sc, &val); if (rv != 0) { printf("%s: cannot read current power mode: %d\n", regnode_get_name(sc->regnode), rv); return (rv); } sc->pwr_mode = val; /* Get current power ramp delay */ rv = max77620_get_pwr_ramp_delay(sc, &intval); if (rv != 0) { printf("%s: cannot read current power mode: %d\n", regnode_get_name(sc->regnode), rv); return (rv); } sc->pwr_ramp_delay = intval; /* Get FPS source if is not specified. */ if (sc->active_fps_src == -1) { rv = max77620_get_fps_src(sc, &val); if (rv != 0) { printf("%s: cannot read current FPS source: %d\n", regnode_get_name(sc->regnode), rv); return (rv); } sc->active_fps_src = val; } /* Configure power mode non-FPS controlled regulators. */ if (sc->active_fps_src != MAX77620_FPS_SRC_NONE || (sc->pwr_mode != MAX77620_POWER_MODE_DISABLE && sc->pwr_mode != sc->enable_pwr_mode)) { rv = max77620_set_pwr_mode(sc, (uint8_t)sc->enable_pwr_mode); if (rv != 0) { printf("%s: cannot set power mode: %d\n", regnode_get_name(sc->regnode), rv); return (rv); } } /* Set FPS source. */ rv = max77620_set_fps_src(sc, sc->active_fps_src); if (rv != 0) { printf("%s: cannot setup FPS source: %d\n", regnode_get_name(sc->regnode), rv); return (rv); } /* Set FPS slots. */ rv = max77620_set_fps_slots(sc, false); if (rv != 0) { printf("%s: cannot setup power slots: %d\n", regnode_get_name(sc->regnode), rv); return (rv); } /* Setup power ramp . */ if (sc->ramp_rate_setting != -1) { rv = max77620_set_pwr_ramp_delay(sc, sc->pwr_ramp_delay); if (rv != 0) { printf("%s: cannot set power ramp delay: %d\n", regnode_get_name(sc->regnode), rv); return (rv); } } return (0); } static void max77620_fdt_parse(struct max77620_softc *sc, phandle_t node, struct reg_def *def, struct max77620_regnode_init_def *init_def) { int rv; phandle_t parent, supply_node; char prop_name[64]; /* Maximum OFW property name length. */ rv = regulator_parse_ofw_stdparam(sc->dev, node, &init_def->reg_init_def); rv = OF_getencprop(node, "maxim,active-fps-source", &init_def->active_fps_src, sizeof(init_def->active_fps_src)); if (rv <= 0) init_def->active_fps_src = MAX77620_FPS_SRC_DEF; rv = OF_getencprop(node, "maxim,active-fps-power-up-slot", &init_def->active_fps_pu_slot, sizeof(init_def->active_fps_pu_slot)); if (rv <= 0) init_def->active_fps_pu_slot = -1; rv = OF_getencprop(node, "maxim,active-fps-power-down-slot", &init_def->active_fps_pd_slot, sizeof(init_def->active_fps_pd_slot)); if (rv <= 0) init_def->active_fps_pd_slot = -1; rv = OF_getencprop(node, "maxim,suspend-fps-source", &init_def->suspend_fps_src, sizeof(init_def->suspend_fps_src)); if (rv <= 0) init_def->suspend_fps_src = -1; rv = OF_getencprop(node, "maxim,suspend-fps-power-up-slot", &init_def->suspend_fps_pu_slot, sizeof(init_def->suspend_fps_pu_slot)); if (rv <= 0) init_def->suspend_fps_pu_slot = -1; rv = OF_getencprop(node, "maxim,suspend-fps-power-down-slot", &init_def->suspend_fps_pd_slot, sizeof(init_def->suspend_fps_pd_slot)); if (rv <= 0) init_def->suspend_fps_pd_slot = -1; rv = OF_getencprop(node, "maxim,ramp-rate-setting", &init_def->ramp_rate_setting, sizeof(init_def->ramp_rate_setting)); if (rv <= 0) init_def->ramp_rate_setting = -1; /* Get parent supply. */ if (def->supply_name == NULL) return; parent = OF_parent(node); snprintf(prop_name, sizeof(prop_name), "%s-supply", def->supply_name); rv = OF_getencprop(parent, prop_name, &supply_node, sizeof(supply_node)); if (rv <= 0) return; supply_node = OF_node_from_xref(supply_node); rv = OF_getprop_alloc(supply_node, "regulator-name", (void **)&init_def->reg_init_def.parent_name); if (rv <= 0) init_def->reg_init_def.parent_name = NULL; } static struct max77620_reg_sc * max77620_attach(struct max77620_softc *sc, phandle_t node, struct reg_def *def) { struct max77620_reg_sc *reg_sc; struct max77620_regnode_init_def init_def; struct regnode *regnode; bzero(&init_def, sizeof(init_def)); max77620_fdt_parse(sc, node, def, &init_def); init_def.reg_init_def.id = def->id; init_def.reg_init_def.ofw_node = node; regnode = regnode_create(sc->dev, &max77620_regnode_class, &init_def.reg_init_def); if (regnode == NULL) { device_printf(sc->dev, "Cannot create regulator.\n"); return (NULL); } reg_sc = regnode_get_softc(regnode); /* Init regulator softc. */ reg_sc->regnode = regnode; reg_sc->base_sc = sc; reg_sc->def = def; reg_sc->xref = OF_xref_from_node(node); reg_sc->param = regnode_get_stdparam(regnode); reg_sc->active_fps_src = init_def.active_fps_src; reg_sc->active_fps_pu_slot = init_def.active_fps_pu_slot; reg_sc->active_fps_pd_slot = init_def.active_fps_pd_slot; reg_sc->suspend_fps_src = init_def.suspend_fps_src; reg_sc->suspend_fps_pu_slot = init_def.suspend_fps_pu_slot; reg_sc->suspend_fps_pd_slot = init_def.suspend_fps_pd_slot; reg_sc->ramp_rate_setting = init_def.ramp_rate_setting; regnode_register(regnode); if (bootverbose) { int volt, rv; regnode_topo_slock(); rv = regnode_get_voltage(regnode, &volt); if (rv == ENODEV) { device_printf(sc->dev, " Regulator %s: parent doesn't exist yet.\n", regnode_get_name(regnode)); } else if (rv != 0) { device_printf(sc->dev, " Regulator %s: voltage: INVALID!!!\n", regnode_get_name(regnode)); } else { device_printf(sc->dev, " Regulator %s: voltage: %d uV\n", regnode_get_name(regnode), volt); device_printf(sc->dev, " FPS source: %d, mode: %d, ramp delay: %d\n", reg_sc->fps_src, reg_sc->pwr_mode, reg_sc->pwr_ramp_delay); } regnode_topo_unlock(); } return (reg_sc); } int max77620_regulator_attach(struct max77620_softc *sc, phandle_t node) { struct max77620_reg_sc *reg; phandle_t child, rnode; int i; rnode = ofw_bus_find_child(node, "regulators"); if (rnode <= 0) { device_printf(sc->dev, " Cannot find regulators subnode\n"); return (ENXIO); } sc->nregs = nitems(max77620s_def); sc->regs = malloc(sizeof(struct max77620_reg_sc *) * sc->nregs, M_MAX77620_REG, M_WAITOK | M_ZERO); /* Attach all known regulators if exist in DT. */ for (i = 0; i < sc->nregs; i++) { child = ofw_bus_find_child(rnode, max77620s_def[i].name); if (child == 0) { if (bootverbose) device_printf(sc->dev, "Regulator %s missing in DT\n", max77620s_def[i].name); continue; } if (ofw_bus_node_status_okay(child) == 0) continue; reg = max77620_attach(sc, child, max77620s_def + i); if (reg == NULL) { device_printf(sc->dev, "Cannot attach regulator: %s\n", max77620s_def[i].name); return (ENXIO); } sc->regs[i] = reg; } return (0); } int max77620_regulator_map(device_t dev, phandle_t xref, int ncells, pcell_t *cells, intptr_t *num) { struct max77620_softc *sc; int i; sc = device_get_softc(dev); for (i = 0; i < sc->nregs; i++) { if (sc->regs[i] == NULL) continue; if (sc->regs[i]->xref == xref) { *num = sc->regs[i]->def->id; return (0); } } return (ENXIO); } static int max77620_regnode_enable(struct regnode *regnode, bool val, int *udelay) { struct max77620_reg_sc *sc; uint8_t mode; int rv; sc = regnode_get_softc(regnode); if (sc->active_fps_src != MAX77620_FPS_SRC_NONE) { *udelay = 0; return (0); } if (val) mode = sc->enable_pwr_mode; else mode = MAX77620_POWER_MODE_DISABLE; rv = max77620_set_pwr_mode(sc, mode); if (rv != 0) { printf("%s: cannot set power mode: %d\n", regnode_get_name(sc->regnode), rv); return (rv); } *udelay = sc->enable_usec; return (0); } static int max77620_regnode_set_volt(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay) { struct max77620_reg_sc *sc; uint8_t sel; int rv; sc = regnode_get_softc(regnode); *udelay = 0; rv = regulator_range_volt_to_sel8(sc->def->ranges, sc->def->nranges, min_uvolt, max_uvolt, &sel); if (rv != 0) return (rv); rv = max77620_set_sel(sc, sel); return (rv); } static int max77620_regnode_get_volt(struct regnode *regnode, int *uvolt) { struct max77620_reg_sc *sc; uint8_t sel; int rv; sc = regnode_get_softc(regnode); rv = max77620_get_sel(sc, &sel); if (rv != 0) return (rv); rv = regulator_range_sel8_to_volt(sc->def->ranges, sc->def->nranges, sel, uvolt); return (rv); return(0); } diff --git a/sys/arm64/nvidia/tegra210/tegra210_cpufreq.c b/sys/arm64/nvidia/tegra210/tegra210_cpufreq.c index 99b54b224e89..9b248a09bd58 100644 --- a/sys/arm64/nvidia/tegra210/tegra210_cpufreq.c +++ b/sys/arm64/nvidia/tegra210/tegra210_cpufreq.c @@ -1,496 +1,496 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright 2020 Michal Meloun * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include "cpufreq_if.h" /* CPU voltage table entry */ struct speedo_entry { uint64_t freq; /* Frequency point */ int c0; /* Coeeficient values for */ int c1; /* quadratic equation: */ int c2; /* c2 * speedo^2 + c1 * speedo + c0 */ }; struct cpu_volt_def { int min_uvolt; /* Min allowed CPU voltage */ int max_uvolt; /* Max allowed CPU voltage */ int step_uvolt; /* Step of CPU voltage */ int speedo_scale; /* Scaling factor for cvt */ int speedo_nitems; /* Size of speedo table */ struct speedo_entry *speedo_tbl; /* CPU voltage table */ }; struct cpu_speed_point { uint64_t freq; /* Frequecy */ int uvolt; /* Requested voltage */ }; static struct speedo_entry tegra210_speedo_tbl[] = { {204000000UL, 1007452, -23865, 370}, {306000000UL, 1052709, -24875, 370}, {408000000UL, 1099069, -25895, 370}, {510000000UL, 1146534, -26905, 370}, {612000000UL, 1195102, -27915, 370}, {714000000UL, 1244773, -28925, 370}, {816000000UL, 1295549, -29935, 370}, {918000000UL, 1347428, -30955, 370}, {1020000000UL, 1400411, -31965, 370}, {1122000000UL, 1454497, -32975, 370}, {1224000000UL, 1509687, -33985, 370}, {1326000000UL, 1565981, -35005, 370}, {1428000000UL, 1623379, -36015, 370}, {1530000000UL, 1681880, -37025, 370}, {1632000000UL, 1741485, -38035, 370}, {1734000000UL, 1802194, -39055, 370}, {1836000000UL, 1864006, -40065, 370}, {1912500000UL, 1910780, -40815, 370}, {2014500000UL, 1227000, 0, 0}, {2218500000UL, 1227000, 0, 0}, }; static struct cpu_volt_def tegra210_cpu_volt_def = { .min_uvolt = 900000, /* 0.9 V */ .max_uvolt = 1227000, /* 1.227 */ .step_uvolt = 10000, /* 10 mV */ .speedo_scale = 100, .speedo_nitems = nitems(tegra210_speedo_tbl), .speedo_tbl = tegra210_speedo_tbl, }; static uint64_t cpu_max_freq[] = { 1912500000UL, 1912500000UL, 2218500000UL, 1785000000UL, 1632000000UL, 1912500000UL, 2014500000UL, 1734000000UL, 1683000000UL, 1555500000UL, 1504500000UL, }; static uint64_t cpu_freq_tbl[] = { 204000000UL, 306000000UL, 408000000UL, 510000000UL, 612000000UL, 714000000UL, 816000000UL, 918000000UL, 1020000000UL, 1122000000UL, 1224000000UL, 1326000000UL, 1428000000UL, 1530000000UL, 1632000000UL, 1734000000UL, 1836000000UL, 1912500000UL, 2014500000UL, 2218500000UL, }; struct tegra210_cpufreq_softc { device_t dev; phandle_t node; clk_t clk_cpu_g; clk_t clk_pll_x; clk_t clk_pll_p; clk_t clk_dfll; int process_id; int speedo_id; int speedo_value; uint64_t cpu_max_freq; struct cpu_volt_def *cpu_def; struct cpu_speed_point *speed_points; int nspeed_points; struct cpu_speed_point *act_speed_point; int latency; }; static int cpufreq_lowest_freq = 1; TUNABLE_INT("hw.tegra210.cpufreq.lowest_freq", &cpufreq_lowest_freq); #define DIV_ROUND_CLOSEST(val, div) (((val) + ((div) / 2)) / (div)) #define ROUND_UP(val, div) roundup(val, div) #define ROUND_DOWN(val, div) rounddown(val, div) /* * Compute requesetd voltage for given frequency and SoC process variations, * - compute base voltage from speedo value using speedo table * - round up voltage to next regulator step * - clamp it to regulator limits */ static int freq_to_voltage(struct tegra210_cpufreq_softc *sc, uint64_t freq) { int uv, scale, min_uvolt, max_uvolt, step_uvolt; struct speedo_entry *ent; int i; /* Get speedo entry with higher frequency */ ent = NULL; for (i = 0; i < sc->cpu_def->speedo_nitems; i++) { if (sc->cpu_def->speedo_tbl[i].freq >= freq) { ent = &sc->cpu_def->speedo_tbl[i]; break; } } if (ent == NULL) ent = &sc->cpu_def->speedo_tbl[sc->cpu_def->speedo_nitems - 1]; scale = sc->cpu_def->speedo_scale; /* uV = (c2 * speedo / scale + c1) * speedo / scale + c0) */ uv = DIV_ROUND_CLOSEST(ent->c2 * sc->speedo_value, scale); uv = DIV_ROUND_CLOSEST((uv + ent->c1) * sc->speedo_value, scale) + ent->c0; step_uvolt = sc->cpu_def->step_uvolt; /* Round up it to next regulator step */ uv = ROUND_UP(uv, step_uvolt); /* Clamp result */ min_uvolt = ROUND_UP(sc->cpu_def->min_uvolt, step_uvolt); max_uvolt = ROUND_DOWN(sc->cpu_def->max_uvolt, step_uvolt); if (uv < min_uvolt) uv = min_uvolt; if (uv > max_uvolt) uv = max_uvolt; return (uv); } static void build_speed_points(struct tegra210_cpufreq_softc *sc) { int i; sc->nspeed_points = nitems(cpu_freq_tbl); sc->speed_points = malloc(sizeof(struct cpu_speed_point) * sc->nspeed_points, M_DEVBUF, M_NOWAIT); for (i = 0; i < sc->nspeed_points; i++) { sc->speed_points[i].freq = cpu_freq_tbl[i]; sc->speed_points[i].uvolt = freq_to_voltage(sc, cpu_freq_tbl[i]); } } static struct cpu_speed_point * get_speed_point(struct tegra210_cpufreq_softc *sc, uint64_t freq) { int i; if (sc->speed_points[0].freq >= freq) return (sc->speed_points + 0); for (i = 0; i < sc->nspeed_points - 1; i++) { if (sc->speed_points[i + 1].freq > freq) return (sc->speed_points + i); } return (sc->speed_points + sc->nspeed_points - 1); } static int tegra210_cpufreq_settings(device_t dev, struct cf_setting *sets, int *count) { struct tegra210_cpufreq_softc *sc; int i, j; if (sets == NULL || count == NULL) return (EINVAL); sc = device_get_softc(dev); memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * (*count)); for (i = 0, j = sc->nspeed_points - 1; j >= 0; j--) { if (sc->cpu_max_freq < sc->speed_points[j].freq) continue; sets[i].freq = sc->speed_points[j].freq / 1000000; sets[i].volts = sc->speed_points[j].uvolt / 1000; sets[i].lat = sc->latency; sets[i].dev = dev; i++; } *count = i; return (0); } static int set_cpu_freq(struct tegra210_cpufreq_softc *sc, uint64_t freq) { struct cpu_speed_point *point; int rv; point = get_speed_point(sc, freq); /* Set PLLX frequency */ rv = clk_set_freq(sc->clk_pll_x, point->freq, CLK_SET_ROUND_DOWN); if (rv != 0) { device_printf(sc->dev, "Can't set CPU clock frequency\n"); return (rv); } sc->act_speed_point = point; return (0); } static int tegra210_cpufreq_set(device_t dev, const struct cf_setting *cf) { struct tegra210_cpufreq_softc *sc; uint64_t freq; int rv; if (cf == NULL || cf->freq < 0) return (EINVAL); sc = device_get_softc(dev); freq = cf->freq; if (freq < cpufreq_lowest_freq) freq = cpufreq_lowest_freq; freq *= 1000000; if (freq >= sc->cpu_max_freq) freq = sc->cpu_max_freq; rv = set_cpu_freq(sc, freq); return (rv); } static int tegra210_cpufreq_get(device_t dev, struct cf_setting *cf) { struct tegra210_cpufreq_softc *sc; if (cf == NULL) return (EINVAL); sc = device_get_softc(dev); memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf)); cf->dev = NULL; cf->freq = sc->act_speed_point->freq / 1000000; cf->volts = sc->act_speed_point->uvolt / 1000; /* Transition latency in us. */ cf->lat = sc->latency; /* Driver providing this setting. */ cf->dev = dev; return (0); } static int tegra210_cpufreq_type(device_t dev, int *type) { if (type == NULL) return (EINVAL); *type = CPUFREQ_TYPE_ABSOLUTE; return (0); } static int get_fdt_resources(struct tegra210_cpufreq_softc *sc, phandle_t node) { int rv; device_t parent_dev; parent_dev = device_get_parent(sc->dev); rv = clk_get_by_ofw_name(parent_dev, 0, "cpu_g", &sc->clk_cpu_g); if (rv != 0) { device_printf(sc->dev, "Cannot get 'cpu_g' clock: %d\n", rv); return (ENXIO); } rv = clk_get_by_ofw_name(parent_dev, 0, "pll_x", &sc->clk_pll_x); if (rv != 0) { device_printf(sc->dev, "Cannot get 'pll_x' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(parent_dev, 0, "pll_p", &sc->clk_pll_p); if (rv != 0) { device_printf(parent_dev, "Cannot get 'pll_p' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(parent_dev, 0, "dfll", &sc->clk_dfll); /* XXX DPLL is not implemented yet */ #if 0 if (rv != 0) { device_printf(sc->dev, "Cannot get 'dfll' clock\n"); return (ENXIO); } #endif return (0); } static void tegra210_cpufreq_identify(driver_t *driver, device_t parent) { phandle_t root; root = OF_finddevice("/"); if (!ofw_bus_node_is_compatible(root, "nvidia,tegra210")) return; if (device_get_unit(parent) != 0) return; if (device_find_child(parent, "tegra210_cpufreq", -1) != NULL) return; if (BUS_ADD_CHILD(parent, 0, "tegra210_cpufreq", -1) == NULL) device_printf(parent, "add child failed\n"); } static int tegra210_cpufreq_probe(device_t dev) { device_set_desc(dev, "CPU Frequency Control"); return (0); } static int tegra210_cpufreq_attach(device_t dev) { struct tegra210_cpufreq_softc *sc; uint64_t freq; int rv; sc = device_get_softc(dev); sc->dev = dev; sc->node = ofw_bus_get_node(device_get_parent(dev)); sc->process_id = tegra_sku_info.cpu_process_id; sc->speedo_id = tegra_sku_info.cpu_speedo_id; sc->speedo_value = tegra_sku_info.cpu_speedo_value; sc->cpu_def = &tegra210_cpu_volt_def; rv = get_fdt_resources(sc, sc->node); if (rv != 0) { return (rv); } build_speed_points(sc); rv = clk_get_freq(sc->clk_cpu_g, &freq); if (rv != 0) { device_printf(dev, "Can't get CPU clock frequency\n"); return (rv); } if (sc->speedo_id < nitems(cpu_max_freq)) sc->cpu_max_freq = cpu_max_freq[sc->speedo_id]; else sc->cpu_max_freq = cpu_max_freq[0]; sc->act_speed_point = get_speed_point(sc, freq); /* Set safe startup CPU frequency. */ rv = set_cpu_freq(sc, 1632000000); if (rv != 0) { device_printf(dev, "Can't set initial CPU clock frequency\n"); return (rv); } /* This device is controlled by cpufreq(4). */ cpufreq_register(dev); return (0); } static int tegra210_cpufreq_detach(device_t dev) { struct tegra210_cpufreq_softc *sc; sc = device_get_softc(dev); cpufreq_unregister(dev); if (sc->clk_cpu_g != NULL) clk_release(sc->clk_cpu_g); if (sc->clk_pll_x != NULL) clk_release(sc->clk_pll_x); if (sc->clk_pll_p != NULL) clk_release(sc->clk_pll_p); if (sc->clk_dfll != NULL) clk_release(sc->clk_dfll); return (0); } static device_method_t tegra210_cpufreq_methods[] = { /* Device interface */ DEVMETHOD(device_identify, tegra210_cpufreq_identify), DEVMETHOD(device_probe, tegra210_cpufreq_probe), DEVMETHOD(device_attach, tegra210_cpufreq_attach), DEVMETHOD(device_detach, tegra210_cpufreq_detach), /* cpufreq interface */ DEVMETHOD(cpufreq_drv_set, tegra210_cpufreq_set), DEVMETHOD(cpufreq_drv_get, tegra210_cpufreq_get), DEVMETHOD(cpufreq_drv_settings, tegra210_cpufreq_settings), DEVMETHOD(cpufreq_drv_type, tegra210_cpufreq_type), DEVMETHOD_END }; static DEFINE_CLASS_0(tegra210_cpufreq, tegra210_cpufreq_driver, tegra210_cpufreq_methods, sizeof(struct tegra210_cpufreq_softc)); DRIVER_MODULE(tegra210_cpufreq, cpu, tegra210_cpufreq_driver, NULL, NULL); diff --git a/sys/arm64/nvidia/tegra210/tegra210_xusbpadctl.c b/sys/arm64/nvidia/tegra210/tegra210_xusbpadctl.c index 75662386427f..944f4e645533 100644 --- a/sys/arm64/nvidia/tegra210/tegra210_xusbpadctl.c +++ b/sys/arm64/nvidia/tegra210/tegra210_xusbpadctl.c @@ -1,1957 +1,1957 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright 2020 Michal Meloun * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #include #include "phynode_if.h" /* FUSE calibration data. */ #define FUSE_SKU_CALIB_0 0x0F0 #define FUSE_SKU_CALIB_0_HS_CURR_LEVEL_123(x, i) (((x) >> (11 + ((i) - 1) * 6)) & 0x3F); #define FUSE_SKU_CALIB_0_HS_TERM_RANGE_ADJ(x) (((x) >> 7) & 0x0F); #define FUSE_SKU_CALIB_0_HS_CURR_LEVEL_0(x) (((x) >> 0) & 0x3F); #define FUSE_USB_CALIB_EXT_0 0x250 #define FUSE_USB_CALIB_EXT_0_RPD_CTRL(x) (((x) >> 0) & 0x1F); /* Registers. */ #define XUSB_PADCTL_USB2_PAD_MUX 0x004 #define XUSB_PADCTL_USB2_PORT_CAP 0x008 #define USB2_PORT_CAP_PORT_REVERSE_ID(p) (1 << (3 + (p) * 4)) #define USB2_PORT_CAP_PORT_INTERNAL(p) (1 << (2 + (p) * 4)) #define USB2_PORT_CAP_PORT_CAP(p, x) (((x) & 3) << ((p) * 4)) #define USB2_PORT_CAP_PORT_CAP_OTG 0x3 #define USB2_PORT_CAP_PORT_CAP_DEVICE 0x2 #define USB2_PORT_CAP_PORT_CAP_HOST 0x1 #define USB2_PORT_CAP_PORT_CAP_DISABLED 0x0 #define XUSB_PADCTL_SS_PORT_MAP 0x014 #define SS_PORT_MAP_PORT_INTERNAL(p) (1 << (3 + (p) * 4)) #define SS_PORT_MAP_PORT_MAP(p, x) (((x) & 7) << ((p) * 4)) #define XUSB_PADCTL_ELPG_PROGRAM1 0x024 #define ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN (1 << 31) #define ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 30) #define ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN (1 << 29) #define ELPG_PROGRAM1_SSP_ELPG_VCORE_DOWN(x) (1 << (2 + (x) * 3)) #define ELPG_PROGRAM1_SSP_ELPG_CLAMP_EN_EARLY(x) (1 << (1 + (x) * 3)) #define ELPG_PROGRAM1_SSP_ELPG_CLAMP_EN(x) (1 << (0 + (x) * 3)) #define XUSB_PADCTL_USB3_PAD_MUX 0x028 #define USB3_PAD_MUX_SATA_IDDQ_DISABLE(x) (1 << (8 + (x))) #define USB3_PAD_MUX_PCIE_IDDQ_DISABLE(x) (1 << (1 + (x))) #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1(x) (0x084 + (x) * 0x40) #define USB2_BATTERY_CHRG_OTGPAD_CTL1_USBON_RPU_OVRD_VAL (1 << 23) #define USB2_BATTERY_CHRG_OTGPAD_CTL1_USBON_RPU_OVRD ( 1 << 22) #define USB2_BATTERY_CHRG_OTGPAD_CTL1_USBON_RPD_OVRD_VAL (1 << 21) #define USB2_BATTERY_CHRG_OTGPAD_CTL1_USBON_RPD_OVRD (1 << 20) #define USB2_BATTERY_CHRG_OTGPAD_CTL1_USBOP_RPU_OVRD_VAL (1 << 19) #define USB2_BATTERY_CHRG_OTGPAD_CTL1_USBOP_RPU_OVRD (1 << 18) #define USB2_BATTERY_CHRG_OTGPAD_CTL1_USBOP_RPD_OVRD_VAL (1 << 17) #define USB2_BATTERY_CHRG_OTGPAD_CTL1_USBOP_RPD_OVRD (1 << 16) #define USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_DYN_DLY(x) (((x) & 0x3) << 9) #define USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV(x) (((x) & 0x3) << 7) #define USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18 (1 << 6) #define USB2_BATTERY_CHRG_OTGPAD_CTL1_DIV_DET_EN (1 << 4) #define USB2_BATTERY_CHRG_OTGPAD_CTL1_VOP_DIV2P7_DET (1 << 3) #define USB2_BATTERY_CHRG_OTGPAD_CTL1_VOP_DIV2P0_DET (1 << 2) #define USB2_BATTERY_CHRG_OTGPAD_CTL1_VON_DIV2P7_DET (1 << 1) #define USB2_BATTERY_CHRG_OTGPAD_CTL1_VON_DIV2P0_DET (1 << 0) #define XUSB_PADCTL_USB2_OTG_PAD_CTL0(x) (0x088 + (x) * 0x40) #define USB2_OTG_PAD_CTL0_PD_ZI (1 << 29) #define USB2_OTG_PAD_CTL0_PD2_OVRD_EN (1 << 28) #define USB2_OTG_PAD_CTL0_PD2 (1 << 27) #define USB2_OTG_PAD_CTL0_PD (1 << 26) #define USB2_OTG_PAD_CTL0_TERM_EN (1 << 25) #define USB2_OTG_PAD_CTL0_LS_FSLEW(x) (((x) & 0x0F) << 21) #define USB2_OTG_PAD_CTL0_LS_RSLEW(x) (((x) & 0x0F) << 17) #define USB2_OTG_PAD_CTL0_FS_FSLEW(x) (((x) & 0x0F) << 13) #define USB2_OTG_PAD_CTL0_FS_RSLEW(x) (((x) & 0x0F) << 9) #define USB2_OTG_PAD_CTL0_HS_SLEW(x) (((x) & 0x3F) << 6) #define USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(x) (((x) & 0x3F) << 0) #define XUSB_PADCTL_USB2_OTG_PAD_CTL1(x) (0x08C + (x) * 0x40) #define USB2_OTG_PAD_CTL1_RPD_CTRL(x) (((x) & 0x1F) << 26) #define USB2_OTG_PAD_CTL1_RPU_STATUS_HIGH (1 << 25) #define USB2_OTG_PAD_CTL1_RPU_SWITCH_LOW (1 << 24) #define USB2_OTG_PAD_CTL1_RPU_SWITCH_OVRD (1 << 23) #define USB2_OTG_PAD_CTL1_HS_LOOPBACK_OVRD_VAL (1 << 22) #define USB2_OTG_PAD_CTL1_HS_LOOPBACK_OVRD_EN (1 << 21) #define USB2_OTG_PAD_CTL1_PTERM_RANGE_ADJ(x) (((x) & 0x0F) << 17) #define USB2_OTG_PAD_CTL1_PD_DISC_OVRD_VAL (1 << 16) #define USB2_OTG_PAD_CTL1_PD_CHRP_OVRD_VAL (1 << 15) #define USB2_OTG_PAD_CTL1_RPU_RANGE_ADJ(x) (((x) & 0x03) << 13) #define USB2_OTG_PAD_CTL1_HS_COUP_EN(x) (((x) & 0x03) << 11) #define USB2_OTG_PAD_CTL1_SPARE(x) (((x) & 0x0F) << 7) #define USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ(x) (((x) & 0x0F) << 3) #define USB2_OTG_PAD_CTL1_PD_DR (1 << 2) #define USB2_OTG_PAD_CTL1_PD_DISC_OVRD (1 << 1) #define USB2_OTG_PAD_CTL1_PD_CHRP_OVRD (1 << 0) #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0(x) (0x0C0 + (x) * 0x40) #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x0284 #define USB2_BIAS_PAD_CTL0_TRK_PWR_ENA (1 << 29) #define USB2_BIAS_PAD_CTL0_SPARE(x) (((x) & 0xF) << 25) #define USB2_BIAS_PAD_CTL0_CHG_DIV(x) (((x) & 0xF) << 21) #define USB2_BIAS_PAD_CTL0_TEMP_COEF(x) (((x) & 0x7) << 18) #define USB2_BIAS_PAD_CTL0_VREF_CTRL(x) (((x) & 0x7) << 15) #define USB2_BIAS_PAD_CTL0_ADJRPU(x) (((x) & 0x7) << 12) #define USB2_BIAS_PAD_CTL0_PD (1 << 11) #define USB2_BIAS_PAD_CTL0_TERM_OFFSETL(x) (((x) & 0x7) << 8) #define USB2_BIAS_PAD_CTL0_HS_CHIRP_LEVEL(x) (((x) & 0x3) << 6) #define USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL(x) (((x) & 0x7) << 3) #define USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL(x) (((x) & 0x7) << 0) #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1 0x0288 #define USB2_BIAS_PAD_CTL1_FORCE_TRK_CLK_EN (1 << 30) #define USB2_BIAS_PAD_CTL1_TRK_SW_OVRD (1 << 29) #define USB2_BIAS_PAD_CTL1_TRK_DONE (1 << 28) #define USB2_BIAS_PAD_CTL1_TRK_START (1 << 27) #define USB2_BIAS_PAD_CTL1_PD_TRK (1 << 26) #define USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER(x) (((x) & 0x7F) << 19) #define USB2_BIAS_PAD_CTL1_TRK_START_TIMER(x) (((x) & 0x7F) << 12) #define USB2_BIAS_PAD_CTL1_PCTRL(x) (((x) & 0x3F) << 6) #define USB2_BIAS_PAD_CTL1_TCTRL(x) (((x) & 0x3F) << 0) #define XUSB_PADCTL_HSIC_PAD_CTL0(x) (0x300 + (x) * 0x20) #define HSIC_PAD_CTL0_RPU_STROBE (1 << 18) #define HSIC_PAD_CTL0_RPU_DATA1 (1 << 17) #define HSIC_PAD_CTL0_RPU_DATA0 (1 << 16) #define HSIC_PAD_CTL0_RPD_STROBE (1 << 15) #define HSIC_PAD_CTL0_RPD_DATA1 (1 << 14) #define HSIC_PAD_CTL0_RPD_DATA0 (1 << 13) #define HSIC_PAD_CTL0_LPBK_STROBE (1 << 12) #define HSIC_PAD_CTL0_LPBK_DATA1 (1 << 11) #define HSIC_PAD_CTL0_LPBK_DATA0 (1 << 10) #define HSIC_PAD_CTL0_PD_ZI_STROBE (1 << 9) #define HSIC_PAD_CTL0_PD_ZI_DATA1 (1 << 8) #define HSIC_PAD_CTL0_PD_ZI_DATA0 (1 << 7) #define HSIC_PAD_CTL0_PD_RX_STROBE (1 << 6) #define HSIC_PAD_CTL0_PD_RX_DATA1 (1 << 5) #define HSIC_PAD_CTL0_PD_RX_DATA0 (1 << 4) #define HSIC_PAD_CTL0_PD_TX_STROBE (1 << 3) #define HSIC_PAD_CTL0_PD_TX_DATA1 (1 << 2) #define HSIC_PAD_CTL0_PD_TX_DATA0 (1 << 1) #define HSIC_PAD_CTL0_IDDQ (1 << 0) #define XUSB_PADCTL_HSIC_PAD_CTL1(x) (0x304 + (x) * 0x20) #define HSIC_PAD_CTL1_RTERM(x) (((x) & 0xF) << 12) #define HSIC_PAD_CTL1_HSIC_OPT(x) (((x) & 0xF) << 8) #define HSIC_PAD_CTL1_TX_SLEW(x) (((x) & 0xF) << 4) #define HSIC_PAD_CTL1_TX_RTUNEP(x) (((x) & 0xF) << 0) #define XUSB_PADCTL_HSIC_PAD_CTL2(x) (0x308 + (x) * 0x20) #define HSIC_PAD_CTL2_RX_STROBE_TRIM(x) (((x) & 0xF) << 8) #define HSIC_PAD_CTL2_RX_DATA1_TRIM(x) (((x) & 0xF) << 4) #define HSIC_PAD_CTL2_RX_DATA0_TRIM(x) (((x) & 0xF) << 0) #define XUSB_PADCTL_HSIC_PAD_TRK_CTL 0x340 #define HSIC_PAD_TRK_CTL_AUTO_RTERM_EN (1 << 24) #define HSIC_PAD_TRK_CTL_FORCE_TRK_CLK_EN (1 << 23) #define HSIC_PAD_TRK_CTL_TRK_SW_OVRD (1 << 22) #define HSIC_PAD_TRK_CTL_TRK_DONE (1 << 21) #define HSIC_PAD_TRK_CTL_TRK_START (1 << 20) #define HSIC_PAD_TRK_CTL_PD_TRK (1 << 19) #define HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER(x) (((x) & 0x3F) << 12) #define HSIC_PAD_TRK_CTL_TRK_START_TIMER(x) (((x) & 0x7F) << 5) #define HSIC_PAD_TRK_CTL_RTERM_OUT(x) (((x) & 0x1F) << 0) #define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL 0x344 #define XUSB_PADCTL_UPHY_PLL_P0_CTL1 0x360 #define UPHY_PLL_P0_CTL1_PLL0_FREQ_PSDIV(x) (((x) & 0x03) << 28) #define UPHY_PLL_P0_CTL1_PLL0_FREQ_NDIV(x) (((x) & 0xFF) << 20) #define UPHY_PLL_P0_CTL1_PLL0_FREQ_MDIV(x) (((x) & 0x03) << 16) #define UPHY_PLL_P0_CTL1_PLL0_LOCKDET_STATUS (1 << 15) #define UPHY_PLL_P0_CTL1_PLL0_MODE_GET(x) (((x) >> 8) & 0x03) #define UPHY_PLL_P0_CTL1_PLL0_BYPASS_EN (1 << 7) #define UPHY_PLL_P0_CTL1_PLL0_FREERUN_EN (1 << 6) #define UPHY_PLL_P0_CTL1_PLL0_PWR_OVRD (1 << 4) #define UPHY_PLL_P0_CTL1_PLL0_ENABLE (1 << 3) #define UPHY_PLL_P0_CTL1_PLL0_SLEEP(x) (((x) & 0x03) << 1) #define UPHY_PLL_P0_CTL1_PLL0_IDDQ (1 << 0) #define XUSB_PADCTL_UPHY_PLL_P0_CTL2 0x364 #define UPHY_PLL_P0_CTL2_PLL0_CAL_CTRL(x) (((x) & 0xFFFFFF) << 4) #define UPHY_PLL_P0_CTL2_PLL0_CAL_RESET (1 << 3) #define UPHY_PLL_P0_CTL2_PLL0_CAL_OVRD (1 << 2) #define UPHY_PLL_P0_CTL2_PLL0_CAL_DONE (1 << 1) #define UPHY_PLL_P0_CTL2_PLL0_CAL_EN (1 << 0) #define XUSB_PADCTL_UPHY_PLL_P0_CTL4 0x36c #define UPHY_PLL_P0_CTL4_PLL0_TCLKOUT_EN (1 << 28) #define UPHY_PLL_P0_CTL4_PLL0_CLKDIST_CTRL(x) (((x) & 0xF) << 20) #define UPHY_PLL_P0_CTL4_PLL0_XDIGCLK_EN (1 << 19) #define UPHY_PLL_P0_CTL4_PLL0_XDIGCLK_SEL(x) (((x) & 0x7) << 16) #define UPHY_PLL_P0_CTL4_PLL0_TXCLKREF_EN (1 << 15) #define UPHY_PLL_P0_CTL4_PLL0_TXCLKREF_SEL(x) (((x) & 0x3) << 12) #define UPHY_PLL_P0_CTL4_PLL0_FBCLKBUF_EN (1 << 9) #define UPHY_PLL_P0_CTL4_PLL0_REFCLKBUF_EN (1 << 8) #define UPHY_PLL_P0_CTL4_PLL0_REFCLK_SEL(x) (((x) & 0xF) << 4) #define UPHY_PLL_P0_CTL4_PLL0_REFCLK_TERM100 (1 << 0) #define XUSB_PADCTL_UPHY_PLL_P0_CTL5 0x370 #define UPHY_PLL_P0_CTL5_PLL0_DCO_CTRL(x) (((x) & 0xFF) << 16) #define UPHY_PLL_P0_CTL5_PLL0_LPF_CTRL(x) (((x) & 0xFF) << 8) #define UPHY_PLL_P0_CTL5_PLL0_CP_CTRL(x) (((x) & 0x0F) << 4) #define UPHY_PLL_P0_CTL5_PLL0_PFD_CTRL(x) (((x) & 0x03) << 0) #define XUSB_PADCTL_UPHY_PLL_P0_CTL8 0x37c #define UPHY_PLL_P0_CTL8_PLL0_RCAL_DONE (1U << 31) #define UPHY_PLL_P0_CTL8_PLL0_RCAL_VAL(x) (((x) & 0x1F) << 24) #define UPHY_PLL_P0_CTL8_PLL0_RCAL_BYP_EN (1 << 23) #define UPHY_PLL_P0_CTL8_PLL0_RCAL_BYP_CODE(x) (((x) & 0x1F) << 16) #define UPHY_PLL_P0_CTL8_PLL0_RCAL_OVRD (1 << 15) #define UPHY_PLL_P0_CTL8_PLL0_RCAL_CLK_EN (1 << 13) #define UPHY_PLL_P0_CTL8_PLL0_RCAL_EN (1 << 12) #define UPHY_PLL_P0_CTL8_PLL0_BGAP_CTRL(x) (((x) & 0xFFF) << 0) #define XUSB_PADCTL_UPHY_MISC_PAD_P_CTL1(x) (0x460 + (x) * 0x40) #define XUSB_PADCTL_UPHY_PLL_S0_CTL1 0x860 #define UPHY_PLL_S0_CTL1_PLL0_FREQ_PSDIV(x) (((x) & 0x03) << 28) #define UPHY_PLL_S0_CTL1_PLL0_FREQ_NDIV(x) (((x) & 0xFF) << 20) #define UPHY_PLL_S0_CTL1_PLL0_FREQ_MDIV(x) (((x) & 0x03) << 16) #define UPHY_PLL_S0_CTL1_PLL0_LOCKDET_STATUS (1 << 15) #define UPHY_PLL_S0_CTL1_PLL0_MODE_GET(x) (((x) >> 8) & 0x03) #define UPHY_PLL_S0_CTL1_PLL0_BYPASS_EN (1 << 7) #define UPHY_PLL_S0_CTL1_PLL0_FREERUN_EN (1 << 6) #define UPHY_PLL_S0_CTL1_PLL0_PWR_OVRD (1 << 4) #define UPHY_PLL_S0_CTL1_PLL0_ENABLE (1 << 3) #define UPHY_PLL_S0_CTL1_PLL0_SLEEP(x) (((x) & 0x03) << 1) #define UPHY_PLL_S0_CTL1_PLL0_IDDQ (1 << 0) #define XUSB_PADCTL_UPHY_PLL_S0_CTL2 0x864 #define UPHY_PLL_S0_CTL2_PLL0_CAL_CTRL(x) (((x) & 0xFFFFFF) << 4) #define UPHY_PLL_S0_CTL2_PLL0_CAL_RESET (1 << 3) #define UPHY_PLL_S0_CTL2_PLL0_CAL_OVRD (1 << 2) #define UPHY_PLL_S0_CTL2_PLL0_CAL_DONE (1 << 1) #define UPHY_PLL_S0_CTL2_PLL0_CAL_EN (1 << 0) #define XUSB_PADCTL_UPHY_PLL_S0_CTL4 0x86c #define UPHY_PLL_S0_CTL4_PLL0_TCLKOUT_EN (1 << 28) #define UPHY_PLL_S0_CTL4_PLL0_CLKDIST_CTRL(x) (((x) & 0xF) << 20) #define UPHY_PLL_S0_CTL4_PLL0_XDIGCLK_EN (1 << 19) #define UPHY_PLL_S0_CTL4_PLL0_XDIGCLK_SEL(x) (((x) & 0x7) << 16) #define UPHY_PLL_S0_CTL4_PLL0_TXCLKREF_EN (1 << 15) #define UPHY_PLL_S0_CTL4_PLL0_TXCLKREF_SEL(x) (((x) & 0x3) << 12) #define UPHY_PLL_S0_CTL4_PLL0_FBCLKBUF_EN (1 << 9) #define UPHY_PLL_S0_CTL4_PLL0_REFCLKBUF_EN (1 << 8) #define UPHY_PLL_S0_CTL4_PLL0_REFCLK_SEL(x) (((x) & 0xF) << 4) #define UPHY_PLL_S0_CTL4_PLL0_REFCLK_TERM100 (1 << 0) #define XUSB_PADCTL_UPHY_PLL_S0_CTL5 0x870 #define UPHY_PLL_S0_CTL5_PLL0_DCO_CTRL(x) (((x) & 0xFF) << 16) #define UPHY_PLL_S0_CTL5_PLL0_LPF_CTRL(x) (((x) & 0xFF) << 8) #define UPHY_PLL_S0_CTL5_PLL0_CP_CTRL(x) (((x) & 0x0F) << 4) #define UPHY_PLL_S0_CTL5_PLL0_PFD_CTRL(x) (((x) & 0x03) << 0) #define XUSB_PADCTL_UPHY_PLL_S0_CTL8 0x87c #define UPHY_PLL_S0_CTL8_PLL0_RCAL_DONE (1U << 31) #define UPHY_PLL_S0_CTL8_PLL0_RCAL_VAL(x) (((x) & 0x1F) << 24) #define UPHY_PLL_S0_CTL8_PLL0_RCAL_BYP_EN (1 << 23) #define UPHY_PLL_S0_CTL8_PLL0_RCAL_BYP_CODE(x) (((x) & 0x1F) << 16) #define UPHY_PLL_S0_CTL8_PLL0_RCAL_OVRD (1 << 15) #define UPHY_PLL_S0_CTL8_PLL0_RCAL_CLK_EN (1 << 13) #define UPHY_PLL_S0_CTL8_PLL0_RCAL_EN (1 << 12) #define UPHY_PLL_S0_CTL8_PLL0_BGAP_CTRL(x) (((x) & 0xFFF) << 0) #define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1 0x960 #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1(x) (0xa60 + (x) * 0x40) #define UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL(x) (((x) & 0x3) << 16) #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL2(x) (0xa64 + (x) * 0x40) #define UPHY_USB3_PAD_ECTL2_RX_IQ_CTRL(x) (((x) & 0x000F) << 16) #define UPHY_USB3_PAD_ECTL2_RX_CTLE(x) (((x) & 0xFFFF) << 0) #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL3(x) (0xa68 + (x) * 0x40) #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL4(x) (0xa6c + (x) * 0x40) #define UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL(x) (((x) & 0xFFFF) << 16) #define UPHY_USB3_PAD_ECTL4_RX_PI_CTRL(x) (((x) & 0x00FF) << 0) #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL6(x) (0xa74 + (x) * 0x40) #define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v)) #define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r)) struct padctl_softc { device_t dev; struct resource *mem_res; hwreset_t rst; int phy_ena_cnt; int pcie_ena_cnt; int sata_ena_cnt; /* Fuses calibration data */ /* USB2 */ uint32_t hs_curr_level[4]; uint32_t hs_curr_level_offs; /* Not inited yet, always 0 */ uint32_t hs_term_range_adj; uint32_t rpd_ctrl; /* HSIC */ uint32_t rx_strobe_trim; /* Not inited yet, always 0 */ uint32_t rx_data0_trim; /* Not inited yet, always 0 */ uint32_t rx_data1_trim; /* Not inited yet, always 0 */ uint32_t tx_rtune_p; /* Not inited yet, always 0 */ uint32_t strobe_trim; /* Not inited yet, always 0 */ }; static struct ofw_compat_data compat_data[] = { {"nvidia,tegra210-xusb-padctl", 1}, {NULL, 0}, }; /* Ports. */ enum padctl_port_type { PADCTL_PORT_USB2, PADCTL_PORT_HSIC, PADCTL_PORT_USB3, }; struct padctl_lane; struct padctl_port { enum padctl_port_type type; const char *name; const char *base_name; int idx; int (*init)(struct padctl_softc *sc, struct padctl_port *port); /* Runtime data. */ phandle_t xref; bool enabled; bool internal; uint32_t companion; regulator_t supply_vbus; struct padctl_lane *lane; }; static int usb3_port_init(struct padctl_softc *sc, struct padctl_port *port); #define PORT(t, n, p, i) { \ .type = t, \ .name = n "-" #p, \ .base_name = n, \ .idx = p, \ .init = i, \ } static struct padctl_port ports_tbl[] = { PORT(PADCTL_PORT_USB2, "usb2", 0, NULL), PORT(PADCTL_PORT_USB2, "usb2", 1, NULL), PORT(PADCTL_PORT_USB2, "usb2", 2, NULL), PORT(PADCTL_PORT_USB2, "usb2", 3, NULL), PORT(PADCTL_PORT_HSIC, "hsic", 0, NULL), PORT(PADCTL_PORT_HSIC, "hsic", 1, NULL), PORT(PADCTL_PORT_USB3, "usb3", 0, usb3_port_init), PORT(PADCTL_PORT_USB3, "usb3", 1, usb3_port_init), }; /* Pads - a group of lannes. */ enum padctl_pad_type { PADCTL_PAD_USB2, PADCTL_PAD_HSIC, PADCTL_PAD_PCIE, PADCTL_PAD_SATA, }; struct padctl_lane; struct padctl_pad { const char *name; enum padctl_pad_type type; const char *clock_name; char *reset_name; /* XXX constify !!!!!! */ int (*enable)(struct padctl_softc *sc, struct padctl_lane *lane); int (*disable)(struct padctl_softc *sc, struct padctl_lane *lane); /* Runtime data. */ bool enabled; clk_t clk; hwreset_t reset; int nlanes; struct padctl_lane *lanes[8]; /* Safe maximum value. */ }; static int usb2_enable(struct padctl_softc *sc, struct padctl_lane *lane); static int usb2_disable(struct padctl_softc *sc, struct padctl_lane *lane); static int hsic_enable(struct padctl_softc *sc, struct padctl_lane *lane); static int hsic_disable(struct padctl_softc *sc, struct padctl_lane *lane); static int pcie_enable(struct padctl_softc *sc, struct padctl_lane *lane); static int pcie_disable(struct padctl_softc *sc, struct padctl_lane *lane); static int sata_enable(struct padctl_softc *sc, struct padctl_lane *lane); static int sata_disable(struct padctl_softc *sc, struct padctl_lane *lane); #define PAD(n, t, cn, rn, e, d) { \ .name = n, \ .type = t, \ .clock_name = cn, \ .reset_name = rn, \ .enable = e, \ .disable = d, \ } static struct padctl_pad pads_tbl[] = { PAD("usb2", PADCTL_PAD_USB2, "trk", NULL, usb2_enable, usb2_disable), PAD("hsic", PADCTL_PAD_HSIC, "trk", NULL, hsic_enable, hsic_disable), PAD("pcie", PADCTL_PAD_PCIE, "pll", "phy", pcie_enable, pcie_disable), PAD("sata", PADCTL_PAD_SATA, "pll", "phy", sata_enable, sata_disable), }; /* Lanes. */ static char *usb_mux[] = {"snps", "xusb", "uart", "rsvd"}; static char *hsic_mux[] = {"snps", "xusb"}; static char *pci_mux[] = {"pcie-x1", "usb3-ss", "sata", "pcie-x4"}; struct padctl_lane { const char *name; int idx; bus_size_t reg; uint32_t shift; uint32_t mask; char **mux; int nmux; /* Runtime data. */ bool enabled; phandle_t xref; struct padctl_pad *pad; struct padctl_port *port; int mux_idx; }; #define LANE(n, p, r, s, m, mx) { \ .name = n "-" #p, \ .idx = p, \ .reg = r, \ .shift = s, \ .mask = m, \ .mux = mx, \ .nmux = nitems(mx), \ } static struct padctl_lane lanes_tbl[] = { LANE("usb2", 0, XUSB_PADCTL_USB2_PAD_MUX, 0, 0x3, usb_mux), LANE("usb2", 1, XUSB_PADCTL_USB2_PAD_MUX, 2, 0x3, usb_mux), LANE("usb2", 2, XUSB_PADCTL_USB2_PAD_MUX, 4, 0x3, usb_mux), LANE("usb2", 3, XUSB_PADCTL_USB2_PAD_MUX, 6, 0x3, usb_mux), LANE("hsic", 0, XUSB_PADCTL_USB2_PAD_MUX, 14, 0x1, hsic_mux), LANE("hsic", 1, XUSB_PADCTL_USB2_PAD_MUX, 15, 0x1, hsic_mux), LANE("pcie", 0, XUSB_PADCTL_USB3_PAD_MUX, 12, 0x3, pci_mux), LANE("pcie", 1, XUSB_PADCTL_USB3_PAD_MUX, 14, 0x3, pci_mux), LANE("pcie", 2, XUSB_PADCTL_USB3_PAD_MUX, 16, 0x3, pci_mux), LANE("pcie", 3, XUSB_PADCTL_USB3_PAD_MUX, 18, 0x3, pci_mux), LANE("pcie", 4, XUSB_PADCTL_USB3_PAD_MUX, 20, 0x3, pci_mux), LANE("pcie", 5, XUSB_PADCTL_USB3_PAD_MUX, 22, 0x3, pci_mux), LANE("pcie", 6, XUSB_PADCTL_USB3_PAD_MUX, 24, 0x3, pci_mux), LANE("sata", 0, XUSB_PADCTL_USB3_PAD_MUX, 30, 0x3, pci_mux), }; /* Define all possible mappings for USB3 port lanes */ struct padctl_lane_map { int port_idx; enum padctl_pad_type pad_type; int lane_idx; }; #define LANE_MAP(pi, pt, li) { \ .port_idx = pi, \ .pad_type = pt, \ .lane_idx = li, \ } static struct padctl_lane_map lane_map_tbl[] = { LANE_MAP(0, PADCTL_PAD_PCIE, 6), /* port USB3-0 -> lane PCIE-0 */ LANE_MAP(1, PADCTL_PAD_PCIE, 5), /* port USB3-1 -> lane PCIE-1 */ LANE_MAP(2, PADCTL_PAD_PCIE, 0), /* port USB3-2 -> lane PCIE-0 */ LANE_MAP(2, PADCTL_PAD_PCIE, 2), /* port USB3-2 -> lane PCIE-2 */ LANE_MAP(3, PADCTL_PAD_PCIE, 4), /* port USB3-3 -> lane PCIE-4 */ }; /* Phy class and methods. */ static int xusbpadctl_phy_enable(struct phynode *phy, bool enable); static phynode_method_t xusbpadctl_phynode_methods[] = { PHYNODEMETHOD(phynode_enable, xusbpadctl_phy_enable), PHYNODEMETHOD_END }; DEFINE_CLASS_1(xusbpadctl_phynode, xusbpadctl_phynode_class, xusbpadctl_phynode_methods, 0, phynode_class); static struct padctl_port *search_lane_port(struct padctl_softc *sc, struct padctl_lane *lane); static void tegra210_xusb_pll_hw_control_enable(void) {} static void tegra210_xusb_pll_hw_sequence_start(void) {} static void tegra210_sata_pll_hw_control_enable(void) {} static void tegra210_sata_pll_hw_sequence_start(void) {} /* ------------------------------------------------------------------------- * * PEX functions */ static int uphy_pex_enable(struct padctl_softc *sc, struct padctl_pad *pad) { uint32_t reg; int rv, i; if (sc->pcie_ena_cnt > 0) { sc->pcie_ena_cnt++; return (0); } /* 22.8.4 UPHY PLLs, Step 4, page 1346 */ /* 1. Deassert PLL/Lane resets. */ rv = clk_enable(pad->clk); if (rv < 0) { device_printf(sc->dev, "Cannot enable clock for pad '%s': %d\n", pad->name, rv); return (rv); } rv = hwreset_deassert(pad->reset); if (rv < 0) { device_printf(sc->dev, "Cannot unreset pad '%s': %d\n", pad->name, rv); clk_disable(pad->clk); return (rv); } reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL2); reg &= ~UPHY_PLL_P0_CTL2_PLL0_CAL_CTRL(~0); reg |= UPHY_PLL_P0_CTL2_PLL0_CAL_CTRL(0x136); WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL2, reg); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL5); reg &= ~UPHY_PLL_P0_CTL5_PLL0_DCO_CTRL(~0); reg |= UPHY_PLL_P0_CTL5_PLL0_DCO_CTRL(0x2a); WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL5, reg); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL1); reg |= UPHY_PLL_P0_CTL1_PLL0_PWR_OVRD; WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL1, reg); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL2); reg |= UPHY_PLL_P0_CTL2_PLL0_CAL_OVRD; WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL2, reg); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL8); reg |= UPHY_PLL_P0_CTL8_PLL0_RCAL_OVRD; WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL8, reg); /* * 2. For the following registers, default values * take care of the desired frequency. */ reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL4); reg &= ~UPHY_PLL_P0_CTL4_PLL0_TXCLKREF_SEL(~0); reg &= ~UPHY_PLL_P0_CTL4_PLL0_REFCLK_SEL(~0); reg |= UPHY_PLL_P0_CTL4_PLL0_TXCLKREF_SEL(0x2); reg |= UPHY_PLL_P0_CTL4_PLL0_TXCLKREF_EN; WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL4, reg); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL1); reg &= ~UPHY_PLL_P0_CTL1_PLL0_FREQ_MDIV(~0); reg &= ~UPHY_PLL_P0_CTL1_PLL0_FREQ_NDIV(~0); reg |= UPHY_PLL_P0_CTL1_PLL0_FREQ_NDIV(0x19); WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL1, reg); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL1); reg &= ~UPHY_PLL_P0_CTL1_PLL0_IDDQ; WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL1, reg); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL1); reg &= ~UPHY_PLL_P0_CTL1_PLL0_SLEEP(~0); WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL1, reg); /* 3. Wait 100 ns. */ DELAY(10); /* XXX This in not in TRM */ reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL4); reg |= UPHY_PLL_P0_CTL4_PLL0_REFCLKBUF_EN; WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL4, reg); /* 4. Calibration. */ reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL2); reg |= UPHY_PLL_P0_CTL2_PLL0_CAL_EN; WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL2, reg); for (i = 30; i > 0; i--) { reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL2); if (reg & UPHY_PLL_P0_CTL2_PLL0_CAL_DONE) break; DELAY(10); } if (i <= 0) { device_printf(sc->dev, "Timedout in calibration step 1 " "for pad '%s' (0x%08X).\n", pad->name, reg); rv = ETIMEDOUT; goto err; } reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL2); reg &= ~UPHY_PLL_P0_CTL2_PLL0_CAL_EN; WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL2, reg); for (i = 10; i > 0; i--) { reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL2); if ((reg & UPHY_PLL_P0_CTL2_PLL0_CAL_DONE) == 0) break; DELAY(10); } if (i <= 0) { device_printf(sc->dev, "Timedout in calibration step 2 " "for pad '%s'.\n", pad->name); rv = ETIMEDOUT; goto err; } /* 5. Enable the PLL (20 μs Lock time) */ reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL1); reg |= UPHY_PLL_P0_CTL1_PLL0_ENABLE; WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL1, reg); for (i = 10; i > 0; i--) { reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL1); if (reg & UPHY_PLL_P0_CTL1_PLL0_LOCKDET_STATUS) break; DELAY(10); } if (i <= 0) { device_printf(sc->dev, "Timedout while enabling PLL " "for pad '%s'.\n", pad->name); rv = ETIMEDOUT; goto err; } /* 6. RCAL. */ reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL8); reg |= UPHY_PLL_P0_CTL8_PLL0_RCAL_EN; reg |= UPHY_PLL_P0_CTL8_PLL0_RCAL_CLK_EN; WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL8, reg); for (i = 10; i > 0; i--) { reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL8); if (reg & UPHY_PLL_P0_CTL8_PLL0_RCAL_DONE) break; DELAY(10); } if (i <= 0) { device_printf(sc->dev, "Timedout in RX calibration step 1 " "for pad '%s'.\n", pad->name); rv = ETIMEDOUT; goto err; } reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL8); reg &= ~UPHY_PLL_P0_CTL8_PLL0_RCAL_EN; WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL8, reg); for (i = 10; i > 0; i--) { reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL8); if (!(reg & UPHY_PLL_P0_CTL8_PLL0_RCAL_DONE)) break; DELAY(10); } if (i <= 0) { device_printf(sc->dev, "Timedout in RX calibration step 2 " "for pad '%s'.\n", pad->name); rv = ETIMEDOUT; goto err; } reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL8); reg &= ~UPHY_PLL_P0_CTL8_PLL0_RCAL_CLK_EN; WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL8, reg); /* Enable Hardware Power Sequencer. */ tegra210_xusb_pll_hw_control_enable(); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL1); reg &= ~UPHY_PLL_P0_CTL1_PLL0_PWR_OVRD; WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL1, reg); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL2); reg &= ~UPHY_PLL_P0_CTL2_PLL0_CAL_OVRD; WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL2, reg); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL8); reg &= ~UPHY_PLL_P0_CTL8_PLL0_RCAL_OVRD; WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL8, reg); DELAY(50); tegra210_xusb_pll_hw_sequence_start(); sc->pcie_ena_cnt++; return (0); err: hwreset_deassert(pad->reset); clk_disable(pad->clk); return (rv); } static void uphy_pex_disable(struct padctl_softc *sc, struct padctl_pad *pad) { int rv; sc->pcie_ena_cnt--; if (sc->pcie_ena_cnt <= 0) { rv = hwreset_assert(pad->reset); if (rv != 0) { device_printf(sc->dev, "Cannot reset pad '%s': %d\n", pad->name, rv); } rv = clk_disable(pad->clk); if (rv != 0) { device_printf(sc->dev, "Cannot dicable clock for pad '%s': %d\n", pad->name, rv); } } } static int uphy_sata_enable(struct padctl_softc *sc, struct padctl_pad *pad, bool usb) { uint32_t reg; int rv, i; /* 22.8.4 UPHY PLLs, Step 4, page 1346 */ /* 1. Deassert PLL/Lane resets. */ if (sc->sata_ena_cnt > 0) { sc->sata_ena_cnt++; return (0); } rv = clk_enable(pad->clk); if (rv < 0) { device_printf(sc->dev, "Cannot enable clock for pad '%s': %d\n", pad->name, rv); return (rv); } rv = hwreset_deassert(pad->reset); if (rv < 0) { device_printf(sc->dev, "Cannot unreset pad '%s': %d\n", pad->name, rv); clk_disable(pad->clk); return (rv); } reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL2); reg &= ~UPHY_PLL_P0_CTL2_PLL0_CAL_CTRL(~0); reg |= UPHY_PLL_P0_CTL2_PLL0_CAL_CTRL(0x136); WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL2, reg); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL5); reg &= ~UPHY_PLL_P0_CTL5_PLL0_DCO_CTRL(~0); reg |= UPHY_PLL_P0_CTL5_PLL0_DCO_CTRL(0x2a); WR4(sc, XUSB_PADCTL_UPHY_PLL_P0_CTL5, reg); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL1); reg |= UPHY_PLL_S0_CTL1_PLL0_PWR_OVRD; WR4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL1, reg); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL2); reg |= UPHY_PLL_S0_CTL2_PLL0_CAL_OVRD; WR4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL2, reg); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL8); reg |= UPHY_PLL_S0_CTL8_PLL0_RCAL_OVRD; WR4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL8, reg); /* * 2. For the following registers, default values * take care of the desired frequency. */ reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL4); reg &= ~UPHY_PLL_S0_CTL4_PLL0_TXCLKREF_SEL(~0); reg &= ~UPHY_PLL_S0_CTL4_PLL0_REFCLK_SEL(~0); reg |= UPHY_PLL_S0_CTL4_PLL0_TXCLKREF_EN; if (usb) reg |= UPHY_PLL_S0_CTL4_PLL0_TXCLKREF_SEL(0x2); else reg |= UPHY_PLL_S0_CTL4_PLL0_TXCLKREF_SEL(0x0); /* XXX PLL0_XDIGCLK_EN */ /* value &= ~(1 << 19); WR4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL4, reg); */ reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL1); reg &= ~UPHY_PLL_S0_CTL1_PLL0_FREQ_MDIV(~0); reg &= ~UPHY_PLL_S0_CTL1_PLL0_FREQ_NDIV(~0); if (usb) reg |= UPHY_PLL_S0_CTL1_PLL0_FREQ_NDIV(0x19); else reg |= UPHY_PLL_S0_CTL1_PLL0_FREQ_NDIV(0x1e); WR4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL1, reg); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL1); reg &= ~UPHY_PLL_S0_CTL1_PLL0_IDDQ; WR4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL1, reg); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL1); reg &= ~UPHY_PLL_S0_CTL1_PLL0_SLEEP(~0); WR4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL1, reg); /* 3. Wait 100 ns. */ DELAY(1); /* XXX This in not in TRM */ reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL4); reg |= UPHY_PLL_S0_CTL4_PLL0_REFCLKBUF_EN; WR4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL4, reg); /* 4. Calibration. */ reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL2); reg |= UPHY_PLL_S0_CTL2_PLL0_CAL_EN; WR4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL2, reg); for (i = 30; i > 0; i--) { reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL2); if (reg & UPHY_PLL_S0_CTL2_PLL0_CAL_DONE) break; DELAY(10); } if (i <= 0) { device_printf(sc->dev, "Timedout in calibration step 1 " "for pad '%s'.\n", pad->name); rv = ETIMEDOUT; goto err; } reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL2); reg &= ~UPHY_PLL_S0_CTL2_PLL0_CAL_EN; WR4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL2, reg); for (i = 10; i > 0; i--) { reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL2); if ((reg & UPHY_PLL_S0_CTL2_PLL0_CAL_DONE) == 0) break; DELAY(10); } if (i <= 0) { device_printf(sc->dev, "Timedout in calibration step 2 " "for pad '%s'.\n", pad->name); rv = ETIMEDOUT; goto err; } /* 5. Enable the PLL (20 μs Lock time) */ reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL1); reg |= UPHY_PLL_S0_CTL1_PLL0_ENABLE; WR4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL1, reg); for (i = 10; i > 0; i--) { reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL1); if (reg & UPHY_PLL_S0_CTL1_PLL0_LOCKDET_STATUS) break; DELAY(10); } if (i <= 0) { device_printf(sc->dev, "Timedout while enabling PLL " "for pad '%s'.\n", pad->name); rv = ETIMEDOUT; goto err; } /* 6. RCAL. */ reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL8); reg |= UPHY_PLL_S0_CTL8_PLL0_RCAL_EN; reg |= UPHY_PLL_S0_CTL8_PLL0_RCAL_CLK_EN; WR4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL8, reg); for (i = 10; i > 0; i--) { reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL8); if (reg & UPHY_PLL_S0_CTL8_PLL0_RCAL_DONE) break; DELAY(10); } if (i <= 0) { device_printf(sc->dev, "Timedout in RX calibration step 1 " "for pad '%s'.\n", pad->name); rv = ETIMEDOUT; goto err; } reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL8); reg &= ~UPHY_PLL_S0_CTL8_PLL0_RCAL_EN; WR4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL8, reg); for (i = 10; i > 0; i--) { reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL8); if (!(reg & UPHY_PLL_S0_CTL8_PLL0_RCAL_DONE)) break; DELAY(10); } if (i <= 0) { device_printf(sc->dev, "Timedout in RX calibration step 2 " "for pad '%s'.\n", pad->name); rv = ETIMEDOUT; goto err; } reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL8); reg &= ~UPHY_PLL_S0_CTL8_PLL0_RCAL_CLK_EN; WR4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL8, reg); /* Enable Hardware Power Sequencer. */ tegra210_sata_pll_hw_control_enable(); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL1); reg &= ~UPHY_PLL_S0_CTL1_PLL0_PWR_OVRD; WR4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL1, reg); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL2); reg &= ~UPHY_PLL_S0_CTL2_PLL0_CAL_OVRD; WR4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL2, reg); reg = RD4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL8); reg &= ~UPHY_PLL_S0_CTL8_PLL0_RCAL_OVRD; WR4(sc, XUSB_PADCTL_UPHY_PLL_S0_CTL8, reg); DELAY(50); tegra210_sata_pll_hw_sequence_start(); sc->sata_ena_cnt++; return (0); err: hwreset_deassert(pad->reset); clk_disable(pad->clk); return (rv); } static void uphy_sata_disable(struct padctl_softc *sc, struct padctl_pad *pad) { int rv; sc->sata_ena_cnt--; if (sc->sata_ena_cnt <= 0) { rv = hwreset_assert(pad->reset); if (rv != 0) { device_printf(sc->dev, "Cannot reset pad '%s': %d\n", pad->name, rv); } rv = clk_disable(pad->clk); if (rv != 0) { device_printf(sc->dev, "Cannot dicable clock for pad '%s': %d\n", pad->name, rv); } } } static int usb3_port_init(struct padctl_softc *sc, struct padctl_port *port) { uint32_t reg; struct padctl_pad *pad; int rv; pad = port->lane->pad; reg = RD4(sc, XUSB_PADCTL_SS_PORT_MAP); if (port->internal) reg &= ~SS_PORT_MAP_PORT_INTERNAL(port->idx); else reg |= SS_PORT_MAP_PORT_INTERNAL(port->idx); reg &= ~SS_PORT_MAP_PORT_MAP(port->idx, ~0); reg |= SS_PORT_MAP_PORT_MAP(port->idx, port->companion); WR4(sc, XUSB_PADCTL_SS_PORT_MAP, reg); if (port->supply_vbus != NULL) { rv = regulator_enable(port->supply_vbus); if (rv != 0) { device_printf(sc->dev, "Cannot enable vbus regulator\n"); return (rv); } } reg = RD4(sc, XUSB_PADCTL_UPHY_USB3_PAD_ECTL1(port->idx)); reg &= ~UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL(~0); reg |= UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL(2); WR4(sc, XUSB_PADCTL_UPHY_USB3_PAD_ECTL1(port->idx), reg); reg = RD4(sc, XUSB_PADCTL_UPHY_USB3_PAD_ECTL2(port->idx)); reg &= ~UPHY_USB3_PAD_ECTL2_RX_CTLE(~0); reg |= UPHY_USB3_PAD_ECTL2_RX_CTLE(0x00fc); WR4(sc, XUSB_PADCTL_UPHY_USB3_PAD_ECTL2(port->idx), reg); WR4(sc, XUSB_PADCTL_UPHY_USB3_PAD_ECTL3(port->idx), 0xc0077f1f); reg = RD4(sc, XUSB_PADCTL_UPHY_USB3_PAD_ECTL4(port->idx)); reg &= ~UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL(~0); reg |= UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL(0x01c7); WR4(sc, XUSB_PADCTL_UPHY_USB3_PAD_ECTL4(port->idx), reg); WR4(sc, XUSB_PADCTL_UPHY_USB3_PAD_ECTL6(port->idx), 0xfcf01368); if (pad->type == PADCTL_PAD_SATA) rv = uphy_sata_enable(sc, pad, true); else rv = uphy_pex_enable(sc, pad); if (rv != 0) return (rv); reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM1); reg &= ~ELPG_PROGRAM1_SSP_ELPG_VCORE_DOWN(port->idx); WR4(sc, XUSB_PADCTL_ELPG_PROGRAM1, reg); DELAY(100); reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM1); reg &= ~ELPG_PROGRAM1_SSP_ELPG_CLAMP_EN_EARLY(port->idx); WR4(sc, XUSB_PADCTL_ELPG_PROGRAM1, reg); DELAY(100); reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM1); reg &= ~ELPG_PROGRAM1_SSP_ELPG_CLAMP_EN(port->idx); WR4(sc, XUSB_PADCTL_ELPG_PROGRAM1, reg); DELAY(100); return (0); } static int pcie_enable(struct padctl_softc *sc, struct padctl_lane *lane) { uint32_t reg; int rv; rv = uphy_pex_enable(sc, lane->pad); if (rv != 0) return (rv); reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); reg |= USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->idx); WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); return (0); } static int pcie_disable(struct padctl_softc *sc, struct padctl_lane *lane) { uint32_t reg; reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); reg &= ~USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->idx); WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); uphy_pex_disable(sc, lane->pad); return (0); } static int sata_enable(struct padctl_softc *sc, struct padctl_lane *lane) { uint32_t reg; int rv; rv = uphy_sata_enable(sc, lane->pad, false); if (rv != 0) return (rv); reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); reg |= USB3_PAD_MUX_SATA_IDDQ_DISABLE(lane->idx); WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); return (0); } static int sata_disable(struct padctl_softc *sc, struct padctl_lane *lane) { uint32_t reg; reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); reg &= ~USB3_PAD_MUX_SATA_IDDQ_DISABLE(lane->idx); WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); uphy_sata_disable(sc, lane->pad); return (0); } static int hsic_enable(struct padctl_softc *sc, struct padctl_lane *lane) { uint32_t reg; struct padctl_pad *pad; struct padctl_port *port; int rv; port = search_lane_port(sc, lane); if (port == NULL) { device_printf(sc->dev, "Cannot find port for lane: %s\n", lane->name); } pad = lane->pad; if (port->supply_vbus != NULL) { rv = regulator_enable(port->supply_vbus); if (rv != 0) { device_printf(sc->dev, "Cannot enable vbus regulator\n"); return (rv); } } WR4(sc, XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL, sc->strobe_trim); reg = RD4(sc, XUSB_PADCTL_HSIC_PAD_CTL1(lane->idx)); reg &= ~HSIC_PAD_CTL1_TX_RTUNEP(~0); reg |= HSIC_PAD_CTL1_TX_RTUNEP(sc->tx_rtune_p); WR4(sc, XUSB_PADCTL_HSIC_PAD_CTL1(lane->idx), reg); reg = RD4(sc, XUSB_PADCTL_HSIC_PAD_CTL2(lane->idx)); reg &= ~HSIC_PAD_CTL2_RX_STROBE_TRIM(~0); reg &= ~HSIC_PAD_CTL2_RX_DATA1_TRIM(~0); reg &= ~HSIC_PAD_CTL2_RX_DATA0_TRIM(~0); reg |= HSIC_PAD_CTL2_RX_STROBE_TRIM(sc->rx_strobe_trim); reg |= HSIC_PAD_CTL2_RX_DATA1_TRIM(sc->rx_data1_trim); reg |= HSIC_PAD_CTL2_RX_DATA0_TRIM(sc->rx_data0_trim); WR4(sc, XUSB_PADCTL_HSIC_PAD_CTL2(lane->idx), reg); reg = RD4(sc, XUSB_PADCTL_HSIC_PAD_CTL0(lane->idx)); reg &= ~HSIC_PAD_CTL0_RPU_DATA0; reg &= ~HSIC_PAD_CTL0_RPU_DATA1; reg &= ~HSIC_PAD_CTL0_RPU_STROBE; reg &= ~HSIC_PAD_CTL0_PD_RX_DATA0; reg &= ~HSIC_PAD_CTL0_PD_RX_DATA1; reg &= ~HSIC_PAD_CTL0_PD_RX_STROBE; reg &= ~HSIC_PAD_CTL0_PD_ZI_DATA0; reg &= ~HSIC_PAD_CTL0_PD_ZI_DATA1; reg &= ~HSIC_PAD_CTL0_PD_ZI_STROBE; reg &= ~HSIC_PAD_CTL0_PD_TX_DATA0; reg &= ~HSIC_PAD_CTL0_PD_TX_DATA1; reg &= ~HSIC_PAD_CTL0_PD_TX_STROBE; reg |= HSIC_PAD_CTL0_RPD_DATA0; reg |= HSIC_PAD_CTL0_RPD_DATA1; reg |= HSIC_PAD_CTL0_RPD_STROBE; WR4(sc, XUSB_PADCTL_HSIC_PAD_CTL0(lane->idx), reg); rv = clk_enable(pad->clk); if (rv < 0) { device_printf(sc->dev, "Cannot enable clock for pad '%s': %d\n", pad->name, rv); if (port->supply_vbus != NULL) regulator_disable(port->supply_vbus); return (rv); } reg = RD4(sc, XUSB_PADCTL_HSIC_PAD_TRK_CTL); reg &= ~HSIC_PAD_TRK_CTL_TRK_START_TIMER(~0); reg &= ~HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER(~0); reg |= HSIC_PAD_TRK_CTL_TRK_START_TIMER(0x1e); reg |= HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER(0x0a); WR4(sc, XUSB_PADCTL_HSIC_PAD_TRK_CTL, reg); DELAY(10); reg = RD4(sc, XUSB_PADCTL_HSIC_PAD_TRK_CTL); reg &= ~HSIC_PAD_TRK_CTL_PD_TRK; WR4(sc, XUSB_PADCTL_HSIC_PAD_TRK_CTL, reg); DELAY(50); clk_disable(pad->clk); return (0); } static int hsic_disable(struct padctl_softc *sc, struct padctl_lane *lane) { uint32_t reg; struct padctl_port *port; int rv; port = search_lane_port(sc, lane); if (port == NULL) { device_printf(sc->dev, "Cannot find port for lane: %s\n", lane->name); } reg = RD4(sc, XUSB_PADCTL_HSIC_PAD_CTL0(lane->idx)); reg |= HSIC_PAD_CTL0_PD_RX_DATA0; reg |= HSIC_PAD_CTL0_PD_RX_DATA1; reg |= HSIC_PAD_CTL0_PD_RX_STROBE; reg |= HSIC_PAD_CTL0_PD_ZI_DATA0; reg |= HSIC_PAD_CTL0_PD_ZI_DATA1; reg |= HSIC_PAD_CTL0_PD_ZI_STROBE; reg |= HSIC_PAD_CTL0_PD_TX_DATA0; reg |= HSIC_PAD_CTL0_PD_TX_DATA1; reg |= HSIC_PAD_CTL0_PD_TX_STROBE; WR4(sc, XUSB_PADCTL_HSIC_PAD_CTL1(lane->idx), reg); if (port->supply_vbus != NULL) { rv = regulator_disable(port->supply_vbus); if (rv != 0) { device_printf(sc->dev, "Cannot disable vbus regulator\n"); return (rv); } } return (0); } static int usb2_enable(struct padctl_softc *sc, struct padctl_lane *lane) { uint32_t reg; struct padctl_pad *pad; struct padctl_port *port; int rv; port = search_lane_port(sc, lane); if (port == NULL) { device_printf(sc->dev, "Cannot find port for lane: %s\n", lane->name); } pad = lane->pad; reg = RD4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); reg &= ~USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL(~0); reg &= ~USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL(~0); reg |= USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL(0x7); WR4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0, reg); reg = RD4(sc, XUSB_PADCTL_USB2_PORT_CAP); reg &= ~USB2_PORT_CAP_PORT_CAP(lane->idx, ~0); reg |= USB2_PORT_CAP_PORT_CAP(lane->idx, USB2_PORT_CAP_PORT_CAP_HOST); WR4(sc, XUSB_PADCTL_USB2_PORT_CAP, reg); reg = RD4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL0(lane->idx)); reg &= ~USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(~0); reg &= ~USB2_OTG_PAD_CTL0_HS_SLEW(~0); reg &= ~USB2_OTG_PAD_CTL0_PD; reg &= ~USB2_OTG_PAD_CTL0_PD2; reg &= ~USB2_OTG_PAD_CTL0_PD_ZI; reg |= USB2_OTG_PAD_CTL0_HS_SLEW(14); reg |= USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(sc->hs_curr_level[lane->idx] + sc->hs_curr_level_offs); WR4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL0(lane->idx), reg); reg = RD4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL1(lane->idx)); reg &= ~USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ(~0); reg &= ~USB2_OTG_PAD_CTL1_RPD_CTRL(~0); reg &= ~USB2_OTG_PAD_CTL1_PD_DR; reg &= ~USB2_OTG_PAD_CTL1_PD_CHRP_OVRD; reg &= ~USB2_OTG_PAD_CTL1_PD_DISC_OVRD; reg |= USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ(sc->hs_term_range_adj); reg |= USB2_OTG_PAD_CTL1_RPD_CTRL(sc->rpd_ctrl); WR4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL1(lane->idx), reg); reg = RD4(sc, XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1(lane->idx)); reg &= ~USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV(~0); reg |= USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18; WR4(sc, XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1(lane->idx), reg); if (port->supply_vbus != NULL) { rv = regulator_enable(port->supply_vbus); if (rv != 0) { device_printf(sc->dev, "Cannot enable vbus regulator\n"); return (rv); } } rv = clk_enable(pad->clk); if (rv < 0) { device_printf(sc->dev, "Cannot enable clock for pad '%s': %d\n", pad->name, rv); if (port->supply_vbus != NULL) regulator_disable(port->supply_vbus); return (rv); } reg = RD4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); reg &= ~USB2_BIAS_PAD_CTL1_TRK_START_TIMER(~0); reg &= ~USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER(~0); reg |= USB2_BIAS_PAD_CTL1_TRK_START_TIMER(0x1e); reg |= USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER(0x0a); WR4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL1, reg); reg = RD4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); reg &= ~USB2_BIAS_PAD_CTL0_PD; WR4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0, reg); return (0); } static int usb2_disable(struct padctl_softc *sc, struct padctl_lane *lane) { uint32_t reg; struct padctl_pad *pad; struct padctl_port *port; int rv; port = search_lane_port(sc, lane); if (port == NULL) { device_printf(sc->dev, "Cannot find port for lane: %s\n", lane->name); } pad = lane->pad; reg = RD4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); reg |= USB2_BIAS_PAD_CTL0_PD; WR4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0, reg); if (port->supply_vbus != NULL) { rv = regulator_disable(port->supply_vbus); if (rv != 0) { device_printf(sc->dev, "Cannot disable vbus regulator\n"); return (rv); } } rv = clk_disable(pad->clk); if (rv < 0) { device_printf(sc->dev, "Cannot disable clock for pad '%s': %d\n", pad->name, rv); return (rv); } return (0); } static int pad_common_enable(struct padctl_softc *sc) { uint32_t reg; reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM1); reg &= ~ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN; WR4(sc, XUSB_PADCTL_ELPG_PROGRAM1, reg); DELAY(100); reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM1); reg &= ~ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY; WR4(sc, XUSB_PADCTL_ELPG_PROGRAM1, reg); DELAY(100); reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM1); reg &= ~ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN; WR4(sc, XUSB_PADCTL_ELPG_PROGRAM1, reg); DELAY(100); return (0); } static int pad_common_disable(struct padctl_softc *sc) { uint32_t reg; reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM1); reg |= ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN; WR4(sc, XUSB_PADCTL_ELPG_PROGRAM1, reg); DELAY(100); reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM1); reg |= ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY; WR4(sc, XUSB_PADCTL_ELPG_PROGRAM1, reg); DELAY(100); reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM1); reg |= ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN; WR4(sc, XUSB_PADCTL_ELPG_PROGRAM1, reg); DELAY(100); return (0); } static int xusbpadctl_phy_enable(struct phynode *phy, bool enable) { device_t dev; intptr_t id; struct padctl_softc *sc; struct padctl_lane *lane; struct padctl_pad *pad; int rv; dev = phynode_get_device(phy); id = phynode_get_id(phy); sc = device_get_softc(dev); if (id < 0 || id >= nitems(lanes_tbl)) { device_printf(dev, "Unknown phy: %d\n", (int)id); return (ENXIO); } lane = lanes_tbl + id; if (!lane->enabled) { device_printf(dev, "Lane is not enabled/configured: %s\n", lane->name); return (ENXIO); } pad = lane->pad; if (enable) { if (sc->phy_ena_cnt == 0) { rv = pad_common_enable(sc); if (rv != 0) return (rv); } sc->phy_ena_cnt++; } if (enable) rv = pad->enable(sc, lane); else rv = pad->disable(sc, lane); if (rv != 0) return (rv); if (!enable) { if (sc->phy_ena_cnt == 1) { rv = pad_common_disable(sc); if (rv != 0) return (rv); } sc->phy_ena_cnt--; } return (0); } /* ------------------------------------------------------------------------- * * FDT processing */ static struct padctl_port * search_port(struct padctl_softc *sc, char *port_name) { int i; for (i = 0; i < nitems(ports_tbl); i++) { if (strcmp(port_name, ports_tbl[i].name) == 0) return (&ports_tbl[i]); } return (NULL); } static struct padctl_port * search_lane_port(struct padctl_softc *sc, struct padctl_lane *lane) { int i; for (i = 0; i < nitems(ports_tbl); i++) { if (!ports_tbl[i].enabled) continue; if (ports_tbl[i].lane == lane) return (ports_tbl + i); } return (NULL); } static struct padctl_lane * search_lane(struct padctl_softc *sc, char *lane_name) { int i; for (i = 0; i < nitems(lanes_tbl); i++) { if (strcmp(lane_name, lanes_tbl[i].name) == 0) return (lanes_tbl + i); } return (NULL); } static struct padctl_lane * search_pad_lane(struct padctl_softc *sc, enum padctl_pad_type type, int idx) { int i; for (i = 0; i < nitems(lanes_tbl); i++) { if (!lanes_tbl[i].enabled) continue; if (type == lanes_tbl[i].pad->type && idx == lanes_tbl[i].idx) return (lanes_tbl + i); } return (NULL); } static struct padctl_lane * search_usb3_pad_lane(struct padctl_softc *sc, int idx) { int i; struct padctl_lane *lane, *tmp; lane = NULL; for (i = 0; i < nitems(lane_map_tbl); i++) { if (idx != lane_map_tbl[i].port_idx) continue; tmp = search_pad_lane(sc, lane_map_tbl[i].pad_type, lane_map_tbl[i].lane_idx); if (tmp == NULL) continue; if (strcmp(tmp->mux[tmp->mux_idx], "usb3-ss") != 0) continue; if (lane != NULL) { device_printf(sc->dev, "Duplicated mappings found for" " lanes: %s and %s\n", lane->name, tmp->name); return (NULL); } lane = tmp; } return (lane); } static struct padctl_pad * search_pad(struct padctl_softc *sc, char *pad_name) { int i; for (i = 0; i < nitems(pads_tbl); i++) { if (strcmp(pad_name, pads_tbl[i].name) == 0) return (pads_tbl + i); } return (NULL); } static int search_mux(struct padctl_softc *sc, struct padctl_lane *lane, char *fnc_name) { int i; for (i = 0; i < lane->nmux; i++) { if (strcmp(fnc_name, lane->mux[i]) == 0) return (i); } return (-1); } static int config_lane(struct padctl_softc *sc, struct padctl_lane *lane) { uint32_t reg; reg = RD4(sc, lane->reg); reg &= ~(lane->mask << lane->shift); reg |= (lane->mux_idx & lane->mask) << lane->shift; WR4(sc, lane->reg, reg); return (0); } static int process_lane(struct padctl_softc *sc, phandle_t node, struct padctl_pad *pad) { struct padctl_lane *lane; struct phynode *phynode; struct phynode_init_def phy_init; char *name; char *function; int rv; name = NULL; function = NULL; rv = OF_getprop_alloc(node, "name", (void **)&name); if (rv <= 0) { device_printf(sc->dev, "Cannot read lane name.\n"); return (ENXIO); } lane = search_lane(sc, name); if (lane == NULL) { device_printf(sc->dev, "Unknown lane: %s\n", name); rv = ENXIO; goto end; } /* Read function (mux) settings. */ rv = OF_getprop_alloc(node, "nvidia,function", (void **)&function); if (rv <= 0) { device_printf(sc->dev, "Cannot read lane function.\n"); rv = ENXIO; goto end; } lane->mux_idx = search_mux(sc, lane, function); if (lane->mux_idx == ~0) { device_printf(sc->dev, "Unknown function %s for lane %s\n", function, name); rv = ENXIO; goto end; } rv = config_lane(sc, lane); if (rv != 0) { device_printf(sc->dev, "Cannot configure lane: %s: %d\n", name, rv); rv = ENXIO; goto end; } lane->xref = OF_xref_from_node(node); lane->pad = pad; lane->enabled = true; pad->lanes[pad->nlanes++] = lane; /* Create and register phy. */ bzero(&phy_init, sizeof(phy_init)); phy_init.id = lane - lanes_tbl; phy_init.ofw_node = node; phynode = phynode_create(sc->dev, &xusbpadctl_phynode_class, &phy_init); if (phynode == NULL) { device_printf(sc->dev, "Cannot create phy\n"); rv = ENXIO; goto end; } if (phynode_register(phynode) == NULL) { device_printf(sc->dev, "Cannot create phy\n"); return (ENXIO); } rv = 0; end: if (name != NULL) OF_prop_free(name); if (function != NULL) OF_prop_free(function); return (rv); } static int process_pad(struct padctl_softc *sc, phandle_t node) { phandle_t xref; struct padctl_pad *pad; char *name; int rv; name = NULL; rv = OF_getprop_alloc(node, "name", (void **)&name); if (rv <= 0) { device_printf(sc->dev, "Cannot read pad name.\n"); return (ENXIO); } pad = search_pad(sc, name); if (pad == NULL) { device_printf(sc->dev, "Unknown pad: %s\n", name); rv = ENXIO; goto end; } if (pad->clock_name != NULL) { rv = clk_get_by_ofw_name(sc->dev, node, pad->clock_name, &pad->clk); if (rv != 0) { device_printf(sc->dev, "Cannot get '%s' clock\n", pad->clock_name); return (ENXIO); } } if (pad->reset_name != NULL) { rv = hwreset_get_by_ofw_name(sc->dev, node, pad->reset_name, &pad->reset); if (rv != 0) { device_printf(sc->dev, "Cannot get '%s' reset\n", pad->reset_name); return (ENXIO); } } /* Read and process associated lanes. */ node = ofw_bus_find_child(node, "lanes"); if (node <= 0) { device_printf(sc->dev, "Cannot find 'lanes' subnode\n"); rv = ENXIO; goto end; } for (node = OF_child(node); node != 0; node = OF_peer(node)) { if (!ofw_bus_node_status_okay(node)) continue; rv = process_lane(sc, node, pad); if (rv != 0) goto end; xref = OF_xref_from_node(node); OF_device_register_xref(xref, sc->dev); } pad->enabled = true; rv = 0; end: if (name != NULL) OF_prop_free(name); return (rv); } static int process_port(struct padctl_softc *sc, phandle_t node) { struct padctl_port *port; char *name; int rv; name = NULL; rv = OF_getprop_alloc(node, "name", (void **)&name); if (rv <= 0) { device_printf(sc->dev, "Cannot read port name.\n"); return (ENXIO); } port = search_port(sc, name); if (port == NULL) { device_printf(sc->dev, "Unknown port: %s\n", name); rv = ENXIO; goto end; } regulator_get_by_ofw_property(sc->dev, node, "vbus-supply", &port->supply_vbus); if (OF_hasprop(node, "nvidia,internal")) port->internal = true; /* Find assigned lane */ if (port->lane == NULL) { switch(port->type) { /* Routing is fixed for USB2 AND HSIC. */ case PADCTL_PORT_USB2: port->lane = search_pad_lane(sc, PADCTL_PAD_USB2, port->idx); break; case PADCTL_PORT_HSIC: port->lane = search_pad_lane(sc, PADCTL_PAD_HSIC, port->idx); break; case PADCTL_PORT_USB3: port->lane = search_usb3_pad_lane(sc, port->idx); break; } } if (port->lane == NULL) { device_printf(sc->dev, "Cannot find lane for port: %s\n", name); rv = ENXIO; goto end; } if (port->type == PADCTL_PORT_USB3) { rv = OF_getencprop(node, "nvidia,usb2-companion", &(port->companion), sizeof(port->companion)); if (rv <= 0) { device_printf(sc->dev, "Missing 'nvidia,usb2-companion' property " "for port: %s\n", name); rv = ENXIO; goto end; } } port->enabled = true; rv = 0; end: if (name != NULL) OF_prop_free(name); return (rv); } static int parse_fdt(struct padctl_softc *sc, phandle_t base_node) { phandle_t node; int rv; rv = 0; node = ofw_bus_find_child(base_node, "pads"); if (node <= 0) { device_printf(sc->dev, "Cannot find pads subnode.\n"); return (ENXIO); } for (node = OF_child(node); node != 0; node = OF_peer(node)) { if (!ofw_bus_node_status_okay(node)) continue; rv = process_pad(sc, node); if (rv != 0) return (rv); } node = ofw_bus_find_child(base_node, "ports"); if (node <= 0) { device_printf(sc->dev, "Cannot find ports subnode.\n"); return (ENXIO); } for (node = OF_child(node); node != 0; node = OF_peer(node)) { if (!ofw_bus_node_status_okay(node)) continue; rv = process_port(sc, node); if (rv != 0) return (rv); } return (0); } static void load_calibration(struct padctl_softc *sc) { uint32_t reg; int i; reg = tegra_fuse_read_4(FUSE_SKU_CALIB_0); sc->hs_curr_level[0] = FUSE_SKU_CALIB_0_HS_CURR_LEVEL_0(reg); for (i = 1; i < nitems(sc->hs_curr_level); i++) { sc->hs_curr_level[i] = FUSE_SKU_CALIB_0_HS_CURR_LEVEL_123(reg, i); } sc->hs_term_range_adj = FUSE_SKU_CALIB_0_HS_TERM_RANGE_ADJ(reg); tegra_fuse_read_4(FUSE_USB_CALIB_EXT_0); sc->rpd_ctrl = FUSE_USB_CALIB_EXT_0_RPD_CTRL(reg); } /* ------------------------------------------------------------------------- * * BUS functions */ static int xusbpadctl_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "Tegra XUSB phy"); return (BUS_PROBE_DEFAULT); } static int xusbpadctl_detach(device_t dev) { /* This device is always present. */ return (EBUSY); } static int xusbpadctl_attach(device_t dev) { struct padctl_softc * sc; int i, rid, rv; struct padctl_port *port; phandle_t node; sc = device_get_softc(dev); sc->dev = dev; node = ofw_bus_get_node(dev); rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) { device_printf(dev, "Cannot allocate memory resources\n"); return (ENXIO); } rv = hwreset_get_by_ofw_name(dev, 0, "padctl", &sc->rst); if (rv != 0) { device_printf(dev, "Cannot get 'padctl' reset: %d\n", rv); return (rv); } rv = hwreset_deassert(sc->rst); if (rv != 0) { device_printf(dev, "Cannot unreset 'padctl' reset: %d\n", rv); return (rv); } load_calibration(sc); rv = parse_fdt(sc, node); if (rv != 0) { device_printf(dev, "Cannot parse fdt configuration: %d\n", rv); return (rv); } for (i = 0; i < nitems(ports_tbl); i++) { port = ports_tbl + i; if (!port->enabled) continue; if (port->init == NULL) continue; rv = port->init(sc, port); if (rv != 0) { device_printf(dev, "Cannot init port '%s'\n", port->name); return (rv); } } return (0); } static device_method_t tegra_xusbpadctl_methods[] = { /* Device interface */ DEVMETHOD(device_probe, xusbpadctl_probe), DEVMETHOD(device_attach, xusbpadctl_attach), DEVMETHOD(device_detach, xusbpadctl_detach), DEVMETHOD_END }; static DEFINE_CLASS_0(xusbpadctl, tegra_xusbpadctl_driver, tegra_xusbpadctl_methods, sizeof(struct padctl_softc)); EARLY_DRIVER_MODULE(tegra_xusbpadctl, simplebus, tegra_xusbpadctl_driver, NULL, NULL, 73); diff --git a/sys/arm64/rockchip/rk3568_combphy.c b/sys/arm64/rockchip/rk3568_combphy.c index 5152f3eed0d1..99144b3315b1 100644 --- a/sys/arm64/rockchip/rk3568_combphy.c +++ b/sys/arm64/rockchip/rk3568_combphy.c @@ -1,469 +1,469 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2021, 2022 Soren Schmidt * * 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 AND CONTRIBUTORS ``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 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 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include "syscon_if.h" #include "phydev_if.h" #include "phynode_if.h" static struct ofw_compat_data compat_data[] = { {"rockchip,rk3568-naneng-combphy", 1}, {NULL, 0} }; struct rk3568_combphy_softc { device_t dev; phandle_t node; struct resource *mem; struct phynode *phynode; struct syscon *pipe_grf; struct syscon *pipe_phy_grf; clk_t ref_clk; clk_t apb_clk; clk_t pipe_clk; hwreset_t phy_reset; int mode; }; #define PHYREG6 0x14 #define PHYREG6_PLL_DIV_MASK 0xc0 #define PHYREG6_PLL_DIV_2 (1 << 6) #define PHYREG7 0x18 #define PHYREG7_TX_RTERM_50OHM (8 << 4) #define PHYREG7_RX_RTERM_44OHM (15 << 0) #define PHYREG8 0x1c #define PHYREG8_SSC_EN 0x10 #define PHYREG11 0x28 #define PHYREG11_SU_TRIM_0_7 0xf0 #define PHYREG12 0x2c #define PHYREG12_PLL_LPF_ADJ_VALUE 4 #define PHYREG15 0x38 #define PHYREG15_CTLE_EN 0x01 #define PHYREG15_SSC_CNT_MASK 0xc0 #define PHYREG15_SSC_CNT_VALUE (1 << 6) #define PHYREG16 0x3c #define PHYREG16_SSC_CNT_VALUE 0x5f #define PHYREG18 0x44 #define PHYREG18_PLL_LOOP 0x32 #define PHYREG32 0x7c #define PHYREG32_SSC_MASK 0xf0 #define PHYREG32_SSC_UPWARD (0 << 4) #define PHYREG32_SSC_DOWNWARD (1 << 4) #define PHYREG32_SSC_OFFSET_500PPM (1 << 6) #define PHYREG33 0x80 #define PHYREG33_PLL_KVCO_MASK 0x1c #define PHYREG33_PLL_KVCO_VALUE (2 << 2) #define PIPE_MASK_ALL (0xffff << 16) #define PIPE_PHY_GRF_PIPE_CON0 0x00 #define PIPE_DATABUSWIDTH_MASK 0x3 #define PIPE_DATABUSWIDTH_32BIT 0 #define PIPE_DATABUSWIDTH_16BIT 1 #define PIPE_PHYMODE_MASK (3 << 2) #define PIPE_PHYMODE_PCIE (0 << 2) #define PIPE_PHYMODE_USB3 (1 << 2) #define PIPE_PHYMODE_SATA (2 << 2) #define PIPE_RATE_MASK (3 << 4) #define PIPE_RATE_PCIE_2_5GBPS (0 << 4) #define PIPE_RATE_PCIE_5GBPS (1 << 4) #define PIPE_RATE_USB3_5GBPS (0 << 4) #define PIPE_RATE_SATA_1GBPS5 (0 << 4) #define PIPE_RATE_SATA_3GBPS (1 << 4) #define PIPE_RATE_SATA_6GBPS (2 << 4) #define PIPE_MAC_PCLKREQ_N (1 << 8) #define PIPE_L1SUB_ENTREQ (1 << 9) #define PIPE_RXTERM (1 << 12) #define PIPE_PHY_GRF_PIPE_CON1 0x04 #define PHY_CLK_SEL_MASK (3 << 13) #define PHY_CLK_SEL_24M (0 << 13) #define PHY_CLK_SEL_25M (1 << 13) #define PHY_CLK_SEL_100M (2 << 13) #define PIPE_PHY_GRF_PIPE_CON2 0x08 #define SEL_PIPE_TXCOMPLIANCE_I (1 << 15) #define SEL_PIPE_TXELECIDLE (1 << 12) #define SEL_PIPE_RXTERM (1 << 8) #define SEL_PIPE_BYPASS_CODEC (1 << 7) #define SEL_PIPE_PIPE_EBUF (1 << 6) #define SEL_PIPE_PIPE_PHYMODE (1 << 1) #define SEL_PIPE_DATABUSWIDTH (1 << 0) #define PIPE_PHY_GRF_PIPE_CON3 0x0c #define PIPE_SEL_MASK (3 << 13) #define PIPE_SEL_PCIE (0 << 13) #define PIPE_SEL_USB3 (1 << 13) #define PIPE_SEL_SATA (2 << 13) #define PIPE_CLK_REF_SRC_I_MASK (3 << 8) #define PIPE_CLK_REF_SRC_I_PLL_CKREF_INNER (2 << 8) #define PIPE_RXELECIDLE (1 << 10) #define PIPE_FROM_PCIE_IO (1 << 11) #define PIPE_GRF_PIPE_CON0 0x00 #define SATA2_PHY_SPDMODE_1GBPS5 (0 << 12) #define SATA2_PHY_SPDMODE_3GBPS (1 << 12) #define SATA2_PHY_SPDMODE_6GBPS (2 << 12) #define SATA1_PHY_SPDMODE_1GBPS5 (0 << 8) #define SATA1_PHY_SPDMODE_3GBPS (1 << 8) #define SATA1_PHY_SPDMODE_6GBPS (2 << 8) #define SATA0_PHY_SPDMODE_1GBPS5 (0 << 4) #define SATA0_PHY_SPDMODE_3GBPS (1 << 4) #define SATA0_PHY_SPDMODE_6GBPS (2 << 4) #define PIPE_GRF_SATA_CON0 0x10 #define PIPE_GRF_SATA_CON1 0x14 #define PIPE_GRF_SATA_CON2 0x18 #define PIPE_GRF_XPCS_CON0 0x40 /* PHY class and methods */ static int rk3568_combphy_enable(struct phynode *phynode, bool enable) { device_t dev = phynode_get_device(phynode); struct rk3568_combphy_softc *sc = device_get_softc(dev); uint64_t rate; if (enable == false) return (0); switch (sc->mode) { case PHY_TYPE_SATA: device_printf(dev, "configuring for SATA"); /* tx_rterm 50 ohm & rx_rterm 44 ohm */ bus_write_4(sc->mem, PHYREG7, PHYREG7_TX_RTERM_50OHM | PHYREG7_RX_RTERM_44OHM); /* Adaptive CTLE */ bus_write_4(sc->mem, PHYREG15, bus_read_4(sc->mem, PHYREG15) | PHYREG15_CTLE_EN); /* config grf_pipe for PCIe */ SYSCON_WRITE_4(sc->pipe_phy_grf, PIPE_PHY_GRF_PIPE_CON3, PIPE_MASK_ALL | PIPE_SEL_SATA | PIPE_RXELECIDLE | 0x7); SYSCON_WRITE_4(sc->pipe_phy_grf, PIPE_PHY_GRF_PIPE_CON2, PIPE_MASK_ALL | SEL_PIPE_TXCOMPLIANCE_I | SEL_PIPE_DATABUSWIDTH | 0xc3); SYSCON_WRITE_4(sc->pipe_phy_grf, PIPE_PHY_GRF_PIPE_CON0, PIPE_MASK_ALL | PIPE_RXTERM | PIPE_DATABUSWIDTH_16BIT | PIPE_RATE_SATA_3GBPS | PIPE_PHYMODE_SATA); SYSCON_WRITE_4(sc->pipe_grf, PIPE_GRF_PIPE_CON0, PIPE_MASK_ALL | SATA0_PHY_SPDMODE_6GBPS | SATA1_PHY_SPDMODE_6GBPS | SATA2_PHY_SPDMODE_6GBPS); break; case PHY_TYPE_PCIE: device_printf(dev, "configuring for PCIe"); /* Set SSC downward spread spectrum */ bus_write_4(sc->mem, PHYREG32, (bus_read_4(sc->mem, PHYREG32) & PHYREG32_SSC_MASK) | PHYREG32_SSC_DOWNWARD); /* config grf_pipe for PCIe */ SYSCON_WRITE_4(sc->pipe_phy_grf, PIPE_PHY_GRF_PIPE_CON3, PIPE_MASK_ALL | PIPE_SEL_PCIE | PIPE_CLK_REF_SRC_I_PLL_CKREF_INNER); SYSCON_WRITE_4(sc->pipe_phy_grf, PIPE_PHY_GRF_PIPE_CON2, PIPE_MASK_ALL | SEL_PIPE_RXTERM | SEL_PIPE_DATABUSWIDTH); SYSCON_WRITE_4(sc->pipe_phy_grf, PIPE_PHY_GRF_PIPE_CON0, PIPE_MASK_ALL | PIPE_RXTERM | PIPE_DATABUSWIDTH_32BIT | PIPE_RATE_PCIE_2_5GBPS | PIPE_PHYMODE_PCIE); break; case PHY_TYPE_USB3: device_printf(dev, "configuring for USB3"); /* Set SSC downward spread spectrum */ bus_write_4(sc->mem, PHYREG32, (bus_read_4(sc->mem, PHYREG32) & PHYREG32_SSC_MASK) | PHYREG32_SSC_DOWNWARD); /* Adaptive CTLE */ bus_write_4(sc->mem, PHYREG15, bus_read_4(sc->mem, PHYREG15) | PHYREG15_CTLE_EN); /* Set PLL KVCO fine tuning signals */ bus_write_4(sc->mem, PHYREG33, (bus_read_4(sc->mem, PHYREG33) & PHYREG33_PLL_KVCO_MASK) | PHYREG33_PLL_KVCO_VALUE); /* Enable controlling random jitter. */ bus_write_4(sc->mem, PHYREG12, PHYREG12_PLL_LPF_ADJ_VALUE); /* Set PLL input clock divider 1/2 */ bus_write_4(sc->mem, PHYREG6, (bus_read_4(sc->mem, PHYREG6) & PHYREG6_PLL_DIV_MASK) | PHYREG6_PLL_DIV_2); /* Set PLL loop divider */ bus_write_4(sc->mem, PHYREG18, PHYREG18_PLL_LOOP); /* Set PLL LPF R1 to su_trim[0:7] */ bus_write_4(sc->mem, PHYREG11, PHYREG11_SU_TRIM_0_7); /* config grf_pipe for USB3 */ SYSCON_WRITE_4(sc->pipe_phy_grf, PIPE_PHY_GRF_PIPE_CON3, PIPE_MASK_ALL | PIPE_SEL_USB3); SYSCON_WRITE_4(sc->pipe_phy_grf, PIPE_PHY_GRF_PIPE_CON2, PIPE_MASK_ALL); SYSCON_WRITE_4(sc->pipe_phy_grf, PIPE_PHY_GRF_PIPE_CON0, PIPE_MASK_ALL | PIPE_DATABUSWIDTH_16BIT | PIPE_PHYMODE_USB3 | PIPE_RATE_USB3_5GBPS); break; default: printf("Unsupported mode=%d\n", sc->mode); return (-1); } clk_get_freq(sc->ref_clk, &rate); printf(" ref_clk=%lu\n", rate); switch (rate) { case 24000000: SYSCON_WRITE_4(sc->pipe_phy_grf, PIPE_PHY_GRF_PIPE_CON1, (PHY_CLK_SEL_MASK << 16) | PHY_CLK_SEL_24M); if (sc->mode == PHY_TYPE_USB3 || sc->mode == PHY_TYPE_SATA) { /* Adaptive CTLE */ bus_write_4(sc->mem, PHYREG15, (bus_read_4(sc->mem, PHYREG15) & PHYREG15_SSC_CNT_MASK) | PHYREG15_SSC_CNT_VALUE); /* SSC control period */ bus_write_4(sc->mem, PHYREG16, PHYREG16_SSC_CNT_VALUE); } break; case 25000000: SYSCON_WRITE_4(sc->pipe_phy_grf, PIPE_PHY_GRF_PIPE_CON1, (PHY_CLK_SEL_MASK << 16) | PHY_CLK_SEL_25M); break; case 100000000: SYSCON_WRITE_4(sc->pipe_phy_grf, PIPE_PHY_GRF_PIPE_CON1, (PHY_CLK_SEL_MASK << 16) | PHY_CLK_SEL_100M); if (sc->mode == PHY_TYPE_PCIE) { /* Set PLL KVCO fine tuning signals */ bus_write_4(sc->mem, PHYREG33, (bus_read_4(sc->mem, PHYREG33) & PHYREG33_PLL_KVCO_MASK) | PHYREG33_PLL_KVCO_VALUE); /* Enable controlling random jitter. */ bus_write_4(sc->mem, PHYREG12, PHYREG12_PLL_LPF_ADJ_VALUE); /* Set PLL input clock divider 1/2 */ bus_write_4(sc->mem, PHYREG6, (bus_read_4(sc->mem, PHYREG6) & PHYREG6_PLL_DIV_MASK) | PHYREG6_PLL_DIV_2); /* Set PLL loop divider */ bus_write_4(sc->mem, PHYREG18, PHYREG18_PLL_LOOP); /* Set PLL LPF R1 to su_trim[0:7] */ bus_write_4(sc->mem, PHYREG11, PHYREG11_SU_TRIM_0_7); } if (sc->mode == PHY_TYPE_SATA) { /* Set SSC downward spread spectrum */ bus_write_4(sc->mem, PHYREG32, (bus_read_4(sc->mem, PHYREG32) & ~0x000000f0) | PHYREG32_SSC_DOWNWARD | PHYREG32_SSC_OFFSET_500PPM); } break; default: device_printf(dev, "unknown ref rate=%lu\n", rate); break; } if (OF_hasprop(sc->node, "rockchip,ext-refclk")) { device_printf(dev, "UNSUPPORTED rockchip,ext-refclk\n"); } if (OF_hasprop(sc->node, "rockchip,enable-ssc")) { device_printf(dev, "setting rockchip,enable-ssc\n"); bus_write_4(sc->mem, PHYREG8, bus_read_4(sc->mem, PHYREG8) | PHYREG8_SSC_EN); } if (hwreset_deassert(sc->phy_reset)) device_printf(dev, "phy_reset failed to clear\n"); return (0); } static phynode_method_t rk3568_combphy_phynode_methods[] = { PHYNODEMETHOD(phynode_enable, rk3568_combphy_enable), PHYNODEMETHOD_END }; DEFINE_CLASS_1(rk3568_combphy_phynode, rk3568_combphy_phynode_class, rk3568_combphy_phynode_methods, 0, phynode_class); /* Device class and methods */ static int rk3568_combphy_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "RockChip combo PHY"); return (BUS_PROBE_DEFAULT); } static int rk3568_combphy_attach(device_t dev) { struct rk3568_combphy_softc *sc = device_get_softc(dev); struct phynode_init_def phy_init; struct phynode *phynode; int rid = 0; sc->dev = dev; sc->node = ofw_bus_get_node(dev); /* Get memory resource */ if (!(sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE))) { device_printf(dev, "Cannot allocate memory resources\n"); return (ENXIO); } /* Get syncons handles */ if (OF_hasprop(sc->node, "rockchip,pipe-grf") && syscon_get_by_ofw_property(dev, sc->node, "rockchip,pipe-grf", &sc->pipe_grf)) return (ENXIO); if (OF_hasprop(sc->node, "rockchip,pipe-phy-grf") && syscon_get_by_ofw_property(dev, sc->node, "rockchip,pipe-phy-grf", &sc->pipe_phy_grf)) return (ENXIO); /* Get & enable clocks */ if (clk_get_by_ofw_name(dev, 0, "ref", &sc->ref_clk)) { device_printf(dev, "getting ref failed\n"); return (ENXIO); } if (clk_enable(sc->ref_clk)) device_printf(dev, "enable ref failed\n"); if (clk_get_by_ofw_name(dev, 0, "apb", &sc->apb_clk)) { device_printf(dev, "getting apb failed\n"); return (ENXIO); } if (clk_enable(sc->apb_clk)) device_printf(dev, "enable apb failed\n"); if (clk_get_by_ofw_name(dev, 0, "pipe", &sc->pipe_clk)) { device_printf(dev, "getting pipe failed\n"); return (ENXIO); } if (clk_enable(sc->pipe_clk)) device_printf(dev, "enable pipe failed\n"); /* get & assert reset */ if (hwreset_get_by_ofw_idx(dev, sc->node, 0, &sc->phy_reset)) { device_printf(dev, "Cannot get reset\n"); return (ENXIO); } hwreset_assert(sc->phy_reset); bzero(&phy_init, sizeof(phy_init)); phy_init.id = 0; phy_init.ofw_node = sc->node; if (!(phynode = phynode_create(dev, &rk3568_combphy_phynode_class, &phy_init))) { device_printf(dev, "failed to create combphy PHY\n"); return (ENXIO); } if (!phynode_register(phynode)) { device_printf(dev, "failed to register combphy PHY\n"); return (ENXIO); } sc->phynode = phynode; sc->mode = 0; return (0); } static int rk3568_combphy_map(device_t dev, phandle_t xref, int ncells, pcell_t *cells, intptr_t *id) { struct rk3568_combphy_softc *sc = device_get_softc(dev); if (phydev_default_ofw_map(dev, xref, ncells, cells, id)) return (ERANGE); /* Store the phy mode that is handed to us in id */ sc->mode = *id; /* Set our id to 0 so the std phy_get_*() works as usual */ *id = 0; return (0); } static device_method_t rk3568_combphy_methods[] = { DEVMETHOD(device_probe, rk3568_combphy_probe), DEVMETHOD(device_attach, rk3568_combphy_attach), DEVMETHOD(phydev_map, rk3568_combphy_map), DEVMETHOD_END }; DEFINE_CLASS_1(rk3568_combphy, rk3568_combphy_driver, rk3568_combphy_methods, sizeof(struct simple_mfd_softc), simple_mfd_driver); EARLY_DRIVER_MODULE(rk3568_combphy, simplebus, rk3568_combphy_driver, 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_LATE); diff --git a/sys/arm64/rockchip/rk3568_pcie.c b/sys/arm64/rockchip/rk3568_pcie.c index 5343a5dd3f2c..9874efdb1ec9 100644 --- a/sys/arm64/rockchip/rk3568_pcie.c +++ b/sys/arm64/rockchip/rk3568_pcie.c @@ -1,397 +1,397 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2021, 2022 Soren Schmidt * * 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, * without modification, immediately at the beginning of the file. * 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #include #include "pcib_if.h" /* APB Registers */ #define PCIE_CLIENT_GENERAL_CON 0x0000 #define DEVICE_TYPE_MASK 0x00f0 #define DEVICE_TYPE_RC (1<<6) #define LINK_REQ_RST_GRT (1<<3) #define LTSSM_ENABLE (1<<2) #define PCIE_CLIENT_INTR_MASK_MSG_RX 0x0018 #define PCIE_CLIENT_INTR_MASK_LEGACY 0x001c #define PCIE_CLIENT_INTR_MASK_ERR 0x0020 #define PCIE_CLIENT_INTR_MASK_MISC 0x0024 #define PCIE_CLIENT_INTR_MASK_PMC 0x0028 #define PCIE_CLIENT_GENERAL_DEBUG_INFO 0x0104 #define PCIE_CLIENT_HOT_RESET_CTRL 0x0180 #define APP_LSSTM_ENABLE_ENHANCE (1<<4) #define PCIE_CLIENT_LTSSM_STATUS 0x0300 #define RDLH_LINK_UP (1<<17) #define SMLH_LINK_UP (1<<16) #define SMLH_LTSSM_STATE_MASK 0x003f #define SMLH_LTSSM_STATE_LINK_UP ((1<<4) | (1<<0)) struct rk3568_pcie_softc { struct pci_dw_softc dw_sc; /* Must be first */ device_t dev; int apb_rid; struct resource *apb_res; int dbi_rid; struct resource *dbi_res; int irq_rid; struct resource *irq_res; void *irq_handle; phandle_t node; struct gpiobus_pin *reset_gpio; clk_t aclk_mst, aclk_slv, aclk_dbi, pclk, aux; regulator_t regulator; hwreset_t hwreset; phy_t phy; }; static struct ofw_compat_data compat_data[] = { {"rockchip,rk3568-pcie", 1}, {NULL, 0} }; static void rk3568_intr(void *data) { struct rk3568_pcie_softc *sc = data; device_printf(sc->dev, "INTERRUPT!!\n"); } static int rk3568_pcie_get_link(device_t dev, bool *status) { struct rk3568_pcie_softc *sc = device_get_softc(dev); uint32_t val; val = bus_read_4(sc->apb_res, PCIE_CLIENT_LTSSM_STATUS); if (((val & (RDLH_LINK_UP | SMLH_LINK_UP)) == (RDLH_LINK_UP | SMLH_LINK_UP)) && ((val & SMLH_LTSSM_STATE_MASK) == SMLH_LTSSM_STATE_LINK_UP)) *status = true; else *status = false; return (0); } static int rk3568_pcie_init_soc(device_t dev) { struct rk3568_pcie_softc *sc = device_get_softc(dev); int err, count; bool status; /* Assert reset */ if (hwreset_assert(sc->hwreset)) device_printf(dev, "Could not assert reset\n"); /* Powerup PCIe */ if (regulator_enable(sc->regulator)) device_printf(dev, "Cannot enable regulator\n"); /* Enable PHY */ if (phy_enable(sc->phy)) device_printf(dev, "Cannot enable phy\n"); /* Deassert reset */ if (hwreset_deassert(sc->hwreset)) device_printf(dev, "Could not deassert reset\n"); /* Enable clocks */ if ((err = clk_enable(sc->aclk_mst))) { device_printf(dev, "Could not enable aclk_mst clk\n"); return (ENXIO); } if ((err = clk_enable(sc->aclk_slv))) { device_printf(dev, "Could not enable aclk_slv clk\n"); return (ENXIO); } if ((err = clk_enable(sc->aclk_dbi))) { device_printf(dev, "Could not enable aclk_dbi clk\n"); return (ENXIO); } if ((err = clk_enable(sc->pclk))) { device_printf(dev, "Could not enable pclk clk\n"); return (ENXIO); } if ((err = clk_enable(sc->aux))) { device_printf(dev, "Could not enable aux clk\n"); return (ENXIO); } /* Set Root Complex (RC) mode */ bus_write_4(sc->apb_res, PCIE_CLIENT_HOT_RESET_CTRL, (APP_LSSTM_ENABLE_ENHANCE << 16) | APP_LSSTM_ENABLE_ENHANCE); bus_write_4(sc->apb_res, PCIE_CLIENT_GENERAL_CON, (DEVICE_TYPE_MASK << 16) | DEVICE_TYPE_RC); /* Assert reset PCIe */ if ((err = gpio_pin_set_active(sc->reset_gpio, false))) device_printf(dev, "reset_gpio set failed\n"); /* Start Link Training and Status State Machine (LTSSM) */ bus_write_4(sc->apb_res, PCIE_CLIENT_GENERAL_CON, (LINK_REQ_RST_GRT | LTSSM_ENABLE) << 16 | (LINK_REQ_RST_GRT | LTSSM_ENABLE)); DELAY(100000); /* Release reset */ if ((err = gpio_pin_set_active(sc->reset_gpio, true))) device_printf(dev, "reset_gpio release failed\n"); /* Wait for link up/stable */ for (count = 20; count; count--) { rk3568_pcie_get_link(dev, &status); if (status) break; DELAY(100000); if (count == 0) { device_printf(dev, "Link up timeout!\n"); return (ENXIO); } } if ((err = pci_dw_init(dev))) return (ENXIO); /* Delay to have things settle */ DELAY(100000); /* Enable all MSG interrupts */ bus_write_4(sc->apb_res, PCIE_CLIENT_INTR_MASK_MSG_RX, 0x7fff0000); /* Enable all Legacy interrupts */ bus_write_4(sc->apb_res, PCIE_CLIENT_INTR_MASK_LEGACY, 0x00ff0000); /* Enable all Error interrupts */ bus_write_4(sc->apb_res, PCIE_CLIENT_INTR_MASK_ERR, 0x0fff0000); return (0); } static int rk3568_pcie_detach(device_t dev) { struct rk3568_pcie_softc *sc = device_get_softc(dev); /* Release allocated resources */ if (sc->irq_handle) bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); if (sc->phy) phy_release(sc->phy); if (sc->aux) clk_release(sc->aux); if (sc->pclk) clk_release(sc->pclk); if (sc->aclk_dbi) clk_release(sc->aclk_dbi); if (sc->aclk_slv) clk_release(sc->aclk_slv); if (sc->aclk_mst) clk_release(sc->aclk_mst); if (sc->hwreset) hwreset_release(sc->hwreset); if (sc->regulator) regulator_release(sc->regulator); if (sc->irq_res) bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq_res); if (sc->dbi_res) bus_release_resource(dev, SYS_RES_MEMORY, sc->dbi_rid, sc->dbi_res); if (sc->apb_res) bus_release_resource(dev, SYS_RES_MEMORY, sc->apb_rid, sc->apb_res); return (0); } static int rk3568_pcie_attach(device_t dev) { struct rk3568_pcie_softc *sc = device_get_softc(dev); int error; sc->dev = dev; sc->node = ofw_bus_get_node(dev); /* Setup resources */ if ((error = ofw_bus_find_string_index(sc->node, "reg-names", "apb", &sc->apb_rid))) { device_printf(dev, "Cannot get APB memory: %d\n", error); goto fail; } if (!(sc->apb_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->apb_rid, RF_ACTIVE))) { device_printf(dev, "Cannot allocate APB resource\n"); goto fail; } if ((error = ofw_bus_find_string_index(sc->node, "reg-names", "dbi", &sc->dbi_rid))) { device_printf(dev, "Cannot get DBI memory: %d\n", error); goto fail; } if (!(sc->dw_sc.dbi_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->dbi_rid, RF_ACTIVE))) { device_printf(dev, "Cannot allocate DBI resource\n"); goto fail; } if (!(sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_ACTIVE | RF_SHAREABLE))) { device_printf(dev, "Cannot allocate IRQ resource\n"); goto fail; } /* Get regulator if present */ if (regulator_get_by_ofw_property(dev, 0, "vpcie3v3-supply", &sc->regulator)) { device_printf(dev, "Cannot get regulator\n"); goto fail; } /* Get reset */ if (hwreset_get_by_ofw_name(dev, 0, "pipe", &sc->hwreset)) { device_printf(dev, "Can not get reset\n"); goto fail; } /* Get GPIO reset */ if (OF_hasprop(sc->node, "reset-gpios")) { if (gpio_pin_get_by_ofw_property(dev, sc->node, "reset-gpios", &sc->reset_gpio)) { device_printf(dev, "Cannot get reset-gpios\n"); goto fail; } gpio_pin_setflags(sc->reset_gpio, GPIO_PIN_OUTPUT); gpio_pin_set_active(sc->reset_gpio, true); } /* Get clocks */ if (clk_get_by_ofw_name(dev, 0, "aclk_mst", &sc->aclk_mst)) { device_printf(dev, "Can not get aclk_mst clk\n"); goto fail; } if (clk_get_by_ofw_name(dev, 0, "aclk_slv", &sc->aclk_slv)) { device_printf(dev, "Can not get aclk_slv clk\n"); goto fail; } if (clk_get_by_ofw_name(dev, 0, "aclk_dbi", &sc->aclk_dbi)) { device_printf(dev, "Can not get aclk_dbi clk\n"); goto fail; } if (clk_get_by_ofw_name(dev, 0, "pclk", &sc->pclk)) { device_printf(dev, "Can not get pclk clk\n"); goto fail; } if (clk_get_by_ofw_name(dev, 0, "aux", &sc->aux)) { device_printf(dev, "Can not get aux clk\n"); goto fail; } /* Get PHY */ if (phy_get_by_ofw_name(dev, 0, "pcie-phy", &sc->phy)) { device_printf(dev, "Cannot get 'pcie-phy'\n"); goto fail; } if ((error = rk3568_pcie_init_soc(dev))) goto fail; /* Enable interrupt */ if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, rk3568_intr, sc, &sc->irq_handle))) { device_printf(dev, "unable to setup interrupt\n"); goto fail; } return (bus_generic_attach(dev)); fail: rk3568_pcie_detach(dev); return (ENXIO); } static int rk3568_pcie_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "RockChip RK3568 PCI-express controller"); return (BUS_PROBE_DEFAULT); } static device_method_t rk3568_pcie_methods[] = { /* Device interface */ DEVMETHOD(device_probe, rk3568_pcie_probe), DEVMETHOD(device_attach, rk3568_pcie_attach), DEVMETHOD(device_detach, rk3568_pcie_detach), /* PCI DW interface */ DEVMETHOD(pci_dw_get_link, rk3568_pcie_get_link), DEVMETHOD_END }; DEFINE_CLASS_1(pcib, rk3568_pcie_driver, rk3568_pcie_methods, sizeof(struct rk3568_pcie_softc), pci_dw_driver); DRIVER_MODULE(rk3568_pcie, simplebus, rk3568_pcie_driver, NULL, NULL); diff --git a/sys/arm64/rockchip/rk3568_pciephy.c b/sys/arm64/rockchip/rk3568_pciephy.c index f277253b577d..50471ea55130 100644 --- a/sys/arm64/rockchip/rk3568_pciephy.c +++ b/sys/arm64/rockchip/rk3568_pciephy.c @@ -1,263 +1,263 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2021, 2022 Soren Schmidt * * 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 AND CONTRIBUTORS ``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 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 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include "syscon_if.h" #include "phydev_if.h" #include "phynode_if.h" #define GRF_PCIE30PHY_CON1 0x04 #define GRF_PCIE30PHY_CON4 0x10 #define GRF_PCIE30PHY_CON5 0x14 #define GRF_PCIE30PHY_CON6 0x18 #define GRF_BIFURCATION_LANE_1 0 #define GRF_BIFURCATION_LANE_2 1 #define GRF_PCIE30PHY_WR_EN (0xf << 16) #define GRF_PCIE30PHY_CON9 0x24 #define GRF_PCIE30PHY_DA_OCM_MASK (1 << (15 + 16)) #define GRF_PCIE30PHY_DA_OCM ((1 << 15) | GRF_PCIE30PHY_DA_OCM_MASK) #define GRF_PCIE30PHY_STATUS0 0x80 #define SRAM_INIT_DONE (1 << 14) static struct ofw_compat_data compat_data[] = { {"rockchip,rk3568-pcie3-phy", 1}, {NULL, 0} }; struct rk3568_pciephy_softc { device_t dev; phandle_t node; struct resource *mem; struct phynode *phynode; struct syscon *phy_grf; clk_t refclk_m; clk_t refclk_n; clk_t pclk; hwreset_t phy_reset; }; static void rk3568_pciephy_bifurcate(device_t dev, int control, uint32_t lane) { struct rk3568_pciephy_softc *sc = device_get_softc(dev); switch (lane) { case 0: SYSCON_WRITE_4(sc->phy_grf, control, GRF_PCIE30PHY_WR_EN); return; case 1: SYSCON_WRITE_4(sc->phy_grf, control, GRF_PCIE30PHY_WR_EN | GRF_BIFURCATION_LANE_1); break; case 2: SYSCON_WRITE_4(sc->phy_grf, control, GRF_PCIE30PHY_WR_EN | GRF_BIFURCATION_LANE_2); break; default: device_printf(dev, "Illegal lane %d\n", lane); return; } if (bootverbose) device_printf(dev, "lane %d @ pcie3x%d\n", lane, (control == GRF_PCIE30PHY_CON5) ? 1 : 2); } /* PHY class and methods */ static int rk3568_pciephy_enable(struct phynode *phynode, bool enable) { device_t dev = phynode_get_device(phynode); struct rk3568_pciephy_softc *sc = device_get_softc(dev); int count; if (enable) { /* Pull PHY out of reset */ hwreset_deassert(sc->phy_reset); /* Poll for SRAM loaded and ready */ for (count = 100; count; count--) { if (SYSCON_READ_4(sc->phy_grf, GRF_PCIE30PHY_STATUS0) & SRAM_INIT_DONE) break; DELAY(10000); if (count == 0) { device_printf(dev, "SRAM init timeout!\n"); return (ENXIO); } } } return (0); } static phynode_method_t rk3568_pciephy_phynode_methods[] = { PHYNODEMETHOD(phynode_enable, rk3568_pciephy_enable), PHYNODEMETHOD_END }; DEFINE_CLASS_1(rk3568_pciephy_phynode, rk3568_pciephy_phynode_class, rk3568_pciephy_phynode_methods, 0, phynode_class); /* Device class and methods */ static int rk3568_pciephy_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "RockChip PCIe PHY"); return (BUS_PROBE_DEFAULT); } static int rk3568_pciephy_attach(device_t dev) { struct rk3568_pciephy_softc *sc = device_get_softc(dev); struct phynode_init_def phy_init; struct phynode *phynode; uint32_t data_lanes[2] = { 0, 0 }; int rid = 0; sc->dev = dev; sc->node = ofw_bus_get_node(dev); /* Get memory resource */ if (!(sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE))) { device_printf(dev, "Cannot allocate memory resources\n"); return (ENXIO); } /* Get syncons handle */ if (OF_hasprop(sc->node, "rockchip,phy-grf") && syscon_get_by_ofw_property(dev, sc->node, "rockchip,phy-grf", &sc->phy_grf)) return (ENXIO); /* Get & enable clocks */ if (clk_get_by_ofw_name(dev, 0, "refclk_m", &sc->refclk_m)) { device_printf(dev, "getting refclk_m failed\n"); return (ENXIO); } if (clk_enable(sc->refclk_m)) device_printf(dev, "enable refclk_m failed\n"); if (clk_get_by_ofw_name(dev, 0, "refclk_n", &sc->refclk_n)) { device_printf(dev, "getting refclk_n failed\n"); return (ENXIO); } if (clk_enable(sc->refclk_n)) device_printf(dev, "enable refclk_n failed\n"); if (clk_get_by_ofw_name(dev, 0, "pclk", &sc->pclk)) { device_printf(dev, "getting pclk failed\n"); return (ENXIO); } if (clk_enable(sc->pclk)) device_printf(dev, "enable pclk failed\n"); /* Get & assert reset */ if (hwreset_get_by_ofw_idx(dev, sc->node, 0, &sc->phy_reset)) { device_printf(dev, "Cannot get reset\n"); } else hwreset_assert(sc->phy_reset); /* Set RC/EP mode not implemented yet (RC mode only) */ /* Set bifurcation according to "data-lanes" entry */ if (OF_hasprop(sc->node, "data-lanes")) { OF_getencprop(sc->node, "data-lanes", data_lanes, sizeof(data_lanes)); } else if (bootverbose) device_printf(dev, "lane 1 & 2 @pcie3x2\n"); /* Deassert PCIe PMA output clamp mode */ SYSCON_WRITE_4(sc->phy_grf, GRF_PCIE30PHY_CON9, GRF_PCIE30PHY_DA_OCM); /* Configure PHY HW accordingly */ rk3568_pciephy_bifurcate(dev, GRF_PCIE30PHY_CON5, data_lanes[0]); rk3568_pciephy_bifurcate(dev, GRF_PCIE30PHY_CON6, data_lanes[1]); if (data_lanes[0] || data_lanes[1]) SYSCON_WRITE_4(sc->phy_grf, GRF_PCIE30PHY_CON1, GRF_PCIE30PHY_DA_OCM); else SYSCON_WRITE_4(sc->phy_grf, GRF_PCIE30PHY_CON1, GRF_PCIE30PHY_DA_OCM_MASK); bzero(&phy_init, sizeof(phy_init)); phy_init.id = PHY_NONE; phy_init.ofw_node = sc->node; if (!(phynode = phynode_create(dev, &rk3568_pciephy_phynode_class, &phy_init))) { device_printf(dev, "failed to create pciephy PHY\n"); return (ENXIO); } if (!phynode_register(phynode)) { device_printf(dev, "failed to register pciephy PHY\n"); return (ENXIO); } sc->phynode = phynode; return (0); } static device_method_t rk3568_pciephy_methods[] = { DEVMETHOD(device_probe, rk3568_pciephy_probe), DEVMETHOD(device_attach, rk3568_pciephy_attach), DEVMETHOD_END }; DEFINE_CLASS_1(rk3568_pciephy, rk3568_pciephy_driver, rk3568_pciephy_methods, sizeof(struct simple_mfd_softc), simple_mfd_driver); EARLY_DRIVER_MODULE(rk3568_pciephy, simplebus, rk3568_pciephy_driver, 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_LATE); diff --git a/sys/arm64/rockchip/rk_iodomain.c b/sys/arm64/rockchip/rk_iodomain.c index 695d941e4f9c..e872ee5a45ed 100644 --- a/sys/arm64/rockchip/rk_iodomain.c +++ b/sys/arm64/rockchip/rk_iodomain.c @@ -1,301 +1,301 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2019 Emmanuel Vadot * * 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 AND CONTRIBUTORS ``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 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 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. * */ #include #include #include #include #include #include #include #include -#include +#include #include "syscon_if.h" #define RK3288_GRF_IO_VSEL 0x380 #define RK3399_GRF_IO_VSEL 0xe640 #define RK3399_PMUGRF_SOC_CON0 0x180 #define RK3568_PMUGRF_IO_VSEL0 0x0140 #define RK3568_PMUGRF_IO_VSEL1 0x0144 #define RK3568_PMUGRF_IO_VSEL2 0x0148 #define MAX_1V8 1850000 enum rk_iodomain_type { RK3328 = 1, RK3399, RK3568, }; struct rk_iodomain_supply { char *name; uint32_t bit; }; struct rk_iodomain_softc; struct rk_iodomain_conf { struct rk_iodomain_supply *supply; int nsupply; uint32_t grf_reg; void (*init)(struct rk_iodomain_softc *sc); enum rk_iodomain_type type; }; struct rk_iodomain_softc { device_t dev; struct syscon *grf; phandle_t node; struct rk_iodomain_conf *conf; }; static struct rk_iodomain_supply rk3288_supply[] = { {"lcdc-supply", 0}, {"dvp-supply", 1}, {"flash0-supply", 2}, {"flash1-supply", 3}, {"wifi-supply", 4}, {"bb-supply", 5}, {"audio-supply", 6}, {"sdcard-supply", 7}, {"gpio30-supply", 8}, {"gpio1830-supply", 9}, }; static struct rk_iodomain_conf rk3288_conf = { .supply = rk3288_supply, .nsupply = nitems(rk3288_supply), .grf_reg = RK3288_GRF_IO_VSEL, .type = RK3328, }; static struct rk_iodomain_supply rk3399_supply[] = { {"bt656-supply", 0}, {"audio-supply", 1}, {"sdmmc-supply", 2}, {"gpio1830-supply", 3}, }; static struct rk_iodomain_conf rk3399_conf = { .supply = rk3399_supply, .nsupply = nitems(rk3399_supply), .grf_reg = RK3399_GRF_IO_VSEL, .type = RK3399, }; static struct rk_iodomain_supply rk3399_pmu_supply[] = { {"pmu1830-supply", 9}, }; static void rk3399_pmu_init(struct rk_iodomain_softc *sc); static struct rk_iodomain_conf rk3399_pmu_conf = { .supply = rk3399_pmu_supply, .nsupply = nitems(rk3399_pmu_supply), .grf_reg = RK3399_PMUGRF_SOC_CON0, .init = rk3399_pmu_init, .type = RK3399, }; static struct rk_iodomain_supply rk3568_pmu_supply[] = { {"pmuio1-supply", 0}, {"pmuio2-supply", 1}, {"vccio1-supply", 1}, {"vccio2-supply", 2}, {"vccio3-supply", 3}, {"vccio4-supply", 4}, {"vccio5-supply", 5}, {"vccio6-supply", 6}, {"vccio7-supply", 7}, }; static struct rk_iodomain_conf rk3568_pmu_conf = { .supply = rk3568_pmu_supply, .nsupply = nitems(rk3568_pmu_supply), .type = RK3568, }; static struct ofw_compat_data compat_data[] = { {"rockchip,rk3288-io-voltage-domain", (uintptr_t)&rk3288_conf}, {"rockchip,rk3399-io-voltage-domain", (uintptr_t)&rk3399_conf}, {"rockchip,rk3399-pmu-io-voltage-domain", (uintptr_t)&rk3399_pmu_conf}, {"rockchip,rk3568-pmu-io-voltage-domain", (uintptr_t)&rk3568_pmu_conf}, {NULL, 0} }; static void rk3399_pmu_init(struct rk_iodomain_softc *sc) { SYSCON_WRITE_4(sc->grf, RK3399_PMUGRF_SOC_CON0, (1 << 8) | (1 << (8 + 16))); /* set pmu1830_volsel */ } static int rk_iodomain_set(struct rk_iodomain_softc *sc) { regulator_t supply; uint32_t reg = 0; uint32_t mask = 0; int uvolt, i; for (i = 0; i < sc->conf->nsupply; i++) { if (regulator_get_by_ofw_property(sc->dev, sc->node, sc->conf->supply[i].name, &supply) != 0) { device_printf(sc->dev, "Cannot get property for regulator %s\n", sc->conf->supply[i].name); return (ENXIO); } if (regulator_get_voltage(supply, &uvolt) != 0) { device_printf(sc->dev, "Cannot get current voltage for regulator %s\n", sc->conf->supply[i].name); return (ENXIO); } if (sc->conf->type != RK3568) { /* RK3328 and RK3399 iodomain */ mask |= (1 << sc->conf->supply[i].bit) << 16; if (uvolt == 1800000) reg |= (1 << sc->conf->supply[i].bit); else if (uvolt != 3000000) device_printf(sc->dev, "%s regulator is at %duV, ignoring\n", sc->conf->supply[i].name, uvolt); } else { /* RK3568 iodomain */ if (bootverbose) { device_printf(sc->dev, "Setting regulator %s voltage=%duV\n", sc->conf->supply[i].name, uvolt); } switch(i) { case 0: /* pmuio1 */ break; case 1: /* pmuio2 */ SYSCON_WRITE_4(sc->grf, RK3568_PMUGRF_IO_VSEL2, (1 << (sc->conf->supply[i].bit + 16)) | (uvolt > MAX_1V8 ? 0 : 1 << sc->conf->supply[i].bit)); SYSCON_WRITE_4(sc->grf, RK3568_PMUGRF_IO_VSEL2, (1 << (sc->conf->supply[i].bit + 4 + 16)) | (uvolt > MAX_1V8 ? 1 << (sc->conf->supply[i].bit + 4) : 0)); case 3: /* vccio2 */ break; case 2: /* vccio1 */ case 4: /* vccio3 */ case 5: /* vccio4 */ case 6: /* vccio5 */ case 7: /* vccio6 */ case 8: /* vccio7 */ SYSCON_WRITE_4(sc->grf, RK3568_PMUGRF_IO_VSEL0, (1 << (sc->conf->supply[i].bit + 16)) | (uvolt > MAX_1V8 ? 0 : 1 << sc->conf->supply[i].bit)); SYSCON_WRITE_4(sc->grf, RK3568_PMUGRF_IO_VSEL1, (1 << (sc->conf->supply[i].bit + 16)) | (uvolt > MAX_1V8 ? 1 << sc->conf->supply[i].bit : 0)); break; default: device_printf(sc->dev, "Index out of range\n"); } } } if (sc->conf->type != RK3568) SYSCON_WRITE_4(sc->grf, sc->conf->grf_reg, reg | mask); if (sc->conf->init != NULL) sc->conf->init(sc); return (0); } static int rk_iodomain_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "RockChip IO Voltage Domain"); return (BUS_PROBE_DEFAULT); } static int rk_iodomain_attach(device_t dev) { struct rk_iodomain_softc *sc; int rv; sc = device_get_softc(dev); sc->dev = dev; sc->node = ofw_bus_get_node(dev); rv = syscon_get_handle_default(dev, &sc->grf); if (rv != 0) { device_printf(dev, "Cannot get grf handle\n"); return (ENXIO); } sc->conf = (struct rk_iodomain_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; rv = rk_iodomain_set(sc); return (rv); } static int rk_iodomain_detach(device_t dev) { return (0); } static device_method_t rk_iodomain_methods[] = { /* Device interface */ DEVMETHOD(device_probe, rk_iodomain_probe), DEVMETHOD(device_attach, rk_iodomain_attach), DEVMETHOD(device_detach, rk_iodomain_detach), DEVMETHOD_END }; static driver_t rk_iodomain_driver = { "rk_iodomain", rk_iodomain_methods, sizeof(struct rk_iodomain_softc), }; EARLY_DRIVER_MODULE(rk_iodomain, simplebus, rk_iodomain_driver, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); diff --git a/sys/arm64/rockchip/rk_pcie.c b/sys/arm64/rockchip/rk_pcie.c index cc6c842a6f6a..ca85637589ee 100644 --- a/sys/arm64/rockchip/rk_pcie.c +++ b/sys/arm64/rockchip/rk_pcie.c @@ -1,1432 +1,1432 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2019 Michal Meloun * * 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 AND CONTRIBUTORS ``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 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 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. * */ /* Rockchip PCIe controller driver */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #include #include #include #include "pcib_if.h" #define ATU_CFG_BUS(x) (((x) & 0x0ff) << 20) #define ATU_CFG_SLOT(x) (((x) & 0x01f) << 15) #define ATU_CFG_FUNC(x) (((x) & 0x007) << 12) #define ATU_CFG_REG(x) (((x) & 0xfff) << 0) #define ATU_TYPE_MEM 0x2 #define ATU_TYPE_IO 0x6 #define ATU_TYPE_CFG0 0xA #define ATU_TYPE_CFG1 0xB #define ATY_TYPE_NOR_MSG 0xC #define ATU_OB_REGIONS 33 #define ATU_OB_REGION_SHIFT 20 #define ATU_OB_REGION_SIZE (1 << ATU_OB_REGION_SHIFT) #define ATU_OB_REGION_0_SIZE (( ATU_OB_REGIONS - 1) * ATU_OB_REGION_SIZE) #define ATU_IB_REGIONS 3 #define PCIE_CLIENT_BASIC_STRAP_CONF 0x000000 #define STRAP_CONF_GEN_2 (1 << 7) #define STRAP_CONF_MODE_RC (1 << 6) #define STRAP_CONF_LANES(n) ((((n) / 2) & 0x3) << 4) #define STRAP_CONF_ARI_EN (1 << 3) #define STRAP_CONF_SR_IOV_EN (1 << 2) #define STRAP_CONF_LINK_TRAIN_EN (1 << 1) #define STRAP_CONF_CONF_EN (1 << 0) #define PCIE_CLIENT_HOT_RESET_CTRL 0x000018 #define HOT_RESET_CTRL_LINK_DOWN_RESET (1 << 1) #define HOT_RESET_CTRL_HOT_RESET_IN (1 << 0) #define PCIE_CLIENT_BASIC_STATUS0 0x000044 #define PCIE_CLIENT_BASIC_STATUS1 0x000048 #define STATUS1_LINK_ST_GET(x) (((x) >> 20) & 0x3) #define STATUS1_LINK_ST_UP 3 #define PCIE_CLIENT_INT_MASK 0x00004C #define PCIE_CLIENT_INT_STATUS 0x000050 #define PCIE_CLIENT_INT_LEGACY_DONE (1 << 15) #define PCIE_CLIENT_INT_MSG (1 << 14) #define PCIE_CLIENT_INT_HOT_RST (1 << 13) #define PCIE_CLIENT_INT_DPA (1 << 12) #define PCIE_CLIENT_INT_FATAL_ERR (1 << 11) #define PCIE_CLIENT_INT_NFATAL_ERR (1 << 10) #define PCIE_CLIENT_INT_CORR_ERR (1 << 9) #define PCIE_CLIENT_INT_INTD (1 << 8) #define PCIE_CLIENT_INT_INTC (1 << 7) #define PCIE_CLIENT_INT_INTB (1 << 6) #define PCIE_CLIENT_INT_INTA (1 << 5) #define PCIE_CLIENT_INT_LOCAL (1 << 4) #define PCIE_CLIENT_INT_UDMA (1 << 3) #define PCIE_CLIENT_INT_PHY (1 << 2) #define PCIE_CLIENT_INT_HOT_PLUG (1 << 1) #define PCIE_CLIENT_INT_PWR_STCG (1 << 0) #define PCIE_CLIENT_INT_LEGACY (PCIE_CLIENT_INT_INTA | \ PCIE_CLIENT_INT_INTB | \ PCIE_CLIENT_INT_INTC | \ PCIE_CLIENT_INT_INTD) #define PCIE_CORE_CTRL0 0x900000 #define CORE_CTRL_LANES_GET(x) (((x) >> 20) & 0x3) #define PCIE_CORE_CTRL1 0x900004 #define PCIE_CORE_CONFIG_VENDOR 0x900044 #define PCIE_CORE_INT_STATUS 0x90020c #define PCIE_CORE_INT_PRFPE (1 << 0) #define PCIE_CORE_INT_CRFPE (1 << 1) #define PCIE_CORE_INT_RRPE (1 << 2) #define PCIE_CORE_INT_PRFO (1 << 3) #define PCIE_CORE_INT_CRFO (1 << 4) #define PCIE_CORE_INT_RT (1 << 5) #define PCIE_CORE_INT_RTR (1 << 6) #define PCIE_CORE_INT_PE (1 << 7) #define PCIE_CORE_INT_MTR (1 << 8) #define PCIE_CORE_INT_UCR (1 << 9) #define PCIE_CORE_INT_FCE (1 << 10) #define PCIE_CORE_INT_CT (1 << 11) #define PCIE_CORE_INT_UTC (1 << 18) #define PCIE_CORE_INT_MMVC (1 << 19) #define PCIE_CORE_INT_MASK 0x900210 #define PCIE_CORE_PHY_FUNC_CONF 0x9002C0 #define PCIE_CORE_RC_BAR_CONF 0x900300 #define PCIE_RC_CONFIG_STD_BASE 0x800000 #define PCIE_RC_CONFIG_PRIV_BASE 0xA00000 #define PCIE_RC_CONFIG_DCSR 0xA000C8 #define PCIE_RC_CONFIG_DCSR_MPS_MASK (0x7 << 5) #define PCIE_RC_CONFIG_DCSR_MPS_128 (0 << 5) #define PCIE_RC_CONFIG_DCSR_MPS_256 (1 << 5) #define PCIE_RC_CONFIG_LINK_CAP 0xA00CC #define PCIE_RC_CONFIG_LINK_CAP_L0S (1 << 10) #define PCIE_RC_CONFIG_LCS 0xA000D0 #define PCIE_RC_CONFIG_THP_CAP 0xA00274 #define PCIE_RC_CONFIG_THP_CAP_NEXT_MASK 0xFFF00000 #define PCIE_CORE_OB_ADDR0(n) (0xC00000 + 0x20 * (n) + 0x00) #define PCIE_CORE_OB_ADDR1(n) (0xC00000 + 0x20 * (n) + 0x04) #define PCIE_CORE_OB_DESC0(n) (0xC00000 + 0x20 * (n) + 0x08) #define PCIE_CORE_OB_DESC1(n) (0xC00000 + 0x20 * (n) + 0x0C) #define PCIE_CORE_OB_DESC2(n) (0xC00000 + 0x20 * (n) + 0x10) #define PCIE_CORE_OB_DESC3(n) (0xC00000 + 0x20 * (n) + 0x14) #define PCIE_CORE_IB_ADDR0(n) (0xC00800 + 0x8 * (n) + 0x00) #define PCIE_CORE_IB_ADDR1(n) (0xC00800 + 0x8 * (n) + 0x04) #define PRIV_CFG_RD4(sc, reg) \ (uint32_t)rk_pcie_local_cfg_read(sc, true, reg, 4) #define PRIV_CFG_RD2(sc, reg) \ (uint16_t)rk_pcie_local_cfg_read(sc, true, reg, 2) #define PRIV_CFG_RD1(sc, reg) \ (uint8_t)rk_pcie_local_cfg_read(sc, true, reg, 1) #define PRIV_CFG_WR4(sc, reg, val) \ rk_pcie_local_cfg_write(sc, true, reg, val, 4) #define PRIV_CFG_WR2(sc, reg, val) \ rk_pcie_local_cfg_write(sc, true, reg, val, 2) #define PRIV_CFG_WR1(sc, reg, val) \ rk_pcie_local_cfg_write(sc, true, reg, val, 1) #define APB_WR4(_sc, _r, _v) bus_write_4((_sc)->apb_mem_res, (_r), (_v)) #define APB_RD4(_sc, _r) bus_read_4((_sc)->apb_mem_res, (_r)) #define MAX_LANES 4 #define RK_PCIE_ENABLE_MSI #define RK_PCIE_ENABLE_MSIX struct rk_pcie_softc { struct ofw_pci_softc ofw_pci; /* Must be first */ struct resource *axi_mem_res; struct resource *apb_mem_res; struct resource *client_irq_res; struct resource *legacy_irq_res; struct resource *sys_irq_res; void *client_irq_cookie; void *legacy_irq_cookie; void *sys_irq_cookie; device_t dev; phandle_t node; struct mtx mtx; struct ofw_pci_range mem_range; struct ofw_pci_range pref_mem_range; struct ofw_pci_range io_range; bool coherent; bus_dma_tag_t dmat; int num_lanes; bool link_is_gen2; bool no_l0s; u_int bus_start; u_int bus_end; u_int root_bus; u_int sub_bus; regulator_t supply_12v; regulator_t supply_3v3; regulator_t supply_1v8; regulator_t supply_0v9; hwreset_t hwreset_core; hwreset_t hwreset_mgmt; hwreset_t hwreset_mgmt_sticky; hwreset_t hwreset_pipe; hwreset_t hwreset_pm; hwreset_t hwreset_aclk; hwreset_t hwreset_pclk; clk_t clk_aclk; clk_t clk_aclk_perf; clk_t clk_hclk; clk_t clk_pm; phy_t phys[MAX_LANES]; gpio_pin_t gpio_ep; }; /* Compatible devices. */ static struct ofw_compat_data compat_data[] = { {"rockchip,rk3399-pcie", 1}, {NULL, 0}, }; static uint32_t rk_pcie_local_cfg_read(struct rk_pcie_softc *sc, bool priv, u_int reg, int bytes) { uint32_t val; bus_addr_t base; if (priv) base = PCIE_RC_CONFIG_PRIV_BASE; else base = PCIE_RC_CONFIG_STD_BASE; switch (bytes) { case 4: val = bus_read_4(sc->apb_mem_res, base + reg); break; case 2: val = bus_read_2(sc->apb_mem_res, base + reg); break; case 1: val = bus_read_1(sc->apb_mem_res, base + reg); break; default: val = 0xFFFFFFFF; } return (val); } static void rk_pcie_local_cfg_write(struct rk_pcie_softc *sc, bool priv, u_int reg, uint32_t val, int bytes) { uint32_t val2; bus_addr_t base; if (priv) base = PCIE_RC_CONFIG_PRIV_BASE; else base = PCIE_RC_CONFIG_STD_BASE; switch (bytes) { case 4: bus_write_4(sc->apb_mem_res, base + reg, val); break; case 2: val2 = bus_read_4(sc->apb_mem_res, base + (reg & ~3)); val2 &= ~(0xffff << ((reg & 3) << 3)); val2 |= ((val & 0xffff) << ((reg & 3) << 3)); bus_write_4(sc->apb_mem_res, base + (reg & ~3), val2); break; case 1: val2 = bus_read_4(sc->apb_mem_res, base + (reg & ~3)); val2 &= ~(0xff << ((reg & 3) << 3)); val2 |= ((val & 0xff) << ((reg & 3) << 3)); bus_write_4(sc->apb_mem_res, base + (reg & ~3), val2); break; } } static bool rk_pcie_check_dev(struct rk_pcie_softc *sc, u_int bus, u_int slot, u_int func, u_int reg) { uint32_t val; if (bus < sc->bus_start || bus > sc->bus_end || slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX) return (false); if (bus == sc->root_bus) { /* we have only 1 device with 1 function root port */ if (slot > 0 || func > 0) return (false); return (true); } /* link is needed for accessing non-root busses */ val = APB_RD4(sc, PCIE_CLIENT_BASIC_STATUS1); if (STATUS1_LINK_ST_GET(val) != STATUS1_LINK_ST_UP) return (false); /* only one device can be on first subordinate bus */ if (bus == sc->sub_bus && slot != 0 ) return (false); return (true); } static void rk_pcie_map_out_atu(struct rk_pcie_softc *sc, int idx, int type, int num_bits, uint64_t pa) { uint32_t addr0; uint64_t max_size __diagused; /* Check HW constrains */ max_size = idx == 0 ? ATU_OB_REGION_0_SIZE: ATU_OB_REGION_SIZE; KASSERT(idx < ATU_OB_REGIONS, ("Invalid region index: %d\n", idx)); KASSERT(num_bits >= 7 && num_bits <= 63, ("Bit width of region is invalid: %d\n", num_bits)); KASSERT(max_size <= (1ULL << (num_bits + 1)), ("Bit width is invalid for given region[%d]: %d\n", idx, num_bits)); addr0 = (uint32_t)pa & 0xFFFFFF00; addr0 |= num_bits; APB_WR4(sc, PCIE_CORE_OB_ADDR0(idx), addr0); APB_WR4(sc, PCIE_CORE_OB_ADDR1(idx), (uint32_t)(pa >> 32)); APB_WR4(sc, PCIE_CORE_OB_DESC0(idx), 1 << 23 | type); APB_WR4(sc, PCIE_CORE_OB_DESC1(idx), sc->root_bus); /* Readback for sync */ APB_RD4(sc, PCIE_CORE_OB_DESC1(idx)); } static void rk_pcie_map_cfg_atu(struct rk_pcie_softc *sc, int idx, int type) { /* Check HW constrains */ KASSERT(idx < ATU_OB_REGIONS, ("Invalid region index: %d\n", idx)); /* * Config window is only 25 bits width, so we cannot encode full bus * range into it. Remaining bits of bus number should be taken from * DESC1 field. */ APB_WR4(sc, PCIE_CORE_OB_ADDR0(idx), 25 - 1); APB_WR4(sc, PCIE_CORE_OB_ADDR1(idx), 0); APB_WR4(sc, PCIE_CORE_OB_DESC0(idx), 1 << 23 | type); APB_WR4(sc, PCIE_CORE_OB_DESC1(idx), sc->root_bus); /* Readback for sync */ APB_RD4(sc, PCIE_CORE_OB_DESC1(idx)); } static void rk_pcie_map_in_atu(struct rk_pcie_softc *sc, int idx, int num_bits, uint64_t pa) { uint32_t addr0; /* Check HW constrains */ KASSERT(idx < ATU_IB_REGIONS, ("Invalid region index: %d\n", idx)); KASSERT(num_bits >= 7 && num_bits <= 63, ("Bit width of region is invalid: %d\n", num_bits)); addr0 = (uint32_t)pa & 0xFFFFFF00; addr0 |= num_bits; APB_WR4(sc, PCIE_CORE_IB_ADDR0(idx), addr0); APB_WR4(sc, PCIE_CORE_IB_ADDR1(idx), (uint32_t)(pa >> 32)); /* Readback for sync */ APB_RD4(sc, PCIE_CORE_IB_ADDR1(idx)); } static int rk_pcie_decode_ranges(struct rk_pcie_softc *sc, struct ofw_pci_range *ranges, int nranges) { int i; for (i = 0; i < nranges; i++) { switch(ranges[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) { case OFW_PCI_PHYS_HI_SPACE_IO: if (sc->io_range.size != 0) { device_printf(sc->dev, "Duplicated IO range found in DT\n"); return (ENXIO); } sc->io_range = ranges[i]; break; case OFW_PCI_PHYS_HI_SPACE_MEM32: case OFW_PCI_PHYS_HI_SPACE_MEM64: if (ranges[i].pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) { if (sc->pref_mem_range.size != 0) { device_printf(sc->dev, "Duplicated memory range found " "in DT\n"); return (ENXIO); } sc->pref_mem_range = ranges[i]; } else { if (sc->mem_range.size != 0) { device_printf(sc->dev, "Duplicated memory range found " "in DT\n"); return (ENXIO); } sc->mem_range = ranges[i]; } } } if (sc->mem_range.size == 0) { device_printf(sc->dev, " At least memory range should be defined in DT.\n"); return (ENXIO); } return (0); } /*----------------------------------------------------------------------------- * * P C I B I N T E R F A C E */ static uint32_t rk_pcie_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { struct rk_pcie_softc *sc; uint32_t d32, data; uint16_t d16; uint8_t d8; uint64_t addr; int type, ret; sc = device_get_softc(dev); if (!rk_pcie_check_dev(sc, bus, slot, func, reg)) return (0xFFFFFFFFU); if (bus == sc->root_bus) return (rk_pcie_local_cfg_read(sc, false, reg, bytes)); addr = ATU_CFG_BUS(bus) | ATU_CFG_SLOT(slot) | ATU_CFG_FUNC(func) | ATU_CFG_REG(reg); type = bus == sc->sub_bus ? ATU_TYPE_CFG0: ATU_TYPE_CFG1; rk_pcie_map_cfg_atu(sc, 0, type); ret = -1; switch (bytes) { case 1: ret = bus_peek_1(sc->axi_mem_res, addr, &d8); data = d8; break; case 2: ret = bus_peek_2(sc->axi_mem_res, addr, &d16); data = d16; break; case 4: ret = bus_peek_4(sc->axi_mem_res, addr, &d32); data = d32; break; } if (ret != 0) data = 0xFFFFFFFF; return (data); } static void rk_pcie_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int bytes) { struct rk_pcie_softc *sc; uint64_t addr; int type; sc = device_get_softc(dev); if (!rk_pcie_check_dev(sc, bus, slot, func, reg)) return; if (bus == sc->root_bus) return (rk_pcie_local_cfg_write(sc, false, reg, val, bytes)); addr = ATU_CFG_BUS(bus) | ATU_CFG_SLOT(slot) | ATU_CFG_FUNC(func) | ATU_CFG_REG(reg); type = bus == sc->sub_bus ? ATU_TYPE_CFG0: ATU_TYPE_CFG1; rk_pcie_map_cfg_atu(sc, 0, type); switch (bytes) { case 1: bus_poke_1(sc->axi_mem_res, addr, (uint8_t)val); break; case 2: bus_poke_2(sc->axi_mem_res, addr, (uint16_t)val); break; case 4: bus_poke_4(sc->axi_mem_res, addr, val); break; default: break; } } #ifdef RK_PCIE_ENABLE_MSI static int rk_pcie_alloc_msi(device_t pci, device_t child, int count, int maxcount, int *irqs) { phandle_t msi_parent; int rv; rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, NULL); if (rv != 0) return (rv); rv = intr_alloc_msi(pci, child, msi_parent, count, maxcount,irqs); return (rv); } static int rk_pcie_release_msi(device_t pci, device_t child, int count, int *irqs) { phandle_t msi_parent; int rv; rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, NULL); if (rv != 0) return (rv); rv = intr_release_msi(pci, child, msi_parent, count, irqs); return (rv); } #endif static int rk_pcie_map_msi(device_t pci, device_t child, int irq, uint64_t *addr, uint32_t *data) { phandle_t msi_parent; int rv; rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, NULL); if (rv != 0) return (rv); rv = intr_map_msi(pci, child, msi_parent, irq, addr, data); return (rv); } #ifdef RK_PCIE_ENABLE_MSIX static int rk_pcie_alloc_msix(device_t pci, device_t child, int *irq) { phandle_t msi_parent; int rv; rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, NULL); if (rv != 0) return (rv); rv = intr_alloc_msix(pci, child, msi_parent, irq); return (rv); } static int rk_pcie_release_msix(device_t pci, device_t child, int irq) { phandle_t msi_parent; int rv; rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, NULL); if (rv != 0) return (rv); rv = intr_release_msix(pci, child, msi_parent, irq); return (rv); } #endif static int rk_pcie_get_id(device_t pci, device_t child, enum pci_id_type type, uintptr_t *id) { phandle_t node; int rv; uint32_t rid; uint16_t pci_rid; if (type != PCI_ID_MSI) return (pcib_get_id(pci, child, type, id)); node = ofw_bus_get_node(pci); pci_rid = pci_get_rid(child); rv = ofw_bus_msimap(node, pci_rid, NULL, &rid); if (rv != 0) return (rv); *id = rid; return (0); } static int rk_pcie_route_interrupt(device_t bus, device_t dev, int pin) { struct rk_pcie_softc *sc; u_int irq; sc = device_get_softc(bus); irq = intr_map_clone_irq(rman_get_start(sc->legacy_irq_res)); device_printf(bus, "route pin %d for device %d.%d to %u\n", pin, pci_get_slot(dev), pci_get_function(dev), irq); return (irq); } /*----------------------------------------------------------------------------- * * B U S / D E V I C E I N T E R F A C E */ static int rk_pcie_parse_fdt_resources(struct rk_pcie_softc *sc) { int i, rv; char buf[16]; /* Regulators. All are optional. */ rv = regulator_get_by_ofw_property(sc->dev, 0, "vpcie12v-supply", &sc->supply_12v); if (rv != 0 && rv != ENOENT) { device_printf(sc->dev,"Cannot get 'vpcie12' regulator\n"); return (ENXIO); } rv = regulator_get_by_ofw_property(sc->dev, 0, "vpcie3v3-supply", &sc->supply_3v3); if (rv != 0 && rv != ENOENT) { device_printf(sc->dev,"Cannot get 'vpcie3v3' regulator\n"); return (ENXIO); } rv = regulator_get_by_ofw_property(sc->dev, 0, "vpcie1v8-supply", &sc->supply_1v8); if (rv != 0 && rv != ENOENT) { device_printf(sc->dev,"Cannot get 'vpcie1v8' regulator\n"); return (ENXIO); } rv = regulator_get_by_ofw_property(sc->dev, 0, "vpcie0v9-supply", &sc->supply_0v9); if (rv != 0 && rv != ENOENT) { device_printf(sc->dev,"Cannot get 'vpcie0v9' regulator\n"); return (ENXIO); } /* Resets. */ rv = hwreset_get_by_ofw_name(sc->dev, 0, "core", &sc->hwreset_core); if (rv != 0) { device_printf(sc->dev, "Cannot get 'core' reset\n"); return (ENXIO); } rv = hwreset_get_by_ofw_name(sc->dev, 0, "mgmt", &sc->hwreset_mgmt); if (rv != 0) { device_printf(sc->dev, "Cannot get 'mgmt' reset\n"); return (ENXIO); } rv = hwreset_get_by_ofw_name(sc->dev, 0, "mgmt-sticky", &sc->hwreset_mgmt_sticky); if (rv != 0) { device_printf(sc->dev, "Cannot get 'mgmt-sticky' reset\n"); return (ENXIO); } rv = hwreset_get_by_ofw_name(sc->dev, 0, "pipe", &sc->hwreset_pipe); if (rv != 0) { device_printf(sc->dev, "Cannot get 'pipe' reset\n"); return (ENXIO); } rv = hwreset_get_by_ofw_name(sc->dev, 0, "pm", &sc->hwreset_pm); if (rv != 0) { device_printf(sc->dev, "Cannot get 'pm' reset\n"); return (ENXIO); } rv = hwreset_get_by_ofw_name(sc->dev, 0, "aclk", &sc->hwreset_aclk); if (rv != 0) { device_printf(sc->dev, "Cannot get 'aclk' reset\n"); return (ENXIO); } rv = hwreset_get_by_ofw_name(sc->dev, 0, "pclk", &sc->hwreset_pclk); if (rv != 0) { device_printf(sc->dev, "Cannot get 'pclk' reset\n"); return (ENXIO); } /* Clocks. */ rv = clk_get_by_ofw_name(sc->dev, 0, "aclk", &sc->clk_aclk); if (rv != 0) { device_printf(sc->dev, "Cannot get 'aclk' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, 0, "aclk-perf", &sc->clk_aclk_perf); if (rv != 0) { device_printf(sc->dev, "Cannot get 'aclk-perf' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, 0, "hclk", &sc->clk_hclk); if (rv != 0) { device_printf(sc->dev, "Cannot get 'hclk' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, 0, "pm", &sc->clk_pm); if (rv != 0) { device_printf(sc->dev, "Cannot get 'pm' clock\n"); return (ENXIO); } /* Phys. */ for (i = 0; i < MAX_LANES; i++ ) { sprintf (buf, "pcie-phy-%d", i); rv = phy_get_by_ofw_name(sc->dev, 0, buf, sc->phys + i); if (rv != 0) { device_printf(sc->dev, "Cannot get '%s' phy\n", buf); return (ENXIO); } } /* GPIO for PERST#. Optional */ rv = gpio_pin_get_by_ofw_property(sc->dev, sc->node, "ep-gpios", &sc->gpio_ep); if (rv != 0 && rv != ENOENT) { device_printf(sc->dev, "Cannot get 'ep-gpios' gpio\n"); return (ENXIO); } return (0); } static int rk_pcie_enable_resources(struct rk_pcie_softc *sc) { int i, rv; uint32_t val; /* Assert all resets */ rv = hwreset_assert(sc->hwreset_pclk); if (rv != 0) { device_printf(sc->dev, "Cannot assert 'pclk' reset\n"); return (rv); } rv = hwreset_assert(sc->hwreset_aclk); if (rv != 0) { device_printf(sc->dev, "Cannot assert 'aclk' reset\n"); return (rv); } rv = hwreset_assert(sc->hwreset_pm); if (rv != 0) { device_printf(sc->dev, "Cannot assert 'pm' reset\n"); return (rv); } rv = hwreset_assert(sc->hwreset_pipe); if (rv != 0) { device_printf(sc->dev, "Cannot assert 'pipe' reset\n"); return (rv); } rv = hwreset_assert(sc->hwreset_mgmt_sticky); if (rv != 0) { device_printf(sc->dev, "Cannot assert 'mgmt_sticky' reset\n"); return (rv); } rv = hwreset_assert(sc->hwreset_mgmt); if (rv != 0) { device_printf(sc->dev, "Cannot assert 'hmgmt' reset\n"); return (rv); } rv = hwreset_assert(sc->hwreset_core); if (rv != 0) { device_printf(sc->dev, "Cannot assert 'hcore' reset\n"); return (rv); } DELAY(10000); /* Enable clockls */ rv = clk_enable(sc->clk_aclk); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'aclk' clock\n"); return (rv); } rv = clk_enable(sc->clk_aclk_perf); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'aclk_perf' clock\n"); return (rv); } rv = clk_enable(sc->clk_hclk); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'hclk' clock\n"); return (rv); } rv = clk_enable(sc->clk_pm); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'pm' clock\n"); return (rv); } /* Power up regulators */ if (sc->supply_12v != NULL) { rv = regulator_enable(sc->supply_12v); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'vpcie12' regulator\n"); return (rv); } } if (sc->supply_3v3 != NULL) { rv = regulator_enable(sc->supply_3v3); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'vpcie3v3' regulator\n"); return (rv); } } if (sc->supply_1v8 != NULL) { rv = regulator_enable(sc->supply_1v8); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'vpcie1v8' regulator\n"); return (rv); } } if (sc->supply_0v9 != NULL) { rv = regulator_enable(sc->supply_0v9); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'vpcie1v8' regulator\n"); return (rv); } } DELAY(1000); /* Deassert basic resets*/ rv = hwreset_deassert(sc->hwreset_pm); if (rv != 0) { device_printf(sc->dev, "Cannot deassert 'pm' reset\n"); return (rv); } rv = hwreset_deassert(sc->hwreset_aclk); if (rv != 0) { device_printf(sc->dev, "Cannot deassert 'aclk' reset\n"); return (rv); } rv = hwreset_deassert(sc->hwreset_pclk); if (rv != 0) { device_printf(sc->dev, "Cannot deassert 'pclk' reset\n"); return (rv); } /* Set basic PCIe core mode (RC, lanes, gen1 or 2) */ val = STRAP_CONF_GEN_2 << 16 | (sc->link_is_gen2 ? STRAP_CONF_GEN_2: 0); val |= STRAP_CONF_MODE_RC << 16 | STRAP_CONF_MODE_RC; val |= STRAP_CONF_LANES(~0) << 16 | STRAP_CONF_LANES(sc->num_lanes); val |= STRAP_CONF_ARI_EN << 16 | STRAP_CONF_ARI_EN; val |= STRAP_CONF_CONF_EN << 16 | STRAP_CONF_CONF_EN; APB_WR4(sc, PCIE_CLIENT_BASIC_STRAP_CONF, val); for (i = 0; i < MAX_LANES; i++) { rv = phy_enable(sc->phys[i]); if (rv != 0) { device_printf(sc->dev, "Cannot enable phy %d\n", i); return (rv); } } /* Deassert rest of resets - order is important ! */ rv = hwreset_deassert(sc->hwreset_mgmt_sticky); if (rv != 0) { device_printf(sc->dev, "Cannot deassert 'mgmt_sticky' reset\n"); return (rv); } rv = hwreset_deassert(sc->hwreset_core); if (rv != 0) { device_printf(sc->dev, "Cannot deassert 'core' reset\n"); return (rv); } rv = hwreset_deassert(sc->hwreset_mgmt); if (rv != 0) { device_printf(sc->dev, "Cannot deassert 'mgmt' reset\n"); return (rv); } rv = hwreset_deassert(sc->hwreset_pipe); if (rv != 0) { device_printf(sc->dev, "Cannot deassert 'pipe' reset\n"); return (rv); } return (0); } static int rk_pcie_setup_hw(struct rk_pcie_softc *sc) { uint32_t val; int i, rv; /* Assert PERST# if defined */ if (sc->gpio_ep != NULL) { rv = gpio_pin_set_active(sc->gpio_ep, 0); if (rv != 0) { device_printf(sc->dev, "Cannot clear 'gpio-ep' gpio\n"); return (rv); } } rv = rk_pcie_enable_resources(sc); if (rv != 0) return(rv); /* Fix wrong default value for transmited FTS for L0s exit */ val = APB_RD4(sc, PCIE_CORE_CTRL1); val |= 0xFFFF << 8; APB_WR4(sc, PCIE_CORE_CTRL1, val); /* Setup PCIE Link Status & Control register */ val = APB_RD4(sc, PCIE_RC_CONFIG_LCS); val |= PCIEM_LINK_CTL_COMMON_CLOCK; APB_WR4(sc, PCIE_RC_CONFIG_LCS, val); val = APB_RD4(sc, PCIE_RC_CONFIG_LCS); val |= PCIEM_LINK_CTL_RCB; APB_WR4(sc, PCIE_RC_CONFIG_LCS, val); /* Enable training for GEN1 */ APB_WR4(sc, PCIE_CLIENT_BASIC_STRAP_CONF, STRAP_CONF_LINK_TRAIN_EN << 16 | STRAP_CONF_LINK_TRAIN_EN); /* Deassert PERST# if defined */ if (sc->gpio_ep != NULL) { rv = gpio_pin_set_active(sc->gpio_ep, 1); if (rv != 0) { device_printf(sc->dev, "Cannot set 'gpio-ep' gpio\n"); return (rv); } } /* Wait for link */ for (i = 500; i > 0; i--) { val = APB_RD4(sc, PCIE_CLIENT_BASIC_STATUS1); if (STATUS1_LINK_ST_GET(val) == STATUS1_LINK_ST_UP) break; DELAY(1000); } if (i <= 0) { device_printf(sc->dev, "Gen1 link training timeouted: 0x%08X.\n", val); return (0); } if (sc->link_is_gen2) { val = APB_RD4(sc, PCIE_RC_CONFIG_LCS); val |= PCIEM_LINK_CTL_RETRAIN_LINK; APB_WR4(sc, PCIE_RC_CONFIG_LCS, val); /* Wait for link */ for (i = 500; i > 0; i--) { val = APB_RD4(sc, PCIE_CLIENT_BASIC_STATUS1); if (STATUS1_LINK_ST_GET(val) == STATUS1_LINK_ST_UP) break; DELAY(1000); } if (i <= 0) device_printf(sc->dev, "Gen2 link training " "timeouted: 0x%08X.\n", val); } val = APB_RD4(sc, PCIE_CORE_CTRL0); val = CORE_CTRL_LANES_GET(val); if (bootverbose) device_printf(sc->dev, "Link width: %d\n", 1 << val); return (0); } static int rk_pcie_setup_sw(struct rk_pcie_softc *sc) { uint32_t val; int i, region; pcib_bridge_init(sc->dev); /* Setup config registers */ APB_WR4(sc, PCIE_CORE_CONFIG_VENDOR, 0x1D87); /* Rockchip vendor ID*/ PRIV_CFG_WR1(sc, PCIR_CLASS, PCIC_BRIDGE); PRIV_CFG_WR1(sc, PCIR_SUBCLASS, PCIS_BRIDGE_PCI); PRIV_CFG_WR1(sc, PCIR_PRIBUS_1, sc->root_bus); PRIV_CFG_WR1(sc, PCIR_SECBUS_1, sc->sub_bus); PRIV_CFG_WR1(sc, PCIR_SUBBUS_1, sc->bus_end); PRIV_CFG_WR2(sc, PCIR_COMMAND, PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_SERRESPEN); /* Don't advertise L1 power substate */ val = APB_RD4(sc, PCIE_RC_CONFIG_THP_CAP); val &= ~PCIE_RC_CONFIG_THP_CAP_NEXT_MASK; APB_WR4(sc, PCIE_RC_CONFIG_THP_CAP, val); /* Don't advertise L0s */ if (sc->no_l0s) { val = APB_RD4(sc, PCIE_RC_CONFIG_LINK_CAP); val &= ~PCIE_RC_CONFIG_THP_CAP_NEXT_MASK; APB_WR4(sc, PCIE_RC_CONFIG_LINK_CAP_L0S, val); } /*Adjust maximum payload size*/ val = APB_RD4(sc, PCIE_RC_CONFIG_DCSR); val &= ~PCIE_RC_CONFIG_DCSR_MPS_MASK; val |= PCIE_RC_CONFIG_DCSR_MPS_128; APB_WR4(sc, PCIE_RC_CONFIG_DCSR, val); /* * Prepare IB ATU * map whole address range in 1:1 mappings */ rk_pcie_map_in_atu(sc, 2, 64 - 1, 0); /* Prepare OB ATU */ /* - region 0 (32 MB) is used for config access */ region = 0; rk_pcie_map_out_atu(sc, region++, ATU_TYPE_CFG0, 25 - 1, 0); /* - then map memory (by using 1MB regions */ for (i = 0; i < sc->mem_range.size / ATU_OB_REGION_SIZE; i++) { rk_pcie_map_out_atu(sc, region++, ATU_TYPE_MEM, ATU_OB_REGION_SHIFT - 1, sc->mem_range.pci + ATU_OB_REGION_SIZE * i); } /* - IO space is next, one region typically*/ for (i = 0; i < sc->io_range.size / ATU_OB_REGION_SIZE; i++) { rk_pcie_map_out_atu(sc, region++, ATU_TYPE_IO, ATU_OB_REGION_SHIFT - 1, sc->io_range.pci + ATU_OB_REGION_SIZE * i); } APB_WR4(sc, PCIE_CORE_RC_BAR_CONF, 0); return (0); } static int rk_pcie_sys_irq(void *arg) { struct rk_pcie_softc *sc; uint32_t irq; sc = (struct rk_pcie_softc *)arg; irq = APB_RD4(sc, PCIE_CLIENT_INT_STATUS); if (irq & PCIE_CLIENT_INT_LOCAL) { irq = APB_RD4(sc, PCIE_CORE_INT_STATUS); APB_WR4(sc, PCIE_CORE_INT_STATUS, irq); APB_WR4(sc, PCIE_CLIENT_INT_STATUS, PCIE_CLIENT_INT_LOCAL); device_printf(sc->dev, "'sys' interrupt received: 0x%04X\n", irq); } return (FILTER_HANDLED); } static int rk_pcie_client_irq(void *arg) { struct rk_pcie_softc *sc; uint32_t irq; sc = (struct rk_pcie_softc *)arg; irq = APB_RD4(sc, PCIE_CLIENT_INT_STATUS); /* Clear causes handled by other interrups */ irq &= ~PCIE_CLIENT_INT_LOCAL; irq &= ~PCIE_CLIENT_INT_LEGACY; APB_WR4(sc, PCIE_CLIENT_INT_STATUS, irq); device_printf(sc->dev, "'client' interrupt received: 0x%04X\n", irq); return (FILTER_HANDLED); } static int rk_pcie_legacy_irq(void *arg) { struct rk_pcie_softc *sc; uint32_t irq; sc = (struct rk_pcie_softc *)arg; irq = APB_RD4(sc, PCIE_CLIENT_INT_STATUS); irq &= PCIE_CLIENT_INT_LEGACY; APB_WR4(sc, PCIE_CLIENT_INT_STATUS, irq); /* all legacy interrupt are shared, do nothing */ return (FILTER_STRAY); } static bus_dma_tag_t rk_pcie_get_dma_tag(device_t dev, device_t child) { struct rk_pcie_softc *sc; sc = device_get_softc(dev); return (sc->dmat); } static int rk_pcie_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Rockchip PCIe controller"); return (BUS_PROBE_DEFAULT); } static int rk_pcie_attach(device_t dev) { struct resource_map_request req; struct resource_map map; struct rk_pcie_softc *sc; uint32_t val; int rv, rid, max_speed; sc = device_get_softc(dev); sc->dev = dev; sc->node = ofw_bus_get_node(dev); mtx_init(&sc->mtx, "rk_pcie_mtx", NULL, MTX_DEF); /* XXX Should not be this configurable ? */ sc->bus_start = 0; sc->bus_end = 0x1F; sc->root_bus = sc->bus_start; sc->sub_bus = 1; /* Read FDT properties */ rv = rk_pcie_parse_fdt_resources(sc); if (rv != 0) goto out; sc->coherent = OF_hasprop(sc->node, "dma-coherent"); sc->no_l0s = OF_hasprop(sc->node, "aspm-no-l0s"); rv = OF_getencprop(sc->node, "num-lanes", &sc->num_lanes, sizeof(sc->num_lanes)); if (rv != sizeof(sc->num_lanes)) sc->num_lanes = 1; if (sc->num_lanes != 1 && sc->num_lanes != 2 && sc->num_lanes != 4) { device_printf(dev, "invalid number of lanes: %d\n",sc->num_lanes); sc->num_lanes = 0; rv = ENXIO; goto out; } rv = OF_getencprop(sc->node, "max-link-speed", &max_speed, sizeof(max_speed)); if (rv != sizeof(max_speed) || max_speed != 1) sc->link_is_gen2 = true; else sc->link_is_gen2 = false; rv = ofw_bus_find_string_index(sc->node, "reg-names", "axi-base", &rid); if (rv != 0) { device_printf(dev, "Cannot get 'axi-base' memory\n"); rv = ENXIO; goto out; } sc->axi_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE | RF_UNMAPPED); if (sc->axi_mem_res == NULL) { device_printf(dev, "Cannot allocate 'axi-base' (rid: %d)\n", rid); rv = ENXIO; goto out; } resource_init_map_request(&req); req.memattr = VM_MEMATTR_DEVICE_NP; rv = bus_map_resource(dev, SYS_RES_MEMORY, sc->axi_mem_res, &req, &map); if (rv != 0) { device_printf(dev, "Cannot map 'axi-base' (rid: %d)\n", rid); goto out; } rman_set_mapping(sc->axi_mem_res, &map); rv = ofw_bus_find_string_index(sc->node, "reg-names", "apb-base", &rid); if (rv != 0) { device_printf(dev, "Cannot get 'apb-base' memory\n"); rv = ENXIO; goto out; } sc->apb_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->apb_mem_res == NULL) { device_printf(dev, "Cannot allocate 'apb-base' (rid: %d)\n", rid); rv = ENXIO; goto out; } rv = ofw_bus_find_string_index(sc->node, "interrupt-names", "client", &rid); if (rv != 0) { device_printf(dev, "Cannot get 'client' IRQ\n"); rv = ENXIO; goto out; } sc->client_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | RF_SHAREABLE); if (sc->client_irq_res == NULL) { device_printf(dev, "Cannot allocate 'client' IRQ resource\n"); rv = ENXIO; goto out; } rv = ofw_bus_find_string_index(sc->node, "interrupt-names", "legacy", &rid); if (rv != 0) { device_printf(dev, "Cannot get 'legacy' IRQ\n"); rv = ENXIO; goto out; } sc->legacy_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | RF_SHAREABLE); if (sc->legacy_irq_res == NULL) { device_printf(dev, "Cannot allocate 'legacy' IRQ resource\n"); rv = ENXIO; goto out; } rv = ofw_bus_find_string_index(sc->node, "interrupt-names", "sys", &rid); if (rv != 0) { device_printf(dev, "Cannot get 'sys' IRQ\n"); rv = ENXIO; goto out; } sc->sys_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | RF_SHAREABLE); if (sc->sys_irq_res == NULL) { device_printf(dev, "Cannot allocate 'sys' IRQ resource\n"); rv = ENXIO; goto out; } if (bootverbose) device_printf(dev, "Bus is%s cache-coherent\n", sc->coherent ? "" : " not"); rv = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 1, 0, /* alignment, bounds */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ BUS_SPACE_MAXSIZE, /* maxsize */ BUS_SPACE_UNRESTRICTED, /* nsegments */ BUS_SPACE_MAXSIZE, /* maxsegsize */ sc->coherent ? BUS_DMA_COHERENT : 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->dmat); if (rv != 0) goto out; rv = ofw_pcib_init(dev); if (rv != 0) goto out; rv = rk_pcie_decode_ranges(sc, sc->ofw_pci.sc_range, sc->ofw_pci.sc_nrange); if (rv != 0) goto out_full; rv = rk_pcie_setup_hw(sc); if (rv != 0) goto out_full; rv = rk_pcie_setup_sw(sc); if (rv != 0) goto out_full; rv = bus_setup_intr(dev, sc->client_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, rk_pcie_client_irq, NULL, sc, &sc->client_irq_cookie); if (rv != 0) { device_printf(dev, "cannot setup client interrupt handler\n"); rv = ENXIO; goto out_full; } rv = bus_setup_intr(dev, sc->legacy_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, rk_pcie_legacy_irq, NULL, sc, &sc->legacy_irq_cookie); if (rv != 0) { device_printf(dev, "cannot setup client interrupt handler\n"); rv = ENXIO; goto out_full; } rv = bus_setup_intr(dev, sc->sys_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, rk_pcie_sys_irq, NULL, sc, &sc->sys_irq_cookie); if (rv != 0) { device_printf(dev, "cannot setup client interrupt handler\n"); rv = ENXIO; goto out_full; } /* Enable interrupts */ val = PCIE_CLIENT_INT_CORR_ERR | PCIE_CLIENT_INT_NFATAL_ERR | PCIE_CLIENT_INT_FATAL_ERR | PCIE_CLIENT_INT_DPA | PCIE_CLIENT_INT_HOT_RST | PCIE_CLIENT_INT_MSG | PCIE_CLIENT_INT_LEGACY_DONE | PCIE_CLIENT_INT_INTA | PCIE_CLIENT_INT_INTB | PCIE_CLIENT_INT_INTC | PCIE_CLIENT_INT_INTD | PCIE_CLIENT_INT_PHY; APB_WR4(sc, PCIE_CLIENT_INT_MASK, (val << 16) & ~val); val = PCIE_CORE_INT_PRFPE | PCIE_CORE_INT_CRFPE | PCIE_CORE_INT_RRPE | PCIE_CORE_INT_CRFO | PCIE_CORE_INT_RT | PCIE_CORE_INT_RTR | PCIE_CORE_INT_PE | PCIE_CORE_INT_MTR | PCIE_CORE_INT_UCR | PCIE_CORE_INT_FCE | PCIE_CORE_INT_CT | PCIE_CORE_INT_UTC | PCIE_CORE_INT_MMVC; APB_WR4(sc, PCIE_CORE_INT_MASK, ~(val)); val = APB_RD4(sc, PCIE_RC_CONFIG_LCS); val |= PCIEM_LINK_CTL_LBMIE | PCIEM_LINK_CTL_LABIE; APB_WR4(sc, PCIE_RC_CONFIG_LCS, val); DELAY(250000); device_add_child(dev, "pci", -1); return (bus_generic_attach(dev)); out_full: bus_teardown_intr(dev, sc->sys_irq_res, sc->sys_irq_cookie); bus_teardown_intr(dev, sc->legacy_irq_res, sc->legacy_irq_cookie); bus_teardown_intr(dev, sc->client_irq_res, sc->client_irq_cookie); ofw_pcib_fini(dev); out: bus_dma_tag_destroy(sc->dmat); bus_free_resource(dev, SYS_RES_IRQ, sc->sys_irq_res); bus_free_resource(dev, SYS_RES_IRQ, sc->legacy_irq_res); bus_free_resource(dev, SYS_RES_IRQ, sc->client_irq_res); bus_free_resource(dev, SYS_RES_MEMORY, sc->apb_mem_res); bus_free_resource(dev, SYS_RES_MEMORY, sc->axi_mem_res); /* GPIO */ gpio_pin_release(sc->gpio_ep); /* Phys */ for (int i = 0; i < MAX_LANES; i++) { phy_release(sc->phys[i]); } /* Clocks */ clk_release(sc->clk_aclk); clk_release(sc->clk_aclk_perf); clk_release(sc->clk_hclk); clk_release(sc->clk_pm); /* Resets */ hwreset_release(sc->hwreset_core); hwreset_release(sc->hwreset_mgmt); hwreset_release(sc->hwreset_pipe); hwreset_release(sc->hwreset_pm); hwreset_release(sc->hwreset_aclk); hwreset_release(sc->hwreset_pclk); /* Regulators */ regulator_release(sc->supply_12v); regulator_release(sc->supply_3v3); regulator_release(sc->supply_1v8); regulator_release(sc->supply_0v9); return (rv); } static device_method_t rk_pcie_methods[] = { /* Device interface */ DEVMETHOD(device_probe, rk_pcie_probe), DEVMETHOD(device_attach, rk_pcie_attach), /* Bus interface */ DEVMETHOD(bus_get_dma_tag, rk_pcie_get_dma_tag), /* pcib interface */ DEVMETHOD(pcib_read_config, rk_pcie_read_config), DEVMETHOD(pcib_write_config, rk_pcie_write_config), DEVMETHOD(pcib_route_interrupt, rk_pcie_route_interrupt), #ifdef RK_PCIE_ENABLE_MSI DEVMETHOD(pcib_alloc_msi, rk_pcie_alloc_msi), DEVMETHOD(pcib_release_msi, rk_pcie_release_msi), #endif #ifdef RK_PCIE_ENABLE_MSIX DEVMETHOD(pcib_alloc_msix, rk_pcie_alloc_msix), DEVMETHOD(pcib_release_msix, rk_pcie_release_msix), #endif DEVMETHOD(pcib_map_msi, rk_pcie_map_msi), DEVMETHOD(pcib_get_id, rk_pcie_get_id), /* OFW bus interface */ DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), DEVMETHOD_END }; DEFINE_CLASS_1(pcib, rk_pcie_driver, rk_pcie_methods, sizeof(struct rk_pcie_softc), ofw_pcib_driver); DRIVER_MODULE( rk_pcie, simplebus, rk_pcie_driver, NULL, NULL); diff --git a/sys/arm64/rockchip/rk_usb2phy.c b/sys/arm64/rockchip/rk_usb2phy.c index 367d4fef61cc..d06dce90c27b 100644 --- a/sys/arm64/rockchip/rk_usb2phy.c +++ b/sys/arm64/rockchip/rk_usb2phy.c @@ -1,430 +1,430 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2019 Emmanuel Vadot * * 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 AND CONTRIBUTORS ``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 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 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. */ /* * Rockchip USB2PHY */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include "clkdev_if.h" #include "syscon_if.h" struct rk_usb2phy_reg { uint32_t offset; uint32_t enable_mask; uint32_t disable_mask; }; struct rk_usb2phy_regs { struct rk_usb2phy_reg clk_ctl; }; struct rk_usb2phy_regs rk3399_regs = { .clk_ctl = { .offset = 0x0000, /* bit 4 put pll in suspend */ .enable_mask = 0x100000, .disable_mask = 0x100010, } }; struct rk_usb2phy_regs rk3568_regs = { .clk_ctl = { .offset = 0x0008, .enable_mask = 0x100000, /* bit 4 put pll in suspend */ .disable_mask = 0x100010, } }; static struct ofw_compat_data compat_data[] = { { "rockchip,rk3399-usb2phy", (uintptr_t)&rk3399_regs }, { "rockchip,rk3568-usb2phy", (uintptr_t)&rk3568_regs }, { NULL, 0 } }; struct rk_usb2phy_softc { device_t dev; struct syscon *grf; regulator_t phy_supply; clk_t clk; int mode; }; /* Phy class and methods. */ static int rk_usb2phy_enable(struct phynode *phynode, bool enable); static int rk_usb2phy_get_mode(struct phynode *phy, int *mode); static int rk_usb2phy_set_mode(struct phynode *phy, int mode); static phynode_method_t rk_usb2phy_phynode_methods[] = { PHYNODEMETHOD(phynode_enable, rk_usb2phy_enable), PHYNODEMETHOD(phynode_usb_get_mode, rk_usb2phy_get_mode), PHYNODEMETHOD(phynode_usb_set_mode, rk_usb2phy_set_mode), PHYNODEMETHOD_END }; DEFINE_CLASS_1(rk_usb2phy_phynode, rk_usb2phy_phynode_class, rk_usb2phy_phynode_methods, sizeof(struct phynode_usb_sc), phynode_usb_class); enum RK_USBPHY { RK_USBPHY_HOST = 0, RK_USBPHY_OTG, }; static int rk_usb2phy_enable(struct phynode *phynode, bool enable) { struct rk_usb2phy_softc *sc; device_t dev; intptr_t phy; int error; dev = phynode_get_device(phynode); phy = phynode_get_id(phynode); sc = device_get_softc(dev); if (phy != RK_USBPHY_HOST) return (ERANGE); if (sc->phy_supply) { if (enable) error = regulator_enable(sc->phy_supply); else error = regulator_disable(sc->phy_supply); if (error != 0) { device_printf(dev, "Cannot %sable the regulator\n", enable ? "En" : "Dis"); goto fail; } } return (0); fail: return (ENXIO); } static int rk_usb2phy_get_mode(struct phynode *phynode, int *mode) { struct rk_usb2phy_softc *sc; intptr_t phy; device_t dev; dev = phynode_get_device(phynode); phy = phynode_get_id(phynode); sc = device_get_softc(dev); if (phy != RK_USBPHY_HOST) return (ERANGE); *mode = sc->mode; return (0); } static int rk_usb2phy_set_mode(struct phynode *phynode, int mode) { struct rk_usb2phy_softc *sc; intptr_t phy; device_t dev; dev = phynode_get_device(phynode); phy = phynode_get_id(phynode); sc = device_get_softc(dev); if (phy != RK_USBPHY_HOST) return (ERANGE); sc->mode = mode; return (0); } /* Clock class and method */ struct rk_usb2phy_clk_sc { device_t clkdev; struct syscon *grf; struct rk_usb2phy_regs *regs; }; static int rk_usb2phy_clk_init(struct clknode *clk, device_t dev) { clknode_init_parent_idx(clk, 0); return (0); } static int rk_usb2phy_clk_set_gate(struct clknode *clk, bool enable) { struct rk_usb2phy_clk_sc *sc; sc = clknode_get_softc(clk); if (enable) SYSCON_WRITE_4(sc->grf, sc->regs->clk_ctl.offset, sc->regs->clk_ctl.enable_mask); else SYSCON_WRITE_4(sc->grf, sc->regs->clk_ctl.offset, sc->regs->clk_ctl.disable_mask); return (0); } static int rk_usb2phy_clk_recalc(struct clknode *clk, uint64_t *freq) { *freq = 480000000; return (0); } static clknode_method_t rk_usb2phy_clk_clknode_methods[] = { /* Device interface */ CLKNODEMETHOD(clknode_init, rk_usb2phy_clk_init), CLKNODEMETHOD(clknode_set_gate, rk_usb2phy_clk_set_gate), CLKNODEMETHOD(clknode_recalc_freq, rk_usb2phy_clk_recalc), CLKNODEMETHOD_END }; DEFINE_CLASS_1(rk_usb2phy_clk_clknode, rk_usb2phy_clk_clknode_class, rk_usb2phy_clk_clknode_methods, sizeof(struct rk_usb2phy_clk_sc), clknode_class); static int rk_usb2phy_clk_ofw_map(struct clkdom *clkdom, uint32_t ncells, phandle_t *cells, struct clknode **clk) { if (ncells != 0) return (ERANGE); *clk = clknode_find_by_id(clkdom, 0); if (*clk == NULL) return (ENXIO); return (0); } static int rk_usb2phy_export_clock(struct rk_usb2phy_softc *devsc) { struct clknode_init_def def; struct rk_usb2phy_clk_sc *sc; const char **clknames; struct clkdom *clkdom; struct clknode *clk; clk_t clk_parent; phandle_t node; phandle_t regs[2]; int i, nclocks, ncells, error; node = ofw_bus_get_node(devsc->dev); error = ofw_bus_parse_xref_list_get_length(node, "clocks", "#clock-cells", &ncells); if (error != 0 || ncells != 1) { device_printf(devsc->dev, "couldn't find parent clock\n"); return (ENXIO); } nclocks = ofw_bus_string_list_to_array(node, "clock-output-names", &clknames); if (nclocks != 1) return (ENXIO); clkdom = clkdom_create(devsc->dev); clkdom_set_ofw_mapper(clkdom, rk_usb2phy_clk_ofw_map); memset(&def, 0, sizeof(def)); def.id = 0; def.name = clknames[0]; def.parent_names = malloc(sizeof(char *) * ncells, M_OFWPROP, M_WAITOK); for (i = 0; i < ncells; i++) { error = clk_get_by_ofw_index(devsc->dev, 0, i, &clk_parent); if (error != 0) { device_printf(devsc->dev, "cannot get clock %d\n", error); return (ENXIO); } def.parent_names[i] = clk_get_name(clk_parent); clk_release(clk_parent); } def.parent_cnt = ncells; clk = clknode_create(clkdom, &rk_usb2phy_clk_clknode_class, &def); if (clk == NULL) { device_printf(devsc->dev, "cannot create clknode\n"); return (ENXIO); } sc = clknode_get_softc(clk); sc->clkdev = device_get_parent(devsc->dev); sc->grf = devsc->grf; sc->regs = (struct rk_usb2phy_regs *)ofw_bus_search_compatible(devsc->dev, compat_data)->ocd_data; if (sc->regs->clk_ctl.offset == 0) { OF_getencprop(node, "reg", regs, sizeof(regs)); sc->regs->clk_ctl.offset = regs[0]; } clknode_register(clkdom, clk); if (clkdom_finit(clkdom) != 0) { device_printf(devsc->dev, "cannot finalize clkdom initialization\n"); return (ENXIO); } if (bootverbose) clkdom_dump(clkdom); return (0); } static int rk_usb2phy_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Rockchip USB2PHY"); return (BUS_PROBE_DEFAULT); } static int rk_usb2phy_attach(device_t dev) { struct rk_usb2phy_softc *sc; struct phynode_init_def phy_init; struct phynode *phynode; phandle_t node, host; int err; sc = device_get_softc(dev); sc->dev = dev; node = ofw_bus_get_node(dev); if (OF_hasprop(node, "rockchip,usbgrf")) { if (syscon_get_by_ofw_property(dev, node, "rockchip,usbgrf", &sc->grf)) { device_printf(dev, "Cannot get syscon handle\n"); return (ENXIO); } } else { if (syscon_get_handle_default(dev, &sc->grf)) { device_printf(dev, "Cannot get syscon handle\n"); return (ENXIO); } } if (clk_get_by_ofw_name(dev, 0, "phyclk", &sc->clk) != 0) { device_printf(dev, "Cannot get clock\n"); return (ENXIO); } err = clk_enable(sc->clk); if (err != 0) { device_printf(dev, "Could not enable clock %s\n", clk_get_name(sc->clk)); return (ENXIO); } err = rk_usb2phy_export_clock(sc); if (err != 0) return (err); /* Only host is supported right now */ host = ofw_bus_find_child(node, "host-port"); if (host == 0) { device_printf(dev, "Cannot find host-port child node\n"); return (ENXIO); } if (!ofw_bus_node_status_okay(host)) { device_printf(dev, "host-port isn't okay\n"); return (0); } regulator_get_by_ofw_property(dev, host, "phy-supply", &sc->phy_supply); phy_init.id = RK_USBPHY_HOST; phy_init.ofw_node = host; phynode = phynode_create(dev, &rk_usb2phy_phynode_class, &phy_init); if (phynode == NULL) { device_printf(dev, "failed to create host USB2PHY\n"); return (ENXIO); } if (phynode_register(phynode) == NULL) { device_printf(dev, "failed to register host USB2PHY\n"); return (ENXIO); } OF_device_register_xref(OF_xref_from_node(host), dev); return (0); } static device_method_t rk_usb2phy_methods[] = { /* Device interface */ DEVMETHOD(device_probe, rk_usb2phy_probe), DEVMETHOD(device_attach, rk_usb2phy_attach), DEVMETHOD_END }; static driver_t rk_usb2phy_driver = { "rk_usb2phy", rk_usb2phy_methods, sizeof(struct rk_usb2phy_softc) }; EARLY_DRIVER_MODULE(rk_usb2phy, simplebus, rk_usb2phy_driver, 0, 0, BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE); MODULE_VERSION(rk_usb2phy, 1); diff --git a/sys/arm64/rockchip/rk_usbphy.c b/sys/arm64/rockchip/rk_usbphy.c index 46859d1442e3..c2020373d040 100644 --- a/sys/arm64/rockchip/rk_usbphy.c +++ b/sys/arm64/rockchip/rk_usbphy.c @@ -1,300 +1,300 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2019 Michal Meloun * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include "phynode_if.h" #include "phynode_usb_if.h" #include "syscon_if.h" /* Phy registers */ #define UOC_CON0 0x00 #define UOC_CON0_SIDDQ (1 << 13) #define UOC_CON0_DISABLE (1 << 4) #define UOC_CON0_COMMON_ON_N (1 << 0) #define UOC_CON2 0x08 #define UOC_CON2_SOFT_CON_SEL (1 << 2) #define UOC_CON3 0x0c #define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v)) #define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r)) static struct ofw_compat_data compat_data[] = { {"rockchip,rk3288-usb-phy", 1}, {NULL, 0}, }; struct rk_usbphy_softc { device_t dev; }; struct rk_phynode_sc { struct phynode_usb_sc usb_sc; uint32_t base; int mode; clk_t clk; hwreset_t hwreset; regulator_t supply_vbus; struct syscon *syscon; }; static int rk_phynode_phy_enable(struct phynode *phy, bool enable) { struct rk_phynode_sc *sc; int rv; sc = phynode_get_softc(phy); rv = SYSCON_MODIFY_4(sc->syscon, sc->base + UOC_CON0, UOC_CON0_SIDDQ << 16 | UOC_CON0_SIDDQ, enable ? 0 : UOC_CON0_SIDDQ); return (rv); } static int rk_phynode_get_mode(struct phynode *phynode, int *mode) { struct rk_phynode_sc *sc; sc = phynode_get_softc(phynode); *mode = sc->mode; return (0); } static int rk_phynode_set_mode(struct phynode *phynode, int mode) { struct rk_phynode_sc *sc; sc = phynode_get_softc(phynode); sc->mode = mode; return (0); } /* Phy controller class and methods. */ static phynode_method_t rk_phynode_methods[] = { PHYNODEUSBMETHOD(phynode_enable, rk_phynode_phy_enable), PHYNODEMETHOD(phynode_usb_get_mode, rk_phynode_get_mode), PHYNODEMETHOD(phynode_usb_set_mode, rk_phynode_set_mode), PHYNODEUSBMETHOD_END }; DEFINE_CLASS_1(rk_phynode, rk_phynode_class, rk_phynode_methods, sizeof(struct rk_phynode_sc), phynode_usb_class); static int rk_usbphy_init_phy(struct rk_usbphy_softc *sc, phandle_t node) { struct phynode *phynode; struct phynode_init_def phy_init; struct rk_phynode_sc *phy_sc; int rv; uint32_t base; clk_t clk; hwreset_t hwreset; regulator_t supply_vbus; struct syscon *syscon; clk = NULL; hwreset = NULL; supply_vbus = NULL; rv = OF_getencprop(node, "reg", &base, sizeof(base)); if (rv <= 0) { device_printf(sc->dev, "cannot get 'reg' property.\n"); goto fail; } /* FDT resources. All are optional. */ rv = clk_get_by_ofw_name(sc->dev, node, "phyclk", &clk); if (rv != 0 && rv != ENOENT) { device_printf(sc->dev, "cannot get 'phyclk' clock.\n"); goto fail; } rv = hwreset_get_by_ofw_name(sc->dev, node, "phy-reset", &hwreset); if (rv != 0 && rv != ENOENT) { device_printf(sc->dev, "Cannot get 'phy-reset' reset\n"); goto fail; } rv = regulator_get_by_ofw_property(sc->dev, node, "vbus-supply", &supply_vbus); if (rv != 0 && rv != ENOENT) { device_printf(sc->dev, "Cannot get 'vbus' regulator.\n"); goto fail; } rv = SYSCON_GET_HANDLE(sc->dev, &syscon); if (rv != 0) { device_printf(sc->dev, "Cannot get parent syscon\n"); goto fail; } /* Init HW resources */ if (hwreset != NULL) { rv = hwreset_assert(hwreset); if (rv != 0) { device_printf(sc->dev, "Cannot assert reset\n"); goto fail; } } if (clk != NULL) { rv = clk_enable(clk); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'phyclk' clock.\n"); goto fail; } } if (hwreset != NULL) { rv = hwreset_deassert(hwreset); if (rv != 0) { device_printf(sc->dev, "Cannot deassert reset\n"); goto fail; } } /* Create and register phy. */ bzero(&phy_init, sizeof(phy_init)); phy_init.id = 1; phy_init.ofw_node = node; phynode = phynode_create(sc->dev, &rk_phynode_class, &phy_init); if (phynode == NULL) { device_printf(sc->dev, "Cannot create phy.\n"); return (ENXIO); } phy_sc = phynode_get_softc(phynode); phy_sc->base = base; phy_sc->clk = clk; phy_sc->hwreset = hwreset; phy_sc->supply_vbus = supply_vbus; phy_sc->syscon = syscon; if (phynode_register(phynode) == NULL) { device_printf(sc->dev, "Cannot register phy.\n"); return (ENXIO); } /* XXX It breaks boot */ /* rk_phynode_phy_enable(phynode, 1); */ return (0); fail: if (supply_vbus != NULL) regulator_release(supply_vbus); if (clk != NULL) clk_release(clk); if (hwreset != NULL) hwreset_release(hwreset); return (ENXIO); } static int rk_usbphy_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "RockChip USB Phy"); return (BUS_PROBE_DEFAULT); } static int rk_usbphy_attach(device_t dev) { struct rk_usbphy_softc *sc; phandle_t node, child; int rv; sc = device_get_softc(dev); sc->dev = dev; node = ofw_bus_get_node(sc->dev); /* Attach child devices */ for (child = OF_child(node); child > 0; child = OF_peer(child)) { rv = rk_usbphy_init_phy(sc, child); if (rv != 0) goto fail; } return (bus_generic_attach(dev)); fail: return (ENXIO); } static int rk_usbphy_detach(device_t dev) { return (0); } static device_method_t rk_usbphy_methods[] = { /* Device interface */ DEVMETHOD(device_probe, rk_usbphy_probe), DEVMETHOD(device_attach, rk_usbphy_attach), DEVMETHOD(device_detach, rk_usbphy_detach), DEVMETHOD_END }; static DEFINE_CLASS_0(rk_usbphy, rk_usbphy_driver, rk_usbphy_methods, sizeof(struct rk_usbphy_softc)); EARLY_DRIVER_MODULE(rk_usbphy, simplebus, rk_usbphy_driver, NULL, NULL, BUS_PASS_TIMER + BUS_PASS_ORDER_LAST); diff --git a/sys/conf/files b/sys/conf/files index e07ac548d93a..f0d4250a4537 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,5240 +1,5240 @@ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and # dependency lines other than the first are silently ignored. # acpi_quirks.h optional acpi \ dependency "$S/tools/acpi_quirks2h.awk $S/dev/acpica/acpi_quirks" \ compile-with "${AWK} -f $S/tools/acpi_quirks2h.awk $S/dev/acpica/acpi_quirks" \ no-obj no-implicit-rule before-depend \ clean "acpi_quirks.h" bhnd_nvram_map.h optional bhnd \ dependency "$S/dev/bhnd/tools/nvram_map_gen.sh $S/dev/bhnd/tools/nvram_map_gen.awk $S/dev/bhnd/nvram/nvram_map" \ compile-with "sh $S/dev/bhnd/tools/nvram_map_gen.sh $S/dev/bhnd/nvram/nvram_map -h" \ no-obj no-implicit-rule before-depend \ clean "bhnd_nvram_map.h" bhnd_nvram_map_data.h optional bhnd \ dependency "$S/dev/bhnd/tools/nvram_map_gen.sh $S/dev/bhnd/tools/nvram_map_gen.awk $S/dev/bhnd/nvram/nvram_map" \ compile-with "sh $S/dev/bhnd/tools/nvram_map_gen.sh $S/dev/bhnd/nvram/nvram_map -d" \ no-obj no-implicit-rule before-depend \ clean "bhnd_nvram_map_data.h" fdt_static_dtb.h optional fdt fdt_dtb_static \ compile-with "sh -c 'MACHINE=${MACHINE} $S/tools/fdt/make_dtbh.sh ${FDT_DTS_FILE} ${.CURDIR}'" \ dependency "${FDT_DTS_FILE:T:R}.dtb" \ no-obj no-implicit-rule before-depend \ clean "fdt_static_dtb.h" feeder_eq_gen.h optional sound \ dependency "$S/tools/sound/feeder_eq_mkfilter.awk" \ compile-with "${AWK} -f $S/tools/sound/feeder_eq_mkfilter.awk -- ${FEEDER_EQ_PRESETS} > feeder_eq_gen.h" \ no-obj no-implicit-rule before-depend \ clean "feeder_eq_gen.h" feeder_rate_gen.h optional sound \ dependency "$S/tools/sound/feeder_rate_mkfilter.awk" \ compile-with "${AWK} -f $S/tools/sound/feeder_rate_mkfilter.awk -- ${FEEDER_RATE_PRESETS} > feeder_rate_gen.h" \ no-obj no-implicit-rule before-depend \ clean "feeder_rate_gen.h" font.h optional sc_dflt_font \ compile-with "uudecode < ${SRCTOP}/share/syscons/fonts/${SC_DFLT_FONT}-8x16.fnt && file2c 'u_char dflt_font_16[16*256] = {' '};' < ${SC_DFLT_FONT}-8x16 > font.h && uudecode < ${SRCTOP}/share/syscons/fonts/${SC_DFLT_FONT}-8x14.fnt && file2c 'u_char dflt_font_14[14*256] = {' '};' < ${SC_DFLT_FONT}-8x14 >> font.h && uudecode < ${SRCTOP}/share/syscons/fonts/${SC_DFLT_FONT}-8x8.fnt && file2c 'u_char dflt_font_8[8*256] = {' '};' < ${SC_DFLT_FONT}-8x8 >> font.h" \ no-obj no-implicit-rule before-depend \ clean "font.h ${SC_DFLT_FONT}-8x14 ${SC_DFLT_FONT}-8x16 ${SC_DFLT_FONT}-8x8" snd_fxdiv_gen.h optional sound \ dependency "$S/tools/sound/snd_fxdiv_gen.awk" \ compile-with "${AWK} -f $S/tools/sound/snd_fxdiv_gen.awk -- > snd_fxdiv_gen.h" \ no-obj no-implicit-rule before-depend \ clean "snd_fxdiv_gen.h" miidevs.h optional miibus | mii \ dependency "$S/tools/miidevs2h.awk $S/dev/mii/miidevs" \ compile-with "${AWK} -f $S/tools/miidevs2h.awk $S/dev/mii/miidevs" \ no-obj no-implicit-rule before-depend \ clean "miidevs.h" kbdmuxmap.h optional kbdmux_dflt_keymap \ compile-with "${KEYMAP} -L ${KBDMUX_DFLT_KEYMAP} | ${KEYMAP_FIX} > ${.TARGET}" \ no-obj no-implicit-rule before-depend \ clean "kbdmuxmap.h" teken_state.h optional sc | vt \ dependency "$S/teken/gensequences $S/teken/sequences" \ compile-with "${AWK} -f $S/teken/gensequences $S/teken/sequences > teken_state.h" \ no-obj no-implicit-rule before-depend \ clean "teken_state.h" ukbdmap.h optional ukbd_dflt_keymap \ compile-with "${KEYMAP} -L ${UKBD_DFLT_KEYMAP} | ${KEYMAP_FIX} > ${.TARGET}" \ no-obj no-implicit-rule before-depend \ clean "ukbdmap.h" usbdevs.h optional usb | hid \ dependency "$S/tools/usbdevs2h.awk $S/dev/usb/usbdevs" \ compile-with "${AWK} -f $S/tools/usbdevs2h.awk $S/dev/usb/usbdevs -h" \ no-obj no-implicit-rule before-depend \ clean "usbdevs.h" usbdevs_data.h optional usb \ dependency "$S/tools/usbdevs2h.awk $S/dev/usb/usbdevs" \ 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 cam/cam_periph.c optional scbus cam/cam_queue.c optional scbus cam/cam_sim.c optional scbus cam/cam_xpt.c optional scbus cam/ata/ata_all.c optional scbus cam/ata/ata_xpt.c optional scbus cam/ata/ata_pmp.c optional scbus cam/nvme/nvme_all.c optional scbus cam/nvme/nvme_da.c optional nda | da cam/nvme/nvme_xpt.c optional scbus cam/scsi/scsi_xpt.c optional scbus cam/scsi/scsi_all.c optional scbus cam/scsi/scsi_cd.c optional cd cam/scsi/scsi_ch.c optional ch cam/ata/ata_da.c optional ada | da cam/ctl/ctl.c optional ctl cam/ctl/ctl_backend.c optional ctl cam/ctl/ctl_backend_block.c optional ctl cam/ctl/ctl_backend_ramdisk.c optional ctl cam/ctl/ctl_cmd_table.c optional ctl cam/ctl/ctl_frontend.c optional ctl cam/ctl/ctl_frontend_cam_sim.c optional ctl cam/ctl/ctl_frontend_ioctl.c optional ctl cam/ctl/ctl_frontend_iscsi.c optional ctl cfiscsi cam/ctl/ctl_ha.c optional ctl cam/ctl/ctl_scsi_all.c optional ctl cam/ctl/ctl_tpc.c optional ctl cam/ctl/ctl_tpc_local.c optional ctl cam/ctl/ctl_error.c optional ctl cam/ctl/ctl_util.c optional ctl cam/ctl/scsi_ctl.c optional ctl cam/mmc/mmc_xpt.c optional scbus mmccam cam/mmc/mmc_sim.c optional scbus mmccam cam/mmc/mmc_sim_if.m optional scbus mmccam cam/mmc/mmc_da.c optional scbus mmccam da cam/scsi/scsi_da.c optional da cam/scsi/scsi_pass.c optional pass cam/scsi/scsi_pt.c optional pt cam/scsi/scsi_sa.c optional sa cam/scsi/scsi_enc.c optional ses cam/scsi/scsi_enc_ses.c optional ses cam/scsi/scsi_enc_safte.c optional ses cam/scsi/scsi_sg.c optional sg cam/scsi/scsi_targ_bh.c optional targbh cam/scsi/scsi_target.c optional targ cam/scsi/smp_all.c optional scbus # shared between zfs and dtrace cddl/compat/opensolaris/kern/opensolaris.c optional dtrace compile-with "${CDDL_C}" cddl/compat/opensolaris/kern/opensolaris_proc.c optional zfs | dtrace compile-with "${CDDL_C}" contrib/openzfs/module/os/freebsd/spl/spl_misc.c optional zfs | dtrace compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/spl_cmn_err.c optional zfs | dtrace compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/spl_taskq.c optional zfs | dtrace compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/spl_kmem.c optional zfs | dtrace compile-with "${ZFS_C}" #zfs solaris portability layer contrib/openzfs/module/os/freebsd/spl/acl_common.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/callb.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/list.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/spl_acl.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/spl_dtrace.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/spl_kstat.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/spl_policy.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/spl_procfs_list.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/spl_string.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/spl_sunddi.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/spl_sysevent.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/spl_uio.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/spl_vfs.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/spl_vm.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/spl_zlib.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/spl/spl_zone.c optional zfs compile-with "${ZFS_C}" # zfs specific #zfs avl contrib/openzfs/module/avl/avl.c optional zfs compile-with "${ZFS_C}" # zfs lua support contrib/openzfs/module/lua/lapi.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/lauxlib.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/lbaselib.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/lcode.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/lcompat.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/lcorolib.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/lctype.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/ldebug.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/ldo.c optional zfs compile-with "${ZFS_C} ${NO_WINFINITE_RECURSION}" contrib/openzfs/module/lua/lfunc.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/lgc.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/llex.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/lmem.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/lobject.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/lopcodes.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/lparser.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/lstate.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/lstring.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/lstrlib.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/ltable.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/ltablib.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/ltm.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/lvm.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/lua/lzio.c optional zfs compile-with "${ZFS_C}" # zfs nvpair support contrib/openzfs/module/nvpair/fnvpair.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/nvpair/nvpair.c optional zfs compile-with "${ZFS_RPC_C} ${NO_WSTRINGOP_OVERREAD}" contrib/openzfs/module/nvpair/nvpair_alloc_fixed.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/nvpair/nvpair_alloc_spl.c optional zfs compile-with "${ZFS_C}" #zfs platform compatibility code contrib/openzfs/module/os/freebsd/zfs/abd_os.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/arc_os.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/crypto_os.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/dmu_os.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/event_os.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/hkdf.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/kmod_core.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/spa_os.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/sysctl_os.c optional zfs compile-with "${ZFS_C} -include $S/modules/zfs/zfs_config.h" contrib/openzfs/module/os/freebsd/zfs/vdev_file.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/vdev_label_os.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/vdev_geom.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/zfs_acl.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/zfs_debug.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/zfs_dir.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/zfs_file_os.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/zfs_ioctl_compat.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/zfs_ioctl_os.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/zfs_racct.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/zfs_vfsops.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/zfs_znode.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/zio_crypt.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/os/freebsd/zfs/zvol_os.c optional zfs compile-with "${ZFS_C}" #zfs unicode support contrib/openzfs/module/unicode/uconv.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/unicode/u8_textprep.c optional zfs compile-with "${ZFS_C}" #zfs checksums / zcommon contrib/openzfs/module/zcommon/cityhash.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zcommon/zfeature_common.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zcommon/zfs_comutil.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zcommon/zfs_deleg.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zcommon/zfs_fletcher.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zcommon/zfs_fletcher_superscalar.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zcommon/zfs_fletcher_superscalar4.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zcommon/zfs_namecheck.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zcommon/zfs_prop.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zcommon/zpool_prop.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zcommon/zprop_common.c optional zfs compile-with "${ZFS_C}" # zfs edon-r hash support contrib/openzfs/module/icp/algs/edonr/edonr.c optional zfs compile-with "${ZFS_C}" # zfs blake3 hash support contrib/openzfs/module/icp/algs/blake3/blake3.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/icp/algs/blake3/blake3_generic.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/icp/algs/blake3/blake3_impl.c optional zfs compile-with "${ZFS_C}" # zfs sha2 hash support contrib/openzfs/module/icp/algs/sha2/sha2_generic.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/icp/algs/sha2/sha256_impl.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/icp/algs/sha2/sha512_impl.c optional zfs compile-with "${ZFS_C}" #zfs core common code contrib/openzfs/module/zfs/abd.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/aggsum.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/arc.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/blake3_zfs.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/blkptr.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/bplist.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/bpobj.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/bptree.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/brt.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/btree.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/bqueue.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dbuf.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dbuf_stats.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dataset_kstats.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/ddt.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/ddt_zap.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dmu.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dmu_diff.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dmu_object.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dmu_objset.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dmu_recv.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dmu_redact.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dmu_send.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dmu_traverse.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dmu_tx.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dmu_zfetch.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dnode.c optional zfs compile-with "${ZFS_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" \ warning "kernel contains CDDL licensed ZFS filesystem" contrib/openzfs/module/zfs/dnode_sync.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dsl_bookmark.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dsl_crypt.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dsl_dataset.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dsl_deadlist.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dsl_deleg.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dsl_destroy.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dsl_dir.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dsl_pool.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dsl_prop.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dsl_scan.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dsl_synctask.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/dsl_userhold.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/edonr_zfs.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/fm.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/gzip.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/lzjb.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/lz4.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/lz4_zfs.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/metaslab.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/mmp.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/multilist.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/objlist.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/pathname.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/range_tree.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/refcount.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/rrwlock.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/sa.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/sha2_zfs.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/skein_zfs.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/spa.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/spa_checkpoint.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/spa_config.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/spa_errlog.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/spa_history.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/spa_log_spacemap.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/spa_misc.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/spa_stats.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/space_map.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/space_reftree.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/txg.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/uberblock.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/unique.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev_draid.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev_draid_rand.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev_indirect.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev_indirect_births.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev_indirect_mapping.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev_initialize.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev_label.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev_mirror.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev_missing.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev_queue.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev_raidz.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev_raidz_math.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev_raidz_math_scalar.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev_rebuild.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev_removal.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev_root.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/vdev_trim.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zap.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zap_leaf.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zap_micro.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zcp.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zcp_get.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zcp_global.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zcp_iter.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zcp_set.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zcp_synctask.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zfeature.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zfs_byteswap.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zfs_chksum.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zfs_fm.c optional zfs compile-with "${ZFS_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" contrib/openzfs/module/zfs/zfs_fuid.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zfs_impl.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zfs_ioctl.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zfs_log.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zfs_onexit.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zfs_quota.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zfs_ratelimit.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zfs_replay.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zfs_rlock.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zfs_sa.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zfs_vnops.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zstd/zfs_zstd.c optional zfs zstdio compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zil.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zio.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zio_checksum.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zio_compress.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zio_inject.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zle.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zrlock.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zthr.c optional zfs compile-with "${ZFS_C}" contrib/openzfs/module/zfs/zvol.c optional zfs compile-with "${ZFS_C}" # dtrace specific cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c optional dtrace compile-with "${DTRACE_C}" \ warning "kernel contains CDDL licensed DTRACE" cddl/contrib/opensolaris/uts/common/dtrace/dtrace_xoroshiro128_plus.c optional dtrace compile-with "${DTRACE_C}" cddl/dev/dtmalloc/dtmalloc.c optional dtmalloc | dtraceall compile-with "${CDDL_C}" cddl/dev/profile/profile.c optional dtrace_profile | dtraceall compile-with "${CDDL_C}" cddl/dev/sdt/sdt.c optional dtrace_sdt | dtraceall compile-with "${CDDL_C}" cddl/dev/fbt/fbt.c optional dtrace_fbt | dtraceall compile-with "${FBT_C}" cddl/dev/systrace/systrace.c optional dtrace_systrace | dtraceall compile-with "${CDDL_C}" cddl/dev/prototype.c optional dtrace_prototype | dtraceall compile-with "${CDDL_C}" fs/nfsclient/nfs_clkdtrace.c optional dtnfscl nfscl | dtraceall nfscl compile-with "${CDDL_C}" compat/freebsd32/freebsd32_abort2.c optional compat_freebsd32 compat/freebsd32/freebsd32_capability.c optional compat_freebsd32 compat/freebsd32/freebsd32_ioctl.c optional compat_freebsd32 compat/freebsd32/freebsd32_misc.c optional compat_freebsd32 compat/freebsd32/freebsd32_syscalls.c optional compat_freebsd32 compat/freebsd32/freebsd32_sysent.c optional compat_freebsd32 contrib/ck/src/ck_array.c standard compile-with "${NORMAL_C} -I$S/contrib/ck/include" contrib/ck/src/ck_barrier_centralized.c standard compile-with "${NORMAL_C} -I$S/contrib/ck/include" contrib/ck/src/ck_barrier_combining.c standard compile-with "${NORMAL_C} -I$S/contrib/ck/include" contrib/ck/src/ck_barrier_dissemination.c standard compile-with "${NORMAL_C} -I$S/contrib/ck/include" contrib/ck/src/ck_barrier_mcs.c standard compile-with "${NORMAL_C} -I$S/contrib/ck/include" contrib/ck/src/ck_barrier_tournament.c standard compile-with "${NORMAL_C} -I$S/contrib/ck/include" contrib/ck/src/ck_epoch.c standard compile-with "${NORMAL_C} -I$S/contrib/ck/include" contrib/ck/src/ck_hp.c standard compile-with "${NORMAL_C} -I$S/contrib/ck/include" contrib/ck/src/ck_hs.c standard compile-with "${NORMAL_C} -I$S/contrib/ck/include" contrib/ck/src/ck_ht.c standard compile-with "${NORMAL_C} -I$S/contrib/ck/include" contrib/ck/src/ck_rhs.c standard compile-with "${NORMAL_C} -I$S/contrib/ck/include" contrib/dev/acpica/common/ahids.c optional acpi acpi_debug contrib/dev/acpica/common/ahuuids.c optional acpi acpi_debug contrib/dev/acpica/components/debugger/dbcmds.c optional acpi acpi_debug contrib/dev/acpica/components/debugger/dbconvert.c optional acpi acpi_debug contrib/dev/acpica/components/debugger/dbdisply.c optional acpi acpi_debug contrib/dev/acpica/components/debugger/dbexec.c optional acpi acpi_debug contrib/dev/acpica/components/debugger/dbhistry.c optional acpi acpi_debug contrib/dev/acpica/components/debugger/dbinput.c optional acpi acpi_debug contrib/dev/acpica/components/debugger/dbmethod.c optional acpi acpi_debug contrib/dev/acpica/components/debugger/dbnames.c optional acpi acpi_debug contrib/dev/acpica/components/debugger/dbobject.c optional acpi acpi_debug contrib/dev/acpica/components/debugger/dbstats.c optional acpi acpi_debug contrib/dev/acpica/components/debugger/dbtest.c optional acpi acpi_debug contrib/dev/acpica/components/debugger/dbutils.c optional acpi acpi_debug contrib/dev/acpica/components/debugger/dbxface.c optional acpi acpi_debug contrib/dev/acpica/components/disassembler/dmbuffer.c optional acpi acpi_debug contrib/dev/acpica/components/disassembler/dmcstyle.c optional acpi acpi_debug contrib/dev/acpica/components/disassembler/dmdeferred.c optional acpi acpi_debug contrib/dev/acpica/components/disassembler/dmnames.c optional acpi acpi_debug contrib/dev/acpica/components/disassembler/dmopcode.c optional acpi acpi_debug contrib/dev/acpica/components/disassembler/dmresrc.c optional acpi acpi_debug contrib/dev/acpica/components/disassembler/dmresrcl.c optional acpi acpi_debug contrib/dev/acpica/components/disassembler/dmresrcl2.c optional acpi acpi_debug contrib/dev/acpica/components/disassembler/dmresrcs.c optional acpi acpi_debug contrib/dev/acpica/components/disassembler/dmutils.c optional acpi acpi_debug contrib/dev/acpica/components/disassembler/dmwalk.c optional acpi acpi_debug contrib/dev/acpica/components/dispatcher/dsargs.c optional acpi contrib/dev/acpica/components/dispatcher/dscontrol.c optional acpi contrib/dev/acpica/components/dispatcher/dsdebug.c optional acpi contrib/dev/acpica/components/dispatcher/dsfield.c optional acpi contrib/dev/acpica/components/dispatcher/dsinit.c optional acpi contrib/dev/acpica/components/dispatcher/dsmethod.c optional acpi contrib/dev/acpica/components/dispatcher/dsmthdat.c optional acpi contrib/dev/acpica/components/dispatcher/dsobject.c optional acpi contrib/dev/acpica/components/dispatcher/dsopcode.c optional acpi contrib/dev/acpica/components/dispatcher/dspkginit.c optional acpi contrib/dev/acpica/components/dispatcher/dsutils.c optional acpi contrib/dev/acpica/components/dispatcher/dswexec.c optional acpi contrib/dev/acpica/components/dispatcher/dswload.c optional acpi contrib/dev/acpica/components/dispatcher/dswload2.c optional acpi contrib/dev/acpica/components/dispatcher/dswscope.c optional acpi contrib/dev/acpica/components/dispatcher/dswstate.c optional acpi contrib/dev/acpica/components/events/evevent.c optional acpi contrib/dev/acpica/components/events/evglock.c optional acpi contrib/dev/acpica/components/events/evgpe.c optional acpi contrib/dev/acpica/components/events/evgpeblk.c optional acpi contrib/dev/acpica/components/events/evgpeinit.c optional acpi contrib/dev/acpica/components/events/evgpeutil.c optional acpi contrib/dev/acpica/components/events/evhandler.c optional acpi contrib/dev/acpica/components/events/evmisc.c optional acpi contrib/dev/acpica/components/events/evregion.c optional acpi contrib/dev/acpica/components/events/evrgnini.c optional acpi contrib/dev/acpica/components/events/evsci.c optional acpi contrib/dev/acpica/components/events/evxface.c optional acpi contrib/dev/acpica/components/events/evxfevnt.c optional acpi contrib/dev/acpica/components/events/evxfgpe.c optional acpi contrib/dev/acpica/components/events/evxfregn.c optional acpi contrib/dev/acpica/components/executer/exconcat.c optional acpi contrib/dev/acpica/components/executer/exconfig.c optional acpi contrib/dev/acpica/components/executer/exconvrt.c optional acpi contrib/dev/acpica/components/executer/excreate.c optional acpi contrib/dev/acpica/components/executer/exdebug.c optional acpi contrib/dev/acpica/components/executer/exdump.c optional acpi contrib/dev/acpica/components/executer/exfield.c optional acpi contrib/dev/acpica/components/executer/exfldio.c optional acpi contrib/dev/acpica/components/executer/exmisc.c optional acpi contrib/dev/acpica/components/executer/exmutex.c optional acpi contrib/dev/acpica/components/executer/exnames.c optional acpi contrib/dev/acpica/components/executer/exoparg1.c optional acpi contrib/dev/acpica/components/executer/exoparg2.c optional acpi contrib/dev/acpica/components/executer/exoparg3.c optional acpi contrib/dev/acpica/components/executer/exoparg6.c optional acpi contrib/dev/acpica/components/executer/exprep.c optional acpi contrib/dev/acpica/components/executer/exregion.c optional acpi contrib/dev/acpica/components/executer/exresnte.c optional acpi contrib/dev/acpica/components/executer/exresolv.c optional acpi contrib/dev/acpica/components/executer/exresop.c optional acpi contrib/dev/acpica/components/executer/exserial.c optional acpi contrib/dev/acpica/components/executer/exstore.c optional acpi contrib/dev/acpica/components/executer/exstoren.c optional acpi contrib/dev/acpica/components/executer/exstorob.c optional acpi contrib/dev/acpica/components/executer/exsystem.c optional acpi contrib/dev/acpica/components/executer/extrace.c optional acpi contrib/dev/acpica/components/executer/exutils.c optional acpi contrib/dev/acpica/components/hardware/hwacpi.c optional acpi contrib/dev/acpica/components/hardware/hwesleep.c optional acpi contrib/dev/acpica/components/hardware/hwgpe.c optional acpi contrib/dev/acpica/components/hardware/hwpci.c optional acpi contrib/dev/acpica/components/hardware/hwregs.c optional acpi contrib/dev/acpica/components/hardware/hwsleep.c optional acpi contrib/dev/acpica/components/hardware/hwtimer.c optional acpi contrib/dev/acpica/components/hardware/hwvalid.c optional acpi contrib/dev/acpica/components/hardware/hwxface.c optional acpi contrib/dev/acpica/components/hardware/hwxfsleep.c optional acpi contrib/dev/acpica/components/namespace/nsaccess.c optional acpi \ compile-with "${NORMAL_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" contrib/dev/acpica/components/namespace/nsalloc.c optional acpi contrib/dev/acpica/components/namespace/nsarguments.c optional acpi contrib/dev/acpica/components/namespace/nsconvert.c optional acpi contrib/dev/acpica/components/namespace/nsdump.c optional acpi contrib/dev/acpica/components/namespace/nseval.c optional acpi contrib/dev/acpica/components/namespace/nsinit.c optional acpi contrib/dev/acpica/components/namespace/nsload.c optional acpi contrib/dev/acpica/components/namespace/nsnames.c optional acpi contrib/dev/acpica/components/namespace/nsobject.c optional acpi contrib/dev/acpica/components/namespace/nsparse.c optional acpi contrib/dev/acpica/components/namespace/nspredef.c optional acpi contrib/dev/acpica/components/namespace/nsprepkg.c optional acpi contrib/dev/acpica/components/namespace/nsrepair.c optional acpi contrib/dev/acpica/components/namespace/nsrepair2.c optional acpi contrib/dev/acpica/components/namespace/nssearch.c optional acpi contrib/dev/acpica/components/namespace/nsutils.c optional acpi contrib/dev/acpica/components/namespace/nswalk.c optional acpi contrib/dev/acpica/components/namespace/nsxfeval.c optional acpi contrib/dev/acpica/components/namespace/nsxfname.c optional acpi contrib/dev/acpica/components/namespace/nsxfobj.c optional acpi contrib/dev/acpica/components/parser/psargs.c optional acpi contrib/dev/acpica/components/parser/psloop.c optional acpi contrib/dev/acpica/components/parser/psobject.c optional acpi contrib/dev/acpica/components/parser/psopcode.c optional acpi contrib/dev/acpica/components/parser/psopinfo.c optional acpi contrib/dev/acpica/components/parser/psparse.c optional acpi contrib/dev/acpica/components/parser/psscope.c optional acpi contrib/dev/acpica/components/parser/pstree.c optional acpi contrib/dev/acpica/components/parser/psutils.c optional acpi contrib/dev/acpica/components/parser/pswalk.c optional acpi contrib/dev/acpica/components/parser/psxface.c optional acpi contrib/dev/acpica/components/resources/rsaddr.c optional acpi contrib/dev/acpica/components/resources/rscalc.c optional acpi contrib/dev/acpica/components/resources/rscreate.c optional acpi contrib/dev/acpica/components/resources/rsdump.c optional acpi acpi_debug contrib/dev/acpica/components/resources/rsdumpinfo.c optional acpi contrib/dev/acpica/components/resources/rsinfo.c optional acpi contrib/dev/acpica/components/resources/rsio.c optional acpi contrib/dev/acpica/components/resources/rsirq.c optional acpi contrib/dev/acpica/components/resources/rslist.c optional acpi contrib/dev/acpica/components/resources/rsmemory.c optional acpi contrib/dev/acpica/components/resources/rsmisc.c optional acpi contrib/dev/acpica/components/resources/rsserial.c optional acpi contrib/dev/acpica/components/resources/rsutils.c optional acpi contrib/dev/acpica/components/resources/rsxface.c optional acpi contrib/dev/acpica/components/tables/tbdata.c optional acpi contrib/dev/acpica/components/tables/tbfadt.c optional acpi contrib/dev/acpica/components/tables/tbfind.c optional acpi contrib/dev/acpica/components/tables/tbinstal.c optional acpi contrib/dev/acpica/components/tables/tbprint.c optional acpi contrib/dev/acpica/components/tables/tbutils.c optional acpi contrib/dev/acpica/components/tables/tbxface.c optional acpi contrib/dev/acpica/components/tables/tbxfload.c optional acpi contrib/dev/acpica/components/tables/tbxfroot.c optional acpi contrib/dev/acpica/components/utilities/utaddress.c optional acpi contrib/dev/acpica/components/utilities/utalloc.c optional acpi contrib/dev/acpica/components/utilities/utascii.c optional acpi contrib/dev/acpica/components/utilities/utbuffer.c optional acpi contrib/dev/acpica/components/utilities/utcache.c optional acpi contrib/dev/acpica/components/utilities/utcksum.c optional acpi contrib/dev/acpica/components/utilities/utcopy.c optional acpi contrib/dev/acpica/components/utilities/utdebug.c optional acpi contrib/dev/acpica/components/utilities/utdecode.c optional acpi contrib/dev/acpica/components/utilities/utdelete.c optional acpi contrib/dev/acpica/components/utilities/uterror.c optional acpi contrib/dev/acpica/components/utilities/uteval.c optional acpi contrib/dev/acpica/components/utilities/utexcep.c optional acpi contrib/dev/acpica/components/utilities/utglobal.c optional acpi contrib/dev/acpica/components/utilities/uthex.c optional acpi contrib/dev/acpica/components/utilities/utids.c optional acpi contrib/dev/acpica/components/utilities/utinit.c optional acpi contrib/dev/acpica/components/utilities/utlock.c optional acpi contrib/dev/acpica/components/utilities/utmath.c optional acpi contrib/dev/acpica/components/utilities/utmisc.c optional acpi contrib/dev/acpica/components/utilities/utmutex.c optional acpi contrib/dev/acpica/components/utilities/utnonansi.c optional acpi contrib/dev/acpica/components/utilities/utobject.c optional acpi contrib/dev/acpica/components/utilities/utosi.c optional acpi contrib/dev/acpica/components/utilities/utownerid.c optional acpi contrib/dev/acpica/components/utilities/utpredef.c optional acpi contrib/dev/acpica/components/utilities/utresdecode.c optional acpi acpi_debug contrib/dev/acpica/components/utilities/utresrc.c optional acpi contrib/dev/acpica/components/utilities/utstate.c optional acpi contrib/dev/acpica/components/utilities/utstring.c optional acpi contrib/dev/acpica/components/utilities/utstrsuppt.c optional acpi contrib/dev/acpica/components/utilities/utstrtoul64.c optional acpi contrib/dev/acpica/components/utilities/utuuid.c optional acpi acpi_debug contrib/dev/acpica/components/utilities/utxface.c optional acpi contrib/dev/acpica/components/utilities/utxferror.c optional acpi contrib/dev/acpica/components/utilities/utxfinit.c optional acpi contrib/dev/acpica/os_specific/service_layers/osgendbg.c optional acpi acpi_debug netpfil/ipfilter/netinet/fil.c optional ipfilter inet \ compile-with "${NORMAL_C} ${NO_WSELF_ASSIGN} -Wno-unused -I$S/netpfil/ipfilter" netpfil/ipfilter/netinet/ip_auth.c optional ipfilter inet \ compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" netpfil/ipfilter/netinet/ip_fil_freebsd.c optional ipfilter inet \ compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" netpfil/ipfilter/netinet/ip_frag.c optional ipfilter inet \ compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" netpfil/ipfilter/netinet/ip_log.c optional ipfilter inet \ compile-with "${NORMAL_C} -I$S/netpfil/ipfilter" netpfil/ipfilter/netinet/ip_nat.c optional ipfilter inet \ compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" netpfil/ipfilter/netinet/ip_proxy.c optional ipfilter inet \ compile-with "${NORMAL_C} ${NO_WSELF_ASSIGN} -Wno-unused -I$S/netpfil/ipfilter" netpfil/ipfilter/netinet/ip_state.c optional ipfilter inet \ compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" netpfil/ipfilter/netinet/ip_lookup.c optional ipfilter inet \ compile-with "${NORMAL_C} ${NO_WSELF_ASSIGN} -Wno-unused -Wno-error -I$S/netpfil/ipfilter" netpfil/ipfilter/netinet/ip_pool.c optional ipfilter inet \ compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" netpfil/ipfilter/netinet/ip_htable.c optional ipfilter inet \ compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter ${NO_WTAUTOLOGICAL_POINTER_COMPARE}" netpfil/ipfilter/netinet/ip_sync.c optional ipfilter inet \ compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" netpfil/ipfilter/netinet/mlfk_ipl.c optional ipfilter inet \ compile-with "${NORMAL_C} -I$S/netpfil/ipfilter" netpfil/ipfilter/netinet/ip_nat6.c optional ipfilter inet \ compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" netpfil/ipfilter/netinet/ip_rules.c optional ipfilter inet \ compile-with "${NORMAL_C} -I$S/netpfil/ipfilter" netpfil/ipfilter/netinet/ip_scan.c optional ipfilter inet \ compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" netpfil/ipfilter/netinet/ip_dstlist.c optional ipfilter inet \ compile-with "${NORMAL_C} -Wno-unused -I$S/netpfil/ipfilter" netpfil/ipfilter/netinet/radix_ipf.c optional ipfilter inet \ compile-with "${NORMAL_C} -I$S/netpfil/ipfilter" contrib/libfdt/fdt.c optional fdt contrib/libfdt/fdt_ro.c optional fdt contrib/libfdt/fdt_rw.c optional fdt contrib/libfdt/fdt_strerror.c optional fdt contrib/libfdt/fdt_sw.c optional fdt contrib/libfdt/fdt_wip.c optional fdt contrib/libnv/cnvlist.c standard contrib/libnv/dnvlist.c standard contrib/libnv/nvlist.c standard contrib/libnv/bsd_nvpair.c standard # xz dev/xz/xz_mod.c optional xz \ compile-with "${NORMAL_C} -DXZ_USE_CRC64 -I$S/contrib/xz-embedded/freebsd/ -I$S/contrib/xz-embedded/linux/lib/xz/ -I$S/contrib/xz-embedded/linux/include/linux/" contrib/xz-embedded/linux/lib/xz/xz_crc32.c optional xz \ compile-with "${NORMAL_C} -DXZ_USE_CRC64 -I$S/contrib/xz-embedded/freebsd/ -I$S/contrib/xz-embedded/linux/lib/xz/ -I$S/contrib/xz-embedded/linux/include/linux/" contrib/xz-embedded/linux/lib/xz/xz_crc64.c optional xz \ compile-with "${NORMAL_C} -DXZ_USE_CRC64 -I$S/contrib/xz-embedded/freebsd/ -I$S/contrib/xz-embedded/linux/lib/xz/ -I$S/contrib/xz-embedded/linux/include/linux/" contrib/xz-embedded/linux/lib/xz/xz_dec_bcj.c optional xz \ compile-with "${NORMAL_C} -DXZ_USE_CRC64 -I$S/contrib/xz-embedded/freebsd/ -I$S/contrib/xz-embedded/linux/lib/xz/ -I$S/contrib/xz-embedded/linux/include/linux/" contrib/xz-embedded/linux/lib/xz/xz_dec_lzma2.c optional xz \ compile-with "${NORMAL_C} -DXZ_USE_CRC64 -I$S/contrib/xz-embedded/freebsd/ -I$S/contrib/xz-embedded/linux/lib/xz/ -I$S/contrib/xz-embedded/linux/include/linux/" contrib/xz-embedded/linux/lib/xz/xz_dec_stream.c optional xz \ compile-with "${NORMAL_C} -DXZ_USE_CRC64 -I$S/contrib/xz-embedded/freebsd/ -I$S/contrib/xz-embedded/linux/lib/xz/ -I$S/contrib/xz-embedded/linux/include/linux/" # Zstd contrib/zstd/lib/freebsd/zstd_kmalloc.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/common/zstd_common.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/common/fse_decompress.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/common/entropy_common.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/common/error_private.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/common/xxhash.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/compress/zstd_compress.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/compress/zstd_compress_literals.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/compress/zstd_compress_sequences.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/compress/zstd_compress_superblock.c optional zstdio compile-with "${ZSTD_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" contrib/zstd/lib/compress/fse_compress.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/compress/hist.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/compress/huf_compress.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/compress/zstd_double_fast.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/compress/zstd_fast.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/compress/zstd_lazy.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/compress/zstd_ldm.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/compress/zstd_opt.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/decompress/zstd_ddict.c optional zstdio compile-with ${ZSTD_C} contrib/zstd/lib/decompress/zstd_decompress.c optional zstdio compile-with ${ZSTD_C} # See comment in sys/conf/kern.pre.mk contrib/zstd/lib/decompress/zstd_decompress_block.c optional zstdio \ compile-with "${ZSTD_C} ${ZSTD_DECOMPRESS_BLOCK_FLAGS}" contrib/zstd/lib/decompress/huf_decompress.c optional zstdio compile-with "${ZSTD_C} ${NO_WBITWISE_INSTEAD_OF_LOGICAL}" # Blake 2 contrib/libb2/blake2b-ref.c optional crypto | !random_loadable random_fenestrasx \ compile-with "${NORMAL_C} -I$S/crypto/blake2 -Wno-cast-qual -DSUFFIX=_ref -Wno-unused-function" contrib/libb2/blake2s-ref.c optional crypto \ compile-with "${NORMAL_C} -I$S/crypto/blake2 -Wno-cast-qual -DSUFFIX=_ref -Wno-unused-function" crypto/blake2/blake2-sw.c optional crypto \ compile-with "${NORMAL_C} -I$S/crypto/blake2 -Wno-cast-qual" crypto/camellia/camellia.c optional crypto crypto/camellia/camellia-api.c optional crypto crypto/chacha20/chacha.c standard crypto/chacha20/chacha-sw.c optional crypto crypto/chacha20_poly1305.c optional crypto crypto/curve25519.c optional crypto \ compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include -I$S/crypto/libsodium" crypto/des/des_ecb.c optional netsmb crypto/des/des_setkey.c optional netsmb crypto/openssl/ossl.c optional ossl crypto/openssl/ossl_aes.c optional ossl crypto/openssl/ossl_chacha20.c optional ossl crypto/openssl/ossl_poly1305.c optional ossl crypto/openssl/ossl_sha1.c optional ossl crypto/openssl/ossl_sha256.c optional ossl crypto/openssl/ossl_sha512.c optional ossl crypto/rc4/rc4.c optional netgraph_mppc_encryption crypto/rijndael/rijndael-alg-fst.c optional crypto | ekcd | geom_bde | \ !random_loadable | wlan_ccmp crypto/rijndael/rijndael-api-fst.c optional ekcd | geom_bde | !random_loadable crypto/rijndael/rijndael-api.c optional crypto | wlan_ccmp crypto/sha1.c optional carp | crypto | ether | \ netgraph_mppc_encryption | sctp crypto/sha2/sha256c.c optional crypto | ekcd | geom_bde | \ !random_loadable | sctp | zfs crypto/sha2/sha512c.c optional crypto | geom_bde | zfs crypto/skein/skein.c optional crypto | zfs crypto/skein/skein_block.c optional crypto | zfs crypto/siphash/siphash.c optional inet | inet6 | wg crypto/siphash/siphash_test.c optional inet | inet6 | wg ddb/db_access.c optional ddb ddb/db_break.c optional ddb ddb/db_capture.c optional ddb ddb/db_command.c optional ddb ddb/db_examine.c optional ddb ddb/db_expr.c optional ddb ddb/db_input.c optional ddb ddb/db_lex.c optional ddb ddb/db_main.c optional ddb ddb/db_output.c optional ddb ddb/db_print.c optional ddb ddb/db_ps.c optional ddb ddb/db_run.c optional ddb ddb/db_script.c optional ddb ddb/db_sym.c optional ddb ddb/db_thread.c optional ddb ddb/db_textdump.c optional ddb ddb/db_variables.c optional ddb ddb/db_watch.c optional ddb ddb/db_write_cmd.c optional ddb dev/aac/aac.c optional aac dev/aac/aac_cam.c optional aacp aac dev/aac/aac_debug.c optional aac dev/aac/aac_disk.c optional aac dev/aac/aac_pci.c optional aac pci dev/aacraid/aacraid.c optional aacraid dev/aacraid/aacraid_cam.c optional aacraid scbus dev/aacraid/aacraid_debug.c optional aacraid dev/aacraid/aacraid_pci.c optional aacraid pci dev/acpi_support/acpi_wmi.c optional acpi_wmi acpi dev/acpi_support/acpi_asus.c optional acpi_asus acpi dev/acpi_support/acpi_asus_wmi.c optional acpi_asus_wmi acpi dev/acpi_support/acpi_fujitsu.c optional acpi_fujitsu acpi dev/acpi_support/acpi_hp.c optional acpi_hp acpi dev/acpi_support/acpi_ibm.c optional acpi_ibm acpi dev/acpi_support/acpi_panasonic.c optional acpi_panasonic acpi dev/acpi_support/acpi_sony.c optional acpi_sony acpi dev/acpi_support/acpi_toshiba.c optional acpi_toshiba acpi dev/acpi_support/atk0110.c optional aibs acpi dev/acpica/Osd/OsdDebug.c optional acpi dev/acpica/Osd/OsdHardware.c optional acpi dev/acpica/Osd/OsdInterrupt.c optional acpi dev/acpica/Osd/OsdMemory.c optional acpi dev/acpica/Osd/OsdSchedule.c optional acpi dev/acpica/Osd/OsdStream.c optional acpi dev/acpica/Osd/OsdSynch.c optional acpi dev/acpica/Osd/OsdTable.c optional acpi dev/acpica/acpi.c optional acpi dev/acpica/acpi_acad.c optional acpi dev/acpica/acpi_apei.c optional acpi dev/acpica/acpi_battery.c optional acpi dev/acpica/acpi_button.c optional acpi dev/acpica/acpi_cmbat.c optional acpi dev/acpica/acpi_cpu.c optional acpi dev/acpica/acpi_ec.c optional acpi dev/acpica/acpi_ged.c optional acpi_ged acpi dev/acpica/acpi_isab.c optional acpi isa dev/acpica/acpi_lid.c optional acpi dev/acpica/acpi_package.c optional acpi dev/acpica/acpi_perf.c optional acpi dev/acpica/acpi_powerres.c optional acpi dev/acpica/acpi_quirk.c optional acpi dev/acpica/acpi_resource.c optional acpi dev/acpica/acpi_container.c optional acpi dev/acpica/acpi_smbat.c optional acpi dev/acpica/acpi_thermal.c optional acpi dev/acpica/acpi_throttle.c optional acpi dev/acpica/acpi_video.c optional acpi_video acpi dev/acpica/acpi_dock.c optional acpi_dock acpi dev/adlink/adlink.c optional adlink dev/ae/if_ae.c optional ae pci dev/age/if_age.c optional age pci dev/agp/agp.c optional agp pci dev/agp/agp_if.m optional agp pci dev/ahci/ahci.c optional ahci dev/ahci/ahciem.c optional ahci dev/ahci/ahci_pci.c optional ahci pci dev/aic7xxx/ahc_isa.c optional ahc isa dev/aic7xxx/ahc_pci.c optional ahc pci \ compile-with "${NORMAL_C} ${NO_WCONSTANT_CONVERSION}" dev/aic7xxx/ahd_pci.c optional ahd pci \ compile-with "${NORMAL_C} ${NO_WCONSTANT_CONVERSION}" dev/aic7xxx/aic7770.c optional ahc dev/aic7xxx/aic79xx.c optional ahd pci dev/aic7xxx/aic79xx_osm.c optional ahd pci dev/aic7xxx/aic79xx_pci.c optional ahd pci dev/aic7xxx/aic79xx_reg_print.c optional ahd pci ahd_reg_pretty_print dev/aic7xxx/aic7xxx.c optional ahc dev/aic7xxx/aic7xxx_93cx6.c optional ahc dev/aic7xxx/aic7xxx_osm.c optional ahc dev/aic7xxx/aic7xxx_pci.c optional ahc pci dev/aic7xxx/aic7xxx_reg_print.c optional ahc ahc_reg_pretty_print dev/al_eth/al_eth.c optional al_eth fdt \ no-depend \ compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${.IMPSRC}" dev/al_eth/al_init_eth_lm.c optional al_eth fdt \ no-depend \ compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${.IMPSRC}" dev/al_eth/al_init_eth_kr.c optional al_eth fdt \ no-depend \ compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${.IMPSRC}" contrib/alpine-hal/al_hal_iofic.c optional al_iofic \ no-depend \ compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${.IMPSRC}" contrib/alpine-hal/al_hal_serdes_25g.c optional al_serdes \ no-depend \ compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${.IMPSRC}" contrib/alpine-hal/al_hal_serdes_hssp.c optional al_serdes \ no-depend \ compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${.IMPSRC}" contrib/alpine-hal/al_hal_udma_config.c optional al_udma \ no-depend \ compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${.IMPSRC}" contrib/alpine-hal/al_hal_udma_debug.c optional al_udma \ no-depend \ compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${.IMPSRC}" contrib/alpine-hal/al_hal_udma_iofic.c optional al_udma \ no-depend \ compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${.IMPSRC}" contrib/alpine-hal/al_hal_udma_main.c optional al_udma \ no-depend \ compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${.IMPSRC}" contrib/alpine-hal/al_serdes.c optional al_serdes \ no-depend \ compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${.IMPSRC}" contrib/alpine-hal/eth/al_hal_eth_kr.c optional al_eth \ no-depend \ compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${.IMPSRC}" contrib/alpine-hal/eth/al_hal_eth_main.c optional al_eth \ no-depend \ compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${.IMPSRC}" dev/alc/if_alc.c optional alc pci dev/ale/if_ale.c optional ale pci dev/alpm/alpm.c optional alpm pci dev/altera/avgen/altera_avgen.c optional altera_avgen dev/altera/avgen/altera_avgen_fdt.c optional altera_avgen fdt dev/altera/avgen/altera_avgen_nexus.c optional altera_avgen dev/altera/msgdma/msgdma.c optional altera_msgdma xdma dev/altera/sdcard/altera_sdcard.c optional altera_sdcard dev/altera/sdcard/altera_sdcard_disk.c optional altera_sdcard dev/altera/sdcard/altera_sdcard_io.c optional altera_sdcard dev/altera/sdcard/altera_sdcard_fdt.c optional altera_sdcard fdt dev/altera/sdcard/altera_sdcard_nexus.c optional altera_sdcard dev/altera/softdma/softdma.c optional altera_softdma xdma fdt dev/altera/pio/pio.c optional altera_pio dev/altera/pio/pio_if.m optional altera_pio dev/amdpm/amdpm.c optional amdpm pci | nfpm pci dev/amdsmb/amdsmb.c optional amdsmb pci # dev/ata/ata_if.m optional ata | atacore dev/ata/ata-all.c optional ata | atacore dev/ata/ata-dma.c optional ata | atacore dev/ata/ata-lowlevel.c optional ata | atacore dev/ata/ata-sata.c optional ata | atacore dev/ata/ata-isa.c optional ata isa | ataisa dev/ata/ata-pci.c optional ata pci | atapci dev/ata/chipsets/ata-acard.c optional ata pci | ataacard dev/ata/chipsets/ata-acerlabs.c optional ata pci | ataacerlabs dev/ata/chipsets/ata-amd.c optional ata pci | ataamd dev/ata/chipsets/ata-ati.c optional ata pci | ataati dev/ata/chipsets/ata-cenatek.c optional ata pci | atacenatek dev/ata/chipsets/ata-cypress.c optional ata pci | atacypress dev/ata/chipsets/ata-cyrix.c optional ata pci | atacyrix dev/ata/chipsets/ata-highpoint.c optional ata pci | atahighpoint dev/ata/chipsets/ata-intel.c optional ata pci | ataintel dev/ata/chipsets/ata-ite.c optional ata pci | ataite dev/ata/chipsets/ata-jmicron.c optional ata pci | atajmicron dev/ata/chipsets/ata-marvell.c optional ata pci | atamarvell dev/ata/chipsets/ata-micron.c optional ata pci | atamicron dev/ata/chipsets/ata-national.c optional ata pci | atanational dev/ata/chipsets/ata-netcell.c optional ata pci | atanetcell dev/ata/chipsets/ata-nvidia.c optional ata pci | atanvidia dev/ata/chipsets/ata-promise.c optional ata pci | atapromise dev/ata/chipsets/ata-serverworks.c optional ata pci | ataserverworks dev/ata/chipsets/ata-siliconimage.c optional ata pci | atasiliconimage | ataati dev/ata/chipsets/ata-sis.c optional ata pci | atasis dev/ata/chipsets/ata-via.c optional ata pci | atavia # dev/ath/if_ath.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_alq.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_beacon.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_btcoex.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_btcoex_mci.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_debug.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_descdma.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_keycache.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_ioctl.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_led.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_lna_div.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_pci.c optional ath pci \ compile-with "${ATH_C}" dev/ath/if_ath_tx.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_tx_edma.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_tx_ht.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_tdma.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_sysctl.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_rx.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_rx_edma.c optional ath \ compile-with "${ATH_C}" dev/ath/if_ath_spectral.c optional ath \ compile-with "${ATH_C}" dev/ath/ah_osdep.c optional ath \ compile-with "${ATH_C}" # dev/ath/ath_hal/ah.c optional ath \ compile-with "${ATH_C}" dev/ath/ath_hal/ah_eeprom_v1.c optional ath_hal | ath_ar5210 \ compile-with "${ATH_C}" dev/ath/ath_hal/ah_eeprom_v3.c optional ath_hal | ath_ar5211 | ath_ar5212 \ compile-with "${ATH_C}" dev/ath/ath_hal/ah_eeprom_v14.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 \ compile-with "${ATH_C}" dev/ath/ath_hal/ah_eeprom_v4k.c \ optional ath_hal | ath_ar9285 \ compile-with "${ATH_C}" dev/ath/ath_hal/ah_eeprom_9287.c \ optional ath_hal | ath_ar9287 \ compile-with "${ATH_C}" dev/ath/ath_hal/ah_regdomain.c optional ath \ compile-with "${ATH_C} ${NO_WSHIFT_COUNT_NEGATIVE} ${NO_WSHIFT_COUNT_OVERFLOW}" # ar5210 dev/ath/ath_hal/ar5210/ar5210_attach.c optional ath_hal | ath_ar5210 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5210/ar5210_beacon.c optional ath_hal | ath_ar5210 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5210/ar5210_interrupts.c optional ath_hal | ath_ar5210 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5210/ar5210_keycache.c optional ath_hal | ath_ar5210 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5210/ar5210_misc.c optional ath_hal | ath_ar5210 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5210/ar5210_phy.c optional ath_hal | ath_ar5210 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5210/ar5210_power.c optional ath_hal | ath_ar5210 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5210/ar5210_recv.c optional ath_hal | ath_ar5210 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5210/ar5210_reset.c optional ath_hal | ath_ar5210 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5210/ar5210_xmit.c optional ath_hal | ath_ar5210 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" # ar5211 dev/ath/ath_hal/ar5211/ar5211_attach.c optional ath_hal | ath_ar5211 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5211/ar5211_beacon.c optional ath_hal | ath_ar5211 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5211/ar5211_interrupts.c optional ath_hal | ath_ar5211 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5211/ar5211_keycache.c optional ath_hal | ath_ar5211 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5211/ar5211_misc.c optional ath_hal | ath_ar5211 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5211/ar5211_phy.c optional ath_hal | ath_ar5211 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5211/ar5211_power.c optional ath_hal | ath_ar5211 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5211/ar5211_recv.c optional ath_hal | ath_ar5211 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5211/ar5211_reset.c optional ath_hal | ath_ar5211 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5211/ar5211_xmit.c optional ath_hal | ath_ar5211 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" # ar5212 dev/ath/ath_hal/ar5212/ar5212_ani.c \ optional ath_hal | ath_ar5212 | ath_ar5416 | ath_ar9160 | ath_ar9280 | \ ath_ar9285 ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar5212_attach.c \ optional ath_hal | ath_ar5212 | ath_ar5416 | ath_ar9160 | ath_ar9280 | \ ath_ar9285 ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar5212_beacon.c \ optional ath_hal | ath_ar5212 | ath_ar5416 | ath_ar9160 | ath_ar9280 | \ ath_ar9285 ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar5212_eeprom.c \ optional ath_hal | ath_ar5212 | ath_ar5416 | ath_ar9160 | ath_ar9280 | \ ath_ar9285 ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar5212_gpio.c \ optional ath_hal | ath_ar5212 | ath_ar5416 | ath_ar9160 | ath_ar9280 | \ ath_ar9285 ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar5212_interrupts.c \ optional ath_hal | ath_ar5212 | ath_ar5416 | ath_ar9160 | ath_ar9280 | \ ath_ar9285 ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar5212_keycache.c \ optional ath_hal | ath_ar5212 | ath_ar5416 | ath_ar9160 | ath_ar9280 | \ ath_ar9285 ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar5212_misc.c \ optional ath_hal | ath_ar5212 | ath_ar5416 | ath_ar9160 | ath_ar9280 | \ ath_ar9285 ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar5212_phy.c \ optional ath_hal | ath_ar5212 | ath_ar5416 | ath_ar9160 | ath_ar9280 | \ ath_ar9285 ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar5212_power.c \ optional ath_hal | ath_ar5212 | ath_ar5416 | ath_ar9160 | ath_ar9280 | \ ath_ar9285 ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar5212_recv.c \ optional ath_hal | ath_ar5212 | ath_ar5416 | ath_ar9160 | ath_ar9280 | \ ath_ar9285 ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar5212_reset.c \ optional ath_hal | ath_ar5212 | ath_ar5416 | ath_ar9160 | ath_ar9280 | \ ath_ar9285 ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar5212_rfgain.c \ optional ath_hal | ath_ar5212 | ath_ar5416 | ath_ar9160 | ath_ar9280 | \ ath_ar9285 ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar5212_xmit.c \ optional ath_hal | ath_ar5212 | ath_ar5416 | ath_ar9160 | ath_ar9280 | \ ath_ar9285 ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" # ar5416 (depends on ar5212) dev/ath/ath_hal/ar5416/ar5416_ani.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_attach.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_beacon.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_btcoex.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_cal.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_cal_iq.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_cal_adcgain.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_cal_adcdc.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_eeprom.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_gpio.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_interrupts.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_keycache.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_misc.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_phy.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_power.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_radar.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_recv.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_reset.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_spectral.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar5416_xmit.c \ optional ath_hal | ath_ar5416 | ath_ar9160 | ath_ar9280 | ath_ar9285 | \ ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" # ar9160 (depends on ar5416) dev/ath/ath_hal/ar9001/ar9160_attach.c optional ath_hal | ath_ar9160 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" # ar9280 (depends on ar5416) dev/ath/ath_hal/ar9002/ar9280_attach.c optional ath_hal | ath_ar9280 | \ ath_ar9285 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar9002/ar9280_olc.c optional ath_hal | ath_ar9280 | \ ath_ar9285 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" # ar9285 (depends on ar5416 and ar9280) dev/ath/ath_hal/ar9002/ar9285_attach.c optional ath_hal | ath_ar9285 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar9002/ar9285_btcoex.c optional ath_hal | ath_ar9285 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar9002/ar9285_reset.c optional ath_hal | ath_ar9285 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar9002/ar9285_cal.c optional ath_hal | ath_ar9285 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar9002/ar9285_phy.c optional ath_hal | ath_ar9285 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar9002/ar9285_diversity.c optional ath_hal | ath_ar9285 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" # ar9287 (depends on ar5416) dev/ath/ath_hal/ar9002/ar9287_attach.c optional ath_hal | ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar9002/ar9287_reset.c optional ath_hal | ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar9002/ar9287_cal.c optional ath_hal | ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar9002/ar9287_olc.c optional ath_hal | ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" # ar9300 contrib/dev/ath/ath_hal/ar9300/ar9300_ani.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_attach.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_beacon.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_eeprom.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal ${NO_WCONSTANT_CONVERSION}" contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_gpio.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_interrupts.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_keycache.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_mci.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_misc.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_paprd.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_phy.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_power.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_radar.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_radio.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_recv.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_recv_ds.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal ${NO_WSOMETIMES_UNINITIALIZED} -Wno-unused-function" contrib/dev/ath/ath_hal/ar9300/ar9300_stub.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_stub_funcs.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_spectral.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_timer.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_xmit.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" contrib/dev/ath/ath_hal/ar9300/ar9300_xmit_ds.c optional ath_hal | ath_ar9300 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal" # rf backends dev/ath/ath_hal/ar5212/ar2316.c optional ath_rf2316 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar2317.c optional ath_rf2317 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar2413.c optional ath_hal | ath_rf2413 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar2425.c optional ath_hal | ath_rf2425 | ath_rf2417 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar5111.c optional ath_hal | ath_rf5111 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar5112.c optional ath_hal | ath_rf5112 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5212/ar5413.c optional ath_hal | ath_rf5413 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar5416/ar2133.c optional ath_hal | ath_ar5416 | \ ath_ar9130 | ath_ar9160 | ath_ar9280 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar9002/ar9280.c optional ath_hal | ath_ar9280 | ath_ar9285 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar9002/ar9285.c optional ath_hal | ath_ar9285 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" dev/ath/ath_hal/ar9002/ar9287.c optional ath_hal | ath_ar9287 \ compile-with "${ATH_C} -I$S/dev/ath/ath_hal" # ath rate control algorithms dev/ath/ath_rate/amrr/amrr.c optional ath_rate_amrr \ compile-with "${ATH_C}" dev/ath/ath_rate/onoe/onoe.c optional ath_rate_onoe \ compile-with "${ATH_C}" dev/ath/ath_rate/sample/sample.c optional ath_rate_sample \ compile-with "${ATH_C}" # ath DFS modules dev/ath/ath_dfs/null/dfs_null.c optional ath \ compile-with "${ATH_C}" # dev/backlight/backlight_if.m optional backlight | compat_linuxkpi dev/backlight/backlight.c optional backlight | compat_linuxkpi dev/bce/if_bce.c optional bce dev/bfe/if_bfe.c optional bfe dev/bge/if_bge.c optional bge dev/bhnd/bhnd.c optional bhnd dev/bhnd/bhnd_erom.c optional bhnd dev/bhnd/bhnd_erom_if.m optional bhnd dev/bhnd/bhnd_subr.c optional bhnd dev/bhnd/bhnd_bus_if.m optional bhnd dev/bhnd/bhndb/bhnd_bhndb.c optional bhndb bhnd dev/bhnd/bhndb/bhndb.c optional bhndb bhnd dev/bhnd/bhndb/bhndb_bus_if.m optional bhndb bhnd dev/bhnd/bhndb/bhndb_hwdata.c optional bhndb bhnd dev/bhnd/bhndb/bhndb_if.m optional bhndb bhnd dev/bhnd/bhndb/bhndb_pci.c optional bhndb_pci bhndb bhnd pci dev/bhnd/bhndb/bhndb_pci_hwdata.c optional bhndb_pci bhndb bhnd pci dev/bhnd/bhndb/bhndb_pci_sprom.c optional bhndb_pci bhndb bhnd pci dev/bhnd/bhndb/bhndb_subr.c optional bhndb bhnd dev/bhnd/bcma/bcma.c optional bcma bhnd dev/bhnd/bcma/bcma_bhndb.c optional bcma bhnd bhndb dev/bhnd/bcma/bcma_erom.c optional bcma bhnd dev/bhnd/bcma/bcma_subr.c optional bcma bhnd dev/bhnd/cores/chipc/bhnd_chipc_if.m optional bhnd dev/bhnd/cores/chipc/bhnd_sprom_chipc.c optional bhnd dev/bhnd/cores/chipc/bhnd_pmu_chipc.c optional bhnd dev/bhnd/cores/chipc/chipc.c optional bhnd dev/bhnd/cores/chipc/chipc_cfi.c optional bhnd cfi dev/bhnd/cores/chipc/chipc_gpio.c optional bhnd gpio dev/bhnd/cores/chipc/chipc_slicer.c optional bhnd cfi | bhnd spibus dev/bhnd/cores/chipc/chipc_spi.c optional bhnd spibus dev/bhnd/cores/chipc/chipc_subr.c optional bhnd dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c optional bhnd dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_if.m optional bhnd dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_hostb_if.m optional bhnd dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c optional bhnd dev/bhnd/cores/pci/bhnd_pci.c optional bhnd pci dev/bhnd/cores/pci/bhnd_pci_hostb.c optional bhndb bhnd pci dev/bhnd/cores/pci/bhnd_pcib.c optional bhnd_pcib bhnd pci dev/bhnd/cores/pcie2/bhnd_pcie2.c optional bhnd pci dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c optional bhndb bhnd pci dev/bhnd/cores/pcie2/bhnd_pcie2b.c optional bhnd_pcie2b bhnd pci dev/bhnd/cores/pmu/bhnd_pmu.c optional bhnd dev/bhnd/cores/pmu/bhnd_pmu_core.c optional bhnd dev/bhnd/cores/pmu/bhnd_pmu_if.m optional bhnd dev/bhnd/cores/pmu/bhnd_pmu_subr.c optional bhnd dev/bhnd/nvram/bhnd_nvram_data.c optional bhnd dev/bhnd/nvram/bhnd_nvram_data_bcm.c optional bhnd dev/bhnd/nvram/bhnd_nvram_data_bcmraw.c optional bhnd dev/bhnd/nvram/bhnd_nvram_data_btxt.c optional bhnd dev/bhnd/nvram/bhnd_nvram_data_sprom.c optional bhnd dev/bhnd/nvram/bhnd_nvram_data_sprom_subr.c optional bhnd dev/bhnd/nvram/bhnd_nvram_data_tlv.c optional bhnd dev/bhnd/nvram/bhnd_nvram_if.m optional bhnd dev/bhnd/nvram/bhnd_nvram_io.c optional bhnd dev/bhnd/nvram/bhnd_nvram_iobuf.c optional bhnd dev/bhnd/nvram/bhnd_nvram_ioptr.c optional bhnd dev/bhnd/nvram/bhnd_nvram_iores.c optional bhnd dev/bhnd/nvram/bhnd_nvram_plist.c optional bhnd dev/bhnd/nvram/bhnd_nvram_store.c optional bhnd dev/bhnd/nvram/bhnd_nvram_store_subr.c optional bhnd dev/bhnd/nvram/bhnd_nvram_subr.c optional bhnd dev/bhnd/nvram/bhnd_nvram_value.c optional bhnd dev/bhnd/nvram/bhnd_nvram_value_fmts.c optional bhnd dev/bhnd/nvram/bhnd_nvram_value_prf.c optional bhnd dev/bhnd/nvram/bhnd_nvram_value_subr.c optional bhnd dev/bhnd/nvram/bhnd_sprom.c optional bhnd dev/bhnd/siba/siba.c optional siba bhnd dev/bhnd/siba/siba_bhndb.c optional siba bhnd bhndb dev/bhnd/siba/siba_erom.c optional siba bhnd dev/bhnd/siba/siba_subr.c optional siba bhnd # dev/bnxt/bnxt_hwrm.c optional bnxt iflib pci dev/bnxt/bnxt_mgmt.c optional bnxt iflib pci dev/bnxt/bnxt_sysctl.c optional bnxt iflib pci dev/bnxt/bnxt_txrx.c optional bnxt iflib pci dev/bnxt/if_bnxt.c optional bnxt iflib pci dev/bwi/bwimac.c optional bwi dev/bwi/bwiphy.c optional bwi dev/bwi/bwirf.c optional bwi dev/bwi/if_bwi.c optional bwi dev/bwi/if_bwi_pci.c optional bwi pci dev/bwn/if_bwn.c optional bwn bhnd dev/bwn/if_bwn_pci.c optional bwn pci bhnd bhndb bhndb_pci dev/bwn/if_bwn_phy_common.c optional bwn bhnd dev/bwn/if_bwn_phy_g.c optional bwn bhnd dev/bwn/if_bwn_phy_lp.c optional bwn bhnd dev/bwn/if_bwn_phy_n.c optional bwn bhnd dev/bwn/if_bwn_util.c optional bwn bhnd dev/cadence/if_cgem.c optional cgem fdt dev/cardbus/card_if.m standard dev/cardbus/cardbus.c optional cardbus dev/cardbus/cardbus_cis.c optional cardbus dev/cardbus/cardbus_device.c optional cardbus dev/cardbus/power_if.m standard dev/cas/if_cas.c optional cas dev/cfi/cfi_bus_fdt.c optional cfi fdt dev/cfi/cfi_bus_nexus.c optional cfi dev/cfi/cfi_core.c optional cfi dev/cfi/cfi_dev.c optional cfi dev/cfi/cfi_disk.c optional cfid dev/chromebook_platform/chromebook_platform.c optional chromebook_platform dev/ciss/ciss.c optional ciss dev/clk/clk.c optional clk dev/clk/clkdev_if.m optional clk dev/clk/clknode_if.m optional clk dev/clk/clk_bus.c optional clk fdt dev/clk/clk_div.c optional clk dev/clk/clk_fixed.c optional clk dev/clk/clk_gate.c optional clk dev/clk/clk_link.c optional clk dev/clk/clk_mux.c optional clk dev/cpufreq/ichss.c optional cpufreq pci dev/cxgb/cxgb_main.c optional cxgb pci \ compile-with "${NORMAL_C} -I$S/dev/cxgb" dev/cxgb/cxgb_sge.c optional cxgb pci \ compile-with "${NORMAL_C} -I$S/dev/cxgb" dev/cxgb/common/cxgb_mc5.c optional cxgb pci \ compile-with "${NORMAL_C} -I$S/dev/cxgb" dev/cxgb/common/cxgb_vsc7323.c optional cxgb pci \ compile-with "${NORMAL_C} -I$S/dev/cxgb" dev/cxgb/common/cxgb_vsc8211.c optional cxgb pci \ compile-with "${NORMAL_C} -I$S/dev/cxgb" dev/cxgb/common/cxgb_ael1002.c optional cxgb pci \ compile-with "${NORMAL_C} -I$S/dev/cxgb" dev/cxgb/common/cxgb_aq100x.c optional cxgb pci \ compile-with "${NORMAL_C} -I$S/dev/cxgb" dev/cxgb/common/cxgb_mv88e1xxx.c optional cxgb pci \ compile-with "${NORMAL_C} -I$S/dev/cxgb" dev/cxgb/common/cxgb_xgmac.c optional cxgb pci \ compile-with "${NORMAL_C} -I$S/dev/cxgb" dev/cxgb/common/cxgb_t3_hw.c optional cxgb pci \ compile-with "${NORMAL_C} -I$S/dev/cxgb" dev/cxgb/common/cxgb_tn1010.c optional cxgb pci \ compile-with "${NORMAL_C} -I$S/dev/cxgb" dev/cxgb/sys/uipc_mvec.c optional cxgb pci \ compile-with "${NORMAL_C} -I$S/dev/cxgb" dev/cxgb/cxgb_t3fw.c optional cxgb cxgb_t3fw \ compile-with "${NORMAL_C} -I$S/dev/cxgb" dev/cxgbe/t4_clip.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/t4_filter.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/t4_if.m optional cxgbe pci dev/cxgbe/t4_iov.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/t4_mp_ring.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/t4_main.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/t4_netmap.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/t4_sched.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/t4_sge.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/t4_smt.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/t4_l2t.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/t4_tracer.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/t4_vf.c optional cxgbev pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/common/t4_hw.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/common/t4vf_hw.c optional cxgbev pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/crypto/t6_kern_tls.c optional cxgbe pci kern_tls \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/crypto/t4_keyctx.c optional cxgbe pci \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/cudbg/cudbg_common.c optional cxgbe \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/cudbg/cudbg_flash_utils.c optional cxgbe \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/cudbg/cudbg_lib.c optional cxgbe \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/cudbg/cudbg_wtp.c optional cxgbe \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/cudbg/fastlz.c optional cxgbe \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cxgbe/cudbg/fastlz_api.c optional cxgbe \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" t4fw_cfg.c optional cxgbe \ compile-with "${AWK} -f $S/tools/fw_stub.awk t4fw_cfg.fw:t4fw_cfg t4fw_cfg_uwire.fw:t4fw_cfg_uwire t4fw.fw:t4fw -mt4fw_cfg -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "t4fw_cfg.c" t4fw_cfg.fwo optional cxgbe \ dependency "t4fw_cfg.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "t4fw_cfg.fwo" t4fw_cfg.fw optional cxgbe \ dependency "$S/dev/cxgbe/firmware/t4fw_cfg.txt" \ compile-with "${CP} ${.ALLSRC} ${.TARGET}" \ no-obj no-implicit-rule \ clean "t4fw_cfg.fw" t4fw_cfg_uwire.fwo optional cxgbe \ dependency "t4fw_cfg_uwire.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "t4fw_cfg_uwire.fwo" t4fw_cfg_uwire.fw optional cxgbe \ dependency "$S/dev/cxgbe/firmware/t4fw_cfg_uwire.txt" \ compile-with "${CP} ${.ALLSRC} ${.TARGET}" \ no-obj no-implicit-rule \ clean "t4fw_cfg_uwire.fw" t4fw.fwo optional cxgbe \ dependency "t4fw.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "t4fw.fwo" t4fw.fw optional cxgbe \ dependency "$S/dev/cxgbe/firmware/t4fw-1.27.5.0.bin" \ compile-with "${CP} ${.ALLSRC} ${.TARGET}" \ no-obj no-implicit-rule \ clean "t4fw.fw" t5fw_cfg.c optional cxgbe \ compile-with "${AWK} -f $S/tools/fw_stub.awk t5fw_cfg.fw:t5fw_cfg t5fw_cfg_uwire.fw:t5fw_cfg_uwire t5fw.fw:t5fw -mt5fw_cfg -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "t5fw_cfg.c" t5fw_cfg.fwo optional cxgbe \ dependency "t5fw_cfg.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "t5fw_cfg.fwo" t5fw_cfg.fw optional cxgbe \ dependency "$S/dev/cxgbe/firmware/t5fw_cfg.txt" \ compile-with "${CP} ${.ALLSRC} ${.TARGET}" \ no-obj no-implicit-rule \ clean "t5fw_cfg.fw" t5fw_cfg_uwire.fwo optional cxgbe \ dependency "t5fw_cfg_uwire.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "t5fw_cfg_uwire.fwo" t5fw_cfg_uwire.fw optional cxgbe \ dependency "$S/dev/cxgbe/firmware/t5fw_cfg_uwire.txt" \ compile-with "${CP} ${.ALLSRC} ${.TARGET}" \ no-obj no-implicit-rule \ clean "t5fw_cfg_uwire.fw" t5fw.fwo optional cxgbe \ dependency "t5fw.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "t5fw.fwo" t5fw.fw optional cxgbe \ dependency "$S/dev/cxgbe/firmware/t5fw-1.27.5.0.bin" \ compile-with "${CP} ${.ALLSRC} ${.TARGET}" \ no-obj no-implicit-rule \ clean "t5fw.fw" t6fw_cfg.c optional cxgbe \ compile-with "${AWK} -f $S/tools/fw_stub.awk t6fw_cfg.fw:t6fw_cfg t6fw_cfg_uwire.fw:t6fw_cfg_uwire t6fw.fw:t6fw -mt6fw_cfg -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "t6fw_cfg.c" t6fw_cfg.fwo optional cxgbe \ dependency "t6fw_cfg.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "t6fw_cfg.fwo" t6fw_cfg.fw optional cxgbe \ dependency "$S/dev/cxgbe/firmware/t6fw_cfg.txt" \ compile-with "${CP} ${.ALLSRC} ${.TARGET}" \ no-obj no-implicit-rule \ clean "t6fw_cfg.fw" t6fw_cfg_uwire.fwo optional cxgbe \ dependency "t6fw_cfg_uwire.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "t6fw_cfg_uwire.fwo" t6fw_cfg_uwire.fw optional cxgbe \ dependency "$S/dev/cxgbe/firmware/t6fw_cfg_uwire.txt" \ compile-with "${CP} ${.ALLSRC} ${.TARGET}" \ no-obj no-implicit-rule \ clean "t6fw_cfg_uwire.fw" t6fw.fwo optional cxgbe \ dependency "t6fw.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "t6fw.fwo" t6fw.fw optional cxgbe \ dependency "$S/dev/cxgbe/firmware/t6fw-1.27.5.0.bin" \ compile-with "${CP} ${.ALLSRC} ${.TARGET}" \ no-obj no-implicit-rule \ clean "t6fw.fw" dev/cxgbe/crypto/t4_crypto.c optional ccr \ compile-with "${NORMAL_C} -I$S/dev/cxgbe" dev/cyapa/cyapa.c optional cyapa iicbus dev/dc/if_dc.c optional dc pci dev/dc/dcphy.c optional dc pci dev/dc/pnphy.c optional dc pci dev/dcons/dcons.c optional dcons dev/dcons/dcons_crom.c optional dcons_crom dev/dcons/dcons_os.c optional dcons dev/dialog/da9063/da9063_if.m optional da9063_pmic dev/dialog/da9063/da9063_iic.c optional da9063_pmic iicbus fdt dev/dialog/da9063/da9063_rtc.c optional da9063_rtc fdt dev/drm2/drm_agpsupport.c optional drm2 dev/drm2/drm_auth.c optional drm2 dev/drm2/drm_bufs.c optional drm2 dev/drm2/drm_buffer.c optional drm2 dev/drm2/drm_context.c optional drm2 dev/drm2/drm_crtc.c optional drm2 dev/drm2/drm_crtc_helper.c optional drm2 dev/drm2/drm_dma.c optional drm2 dev/drm2/drm_dp_helper.c optional drm2 dev/drm2/drm_dp_iic_helper.c optional drm2 dev/drm2/drm_drv.c optional drm2 dev/drm2/drm_edid.c optional drm2 dev/drm2/drm_fb_helper.c optional drm2 dev/drm2/drm_fops.c optional drm2 dev/drm2/drm_gem.c optional drm2 dev/drm2/drm_gem_names.c optional drm2 dev/drm2/drm_global.c optional drm2 dev/drm2/drm_hashtab.c optional drm2 dev/drm2/drm_ioctl.c optional drm2 dev/drm2/drm_irq.c optional drm2 dev/drm2/drm_linux_list_sort.c optional drm2 dev/drm2/drm_lock.c optional drm2 dev/drm2/drm_memory.c optional drm2 dev/drm2/drm_mm.c optional drm2 dev/drm2/drm_modes.c optional drm2 dev/drm2/drm_pci.c optional drm2 dev/drm2/drm_platform.c optional drm2 dev/drm2/drm_scatter.c optional drm2 dev/drm2/drm_stub.c optional drm2 dev/drm2/drm_sysctl.c optional drm2 dev/drm2/drm_vm.c optional drm2 dev/drm2/drm_os_freebsd.c optional drm2 dev/drm2/ttm/ttm_agp_backend.c optional drm2 dev/drm2/ttm/ttm_lock.c optional drm2 dev/drm2/ttm/ttm_object.c optional drm2 dev/drm2/ttm/ttm_tt.c optional drm2 dev/drm2/ttm/ttm_bo_util.c optional drm2 dev/drm2/ttm/ttm_bo.c optional drm2 dev/drm2/ttm/ttm_bo_manager.c optional drm2 dev/drm2/ttm/ttm_execbuf_util.c optional drm2 dev/drm2/ttm/ttm_memory.c optional drm2 dev/drm2/ttm/ttm_page_alloc.c optional drm2 dev/drm2/ttm/ttm_bo_vm.c optional drm2 dev/efidev/efidev.c optional efirt dev/efidev/efirt.c optional efirt dev/efidev/efirtc.c optional efirt dev/e1000/if_em.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/em_txrx.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/igb_txrx.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_80003es2lan.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_82540.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_82541.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_82542.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_82543.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_82571.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_82575.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_ich8lan.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_i210.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_api.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_base.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_mac.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_manage.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_nvm.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_phy.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_vf.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_mbx.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/e1000/e1000_osdep.c optional em \ compile-with "${NORMAL_C} -I$S/dev/e1000" dev/et/if_et.c optional et dev/ena/ena.c optional ena \ compile-with "${NORMAL_C} -I$S/contrib" dev/ena/ena_datapath.c optional ena \ compile-with "${NORMAL_C} -I$S/contrib" dev/ena/ena_netmap.c optional ena \ compile-with "${NORMAL_C} -I$S/contrib" dev/ena/ena_rss.c optional ena \ compile-with "${NORMAL_C} -I$S/contrib" dev/ena/ena_sysctl.c optional ena \ compile-with "${NORMAL_C} -I$S/contrib" contrib/ena-com/ena_com.c optional ena contrib/ena-com/ena_eth_com.c optional ena dev/etherswitch/arswitch/arswitch.c optional arswitch dev/etherswitch/arswitch/arswitch_reg.c optional arswitch dev/etherswitch/arswitch/arswitch_phy.c optional arswitch dev/etherswitch/arswitch/arswitch_8216.c optional arswitch dev/etherswitch/arswitch/arswitch_8226.c optional arswitch dev/etherswitch/arswitch/arswitch_8316.c optional arswitch dev/etherswitch/arswitch/arswitch_8327.c optional arswitch dev/etherswitch/arswitch/arswitch_vlans.c optional arswitch dev/etherswitch/etherswitch.c optional etherswitch dev/etherswitch/etherswitch_if.m optional etherswitch dev/etherswitch/ip17x/ip17x.c optional ip17x dev/etherswitch/ip17x/ip175c.c optional ip17x dev/etherswitch/ip17x/ip175d.c optional ip17x dev/etherswitch/ip17x/ip17x_phy.c optional ip17x dev/etherswitch/ip17x/ip17x_vlans.c optional ip17x dev/etherswitch/miiproxy.c optional miiproxy dev/etherswitch/rtl8366/rtl8366rb.c optional rtl8366rb dev/etherswitch/e6000sw/e6000sw.c optional e6000sw fdt dev/etherswitch/e6000sw/e6060sw.c optional e6060sw dev/etherswitch/infineon/adm6996fc.c optional adm6996fc dev/etherswitch/micrel/ksz8995ma.c optional ksz8995ma dev/etherswitch/ukswitch/ukswitch.c optional ukswitch dev/evdev/cdev.c optional evdev dev/evdev/evdev.c optional evdev dev/evdev/evdev_mt.c optional evdev dev/evdev/evdev_utils.c optional evdev dev/evdev/uinput.c optional evdev uinput dev/exca/exca.c optional cbb dev/extres/phy/phy.c optional phy dev/extres/phy/phydev_if.m optional phy fdt dev/extres/phy/phynode_if.m optional phy dev/extres/phy/phy_usb.c optional phy dev/extres/phy/phynode_usb_if.m optional phy -dev/extres/regulator/regdev_if.m optional regulator fdt -dev/extres/regulator/regnode_if.m optional regulator -dev/extres/regulator/regulator.c optional regulator -dev/extres/regulator/regulator_bus.c optional regulator fdt -dev/extres/regulator/regulator_fixed.c optional regulator dev/extres/syscon/syscon.c optional syscon dev/extres/syscon/syscon_generic.c optional syscon fdt dev/extres/syscon/syscon_if.m optional syscon dev/extres/syscon/syscon_power.c optional syscon syscon_power dev/fb/fbd.c optional fbd | vt dev/fb/fb_if.m standard dev/fb/splash.c optional sc splash dev/fdt/fdt_clock.c optional fdt fdt_clock dev/fdt/fdt_clock_if.m optional fdt fdt_clock dev/fdt/fdt_common.c optional fdt dev/fdt/fdt_pinctrl.c optional fdt fdt_pinctrl dev/fdt/fdt_pinctrl_if.m optional fdt fdt_pinctrl dev/fdt/fdt_slicer.c optional fdt cfi | fdt mx25l | fdt n25q | fdt at45d dev/fdt/fdt_static_dtb.S optional fdt fdt_dtb_static \ dependency "${FDT_DTS_FILE:T:R}.dtb" dev/fdt/simplebus.c optional fdt dev/fdt/simple_mfd.c optional syscon fdt dev/filemon/filemon.c optional filemon dev/firewire/firewire.c optional firewire dev/firewire/fwcrom.c optional firewire dev/firewire/fwdev.c optional firewire dev/firewire/fwdma.c optional firewire dev/firewire/fwmem.c optional firewire dev/firewire/fwohci.c optional firewire dev/firewire/fwohci_pci.c optional firewire pci dev/firewire/if_fwe.c optional fwe dev/firewire/if_fwip.c optional fwip dev/firewire/sbp.c optional sbp dev/firewire/sbp_targ.c optional sbp_targ dev/flash/at45d.c optional at45d dev/flash/cqspi.c optional cqspi fdt xdma dev/flash/mx25l.c optional mx25l dev/flash/n25q.c optional n25q fdt dev/flash/qspi_if.m optional cqspi fdt | n25q fdt dev/fxp/if_fxp.c optional fxp dev/fxp/inphy.c optional fxp dev/gem/if_gem.c optional gem dev/gem/if_gem_pci.c optional gem pci dev/gve/gve_adminq.c optional gve dev/gve/gve_main.c optional gve dev/gve/gve_qpl.c optional gve dev/gve/gve_rx.c optional gve dev/gve/gve_sysctl.c optional gve dev/gve/gve_tx.c optional gve dev/gve/gve_utils.c optional gve dev/goldfish/goldfish_rtc.c optional goldfish_rtc fdt dev/gpio/dwgpio/dwgpio.c optional gpio dwgpio fdt dev/gpio/dwgpio/dwgpio_bus.c optional gpio dwgpio fdt dev/gpio/dwgpio/dwgpio_if.m optional gpio dwgpio fdt dev/gpio/gpiobacklight.c optional gpiobacklight fdt dev/gpio/gpiokeys.c optional gpiokeys fdt dev/gpio/gpiokeys_codes.c optional gpiokeys fdt dev/gpio/gpiobus.c optional gpio \ dependency "gpiobus_if.h" dev/gpio/gpioc.c optional gpio \ dependency "gpio_if.h" dev/gpio/gpioiic.c optional gpioiic dev/gpio/gpioled.c optional gpioled !fdt dev/gpio/gpioled_fdt.c optional gpioled fdt dev/gpio/gpiomdio.c optional gpiomdio mii_bitbang dev/gpio/gpiopower.c optional gpiopower fdt dev/gpio/gpioregulator.c optional gpioregulator fdt dev/gpio/gpiospi.c optional gpiospi dev/gpio/gpioths.c optional gpioths dev/gpio/gpio_if.m optional gpio dev/gpio/gpiobus_if.m optional gpio dev/gpio/gpiopps.c optional gpiopps fdt dev/gpio/ofw_gpiobus.c optional fdt gpio dev/hid/bcm5974.c optional bcm5974 dev/hid/hconf.c optional hconf dev/hid/hcons.c optional hcons dev/hid/hgame.c optional hgame dev/hid/hid.c optional hid dev/hid/hid_if.m optional hid dev/hid/hidbus.c optional hidbus dev/hid/hidmap.c optional hidmap dev/hid/hidquirk.c optional hid dev/hid/hidraw.c optional hidraw dev/hid/hkbd.c optional hkbd dev/hid/hms.c optional hms dev/hid/hmt.c optional hmt hconf dev/hid/hpen.c optional hpen dev/hid/hsctrl.c optional hsctrl dev/hid/ietp.c optional ietp dev/hid/ps4dshock.c optional ps4dshock dev/hid/xb360gp.c optional xb360gp dev/hifn/hifn7751.c optional hifn dev/hptiop/hptiop.c optional hptiop scbus dev/hwpmc/hwpmc_logging.c optional hwpmc dev/hwpmc/hwpmc_mod.c optional hwpmc dev/hwpmc/hwpmc_soft.c optional hwpmc dev/hwreset/hwreset.c optional hwreset dev/hwreset/hwreset_array.c optional hwreset dev/hwreset/hwreset_if.m optional hwreset dev/ichiic/ig4_acpi.c optional ig4 acpi iicbus dev/ichiic/ig4_iic.c optional ig4 iicbus dev/ichiic/ig4_pci.c optional ig4 pci iicbus dev/ichsmb/ichsmb.c optional ichsmb dev/ichsmb/ichsmb_pci.c optional ichsmb pci dev/ida/ida.c optional ida dev/ida/ida_disk.c optional ida dev/ida/ida_pci.c optional ida pci dev/iicbus/acpi_iicbus.c optional acpi iicbus | acpi compat_linuxkpi dev/iicbus/icee.c optional icee dev/iicbus/if_ic.c optional ic dev/iicbus/iic.c optional iic dev/iicbus/iic_recover_bus.c optional iicbus | compat_linuxkpi dev/iicbus/iicbb.c optional iicbb | compat_linuxkpi dev/iicbus/iicbb_if.m optional iicbb | compat_linuxkpi dev/iicbus/iicbus.c optional iicbus | compat_linuxkpi dev/iicbus/iicbus_if.m optional iicbus | compat_linuxkpi dev/iicbus/iichid.c optional iichid acpi hid iicbus dev/iicbus/iiconf.c optional iicbus | compat_linuxkpi dev/iicbus/iicsmb.c optional iicsmb \ dependency "iicbus_if.h" dev/iicbus/adc/ad7418.c optional ad7418 dev/iicbus/adc/ads111x.c optional ads111x dev/iicbus/adc/pcf8591.c optional pcf8591 dev/iicbus/controller/opencores/iicoc.c optional iicoc dev/iicbus/controller/opencores/iicoc_fdt.c optional iicoc fdt dev/iicbus/controller/opencores/iicoc_pci.c optional iicoc pci dev/iicbus/mux/iicmux.c optional iicmux dev/iicbus/mux/iicmux_if.m optional iicmux dev/iicbus/mux/iic_gpiomux.c optional iic_gpiomux fdt dev/iicbus/mux/ltc430x.c optional ltc430x dev/iicbus/mux/pca954x.c optional pca954x iicbus iicmux dev/iicbus/ofw_iicbus.c optional fdt iicbus dev/iicbus/ofw_iicbus_if.m optional fdt iicbus dev/iicbus/rtc/ds1307.c optional ds1307 dev/iicbus/rtc/ds13rtc.c optional ds13rtc | ds133x | ds1374 dev/iicbus/rtc/ds1672.c optional ds1672 dev/iicbus/rtc/ds3231.c optional ds3231 dev/iicbus/rtc/isl12xx.c optional isl12xx dev/iicbus/rtc/nxprtc.c optional nxprtc | pcf8563 dev/iicbus/rtc/pcf85063.c optional pcf85063 iicbus fdt dev/iicbus/rtc/rtc8583.c optional rtc8583 dev/iicbus/rtc/rv3032.c optional rv3032 iicbus fdt dev/iicbus/rtc/rx8803.c optional rx8803 iicbus fdt dev/iicbus/rtc/s35390a.c optional s35390a dev/iicbus/sensor/htu21.c optional htu21 dev/iicbus/sensor/lm75.c optional lm75 dev/iicbus/sensor/max44009.c optional max44009 dev/iicbus/gpio/pcf8574.c optional pcf8574 dev/iicbus/gpio/tca64xx.c optional tca64xx fdt gpio dev/iicbus/pmic/fan53555.c optional fan53555 fdt | tcs4525 fdt dev/iicbus/pmic/silergy/sy8106a.c optional sy8106a fdt dev/iicbus/pmic/silergy/syr827.c optional syr827 fdt dev/igc/if_igc.c optional igc iflib pci dev/igc/igc_api.c optional igc iflib pci dev/igc/igc_base.c optional igc iflib pci dev/igc/igc_i225.c optional igc iflib pci dev/igc/igc_mac.c optional igc iflib pci dev/igc/igc_nvm.c optional igc iflib pci dev/igc/igc_phy.c optional igc iflib pci dev/igc/igc_txrx.c optional igc iflib pci dev/intpm/intpm.c optional intpm pci # XXX Work around clang warning, until maintainer approves fix. dev/ips/ips.c optional ips \ compile-with "${NORMAL_C} ${NO_WSOMETIMES_UNINITIALIZED}" dev/ips/ips_commands.c optional ips dev/ips/ips_disk.c optional ips dev/ips/ips_ioctl.c optional ips dev/ips/ips_pci.c optional ips pci dev/ipw/if_ipw.c optional ipw ipwbssfw.c optional ipwbssfw | ipwfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk ipw_bss.fw:ipw_bss:130 -lintel_ipw -mipw_bss -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "ipwbssfw.c" ipw_bss.fwo optional ipwbssfw | ipwfw \ dependency "ipw_bss.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "ipw_bss.fwo" ipw_bss.fw optional ipwbssfw | ipwfw \ dependency "$S/contrib/dev/ipw/ipw2100-1.3.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "ipw_bss.fw" ipwibssfw.c optional ipwibssfw | ipwfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk ipw_ibss.fw:ipw_ibss:130 -lintel_ipw -mipw_ibss -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "ipwibssfw.c" ipw_ibss.fwo optional ipwibssfw | ipwfw \ dependency "ipw_ibss.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "ipw_ibss.fwo" ipw_ibss.fw optional ipwibssfw | ipwfw \ dependency "$S/contrib/dev/ipw/ipw2100-1.3-i.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "ipw_ibss.fw" ipwmonitorfw.c optional ipwmonitorfw | ipwfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk ipw_monitor.fw:ipw_monitor:130 -lintel_ipw -mipw_monitor -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "ipwmonitorfw.c" ipw_monitor.fwo optional ipwmonitorfw | ipwfw \ dependency "ipw_monitor.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "ipw_monitor.fwo" ipw_monitor.fw optional ipwmonitorfw | ipwfw \ dependency "$S/contrib/dev/ipw/ipw2100-1.3-p.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "ipw_monitor.fw" dev/iscsi/icl.c optional iscsi dev/iscsi/icl_conn_if.m optional cfiscsi | iscsi dev/iscsi/icl_soft.c optional iscsi dev/iscsi/icl_soft_proxy.c optional iscsi dev/iscsi/iscsi.c optional iscsi scbus dev/ismt/ismt.c optional ismt dev/isl/isl.c optional isl iicbus dev/isp/isp.c optional isp dev/isp/isp_freebsd.c optional isp dev/isp/isp_library.c optional isp dev/isp/isp_pci.c optional isp pci dev/isp/isp_target.c optional isp dev/ispfw/ispfw.c optional ispfw dev/iwi/if_iwi.c optional iwi iwibssfw.c optional iwibssfw | iwifw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwi_bss.fw:iwi_bss:300 -lintel_iwi -miwi_bss -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwibssfw.c" iwi_bss.fwo optional iwibssfw | iwifw \ dependency "iwi_bss.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwi_bss.fwo" iwi_bss.fw optional iwibssfw | iwifw \ dependency "$S/contrib/dev/iwi/ipw2200-bss.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwi_bss.fw" iwiibssfw.c optional iwiibssfw | iwifw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwi_ibss.fw:iwi_ibss:300 -lintel_iwi -miwi_ibss -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwiibssfw.c" iwi_ibss.fwo optional iwiibssfw | iwifw \ dependency "iwi_ibss.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwi_ibss.fwo" iwi_ibss.fw optional iwiibssfw | iwifw \ dependency "$S/contrib/dev/iwi/ipw2200-ibss.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwi_ibss.fw" iwimonitorfw.c optional iwimonitorfw | iwifw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwi_monitor.fw:iwi_monitor:300 -lintel_iwi -miwi_monitor -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwimonitorfw.c" iwi_monitor.fwo optional iwimonitorfw | iwifw \ dependency "iwi_monitor.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwi_monitor.fwo" iwi_monitor.fw optional iwimonitorfw | iwifw \ dependency "$S/contrib/dev/iwi/ipw2200-sniffer.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwi_monitor.fw" dev/iwm/if_iwm.c optional iwm dev/iwm/if_iwm_7000.c optional iwm dev/iwm/if_iwm_8000.c optional iwm dev/iwm/if_iwm_9000.c optional iwm dev/iwm/if_iwm_9260.c optional iwm dev/iwm/if_iwm_binding.c optional iwm dev/iwm/if_iwm_fw.c optional iwm dev/iwm/if_iwm_led.c optional iwm dev/iwm/if_iwm_mac_ctxt.c optional iwm dev/iwm/if_iwm_notif_wait.c optional iwm dev/iwm/if_iwm_pcie_trans.c optional iwm dev/iwm/if_iwm_phy_ctxt.c optional iwm dev/iwm/if_iwm_phy_db.c optional iwm dev/iwm/if_iwm_power.c optional iwm dev/iwm/if_iwm_scan.c optional iwm dev/iwm/if_iwm_sf.c optional iwm dev/iwm/if_iwm_sta.c optional iwm dev/iwm/if_iwm_time_event.c optional iwm dev/iwm/if_iwm_util.c optional iwm iwm3160fw.c optional iwm3160fw | iwmfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwm3160.fw:iwm3160fw -miwm3160fw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwm3160fw.c" iwm3160fw.fwo optional iwm3160fw | iwmfw \ dependency "iwm3160.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwm3160fw.fwo" iwm3160.fw optional iwm3160fw | iwmfw \ dependency "$S/contrib/dev/iwm/iwm-3160-17.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwm3160.fw" iwm3168fw.c optional iwm3168fw | iwmfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwm3168.fw:iwm3168fw -miwm3168fw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwm3168fw.c" iwm3168fw.fwo optional iwm3168fw | iwmfw \ dependency "iwm3168.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwm3168fw.fwo" iwm3168.fw optional iwm3168fw | iwmfw \ dependency "$S/contrib/dev/iwm/iwm-3168-22.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwm3168.fw" iwm7260fw.c optional iwm7260fw | iwmfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwm7260.fw:iwm7260fw -miwm7260fw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwm7260fw.c" iwm7260fw.fwo optional iwm7260fw | iwmfw \ dependency "iwm7260.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwm7260fw.fwo" iwm7260.fw optional iwm7260fw | iwmfw \ dependency "$S/contrib/dev/iwm/iwm-7260-17.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwm7260.fw" iwm7265fw.c optional iwm7265fw | iwmfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwm7265.fw:iwm7265fw -miwm7265fw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwm7265fw.c" iwm7265fw.fwo optional iwm7265fw | iwmfw \ dependency "iwm7265.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwm7265fw.fwo" iwm7265.fw optional iwm7265fw | iwmfw \ dependency "$S/contrib/dev/iwm/iwm-7265-17.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwm7265.fw" iwm7265Dfw.c optional iwm7265Dfw | iwmfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwm7265D.fw:iwm7265Dfw -miwm7265Dfw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwm7265Dfw.c" iwm7265Dfw.fwo optional iwm7265Dfw | iwmfw \ dependency "iwm7265D.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwm7265Dfw.fwo" iwm7265D.fw optional iwm7265Dfw | iwmfw \ dependency "$S/contrib/dev/iwm/iwm-7265D-17.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwm7265D.fw" iwm8000Cfw.c optional iwm8000Cfw | iwmfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwm8000C.fw:iwm8000Cfw -miwm8000Cfw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwm8000Cfw.c" iwm8000Cfw.fwo optional iwm8000Cfw | iwmfw \ dependency "iwm8000C.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwm8000Cfw.fwo" iwm8000C.fw optional iwm8000Cfw | iwmfw \ dependency "$S/contrib/dev/iwm/iwm-8000C-16.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwm8000C.fw" iwm8265.fw optional iwm8265fw | iwmfw \ dependency "$S/contrib/dev/iwm/iwm-8265-22.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwm8265.fw" iwm8265fw.c optional iwm8265fw | iwmfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwm8265.fw:iwm8265fw -miwm8265fw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwm8265fw.c" iwm8265fw.fwo optional iwm8265fw | iwmfw \ dependency "iwm8265.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwm8265fw.fwo" dev/iwn/if_iwn.c optional iwn iwn1000fw.c optional iwn1000fw | iwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwn1000.fw:iwn1000fw -miwn1000fw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwn1000fw.c" iwn1000fw.fwo optional iwn1000fw | iwnfw \ dependency "iwn1000.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwn1000fw.fwo" iwn1000.fw optional iwn1000fw | iwnfw \ dependency "$S/contrib/dev/iwn/iwlwifi-1000-39.31.5.1.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwn1000.fw" iwn100fw.c optional iwn100fw | iwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwn100.fw:iwn100fw -miwn100fw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwn100fw.c" iwn100fw.fwo optional iwn100fw | iwnfw \ dependency "iwn100.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwn100fw.fwo" iwn100.fw optional iwn100fw | iwnfw \ dependency "$S/contrib/dev/iwn/iwlwifi-100-39.31.5.1.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwn100.fw" iwn105fw.c optional iwn105fw | iwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwn105.fw:iwn105fw -miwn105fw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwn105fw.c" iwn105fw.fwo optional iwn105fw | iwnfw \ dependency "iwn105.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwn105fw.fwo" iwn105.fw optional iwn105fw | iwnfw \ dependency "$S/contrib/dev/iwn/iwlwifi-105-6-18.168.6.1.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwn105.fw" iwn135fw.c optional iwn135fw | iwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwn135.fw:iwn135fw -miwn135fw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwn135fw.c" iwn135fw.fwo optional iwn135fw | iwnfw \ dependency "iwn135.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwn135fw.fwo" iwn135.fw optional iwn135fw | iwnfw \ dependency "$S/contrib/dev/iwn/iwlwifi-135-6-18.168.6.1.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwn135.fw" iwn2000fw.c optional iwn2000fw | iwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwn2000.fw:iwn2000fw -miwn2000fw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwn2000fw.c" iwn2000fw.fwo optional iwn2000fw | iwnfw \ dependency "iwn2000.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwn2000fw.fwo" iwn2000.fw optional iwn2000fw | iwnfw \ dependency "$S/contrib/dev/iwn/iwlwifi-2000-18.168.6.1.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwn2000.fw" iwn2030fw.c optional iwn2030fw | iwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwn2030.fw:iwn2030fw -miwn2030fw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwn2030fw.c" iwn2030fw.fwo optional iwn2030fw | iwnfw \ dependency "iwn2030.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwn2030fw.fwo" iwn2030.fw optional iwn2030fw | iwnfw \ dependency "$S/contrib/dev/iwn/iwnwifi-2030-18.168.6.1.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwn2030.fw" iwn4965fw.c optional iwn4965fw | iwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwn4965.fw:iwn4965fw -miwn4965fw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwn4965fw.c" iwn4965fw.fwo optional iwn4965fw | iwnfw \ dependency "iwn4965.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwn4965fw.fwo" iwn4965.fw optional iwn4965fw | iwnfw \ dependency "$S/contrib/dev/iwn/iwlwifi-4965-228.61.2.24.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwn4965.fw" iwn5000fw.c optional iwn5000fw | iwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwn5000.fw:iwn5000fw -miwn5000fw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwn5000fw.c" iwn5000fw.fwo optional iwn5000fw | iwnfw \ dependency "iwn5000.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwn5000fw.fwo" iwn5000.fw optional iwn5000fw | iwnfw \ dependency "$S/contrib/dev/iwn/iwlwifi-5000-8.83.5.1.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwn5000.fw" iwn5150fw.c optional iwn5150fw | iwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwn5150.fw:iwn5150fw -miwn5150fw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwn5150fw.c" iwn5150fw.fwo optional iwn5150fw | iwnfw \ dependency "iwn5150.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwn5150fw.fwo" iwn5150.fw optional iwn5150fw | iwnfw \ dependency "$S/contrib/dev/iwn/iwlwifi-5150-8.24.2.2.fw.uu"\ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwn5150.fw" iwn6000fw.c optional iwn6000fw | iwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwn6000.fw:iwn6000fw -miwn6000fw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwn6000fw.c" iwn6000fw.fwo optional iwn6000fw | iwnfw \ dependency "iwn6000.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwn6000fw.fwo" iwn6000.fw optional iwn6000fw | iwnfw \ dependency "$S/contrib/dev/iwn/iwlwifi-6000-9.221.4.1.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwn6000.fw" iwn6000g2afw.c optional iwn6000g2afw | iwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwn6000g2a.fw:iwn6000g2afw -miwn6000g2afw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwn6000g2afw.c" iwn6000g2afw.fwo optional iwn6000g2afw | iwnfw \ dependency "iwn6000g2a.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwn6000g2afw.fwo" iwn6000g2a.fw optional iwn6000g2afw | iwnfw \ dependency "$S/contrib/dev/iwn/iwlwifi-6000g2a-18.168.6.1.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwn6000g2a.fw" iwn6000g2bfw.c optional iwn6000g2bfw | iwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwn6000g2b.fw:iwn6000g2bfw -miwn6000g2bfw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwn6000g2bfw.c" iwn6000g2bfw.fwo optional iwn6000g2bfw | iwnfw \ dependency "iwn6000g2b.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwn6000g2bfw.fwo" iwn6000g2b.fw optional iwn6000g2bfw | iwnfw \ dependency "$S/contrib/dev/iwn/iwlwifi-6000g2b-18.168.6.1.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwn6000g2b.fw" iwn6050fw.c optional iwn6050fw | iwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk iwn6050.fw:iwn6050fw -miwn6050fw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "iwn6050fw.c" iwn6050fw.fwo optional iwn6050fw | iwnfw \ dependency "iwn6050.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "iwn6050fw.fwo" iwn6050.fw optional iwn6050fw | iwnfw \ dependency "$S/contrib/dev/iwn/iwlwifi-6050-41.28.5.1.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "iwn6050.fw" dev/ixgbe/if_ix.c optional ix inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe -DSMP" dev/ixgbe/if_ixv.c optional ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe -DSMP" dev/ixgbe/if_bypass.c optional ix inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/if_fdir.c optional ix inet | ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/if_sriov.c optional ix inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/ix_txrx.c optional ix inet | ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/ixgbe_osdep.c optional ix inet | ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/ixgbe_phy.c optional ix inet | ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/ixgbe_api.c optional ix inet | ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/ixgbe_common.c optional ix inet | ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/ixgbe_mbx.c optional ix inet | ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/ixgbe_vf.c optional ix inet | ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/ixgbe_82598.c optional ix inet | ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/ixgbe_82599.c optional ix inet | ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/ixgbe_x540.c optional ix inet | ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/ixgbe_x550.c optional ix inet | ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/ixgbe_dcb.c optional ix inet | ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/ixgbe_dcb_82598.c optional ix inet | ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/ixgbe/ixgbe_dcb_82599.c optional ix inet | ixv inet \ compile-with "${NORMAL_C} -I$S/dev/ixgbe" dev/jedec_dimm/jedec_dimm.c optional jedec_dimm smbus dev/jme/if_jme.c optional jme pci dev/kbd/kbd.c optional atkbd | pckbd | sc | ukbd | vt | hkbd dev/kbdmux/kbdmux.c optional kbdmux dev/ksyms/ksyms.c optional ksyms dev/le/am7990.c optional le dev/le/am79900.c optional le dev/le/if_le_pci.c optional le pci dev/le/lance.c optional le dev/led/led.c standard dev/lge/if_lge.c optional lge dev/liquidio/base/cn23xx_pf_device.c optional lio \ compile-with "${NORMAL_C} \ -I$S/dev/liquidio -I$S/dev/liquidio/base -DSMP" dev/liquidio/base/lio_console.c optional lio \ compile-with "${NORMAL_C} \ -I$S/dev/liquidio -I$S/dev/liquidio/base -DSMP" dev/liquidio/base/lio_ctrl.c optional lio \ compile-with "${NORMAL_C} \ -I$S/dev/liquidio -I$S/dev/liquidio/base -DSMP" dev/liquidio/base/lio_device.c optional lio \ compile-with "${NORMAL_C} \ -I$S/dev/liquidio -I$S/dev/liquidio/base -DSMP" dev/liquidio/base/lio_droq.c optional lio \ compile-with "${NORMAL_C} \ -I$S/dev/liquidio -I$S/dev/liquidio/base -DSMP" dev/liquidio/base/lio_mem_ops.c optional lio \ compile-with "${NORMAL_C} \ -I$S/dev/liquidio -I$S/dev/liquidio/base -DSMP" dev/liquidio/base/lio_request_manager.c optional lio \ compile-with "${NORMAL_C} \ -I$S/dev/liquidio -I$S/dev/liquidio/base -DSMP" dev/liquidio/base/lio_response_manager.c optional lio \ compile-with "${NORMAL_C} \ -I$S/dev/liquidio -I$S/dev/liquidio/base -DSMP" dev/liquidio/lio_core.c optional lio \ compile-with "${NORMAL_C} \ -I$S/dev/liquidio -I$S/dev/liquidio/base -DSMP" dev/liquidio/lio_ioctl.c optional lio \ compile-with "${NORMAL_C} \ -I$S/dev/liquidio -I$S/dev/liquidio/base -DSMP" dev/liquidio/lio_main.c optional lio \ compile-with "${NORMAL_C} \ -I$S/dev/liquidio -I$S/dev/liquidio/base -DSMP" dev/liquidio/lio_rss.c optional lio \ compile-with "${NORMAL_C} \ -I$S/dev/liquidio -I$S/dev/liquidio/base -DSMP" dev/liquidio/lio_rxtx.c optional lio \ compile-with "${NORMAL_C} \ -I$S/dev/liquidio -I$S/dev/liquidio/base -DSMP" dev/liquidio/lio_sysctl.c optional lio \ compile-with "${NORMAL_C} \ -I$S/dev/liquidio -I$S/dev/liquidio/base -DSMP" lio.c optional lio \ compile-with "${AWK} -f $S/tools/fw_stub.awk lio_23xx_nic.bin.fw:lio_23xx_nic.bin -mlio_23xx_nic.bin -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "lio.c" lio_23xx_nic.bin.fw.fwo optional lio \ dependency "lio_23xx_nic.bin.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "lio_23xx_nic.bin.fw.fwo" lio_23xx_nic.bin.fw optional lio \ dependency "$S/contrib/dev/liquidio/lio_23xx_nic.bin.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "lio_23xx_nic.bin.fw" dev/malo/if_malo.c optional malo dev/malo/if_malohal.c optional malo dev/malo/if_malo_pci.c optional malo pci dev/md/md.c optional md dev/mdio/mdio_if.m optional miiproxy | mdio dev/mdio/mdio.c optional miiproxy | mdio dev/mem/memdev.c optional mem dev/mem/memutil.c optional mem dev/mfi/mfi.c optional mfi dev/mfi/mfi_debug.c optional mfi dev/mfi/mfi_pci.c optional mfi pci dev/mfi/mfi_disk.c optional mfi dev/mfi/mfi_syspd.c optional mfi dev/mfi/mfi_tbolt.c optional mfi dev/mfi/mfi_cam.c optional mfip scbus dev/mii/acphy.c optional miibus | acphy dev/mii/amphy.c optional miibus | amphy dev/mii/atphy.c optional miibus | atphy dev/mii/axphy.c optional miibus | axphy dev/mii/bmtphy.c optional miibus | bmtphy dev/mii/brgphy.c optional miibus | brgphy dev/mii/ciphy.c optional miibus | ciphy dev/mii/dp83822phy.c optional miibus | dp83822phy dev/mii/dp83867phy.c optional miibus | dp83867phy dev/mii/e1000phy.c optional miibus | e1000phy dev/mii/gentbi.c optional miibus | gentbi dev/mii/icsphy.c optional miibus | icsphy dev/mii/ip1000phy.c optional miibus | ip1000phy dev/mii/jmphy.c optional miibus | jmphy dev/mii/lxtphy.c optional miibus | lxtphy dev/mii/mcommphy.c optional miibus | mcommphy dev/mii/micphy.c optional miibus fdt | micphy fdt dev/mii/mii.c optional miibus | mii dev/mii/mii_bitbang.c optional miibus | mii_bitbang dev/mii/mii_physubr.c optional miibus | mii dev/mii/mii_fdt.c optional miibus fdt | mii fdt dev/mii/miibus_if.m optional miibus | mii dev/mii/mv88e151x.c optional miibus | mv88e151x dev/mii/nsgphy.c optional miibus | nsgphy dev/mii/nsphy.c optional miibus | nsphy dev/mii/nsphyter.c optional miibus | nsphyter dev/mii/pnaphy.c optional miibus | pnaphy dev/mii/qsphy.c optional miibus | qsphy dev/mii/rdcphy.c optional miibus | rdcphy dev/mii/rgephy.c optional miibus | rgephy dev/mii/rlphy.c optional miibus | rlphy dev/mii/rlswitch.c optional rlswitch dev/mii/smcphy.c optional miibus | smcphy dev/mii/smscphy.c optional miibus | smscphy dev/mii/tdkphy.c optional miibus | tdkphy dev/mii/truephy.c optional miibus | truephy dev/mii/ukphy.c optional miibus | mii dev/mii/ukphy_subr.c optional miibus | mii dev/mii/vscphy.c optional miibus | vscphy dev/mii/xmphy.c optional miibus | xmphy dev/mlxfw/mlxfw_fsm.c optional mlxfw \ compile-with "${MLXFW_C}" dev/mlxfw/mlxfw_mfa2.c optional mlxfw \ compile-with "${MLXFW_C}" dev/mlxfw/mlxfw_mfa2_tlv_multi.c optional mlxfw \ compile-with "${MLXFW_C}" dev/mlx/mlx.c optional mlx dev/mlx/mlx_disk.c optional mlx dev/mlx/mlx_pci.c optional mlx pci dev/mmc/mmc_subr.c optional mmc | mmcsd !mmccam dev/mmc/mmc.c optional mmc !mmccam dev/mmc/mmcbr_if.m standard dev/mmc/mmcbus_if.m standard dev/mmc/mmcsd.c optional mmcsd !mmccam dev/mmc/mmc_fdt_helpers.c optional mmc regulator clk fdt | mmccam regulator clk fdt dev/mmc/mmc_helpers.c optional mmc gpio regulator clk | mmccam gpio regulator clk dev/mmc/mmc_pwrseq.c optional mmc clk regulator fdt | mmccam clk regulator fdt dev/mmc/mmc_pwrseq_if.m optional mmc clk regulator fdt | mmccam clk regulator fdt dev/mmcnull/mmcnull.c optional mmcnull dev/mpr/mpr.c optional mpr dev/mpr/mpr_config.c optional mpr # XXX Work around clang warning, until maintainer approves fix. dev/mpr/mpr_mapping.c optional mpr \ compile-with "${NORMAL_C} ${NO_WSOMETIMES_UNINITIALIZED}" dev/mpr/mpr_pci.c optional mpr pci dev/mpr/mpr_sas.c optional mpr \ compile-with "${NORMAL_C} ${NO_WUNNEEDED_INTERNAL_DECL}" dev/mpr/mpr_sas_lsi.c optional mpr dev/mpr/mpr_table.c optional mpr dev/mpr/mpr_user.c optional mpr dev/mps/mps.c optional mps dev/mps/mps_config.c optional mps # XXX Work around clang warning, until maintainer approves fix. dev/mps/mps_mapping.c optional mps \ compile-with "${NORMAL_C} ${NO_WSOMETIMES_UNINITIALIZED}" dev/mps/mps_pci.c optional mps pci dev/mps/mps_sas.c optional mps \ compile-with "${NORMAL_C} ${NO_WUNNEEDED_INTERNAL_DECL}" dev/mps/mps_sas_lsi.c optional mps dev/mps/mps_table.c optional mps dev/mps/mps_user.c optional mps dev/mpt/mpt.c optional mpt dev/mpt/mpt_cam.c optional mpt dev/mpt/mpt_debug.c optional mpt dev/mpt/mpt_pci.c optional mpt pci dev/mpt/mpt_raid.c optional mpt dev/mpt/mpt_user.c optional mpt dev/mrsas/mrsas.c optional mrsas dev/mrsas/mrsas_cam.c optional mrsas dev/mrsas/mrsas_ioctl.c optional mrsas dev/mrsas/mrsas_fp.c optional mrsas dev/msk/if_msk.c optional msk dev/mvs/mvs.c optional mvs dev/mvs/mvs_if.m optional mvs dev/mvs/mvs_pci.c optional mvs pci dev/mwl/if_mwl.c optional mwl dev/mwl/if_mwl_pci.c optional mwl pci dev/mwl/mwlhal.c optional mwl mwlfw.c optional mwlfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk mw88W8363.fw:mw88W8363fw mwlboot.fw:mwlboot -mmwl -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "mwlfw.c" mw88W8363.fwo optional mwlfw \ dependency "mw88W8363.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "mw88W8363.fwo" mw88W8363.fw optional mwlfw \ dependency "$S/contrib/dev/mwl/mw88W8363.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "mw88W8363.fw" mwlboot.fwo optional mwlfw \ dependency "mwlboot.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "mwlboot.fwo" mwlboot.fw optional mwlfw \ dependency "$S/contrib/dev/mwl/mwlboot.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "mwlboot.fw" dev/mxge/if_mxge.c optional mxge pci dev/mxge/mxge_eth_z8e.c optional mxge pci dev/mxge/mxge_ethp_z8e.c optional mxge pci dev/mxge/mxge_rss_eth_z8e.c optional mxge pci dev/mxge/mxge_rss_ethp_z8e.c optional mxge pci dev/my/if_my.c optional my dev/netmap/if_ptnet.c optional netmap inet dev/netmap/netmap.c optional netmap dev/netmap/netmap_bdg.c optional netmap dev/netmap/netmap_freebsd.c optional netmap dev/netmap/netmap_generic.c optional netmap dev/netmap/netmap_kloop.c optional netmap dev/netmap/netmap_legacy.c optional netmap dev/netmap/netmap_mbq.c optional netmap dev/netmap/netmap_mem2.c optional netmap dev/netmap/netmap_monitor.c optional netmap dev/netmap/netmap_null.c optional netmap dev/netmap/netmap_offloadings.c optional netmap dev/netmap/netmap_pipe.c optional netmap dev/netmap/netmap_vale.c optional netmap # compile-with "${NORMAL_C} -Wconversion -Wextra" dev/nfsmb/nfsmb.c optional nfsmb pci dev/nge/if_nge.c optional nge dev/nmdm/nmdm.c optional nmdm dev/null/null.c standard dev/nvd/nvd.c optional nvd nvme dev/nvme/nvme.c optional nvme dev/nvme/nvme_ahci.c optional nvme ahci dev/nvme/nvme_ctrlr.c optional nvme dev/nvme/nvme_ctrlr_cmd.c optional nvme dev/nvme/nvme_ns.c optional nvme dev/nvme/nvme_ns_cmd.c optional nvme dev/nvme/nvme_pci.c optional nvme pci dev/nvme/nvme_qpair.c optional nvme dev/nvme/nvme_sim.c optional nvme scbus dev/nvme/nvme_sysctl.c optional nvme dev/nvme/nvme_test.c optional nvme dev/nvme/nvme_util.c optional nvme dev/nvmem/nvmem.c optional nvmem fdt dev/nvmem/nvmem_if.m optional nvmem dev/oce/oce_hw.c optional oce pci dev/oce/oce_if.c optional oce pci dev/oce/oce_mbox.c optional oce pci dev/oce/oce_queue.c optional oce pci dev/oce/oce_sysctl.c optional oce pci dev/oce/oce_util.c optional oce pci dev/ocs_fc/ocs_gendump.c optional ocs_fc pci dev/ocs_fc/ocs_pci.c optional ocs_fc pci dev/ocs_fc/ocs_ioctl.c optional ocs_fc pci dev/ocs_fc/ocs_os.c optional ocs_fc pci dev/ocs_fc/ocs_utils.c optional ocs_fc pci dev/ocs_fc/ocs_hw.c optional ocs_fc pci dev/ocs_fc/ocs_hw_queues.c optional ocs_fc pci dev/ocs_fc/sli4.c optional ocs_fc pci dev/ocs_fc/ocs_sm.c optional ocs_fc pci dev/ocs_fc/ocs_device.c optional ocs_fc pci dev/ocs_fc/ocs_xport.c optional ocs_fc pci dev/ocs_fc/ocs_domain.c optional ocs_fc pci dev/ocs_fc/ocs_sport.c optional ocs_fc pci dev/ocs_fc/ocs_els.c optional ocs_fc pci dev/ocs_fc/ocs_fabric.c optional ocs_fc pci dev/ocs_fc/ocs_io.c optional ocs_fc pci dev/ocs_fc/ocs_node.c optional ocs_fc pci dev/ocs_fc/ocs_scsi.c optional ocs_fc pci dev/ocs_fc/ocs_unsol.c optional ocs_fc pci dev/ocs_fc/ocs_ddump.c optional ocs_fc pci dev/ocs_fc/ocs_mgmt.c optional ocs_fc pci dev/ocs_fc/ocs_cam.c optional ocs_fc pci dev/ofw/ofw_bus_if.m optional fdt dev/ofw/ofw_bus_subr.c optional fdt dev/ofw/ofw_cpu.c optional fdt dev/ofw/ofw_fdt.c optional fdt dev/ofw/ofw_firmware.c optional fdt dev/ofw/ofw_if.m optional fdt dev/ofw/ofw_graph.c optional fdt dev/ofw/ofw_subr.c optional fdt dev/ofw/ofwbus.c optional fdt dev/ofw/openfirm.c optional fdt dev/ofw/openfirmio.c optional fdt dev/ow/ow.c optional ow \ dependency "owll_if.h" \ dependency "own_if.h" dev/ow/owll_if.m optional ow dev/ow/own_if.m optional ow dev/ow/ow_temp.c optional ow_temp dev/ow/owc_gpiobus.c optional owc gpio dev/pbio/pbio.c optional pbio isa dev/pccbb/pccbb.c optional cbb dev/pccbb/pccbb_pci.c optional cbb pci dev/pcf/pcf.c optional pcf dev/pci/fixup_pci.c optional pci dev/pci/hostb_pci.c optional pci dev/pci/ignore_pci.c optional pci dev/pci/isa_pci.c optional pci isa dev/pci/pci.c optional pci dev/pci/pci_if.m standard dev/pci/pci_iov.c optional pci pci_iov dev/pci/pci_iov_if.m standard dev/pci/pci_iov_schema.c optional pci pci_iov dev/pci/pci_pci.c optional pci dev/pci/pci_subr.c optional pci dev/pci/pci_user.c optional pci dev/pci/pcib_if.m standard dev/pci/pcib_support.c standard dev/pci/vga_pci.c optional pci dev/pms/freebsd/driver/ini/src/agtiapi.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sallsdk/spc/sadisc.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sallsdk/spc/mpi.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sallsdk/spc/saframe.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sallsdk/spc/sahw.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sallsdk/spc/sainit.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sallsdk/spc/saint.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sallsdk/spc/sampicmd.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sallsdk/spc/sampirsp.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sallsdk/spc/saphy.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sallsdk/spc/saport.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sallsdk/spc/sasata.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sallsdk/spc/sasmp.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sallsdk/spc/sassp.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sallsdk/spc/satimer.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sallsdk/spc/sautil.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sallsdk/spc/saioctlcmd.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sallsdk/spc/mpidebug.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/discovery/dm/dminit.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/discovery/dm/dmsmp.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/discovery/dm/dmdisc.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/discovery/dm/dmport.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/discovery/dm/dmtimer.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/discovery/dm/dmmisc.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sat/src/sminit.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sat/src/smmisc.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sat/src/smsat.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sat/src/smsatcb.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sat/src/smsathw.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/sat/src/smtimer.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/common/tdinit.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/common/tdmisc.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/common/tdesgl.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/common/tdport.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/common/tdint.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/common/tdioctl.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/common/tdhw.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/common/ossacmnapi.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/common/tddmcmnapi.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/common/tdsmcmnapi.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/common/tdtimers.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/sas/ini/itdio.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/sas/ini/itdcb.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/sas/ini/itdinit.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/sas/ini/itddisc.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/sata/host/sat.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/sata/host/ossasat.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/pms/RefTisa/tisa/sassata/sata/host/sathw.c optional pmspcv \ compile-with "${NORMAL_C} -Wunused-variable -Woverflow -Wparentheses -w" dev/ppbus/if_plip.c optional plip dev/ppbus/lpbb.c optional lpbb dev/ppbus/lpt.c optional lpt dev/ppbus/pcfclock.c optional pcfclock dev/ppbus/ppb_1284.c optional ppbus dev/ppbus/ppb_base.c optional ppbus dev/ppbus/ppb_msq.c optional ppbus dev/ppbus/ppbconf.c optional ppbus dev/ppbus/ppbus_if.m optional ppbus dev/ppbus/ppi.c optional ppi dev/ppbus/pps.c optional pps dev/ppc/ppc.c optional ppc dev/ppc/ppc_acpi.c optional ppc acpi dev/ppc/ppc_isa.c optional ppc isa dev/ppc/ppc_pci.c optional ppc pci dev/ppc/ppc_puc.c optional ppc puc dev/proto/proto_bus_isa.c optional proto acpi | proto isa dev/proto/proto_bus_pci.c optional proto pci dev/proto/proto_busdma.c optional proto dev/proto/proto_core.c optional proto dev/pst/pst-iop.c optional pst dev/pst/pst-pci.c optional pst pci dev/pst/pst-raid.c optional pst dev/pty/pty.c optional pty dev/puc/puc.c optional puc dev/puc/puc_cfg.c optional puc dev/puc/puc_pci.c optional puc pci dev/pwm/pwmc.c optional pwm | pwmc dev/pwm/pwmbus.c optional pwm | pwmbus dev/pwm/pwmbus_if.m optional pwm | pwmbus dev/pwm/ofw_pwm.c optional pwm fdt | pwmbus fdt dev/pwm/ofw_pwmbus.c optional pwm fdt | pwmbus fdt dev/pwm/pwm_backlight.c optional pwm pwm_backlight fdt backlight dev/quicc/quicc_core.c optional quicc dev/ral/rt2560.c optional ral dev/ral/rt2661.c optional ral dev/ral/rt2860.c optional ral dev/ral/if_ral_pci.c optional ral pci rt2561fw.c optional rt2561fw | ralfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk rt2561.fw:rt2561fw -mrt2561 -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "rt2561fw.c" rt2561fw.fwo optional rt2561fw | ralfw \ dependency "rt2561.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "rt2561fw.fwo" rt2561.fw optional rt2561fw | ralfw \ dependency "$S/contrib/dev/ral/rt2561.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rt2561.fw" rt2561sfw.c optional rt2561sfw | ralfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk rt2561s.fw:rt2561sfw -mrt2561s -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "rt2561sfw.c" rt2561sfw.fwo optional rt2561sfw | ralfw \ dependency "rt2561s.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "rt2561sfw.fwo" rt2561s.fw optional rt2561sfw | ralfw \ dependency "$S/contrib/dev/ral/rt2561s.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rt2561s.fw" rt2661fw.c optional rt2661fw | ralfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk rt2661.fw:rt2661fw -mrt2661 -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "rt2661fw.c" rt2661fw.fwo optional rt2661fw | ralfw \ dependency "rt2661.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "rt2661fw.fwo" rt2661.fw optional rt2661fw | ralfw \ dependency "$S/contrib/dev/ral/rt2661.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rt2661.fw" rt2860fw.c optional rt2860fw | ralfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk rt2860.fw:rt2860fw -mrt2860 -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "rt2860fw.c" rt2860fw.fwo optional rt2860fw | ralfw \ dependency "rt2860.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "rt2860fw.fwo" rt2860.fw optional rt2860fw | ralfw \ dependency "$S/contrib/dev/ral/rt2860.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rt2860.fw" dev/random/random_infra.c standard dev/random/random_harvestq.c standard dev/random/randomdev.c optional !random_loadable dev/random/fenestrasX/fx_brng.c optional !random_loadable random_fenestrasx dev/random/fenestrasX/fx_main.c optional !random_loadable random_fenestrasx \ compile-with "${NORMAL_C} -I$S/crypto/blake2" dev/random/fenestrasX/fx_pool.c optional !random_loadable random_fenestrasx \ compile-with "${NORMAL_C} -I$S/crypto/blake2" dev/random/fenestrasX/fx_rng.c optional !random_loadable random_fenestrasx \ compile-with "${NORMAL_C} -I$S/crypto/blake2" dev/random/fortuna.c optional !random_loadable !random_fenestrasx dev/random/hash.c optional !random_loadable dev/rccgpio/rccgpio.c optional rccgpio gpio dev/re/if_re.c optional re +dev/regulator/regdev_if.m optional regulator fdt +dev/regulator/regnode_if.m optional regulator +dev/regulator/regulator.c optional regulator +dev/regulator/regulator_bus.c optional regulator fdt +dev/regulator/regulator_fixed.c optional regulator dev/rl/if_rl.c optional rl pci dev/rndtest/rndtest.c optional rndtest # dev/rtsx/rtsx.c optional rtsx pci # dev/rtwn/if_rtwn.c optional rtwn dev/rtwn/if_rtwn_beacon.c optional rtwn dev/rtwn/if_rtwn_calib.c optional rtwn dev/rtwn/if_rtwn_cam.c optional rtwn dev/rtwn/if_rtwn_efuse.c optional rtwn dev/rtwn/if_rtwn_fw.c optional rtwn dev/rtwn/if_rtwn_rx.c optional rtwn dev/rtwn/if_rtwn_task.c optional rtwn dev/rtwn/if_rtwn_tx.c optional rtwn # dev/rtwn/pci/rtwn_pci_attach.c optional rtwn_pci pci dev/rtwn/pci/rtwn_pci_reg.c optional rtwn_pci pci dev/rtwn/pci/rtwn_pci_rx.c optional rtwn_pci pci dev/rtwn/pci/rtwn_pci_tx.c optional rtwn_pci pci # dev/rtwn/usb/rtwn_usb_attach.c optional rtwn_usb dev/rtwn/usb/rtwn_usb_ep.c optional rtwn_usb dev/rtwn/usb/rtwn_usb_reg.c optional rtwn_usb dev/rtwn/usb/rtwn_usb_rx.c optional rtwn_usb dev/rtwn/usb/rtwn_usb_tx.c optional rtwn_usb # RTL8188E dev/rtwn/rtl8188e/r88e_beacon.c optional rtwn dev/rtwn/rtl8188e/r88e_calib.c optional rtwn dev/rtwn/rtl8188e/r88e_chan.c optional rtwn dev/rtwn/rtl8188e/r88e_fw.c optional rtwn dev/rtwn/rtl8188e/r88e_init.c optional rtwn dev/rtwn/rtl8188e/r88e_led.c optional rtwn dev/rtwn/rtl8188e/r88e_tx.c optional rtwn dev/rtwn/rtl8188e/r88e_rf.c optional rtwn dev/rtwn/rtl8188e/r88e_rom.c optional rtwn dev/rtwn/rtl8188e/r88e_rx.c optional rtwn dev/rtwn/rtl8188e/pci/r88ee_attach.c optional rtwn_pci pci dev/rtwn/rtl8188e/pci/r88ee_init.c optional rtwn_pci pci dev/rtwn/rtl8188e/pci/r88ee_rx.c optional rtwn_pci pci dev/rtwn/rtl8188e/usb/r88eu_attach.c optional rtwn_usb dev/rtwn/rtl8188e/usb/r88eu_init.c optional rtwn_usb # RTL8192C dev/rtwn/rtl8192c/r92c_attach.c optional rtwn dev/rtwn/rtl8192c/r92c_beacon.c optional rtwn dev/rtwn/rtl8192c/r92c_calib.c optional rtwn dev/rtwn/rtl8192c/r92c_chan.c optional rtwn dev/rtwn/rtl8192c/r92c_fw.c optional rtwn dev/rtwn/rtl8192c/r92c_init.c optional rtwn dev/rtwn/rtl8192c/r92c_llt.c optional rtwn dev/rtwn/rtl8192c/r92c_rf.c optional rtwn dev/rtwn/rtl8192c/r92c_rom.c optional rtwn dev/rtwn/rtl8192c/r92c_rx.c optional rtwn dev/rtwn/rtl8192c/r92c_tx.c optional rtwn dev/rtwn/rtl8192c/pci/r92ce_attach.c optional rtwn_pci pci dev/rtwn/rtl8192c/pci/r92ce_calib.c optional rtwn_pci pci dev/rtwn/rtl8192c/pci/r92ce_fw.c optional rtwn_pci pci dev/rtwn/rtl8192c/pci/r92ce_init.c optional rtwn_pci pci dev/rtwn/rtl8192c/pci/r92ce_led.c optional rtwn_pci pci dev/rtwn/rtl8192c/pci/r92ce_rx.c optional rtwn_pci pci dev/rtwn/rtl8192c/pci/r92ce_tx.c optional rtwn_pci pci dev/rtwn/rtl8192c/usb/r92cu_attach.c optional rtwn_usb dev/rtwn/rtl8192c/usb/r92cu_init.c optional rtwn_usb dev/rtwn/rtl8192c/usb/r92cu_led.c optional rtwn_usb dev/rtwn/rtl8192c/usb/r92cu_rx.c optional rtwn_usb dev/rtwn/rtl8192c/usb/r92cu_tx.c optional rtwn_usb # RTL8192E dev/rtwn/rtl8192e/r92e_chan.c optional rtwn dev/rtwn/rtl8192e/r92e_fw.c optional rtwn dev/rtwn/rtl8192e/r92e_init.c optional rtwn dev/rtwn/rtl8192e/r92e_led.c optional rtwn dev/rtwn/rtl8192e/r92e_rf.c optional rtwn dev/rtwn/rtl8192e/r92e_rom.c optional rtwn dev/rtwn/rtl8192e/r92e_rx.c optional rtwn dev/rtwn/rtl8192e/usb/r92eu_attach.c optional rtwn_usb dev/rtwn/rtl8192e/usb/r92eu_init.c optional rtwn_usb # RTL8812A dev/rtwn/rtl8812a/r12a_beacon.c optional rtwn dev/rtwn/rtl8812a/r12a_calib.c optional rtwn dev/rtwn/rtl8812a/r12a_caps.c optional rtwn dev/rtwn/rtl8812a/r12a_chan.c optional rtwn dev/rtwn/rtl8812a/r12a_fw.c optional rtwn dev/rtwn/rtl8812a/r12a_init.c optional rtwn dev/rtwn/rtl8812a/r12a_led.c optional rtwn dev/rtwn/rtl8812a/r12a_rf.c optional rtwn dev/rtwn/rtl8812a/r12a_rom.c optional rtwn dev/rtwn/rtl8812a/r12a_rx.c optional rtwn dev/rtwn/rtl8812a/r12a_tx.c optional rtwn dev/rtwn/rtl8812a/usb/r12au_attach.c optional rtwn_usb dev/rtwn/rtl8812a/usb/r12au_init.c optional rtwn_usb dev/rtwn/rtl8812a/usb/r12au_rx.c optional rtwn_usb dev/rtwn/rtl8812a/usb/r12au_tx.c optional rtwn_usb # RTL8821A dev/rtwn/rtl8821a/r21a_beacon.c optional rtwn dev/rtwn/rtl8821a/r21a_calib.c optional rtwn dev/rtwn/rtl8821a/r21a_chan.c optional rtwn dev/rtwn/rtl8821a/r21a_fw.c optional rtwn dev/rtwn/rtl8821a/r21a_init.c optional rtwn dev/rtwn/rtl8821a/r21a_led.c optional rtwn dev/rtwn/rtl8821a/r21a_rom.c optional rtwn dev/rtwn/rtl8821a/r21a_rx.c optional rtwn dev/rtwn/rtl8821a/usb/r21au_attach.c optional rtwn_usb dev/rtwn/rtl8821a/usb/r21au_dfs.c optional rtwn_usb dev/rtwn/rtl8821a/usb/r21au_init.c optional rtwn_usb rtwn-rtl8188eefw.c optional rtwn-rtl8188eefw | rtwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk rtwn-rtl8188eefw.fw:rtwn-rtl8188eefw:111 -mrtwn-rtl8188eefw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "rtwn-rtl8188eefw.c" rtwn-rtl8188eefw.fwo optional rtwn-rtl8188eefw | rtwnfw \ dependency "rtwn-rtl8188eefw.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "rtwn-rtl8188eefw.fwo" rtwn-rtl8188eefw.fw optional rtwn-rtl8188eefw | rtwnfw \ dependency "$S/contrib/dev/rtwn/rtwn-rtl8188eefw.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rtwn-rtl8188eefw.fw" rtwn-rtl8188eufw.c optional rtwn-rtl8188eufw | rtwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk rtwn-rtl8188eufw.fw:rtwn-rtl8188eufw:111 -mrtwn-rtl8188eufw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "rtwn-rtl8188eufw.c" rtwn-rtl8188eufw.fwo optional rtwn-rtl8188eufw | rtwnfw \ dependency "rtwn-rtl8188eufw.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "rtwn-rtl8188eufw.fwo" rtwn-rtl8188eufw.fw optional rtwn-rtl8188eufw | rtwnfw \ dependency "$S/contrib/dev/rtwn/rtwn-rtl8188eufw.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rtwn-rtl8188eufw.fw" rtwn-rtl8192cfwE.c optional rtwn-rtl8192cfwE | rtwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk rtwn-rtl8192cfwE.fw:rtwn-rtl8192cfwE:111 -mrtwn-rtl8192cfwE -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "rtwn-rtl8192cfwE.c" rtwn-rtl8192cfwE.fwo optional rtwn-rtl8192cfwE | rtwnfw \ dependency "rtwn-rtl8192cfwE.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "rtwn-rtl8192cfwE.fwo" rtwn-rtl8192cfwE.fw optional rtwn-rtl8192cfwE | rtwnfw \ dependency "$S/contrib/dev/rtwn/rtwn-rtl8192cfwE.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rtwn-rtl8192cfwE.fw" rtwn-rtl8192cfwE_B.c optional rtwn-rtl8192cfwE_B | rtwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk rtwn-rtl8192cfwE_B.fw:rtwn-rtl8192cfwE_B:111 -mrtwn-rtl8192cfwE_B -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "rtwn-rtl8192cfwE_B.c" rtwn-rtl8192cfwE_B.fwo optional rtwn-rtl8192cfwE_B | rtwnfw \ dependency "rtwn-rtl8192cfwE_B.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "rtwn-rtl8192cfwE_B.fwo" rtwn-rtl8192cfwE_B.fw optional rtwn-rtl8192cfwE_B | rtwnfw \ dependency "$S/contrib/dev/rtwn/rtwn-rtl8192cfwE_B.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rtwn-rtl8192cfwE_B.fw" rtwn-rtl8192cfwT.c optional rtwn-rtl8192cfwT | rtwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk rtwn-rtl8192cfwT.fw:rtwn-rtl8192cfwT:111 -mrtwn-rtl8192cfwT -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "rtwn-rtl8192cfwT.c" rtwn-rtl8192cfwT.fwo optional rtwn-rtl8192cfwT | rtwnfw \ dependency "rtwn-rtl8192cfwT.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "rtwn-rtl8192cfwT.fwo" rtwn-rtl8192cfwT.fw optional rtwn-rtl8192cfwT | rtwnfw \ dependency "$S/contrib/dev/rtwn/rtwn-rtl8192cfwT.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rtwn-rtl8192cfwT.fw" rtwn-rtl8192cfwU.c optional rtwn-rtl8192cfwU | rtwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk rtwn-rtl8192cfwU.fw:rtwn-rtl8192cfwU:111 -mrtwn-rtl8192cfwU -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "rtwn-rtl8192cfwU.c" rtwn-rtl8192cfwU.fwo optional rtwn-rtl8192cfwU | rtwnfw \ dependency "rtwn-rtl8192cfwU.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "rtwn-rtl8192cfwU.fwo" rtwn-rtl8192cfwU.fw optional rtwn-rtl8192cfwU | rtwnfw \ dependency "$S/contrib/dev/rtwn/rtwn-rtl8192cfwU.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rtwn-rtl8192cfwU.fw" rtwn-rtl8192eufw.c optional rtwn-rtl8192eufw | rtwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk rtwn-rtl8192eufw.fw:rtwn-rtl8192eufw:111 -mrtwn-rtl8192eufw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "rtwn-rtl8192eufw.c" rtwn-rtl8192eufw.fwo optional rtwn-rtl8192eufw | rtwnfw \ dependency "rtwn-rtl8192eufw.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "rtwn-rtl8192eufw.fwo" rtwn-rtl8192eufw.fw optional rtwn-rtl8192eufw | rtwnfw \ dependency "$S/contrib/dev/rtwn/rtwn-rtl8192eufw.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rtwn-rtl8192eufw.fw" rtwn-rtl8812aufw.c optional rtwn-rtl8812aufw | rtwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk rtwn-rtl8812aufw.fw:rtwn-rtl8812aufw:111 -mrtwn-rtl8812aufw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "rtwn-rtl8812aufw.c" rtwn-rtl8812aufw.fwo optional rtwn-rtl8812aufw | rtwnfw \ dependency "rtwn-rtl8812aufw.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "rtwn-rtl8812aufw.fwo" rtwn-rtl8812aufw.fw optional rtwn-rtl8812aufw | rtwnfw \ dependency "$S/contrib/dev/rtwn/rtwn-rtl8812aufw.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rtwn-rtl8812aufw.fw" rtwn-rtl8821aufw.c optional rtwn-rtl8821aufw | rtwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk rtwn-rtl8821aufw.fw:rtwn-rtl8821aufw:111 -mrtwn-rtl8821aufw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "rtwn-rtl8821aufw.c" rtwn-rtl8821aufw.fwo optional rtwn-rtl8821aufw | rtwnfw \ dependency "rtwn-rtl8821aufw.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "rtwn-rtl8821aufw.fwo" rtwn-rtl8821aufw.fw optional rtwn-rtl8821aufw | rtwnfw \ dependency "$S/contrib/dev/rtwn/rtwn-rtl8821aufw.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rtwn-rtl8821aufw.fw" dev/safe/safe.c optional safe dev/scc/scc_if.m optional scc dev/scc/scc_bfe_quicc.c optional scc quicc dev/scc/scc_core.c optional scc dev/scc/scc_dev_quicc.c optional scc quicc dev/scc/scc_dev_z8530.c optional scc dev/sdhci/sdhci.c optional sdhci dev/sdhci/sdhci_fdt.c optional sdhci fdt regulator clk dev/sdhci/sdhci_fdt_gpio.c optional sdhci fdt gpio dev/sdhci/sdhci_fsl_fdt.c optional sdhci fdt gpio regulator clk 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/sff/sff_if.m optional sff dev/sff/sfp_fdt.c optional sff fdt dev/sge/if_sge.c optional sge pci dev/siis/siis.c optional siis pci dev/sis/if_sis.c optional sis pci dev/sk/if_sk.c optional sk pci dev/smbios/smbios.c optional smbios dev/smbus/smb.c optional smb dev/smbus/smbconf.c optional smbus dev/smbus/smbus.c optional smbus dev/smbus/smbus_if.m optional smbus dev/smc/if_smc.c optional smc dev/smc/if_smc_acpi.c optional smc acpi dev/smc/if_smc_fdt.c optional smc fdt dev/snp/snp.c optional snp dev/sound/clone.c optional sound dev/sound/unit.c optional sound dev/sound/pci/als4000.c optional snd_als4000 pci dev/sound/pci/atiixp.c optional snd_atiixp pci dev/sound/pci/cmi.c optional snd_cmi pci dev/sound/pci/cs4281.c optional snd_cs4281 pci dev/sound/pci/csa.c optional snd_csa pci dev/sound/pci/csapcm.c optional snd_csa pci dev/sound/pci/emu10k1.c optional snd_emu10k1 pci dev/sound/pci/emu10kx.c optional snd_emu10kx pci dev/sound/pci/emu10kx-pcm.c optional snd_emu10kx pci dev/sound/pci/emu10kx-midi.c optional snd_emu10kx pci dev/sound/pci/envy24.c optional snd_envy24 pci dev/sound/pci/envy24ht.c optional snd_envy24ht pci dev/sound/pci/es137x.c optional snd_es137x pci dev/sound/pci/fm801.c optional snd_fm801 pci dev/sound/pci/ich.c optional snd_ich pci dev/sound/pci/maestro3.c optional snd_maestro3 pci dev/sound/pci/neomagic.c optional snd_neomagic pci dev/sound/pci/solo.c optional snd_solo pci dev/sound/pci/spicds.c optional snd_spicds pci dev/sound/pci/t4dwave.c optional snd_t4dwave pci dev/sound/pci/via8233.c optional snd_via8233 pci dev/sound/pci/via82c686.c optional snd_via82c686 pci dev/sound/pci/vibes.c optional snd_vibes pci dev/sound/pci/hda/hdaa.c optional snd_hda pci dev/sound/pci/hda/hdaa_patches.c optional snd_hda pci dev/sound/pci/hda/hdac.c optional snd_hda pci dev/sound/pci/hda/hdac_if.m optional snd_hda pci dev/sound/pci/hda/hdacc.c optional snd_hda pci dev/sound/pci/hdspe.c optional snd_hdspe pci dev/sound/pci/hdspe-pcm.c optional snd_hdspe pci dev/sound/pcm/ac97.c optional sound dev/sound/pcm/ac97_if.m optional sound dev/sound/pcm/ac97_patch.c optional sound dev/sound/pcm/buffer.c optional sound \ dependency "snd_fxdiv_gen.h" dev/sound/pcm/channel.c optional sound dev/sound/pcm/channel_if.m optional sound dev/sound/pcm/dsp.c optional sound dev/sound/pcm/feeder.c optional sound dev/sound/pcm/feeder_chain.c optional sound dev/sound/pcm/feeder_eq.c optional sound \ dependency "feeder_eq_gen.h" \ dependency "snd_fxdiv_gen.h" dev/sound/pcm/feeder_if.m optional sound dev/sound/pcm/feeder_format.c optional sound \ dependency "snd_fxdiv_gen.h" dev/sound/pcm/feeder_matrix.c optional sound \ dependency "snd_fxdiv_gen.h" dev/sound/pcm/feeder_mixer.c optional sound \ dependency "snd_fxdiv_gen.h" dev/sound/pcm/feeder_rate.c optional sound \ dependency "feeder_rate_gen.h" \ dependency "snd_fxdiv_gen.h" dev/sound/pcm/feeder_volume.c optional sound \ dependency "snd_fxdiv_gen.h" dev/sound/pcm/mixer.c optional sound dev/sound/pcm/mixer_if.m optional sound dev/sound/pcm/sndstat.c optional sound dev/sound/pcm/sound.c optional sound dev/sound/pcm/vchan.c optional sound dev/sound/usb/uaudio.c optional snd_uaudio usb dev/sound/usb/uaudio_pcm.c optional snd_uaudio usb dev/sound/midi/midi.c optional sound dev/sound/midi/mpu401.c optional sound dev/sound/midi/mpu_if.m optional sound dev/sound/midi/mpufoi_if.m optional sound dev/sound/midi/sequencer.c optional sound dev/sound/midi/synth_if.m optional sound dev/spibus/acpi_spibus.c optional acpi spibus dev/spibus/ofw_spibus.c optional fdt spibus dev/spibus/spibus.c optional spibus \ dependency "spibus_if.h" dev/spibus/spigen.c optional spigen dev/spibus/spibus_if.m optional spibus dev/ste/if_ste.c optional ste pci dev/stge/if_stge.c optional stge dev/sym/sym_hipd.c optional sym \ dependency "$S/dev/sym/sym_{conf,defs}.h" dev/syscons/blank/blank_saver.c optional blank_saver dev/syscons/daemon/daemon_saver.c optional daemon_saver dev/syscons/dragon/dragon_saver.c optional dragon_saver dev/syscons/fade/fade_saver.c optional fade_saver dev/syscons/fire/fire_saver.c optional fire_saver dev/syscons/green/green_saver.c optional green_saver dev/syscons/logo/logo.c optional logo_saver dev/syscons/logo/logo_saver.c optional logo_saver dev/syscons/rain/rain_saver.c optional rain_saver dev/syscons/schistory.c optional sc dev/syscons/scmouse.c optional sc dev/syscons/scterm.c optional sc dev/syscons/scterm-dumb.c optional sc !SC_NO_TERM_DUMB dev/syscons/scterm-sc.c optional sc !SC_NO_TERM_SC dev/syscons/scterm-teken.c optional sc !SC_NO_TERM_TEKEN dev/syscons/scvidctl.c optional sc dev/syscons/scvtb.c optional sc dev/syscons/snake/snake_saver.c optional snake_saver dev/syscons/star/star_saver.c optional star_saver dev/syscons/syscons.c optional sc dev/syscons/sysmouse.c optional sc dev/syscons/warp/warp_saver.c optional warp_saver dev/tcp_log/tcp_log_dev.c optional tcp_blackbox inet | tcp_blackbox inet6 dev/tdfx/tdfx_pci.c optional tdfx pci dev/ti/if_ti.c optional ti pci dev/tws/tws.c optional tws dev/tws/tws_cam.c optional tws dev/tws/tws_hdm.c optional tws dev/tws/tws_services.c optional tws dev/tws/tws_user.c optional tws dev/uart/uart_bus_acpi.c optional uart acpi dev/uart/uart_bus_fdt.c optional uart fdt dev/uart/uart_bus_isa.c optional uart isa dev/uart/uart_bus_pci.c optional uart pci dev/uart/uart_bus_puc.c optional uart puc dev/uart/uart_bus_scc.c optional uart scc dev/uart/uart_core.c optional uart dev/uart/uart_cpu_acpi.c optional uart acpi dev/uart/uart_dbg.c optional uart gdb dev/uart/uart_dev_imx.c optional uart uart_imx fdt dev/uart/uart_dev_msm.c optional uart uart_msm fdt dev/uart/uart_dev_mvebu.c optional uart uart_mvebu fdt dev/uart/uart_dev_ns8250.c optional uart uart_ns8250 | uart uart_snps dev/uart/uart_dev_pl011.c optional uart pl011 dev/uart/uart_dev_quicc.c optional uart quicc dev/uart/uart_dev_snps.c optional uart uart_snps fdt dev/uart/uart_dev_z8530.c optional uart uart_z8530 | uart scc dev/uart/uart_if.m optional uart dev/uart/uart_subr.c optional uart dev/uart/uart_tty.c optional uart # # USB controller drivers # dev/usb/controller/musb_otg.c optional musb dev/usb/controller/dwc_otg.c optional dwcotg dev/usb/controller/dwc_otg_fdt.c optional dwcotg fdt dev/usb/controller/dwc_otg_acpi.c optional dwcotg acpi dev/usb/controller/ehci.c optional ehci dev/usb/controller/ehci_msm.c optional ehci_msm fdt dev/usb/controller/ehci_pci.c optional ehci pci dev/usb/controller/ohci.c optional ohci dev/usb/controller/ohci_pci.c optional ohci pci dev/usb/controller/uhci.c optional uhci dev/usb/controller/uhci_pci.c optional uhci pci dev/usb/controller/xhci.c optional xhci dev/usb/controller/xhci_pci.c optional xhci pci dev/usb/controller/saf1761_otg.c optional saf1761otg dev/usb/controller/saf1761_otg_fdt.c optional saf1761otg fdt dev/usb/controller/uss820dci.c optional uss820dci dev/usb/controller/usb_controller.c optional usb # # USB storage drivers # dev/usb/storage/cfumass.c optional cfumass ctl dev/usb/storage/umass.c optional umass dev/usb/storage/urio.c optional urio dev/usb/storage/ustorage_fs.c optional usfs # # USB core # dev/usb/usb_busdma.c optional usb dev/usb/usb_core.c optional usb dev/usb/usb_debug.c optional usb dev/usb/usb_dev.c optional usb dev/usb/usb_device.c optional usb dev/usb/usb_dynamic.c optional usb dev/usb/usb_error.c optional usb dev/usb/usb_fdt_support.c optional usb fdt dev/usb/usb_generic.c optional usb dev/usb/usb_handle_request.c optional usb dev/usb/usb_hid.c optional usb dev/usb/usb_hub.c optional usb dev/usb/usb_hub_acpi.c optional uacpi acpi dev/usb/usb_if.m optional usb dev/usb/usb_lookup.c optional usb dev/usb/usb_mbuf.c optional usb dev/usb/usb_msctest.c optional usb dev/usb/usb_parse.c optional usb dev/usb/usb_pf.c optional usb dev/usb/usb_process.c optional usb dev/usb/usb_request.c optional usb dev/usb/usb_transfer.c optional usb dev/usb/usb_util.c optional usb # # USB network drivers # dev/usb/net/if_aue.c optional aue dev/usb/net/if_axe.c optional axe dev/usb/net/if_axge.c optional axge dev/usb/net/if_cdce.c optional cdce dev/usb/net/if_cdceem.c optional cdceem dev/usb/net/if_cue.c optional cue dev/usb/net/if_ipheth.c optional ipheth dev/usb/net/if_kue.c optional kue dev/usb/net/if_mos.c optional mos dev/usb/net/if_muge.c optional muge dev/usb/net/if_rue.c optional rue dev/usb/net/if_smsc.c optional smsc dev/usb/net/if_udav.c optional udav dev/usb/net/if_ure.c optional ure dev/usb/net/if_usie.c optional usie dev/usb/net/if_urndis.c optional urndis dev/usb/net/ruephy.c optional rue dev/usb/net/usb_ethernet.c optional uether | aue | axe | axge | cdce | \ cdceem | cue | ipheth | kue | mos | \ rue | smsc | udav | ure | urndis | muge dev/usb/net/uhso.c optional uhso # # USB WLAN drivers # dev/usb/wlan/if_rsu.c optional rsu rsu-rtl8712fw.c optional rsu-rtl8712fw | rsufw \ compile-with "${AWK} -f $S/tools/fw_stub.awk rsu-rtl8712fw.fw:rsu-rtl8712fw:120 -mrsu-rtl8712fw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "rsu-rtl8712fw.c" rsu-rtl8712fw.fwo optional rsu-rtl8712fw | rsufw \ dependency "rsu-rtl8712fw.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "rsu-rtl8712fw.fwo" rsu-rtl8712fw.fw optional rsu-rtl8712.fw | rsufw \ dependency "$S/contrib/dev/rsu/rsu-rtl8712fw.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rsu-rtl8712fw.fw" dev/usb/wlan/if_rum.c optional rum dev/usb/wlan/if_run.c optional run runfw.c optional runfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk run.fw:runfw -mrunfw -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "runfw.c" runfw.fwo optional runfw \ dependency "run.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "runfw.fwo" run.fw optional runfw \ dependency "$S/contrib/dev/run/rt2870.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "run.fw" dev/usb/wlan/if_uath.c optional uath dev/usb/wlan/if_upgt.c optional upgt dev/usb/wlan/if_ural.c optional ural dev/usb/wlan/if_urtw.c optional urtw dev/usb/wlan/if_zyd.c optional zyd # # USB serial and parallel port drivers # dev/usb/serial/u3g.c optional u3g dev/usb/serial/uark.c optional uark dev/usb/serial/ubsa.c optional ubsa dev/usb/serial/ubser.c optional ubser dev/usb/serial/uchcom.c optional uchcom dev/usb/serial/ucycom.c optional ucycom dev/usb/serial/ufoma.c optional ufoma dev/usb/serial/uftdi.c optional uftdi dev/usb/serial/ugensa.c optional ugensa dev/usb/serial/uipaq.c optional uipaq dev/usb/serial/ulpt.c optional ulpt dev/usb/serial/umcs.c optional umcs dev/usb/serial/umct.c optional umct dev/usb/serial/umodem.c optional umodem dev/usb/serial/umoscom.c optional umoscom dev/usb/serial/uplcom.c optional uplcom dev/usb/serial/uslcom.c optional uslcom dev/usb/serial/uvisor.c optional uvisor dev/usb/serial/uvscom.c optional uvscom dev/usb/serial/usb_serial.c optional ucom | u3g | uark | ubsa | ubser | \ uchcom | ucycom | ufoma | uftdi | \ ugensa | uipaq | umcs | umct | \ umodem | umoscom | uplcom | usie | \ uslcom | uvisor | uvscom # # USB misc drivers # dev/usb/misc/cp2112.c optional cp2112 dev/usb/misc/udbp.c optional udbp dev/usb/misc/ugold.c optional ugold dev/usb/misc/uled.c optional uled # # USB input drivers # dev/usb/input/atp.c optional atp dev/usb/input/uep.c optional uep dev/usb/input/uhid.c optional uhid dev/usb/input/uhid_snes.c optional uhid_snes dev/usb/input/ukbd.c optional ukbd dev/usb/input/ums.c optional ums dev/usb/input/usbhid.c optional usbhid dev/usb/input/wmt.c optional wmt dev/usb/input/wsp.c optional wsp # # USB quirks # dev/usb/quirk/usb_quirk.c optional usb # # USB templates # dev/usb/template/usb_template.c optional usb_template dev/usb/template/usb_template_audio.c optional usb_template dev/usb/template/usb_template_cdce.c optional usb_template dev/usb/template/usb_template_kbd.c optional usb_template dev/usb/template/usb_template_modem.c optional usb_template dev/usb/template/usb_template_mouse.c optional usb_template dev/usb/template/usb_template_msc.c optional usb_template dev/usb/template/usb_template_mtp.c optional usb_template dev/usb/template/usb_template_phone.c optional usb_template dev/usb/template/usb_template_serialnet.c optional usb_template dev/usb/template/usb_template_midi.c optional usb_template dev/usb/template/usb_template_multi.c optional usb_template dev/usb/template/usb_template_cdceem.c optional usb_template # # USB video drivers # dev/usb/video/udl.c optional udl # # USB END # dev/videomode/videomode.c optional videomode dev/videomode/edid.c optional videomode dev/videomode/pickmode.c optional videomode dev/videomode/vesagtf.c optional videomode dev/veriexec/verified_exec.c optional mac_veriexec dev/vge/if_vge.c optional vge dev/viapm/viapm.c optional viapm pci dev/virtio/virtio.c optional virtio dev/virtio/virtqueue.c optional virtio dev/virtio/virtio_bus_if.m optional virtio dev/virtio/virtio_if.m optional virtio dev/virtio/pci/virtio_pci.c optional virtio_pci dev/virtio/pci/virtio_pci_if.m optional virtio_pci dev/virtio/pci/virtio_pci_legacy.c optional virtio_pci dev/virtio/pci/virtio_pci_modern.c optional virtio_pci dev/virtio/mmio/virtio_mmio.c optional virtio_mmio dev/virtio/mmio/virtio_mmio_acpi.c optional virtio_mmio acpi dev/virtio/mmio/virtio_mmio_cmdline.c optional virtio_mmio dev/virtio/mmio/virtio_mmio_fdt.c optional virtio_mmio fdt dev/virtio/mmio/virtio_mmio_if.m optional virtio_mmio dev/virtio/network/if_vtnet.c optional vtnet dev/virtio/block/virtio_blk.c optional virtio_blk dev/virtio/balloon/virtio_balloon.c optional virtio_balloon dev/virtio/gpu/virtio_gpu.c optional virtio_gpu dev/virtio/scsi/virtio_scsi.c optional virtio_scsi dev/virtio/random/virtio_random.c optional virtio_random dev/virtio/console/virtio_console.c optional virtio_console dev/vkbd/vkbd.c optional vkbd dev/vmgenc/vmgenc_acpi.c optional acpi dev/vmware/vmxnet3/if_vmx.c optional vmx dev/vmware/vmci/vmci.c optional vmci dev/vmware/vmci/vmci_datagram.c optional vmci dev/vmware/vmci/vmci_doorbell.c optional vmci dev/vmware/vmci/vmci_driver.c optional vmci dev/vmware/vmci/vmci_event.c optional vmci dev/vmware/vmci/vmci_hashtable.c optional vmci dev/vmware/vmci/vmci_kernel_if.c optional vmci dev/vmware/vmci/vmci_qpair.c optional vmci dev/vmware/vmci/vmci_queue_pair.c optional vmci dev/vmware/vmci/vmci_resource.c optional vmci dev/vmware/pvscsi/pvscsi.c optional pvscsi dev/vr/if_vr.c optional vr pci dev/vt/colors/vt_termcolors.c optional vt dev/vt/font/vt_font_default.c optional vt dev/vt/font/vt_mouse_cursor.c optional vt dev/vt/hw/efifb/efifb.c optional vt_efifb dev/vt/hw/simplefb/simplefb.c optional vt_simplefb fdt dev/vt/hw/vbefb/vbefb.c optional vt_vbefb dev/vt/hw/fb/vt_fb.c optional vt dev/vt/hw/vga/vt_vga.c optional vt vt_vga dev/vt/logo/logo_freebsd.c optional vt splash dev/vt/logo/logo_beastie.c optional vt splash dev/vt/vt_buf.c optional vt dev/vt/vt_consolectl.c optional vt dev/vt/vt_core.c optional vt dev/vt/vt_cpulogos.c optional vt splash dev/vt/vt_font.c optional vt dev/vt/vt_sysmouse.c optional vt dev/vte/if_vte.c optional vte pci dev/watchdog/watchdog.c standard dev/wg/if_wg.c optional wg \ compile-with "${NORMAL_C} -include $S/dev/wg/compat.h" dev/wg/wg_cookie.c optional wg \ compile-with "${NORMAL_C} -include $S/dev/wg/compat.h" dev/wg/wg_crypto.c optional wg \ compile-with "${NORMAL_C} -include $S/dev/wg/compat.h" dev/wg/wg_noise.c optional wg \ compile-with "${NORMAL_C} -include $S/dev/wg/compat.h" dev/wpi/if_wpi.c optional wpi pci wpifw.c optional wpifw \ compile-with "${AWK} -f $S/tools/fw_stub.awk wpi.fw:wpifw:153229 -mwpi -c${.TARGET}" \ no-ctfconvert no-implicit-rule before-depend local \ clean "wpifw.c" wpifw.fwo optional wpifw \ dependency "wpi.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ clean "wpifw.fwo" wpi.fw optional wpifw \ dependency "$S/contrib/dev/wpi/iwlwifi-3945-15.32.2.9.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "wpi.fw" dev/xdma/controller/pl330.c optional xdma pl330 fdt dev/xdma/xdma.c optional xdma dev/xdma/xdma_bank.c optional xdma dev/xdma/xdma_bio.c optional xdma dev/xdma/xdma_fdt_test.c optional xdma xdma_test fdt dev/xdma/xdma_if.m optional xdma dev/xdma/xdma_iommu.c optional xdma dev/xdma/xdma_mbuf.c optional xdma dev/xdma/xdma_queue.c optional xdma dev/xdma/xdma_sg.c optional xdma dev/xdma/xdma_sglist.c optional xdma dev/xen/balloon/balloon.c optional xenhvm dev/xen/blkfront/blkfront.c optional xenhvm dev/xen/blkback/blkback.c optional xenhvm dev/xen/bus/xen_intr.c optional xenhvm dev/xen/bus/xenpv.c optional xenhvm dev/xen/console/xen_console.c optional xenhvm dev/xen/control/control.c optional xenhvm dev/xen/cpu/xen_acpi_cpu.c optional xenhvm acpi dev/xen/efi/pvefi.c optional xenhvm xenefi efirt dev/xen/grant_table/grant_table.c optional xenhvm dev/xen/netback/netback.c optional xenhvm dev/xen/netfront/netfront.c optional xenhvm dev/xen/timer/xen_timer.c optional xenhvm xentimer dev/xen/xenpci/xenpci.c optional xenpci dev/xen/xenstore/xenstore.c optional xenhvm dev/xen/xenstore/xenstore_dev.c optional xenhvm dev/xen/xenstore/xenstored_dev.c optional xenhvm dev/xen/evtchn/evtchn_dev.c optional xenhvm dev/xen/privcmd/privcmd.c optional xenhvm dev/xen/gntdev/gntdev.c optional xenhvm dev/xen/debug/debug.c optional xenhvm dev/xl/if_xl.c optional xl pci dev/xl/xlphy.c optional xl pci fs/autofs/autofs.c optional autofs fs/autofs/autofs_vfsops.c optional autofs fs/autofs/autofs_vnops.c optional autofs fs/deadfs/dead_vnops.c standard fs/devfs/devfs_devs.c standard fs/devfs/devfs_dir.c standard fs/devfs/devfs_rule.c standard fs/devfs/devfs_vfsops.c standard fs/devfs/devfs_vnops.c standard fs/fdescfs/fdesc_vfsops.c optional fdescfs fs/fdescfs/fdesc_vnops.c optional fdescfs fs/fifofs/fifo_vnops.c standard fs/cuse/cuse.c optional cuse fs/fuse/fuse_device.c optional fusefs fs/fuse/fuse_file.c optional fusefs fs/fuse/fuse_internal.c optional fusefs fs/fuse/fuse_io.c optional fusefs fs/fuse/fuse_ipc.c optional fusefs fs/fuse/fuse_main.c optional fusefs fs/fuse/fuse_node.c optional fusefs fs/fuse/fuse_vfsops.c optional fusefs fs/fuse/fuse_vnops.c optional fusefs fs/mntfs/mntfs_vnops.c standard fs/msdosfs/msdosfs_conv.c optional msdosfs fs/msdosfs/msdosfs_denode.c optional msdosfs fs/msdosfs/msdosfs_fat.c optional msdosfs fs/msdosfs/msdosfs_iconv.c optional msdosfs_iconv fs/msdosfs/msdosfs_lookup.c optional msdosfs fs/msdosfs/msdosfs_vfsops.c optional msdosfs fs/msdosfs/msdosfs_vnops.c optional msdosfs fs/nfs/nfs_commonkrpc.c optional nfscl | nfslockd | nfsd fs/nfs/nfs_commonsubs.c optional nfscl | nfslockd | nfsd fs/nfs/nfs_commonport.c optional nfscl | nfslockd | nfsd fs/nfs/nfs_commonacl.c optional nfscl | nfslockd | nfsd fs/nfsclient/nfs_clcomsubs.c optional nfscl fs/nfsclient/nfs_clsubs.c optional nfscl fs/nfsclient/nfs_clstate.c optional nfscl fs/nfsclient/nfs_clkrpc.c optional nfscl fs/nfsclient/nfs_clrpcops.c optional nfscl fs/nfsclient/nfs_clvnops.c optional nfscl fs/nfsclient/nfs_clnode.c optional nfscl fs/nfsclient/nfs_clvfsops.c optional nfscl fs/nfsclient/nfs_clport.c optional nfscl fs/nfsclient/nfs_clbio.c optional nfscl fs/nfsclient/nfs_clnfsiod.c optional nfscl fs/nfsserver/nfs_fha_new.c optional nfsd inet fs/nfsserver/nfs_nfsdsocket.c optional nfsd inet fs/nfsserver/nfs_nfsdsubs.c optional nfsd inet fs/nfsserver/nfs_nfsdstate.c optional nfsd inet fs/nfsserver/nfs_nfsdkrpc.c optional nfsd inet fs/nfsserver/nfs_nfsdserv.c optional nfsd inet fs/nfsserver/nfs_nfsdport.c optional nfsd inet fs/nfsserver/nfs_nfsdcache.c optional nfsd inet fs/nullfs/null_subr.c optional nullfs fs/nullfs/null_vfsops.c optional nullfs fs/nullfs/null_vnops.c optional nullfs fs/procfs/procfs.c optional procfs fs/procfs/procfs_dbregs.c optional procfs fs/procfs/procfs_fpregs.c optional procfs fs/procfs/procfs_map.c optional procfs fs/procfs/procfs_mem.c optional procfs fs/procfs/procfs_note.c optional procfs fs/procfs/procfs_osrel.c optional procfs fs/procfs/procfs_regs.c optional procfs fs/procfs/procfs_rlimit.c optional procfs fs/procfs/procfs_status.c optional procfs fs/procfs/procfs_type.c optional procfs fs/pseudofs/pseudofs.c optional pseudofs fs/pseudofs/pseudofs_fileno.c optional pseudofs fs/pseudofs/pseudofs_vncache.c optional pseudofs fs/pseudofs/pseudofs_vnops.c optional pseudofs fs/smbfs/smbfs_io.c optional smbfs fs/smbfs/smbfs_node.c optional smbfs fs/smbfs/smbfs_smb.c optional smbfs fs/smbfs/smbfs_subr.c optional smbfs fs/smbfs/smbfs_vfsops.c optional smbfs fs/smbfs/smbfs_vnops.c optional smbfs fs/tarfs/tarfs_io.c optional tarfs compile-with "${NORMAL_C} -I$S/contrib/zstd/lib/freebsd" fs/tarfs/tarfs_subr.c optional tarfs fs/tarfs/tarfs_vfsops.c optional tarfs fs/tarfs/tarfs_vnops.c optional tarfs fs/udf/osta.c optional udf fs/udf/udf_iconv.c optional udf_iconv fs/udf/udf_vfsops.c optional udf fs/udf/udf_vnops.c optional udf fs/unionfs/union_subr.c optional unionfs fs/unionfs/union_vfsops.c optional unionfs fs/unionfs/union_vnops.c optional unionfs fs/tmpfs/tmpfs_vnops.c optional tmpfs fs/tmpfs/tmpfs_fifoops.c optional tmpfs fs/tmpfs/tmpfs_vfsops.c optional tmpfs fs/tmpfs/tmpfs_subr.c optional tmpfs gdb/gdb_cons.c optional gdb gdb/gdb_main.c optional gdb gdb/gdb_packet.c optional gdb gdb/netgdb.c optional ddb debugnet gdb netgdb inet geom/bde/g_bde.c optional geom_bde geom/bde/g_bde_crypt.c optional geom_bde geom/bde/g_bde_lock.c optional geom_bde geom/bde/g_bde_work.c optional geom_bde geom/cache/g_cache.c optional geom_cache geom/concat/g_concat.c optional geom_concat geom/eli/g_eli.c optional geom_eli geom/eli/g_eli_crypto.c optional geom_eli geom/eli/g_eli_ctl.c optional geom_eli geom/eli/g_eli_hmac.c optional geom_eli geom/eli/g_eli_integrity.c optional geom_eli geom/eli/g_eli_key.c optional geom_eli geom/eli/g_eli_key_cache.c optional geom_eli geom/eli/g_eli_privacy.c optional geom_eli geom/eli/pkcs5v2.c optional geom_eli geom/gate/g_gate.c optional geom_gate geom/geom_bsd_enc.c optional geom_part_bsd geom/geom_ccd.c optional ccd | geom_ccd geom/geom_ctl.c standard geom/geom_dev.c standard geom/geom_disk.c standard geom/geom_dump.c standard geom/geom_event.c standard geom/geom_flashmap.c optional fdt cfi | fdt mx25l | mmcsd | fdt n25q | fdt at45d geom/geom_io.c standard geom/geom_kern.c standard geom/geom_map.c optional geom_map geom/geom_redboot.c optional geom_redboot geom/geom_slice.c standard geom/geom_subr.c standard geom/geom_vfs.c standard geom/journal/g_journal.c optional geom_journal geom/journal/g_journal_ufs.c optional geom_journal geom/label/g_label.c optional geom_label | geom_label_gpt geom/label/g_label_ext2fs.c optional geom_label geom/label/g_label_flashmap.c optional geom_label geom/label/g_label_iso9660.c optional geom_label geom/label/g_label_msdosfs.c optional geom_label geom/label/g_label_ntfs.c optional geom_label geom/label/g_label_reiserfs.c optional geom_label geom/label/g_label_ufs.c optional geom_label geom/label/g_label_gpt.c optional geom_label | geom_label_gpt geom/label/g_label_disk_ident.c optional geom_label geom/linux_lvm/g_linux_lvm.c optional geom_linux_lvm geom/mirror/g_mirror.c optional geom_mirror geom/mirror/g_mirror_ctl.c optional geom_mirror geom/mountver/g_mountver.c optional geom_mountver geom/multipath/g_multipath.c optional geom_multipath geom/nop/g_nop.c optional geom_nop geom/part/g_part.c standard geom/part/g_part_if.m standard geom/part/g_part_apm.c optional geom_part_apm geom/part/g_part_bsd.c optional geom_part_bsd geom/part/g_part_bsd64.c optional geom_part_bsd64 geom/part/g_part_ebr.c optional geom_part_ebr geom/part/g_part_gpt.c optional geom_part_gpt geom/part/g_part_ldm.c optional geom_part_ldm geom/part/g_part_mbr.c optional geom_part_mbr geom/raid/g_raid.c optional geom_raid geom/raid/g_raid_ctl.c optional geom_raid geom/raid/g_raid_md_if.m optional geom_raid geom/raid/g_raid_tr_if.m optional geom_raid geom/raid/md_ddf.c optional geom_raid geom/raid/md_intel.c optional geom_raid geom/raid/md_jmicron.c optional geom_raid geom/raid/md_nvidia.c optional geom_raid geom/raid/md_promise.c optional geom_raid geom/raid/md_sii.c optional geom_raid geom/raid/tr_concat.c optional geom_raid geom/raid/tr_raid0.c optional geom_raid geom/raid/tr_raid1.c optional geom_raid geom/raid/tr_raid1e.c optional geom_raid geom/raid/tr_raid5.c optional geom_raid geom/raid3/g_raid3.c optional geom_raid3 geom/raid3/g_raid3_ctl.c optional geom_raid3 geom/shsec/g_shsec.c optional geom_shsec geom/stripe/g_stripe.c optional geom_stripe geom/union/g_union.c optional geom_union geom/uzip/g_uzip.c optional geom_uzip geom/uzip/g_uzip_lzma.c optional geom_uzip geom/uzip/g_uzip_wrkthr.c optional geom_uzip geom/uzip/g_uzip_zlib.c optional geom_uzip geom/uzip/g_uzip_zstd.c optional geom_uzip zstdio \ compile-with "${NORMAL_C} -I$S/contrib/zstd/lib/freebsd" geom/vinum/geom_vinum.c optional geom_vinum geom/vinum/geom_vinum_create.c optional geom_vinum geom/vinum/geom_vinum_drive.c optional geom_vinum geom/vinum/geom_vinum_plex.c optional geom_vinum geom/vinum/geom_vinum_volume.c optional geom_vinum geom/vinum/geom_vinum_subr.c optional geom_vinum geom/vinum/geom_vinum_raid5.c optional geom_vinum geom/vinum/geom_vinum_share.c optional geom_vinum geom/vinum/geom_vinum_list.c optional geom_vinum geom/vinum/geom_vinum_rm.c optional geom_vinum geom/vinum/geom_vinum_init.c optional geom_vinum geom/vinum/geom_vinum_state.c optional geom_vinum geom/vinum/geom_vinum_rename.c optional geom_vinum geom/vinum/geom_vinum_move.c optional geom_vinum geom/vinum/geom_vinum_events.c optional geom_vinum geom/virstor/binstream.c optional geom_virstor geom/virstor/g_virstor.c optional geom_virstor geom/virstor/g_virstor_md.c optional geom_virstor geom/zero/g_zero.c optional geom_zero fs/ext2fs/ext2_acl.c optional ext2fs fs/ext2fs/ext2_alloc.c optional ext2fs fs/ext2fs/ext2_balloc.c optional ext2fs fs/ext2fs/ext2_bmap.c optional ext2fs fs/ext2fs/ext2_csum.c optional ext2fs fs/ext2fs/ext2_extattr.c optional ext2fs fs/ext2fs/ext2_extents.c optional ext2fs fs/ext2fs/ext2_inode.c optional ext2fs fs/ext2fs/ext2_inode_cnv.c optional ext2fs fs/ext2fs/ext2_hash.c optional ext2fs fs/ext2fs/ext2_htree.c optional ext2fs fs/ext2fs/ext2_lookup.c optional ext2fs fs/ext2fs/ext2_subr.c optional ext2fs fs/ext2fs/ext2_vfsops.c optional ext2fs fs/ext2fs/ext2_vnops.c optional ext2fs # isa/isa_if.m standard isa/isa_common.c optional isa isa/isahint.c optional isa isa/pnp.c optional isa isapnp isa/pnpparse.c optional isa isapnp fs/cd9660/cd9660_bmap.c optional cd9660 fs/cd9660/cd9660_lookup.c optional cd9660 fs/cd9660/cd9660_node.c optional cd9660 fs/cd9660/cd9660_rrip.c optional cd9660 fs/cd9660/cd9660_util.c optional cd9660 fs/cd9660/cd9660_vfsops.c optional cd9660 fs/cd9660/cd9660_vnops.c optional cd9660 fs/cd9660/cd9660_iconv.c optional cd9660_iconv gnu/gcov/gcc_4_7.c optional gcov \ warning "kernel contains GPL licensed gcov support" gnu/gcov/gcov_fs.c optional gcov lindebugfs \ compile-with "${LINUXKPI_C}" gnu/gcov/gcov_subr.c optional gcov kern/bus_if.m standard kern/clock_if.m standard kern/cpufreq_if.m standard kern/device_if.m standard kern/imgact_binmisc.c optional imgact_binmisc kern/imgact_elf.c standard kern/imgact_elf32.c optional compat_freebsd32 kern/imgact_shell.c standard kern/init_main.c standard kern/init_sysent.c standard kern/ksched.c optional _kposix_priority_scheduling kern/kern_acct.c standard kern/kern_alq.c optional alq kern/kern_boottrace.c standard kern/kern_clock.c standard kern/kern_clocksource.c standard kern/kern_condvar.c standard kern/kern_conf.c standard kern/kern_cons.c standard kern/kern_cpu.c standard kern/kern_cpuset.c standard kern/kern_context.c standard kern/kern_descrip.c standard kern/kern_devctl.c standard kern/kern_dtrace.c optional kdtrace_hooks kern/kern_dump.c standard kern/kern_environment.c standard kern/kern_et.c standard kern/kern_event.c standard kern/kern_exec.c standard kern/kern_exit.c standard kern/kern_fail.c standard kern/kern_ffclock.c standard kern/kern_fork.c standard kern/kern_hhook.c standard kern/kern_idle.c standard kern/kern_intr.c standard kern/kern_jail.c standard kern/kern_kcov.c optional kcov \ compile-with "${NORMAL_C:N-fsanitize*} ${NORMAL_C:M-fsanitize=kernel-memory}" kern/kern_khelp.c standard kern/kern_kthread.c standard kern/kern_ktr.c optional ktr kern/kern_ktrace.c standard kern/kern_linker.c standard kern/kern_lock.c standard kern/kern_lockf.c standard kern/kern_lockstat.c optional kdtrace_hooks kern/kern_loginclass.c standard kern/kern_malloc.c standard kern/kern_mbuf.c standard kern/kern_membarrier.c standard kern/kern_mib.c standard kern/kern_module.c standard kern/kern_mtxpool.c standard kern/kern_mutex.c standard kern/kern_ntptime.c standard kern/kern_osd.c standard kern/kern_physio.c standard kern/kern_pmc.c standard kern/kern_poll.c optional device_polling kern/kern_priv.c standard kern/kern_proc.c standard kern/kern_procctl.c standard kern/kern_prot.c standard kern/kern_racct.c optional racct kern/kern_rangelock.c standard kern/kern_rctl.c standard kern/kern_resource.c standard kern/kern_rmlock.c standard kern/kern_rwlock.c standard kern/kern_sdt.c optional kdtrace_hooks kern/kern_sema.c standard kern/kern_sendfile.c standard kern/kern_sharedpage.c standard kern/kern_shutdown.c standard kern/kern_sig.c standard kern/kern_switch.c standard kern/kern_sx.c standard kern/kern_synch.c standard kern/kern_syscalls.c standard kern/kern_sysctl.c standard kern/kern_tc.c standard kern/kern_thr.c standard kern/kern_thread.c standard kern/kern_time.c standard kern/kern_timeout.c standard kern/kern_tslog.c optional tslog kern/kern_ubsan.c optional kubsan kern/kern_umtx.c standard kern/kern_uuid.c standard kern/kern_vnodedumper.c standard kern/kern_xxx.c standard kern/link_elf.c standard kern/linker_if.m standard kern/md4c.c optional netsmb kern/md5c.c standard kern/p1003_1b.c standard kern/posix4_mib.c standard kern/sched_4bsd.c optional sched_4bsd kern/sched_ule.c optional sched_ule kern/serdev_if.m standard kern/stack_protector.c standard \ compile-with "${NORMAL_C:N-fstack-protector*}" kern/subr_acl_nfs4.c optional ufs_acl | zfs kern/subr_acl_posix1e.c optional ufs_acl kern/subr_asan.c optional kasan \ compile-with "${NORMAL_C:N-fsanitize*:N-fstack-protector*}" kern/subr_autoconf.c standard kern/subr_blist.c standard kern/subr_boot.c standard kern/subr_bus.c standard kern/subr_bus_dma.c standard kern/subr_bufring.c standard kern/subr_capability.c standard kern/subr_clock.c standard kern/subr_compressor.c standard \ compile-with "${NORMAL_C} -I$S/contrib/zstd/lib/freebsd" kern/subr_coverage.c optional coverage \ compile-with "${NORMAL_C:N-fsanitize*}" kern/subr_counter.c standard kern/subr_csan.c optional kcsan \ compile-with "${NORMAL_C:N-fsanitize*:N-fstack-protector*}" kern/subr_devstat.c standard kern/subr_disk.c standard kern/subr_early.c standard kern/subr_epoch.c standard kern/subr_eventhandler.c standard kern/subr_fattime.c standard kern/subr_firmware.c optional firmware kern/subr_filter.c standard kern/subr_gtaskqueue.c standard kern/subr_hash.c standard kern/subr_hints.c standard kern/subr_kdb.c standard kern/subr_kobj.c standard kern/subr_lock.c standard kern/subr_log.c standard kern/subr_mchain.c optional libmchain kern/subr_memdesc.c standard kern/subr_module.c standard kern/subr_msan.c optional kmsan \ compile-with "${NORMAL_C:N-fsanitize*:N-fno-sanitize*:N-fstack-protector*}" kern/subr_msgbuf.c standard kern/subr_param.c standard kern/subr_pcpu.c standard kern/subr_pctrie.c standard kern/subr_pidctrl.c standard kern/subr_power.c standard kern/subr_prf.c standard kern/subr_prng.c standard kern/subr_prof.c standard kern/subr_rangeset.c standard kern/subr_rman.c standard kern/subr_rtc.c standard kern/subr_sbuf.c standard kern/subr_scanf.c standard kern/subr_sglist.c standard kern/subr_sleepqueue.c standard kern/subr_smp.c standard kern/subr_smr.c standard kern/subr_stack.c optional ddb | stack | ktr kern/subr_stats.c optional stats kern/subr_taskqueue.c standard kern/subr_terminal.c optional vt kern/subr_trap.c standard kern/subr_turnstile.c standard kern/subr_uio.c standard kern/subr_unit.c standard kern/subr_vmem.c standard kern/subr_witness.c optional witness kern/sys_capability.c standard kern/sys_eventfd.c standard kern/sys_generic.c standard kern/sys_getrandom.c standard kern/sys_pipe.c standard kern/sys_procdesc.c standard kern/sys_process.c standard kern/sys_socket.c standard kern/sys_timerfd.c standard kern/syscalls.c standard kern/sysv_ipc.c standard kern/sysv_msg.c optional sysvmsg kern/sysv_sem.c optional sysvsem kern/sysv_shm.c optional sysvshm kern/tty.c standard kern/tty_compat.c optional compat_43tty kern/tty_info.c standard kern/tty_inq.c standard kern/tty_outq.c standard kern/tty_pts.c standard kern/tty_tty.c standard kern/tty_ttydisc.c standard kern/uipc_accf.c standard kern/uipc_debug.c optional ddb kern/uipc_domain.c standard kern/uipc_ktls.c optional kern_tls kern/uipc_mbuf.c standard kern/uipc_mbuf2.c standard kern/uipc_mbufhash.c standard kern/uipc_mqueue.c optional p1003_1b_mqueue kern/uipc_sem.c optional p1003_1b_semaphores kern/uipc_shm.c standard kern/uipc_sockbuf.c standard kern/uipc_socket.c standard kern/uipc_syscalls.c standard kern/uipc_usrreq.c standard kern/vfs_acl.c standard kern/vfs_aio.c standard kern/vfs_bio.c standard kern/vfs_cache.c standard kern/vfs_cluster.c standard kern/vfs_default.c standard kern/vfs_export.c standard kern/vfs_extattr.c standard kern/vfs_hash.c standard kern/vfs_init.c standard kern/vfs_lookup.c standard kern/vfs_mount.c standard kern/vfs_mountroot.c standard kern/vfs_subr.c standard kern/vfs_syscalls.c standard kern/vfs_vnops.c standard # # Kernel GSS-API # gssd.h optional kgssapi \ dependency "$S/kgssapi/gssd.x" \ compile-with "RPCGEN_CPP='${CPP}' rpcgen -hM $S/kgssapi/gssd.x | grep -v pthread.h > gssd.h" \ no-obj no-implicit-rule before-depend local \ clean "gssd.h" gssd_xdr.c optional kgssapi \ dependency "$S/kgssapi/gssd.x gssd.h" \ compile-with "RPCGEN_CPP='${CPP}' rpcgen -c $S/kgssapi/gssd.x -o gssd_xdr.c" \ no-ctfconvert no-implicit-rule before-depend local \ clean "gssd_xdr.c" gssd_clnt.c optional kgssapi \ dependency "$S/kgssapi/gssd.x gssd.h" \ compile-with "RPCGEN_CPP='${CPP}' rpcgen -lM $S/kgssapi/gssd.x | grep -v string.h > gssd_clnt.c" \ no-ctfconvert no-implicit-rule before-depend local \ clean "gssd_clnt.c" kgssapi/gss_accept_sec_context.c optional kgssapi kgssapi/gss_add_oid_set_member.c optional kgssapi kgssapi/gss_acquire_cred.c optional kgssapi kgssapi/gss_canonicalize_name.c optional kgssapi kgssapi/gss_create_empty_oid_set.c optional kgssapi kgssapi/gss_delete_sec_context.c optional kgssapi kgssapi/gss_display_status.c optional kgssapi kgssapi/gss_export_name.c optional kgssapi kgssapi/gss_get_mic.c optional kgssapi kgssapi/gss_init_sec_context.c optional kgssapi kgssapi/gss_impl.c optional kgssapi kgssapi/gss_import_name.c optional kgssapi kgssapi/gss_ip_to_dns.c optional kgssapi kgssapi/gss_names.c optional kgssapi kgssapi/gss_pname_to_uid.c optional kgssapi kgssapi/gss_release_buffer.c optional kgssapi kgssapi/gss_release_cred.c optional kgssapi kgssapi/gss_release_name.c optional kgssapi kgssapi/gss_release_oid_set.c optional kgssapi kgssapi/gss_set_cred_option.c optional kgssapi kgssapi/gss_test_oid_set_member.c optional kgssapi kgssapi/gss_unwrap.c optional kgssapi kgssapi/gss_verify_mic.c optional kgssapi kgssapi/gss_wrap.c optional kgssapi kgssapi/gss_wrap_size_limit.c optional kgssapi kgssapi/gssd_prot.c optional kgssapi kgssapi/krb5/krb5_mech.c optional kgssapi kgssapi/krb5/kcrypto.c optional kgssapi kgssapi/krb5/kcrypto_aes.c optional kgssapi kgssapi/kgss_if.m optional kgssapi kgssapi/gsstest.c optional kgssapi_debug # These files in libkern/ are those needed by all architectures. Some # of the files in libkern/ are only needed on some architectures, e.g., # libkern/divdi3.c is needed by i386 but not alpha. Also, some of these # routines may be optimized for a particular platform. In either case, # the file should be moved to conf/files. from here. # libkern/arc4random.c standard libkern/arc4random_uniform.c standard libkern/asprintf.c standard libkern/bcd.c standard libkern/bsearch.c standard libkern/crc16.c standard libkern/explicit_bzero.c standard libkern/fnmatch.c standard libkern/gsb_crc32.c standard libkern/iconv.c optional libiconv libkern/iconv_converter_if.m optional libiconv libkern/iconv_ucs.c optional libiconv libkern/iconv_xlat.c optional libiconv libkern/iconv_xlat16.c optional libiconv libkern/inet_aton.c standard libkern/inet_ntoa.c standard libkern/inet_ntop.c standard libkern/inet_pton.c standard libkern/jenkins_hash.c standard libkern/murmur3_32.c standard libkern/memcchr.c standard libkern/memchr.c standard libkern/memmem.c optional gdb libkern/qsort.c standard libkern/qsort_r.c standard libkern/random.c standard libkern/scanc.c standard libkern/strcasecmp.c standard libkern/strcasestr.c standard libkern/strcat.c standard libkern/strchr.c standard libkern/strchrnul.c standard libkern/strcpy.c standard libkern/strcspn.c standard libkern/strdup.c standard libkern/strndup.c standard libkern/strlcat.c standard libkern/strlcpy.c standard libkern/strncat.c standard libkern/strncpy.c standard libkern/strnlen.c standard libkern/strnstr.c standard libkern/strrchr.c standard libkern/strsep.c standard libkern/strspn.c standard libkern/strstr.c standard libkern/strtol.c standard libkern/strtoq.c standard libkern/strtoul.c standard libkern/strtouq.c standard libkern/strvalid.c standard libkern/timingsafe_bcmp.c standard contrib/zlib/adler32.c optional crypto | geom_uzip | \ mxge | ddb_ctf | gzio | zfs | zlib \ compile-with "${ZLIB_C}" contrib/zlib/compress.c optional crypto | geom_uzip | \ mxge | ddb_ctf | gzio | zfs | zlib \ compile-with "${ZLIB_C}" contrib/zlib/crc32.c optional crypto | geom_uzip | \ mxge | ddb_ctf | gzio | zfs | zlib \ compile-with "${ZLIB_C}" contrib/zlib/deflate.c optional crypto | geom_uzip | \ mxge | ddb_ctf | gzio | zfs | zlib \ compile-with "${ZLIB_C}" contrib/zlib/inffast.c optional crypto | geom_uzip | \ mxge | ddb_ctf | gzio | zfs | zlib \ compile-with "${ZLIB_C}" contrib/zlib/inflate.c optional crypto | geom_uzip | \ mxge | ddb_ctf | gzio | zfs | zlib \ compile-with "${ZLIB_C}" contrib/zlib/inftrees.c optional crypto | geom_uzip | \ mxge | ddb_ctf | gzio | zfs | zlib \ compile-with "${ZLIB_C}" contrib/zlib/trees.c optional crypto | geom_uzip | \ mxge | ddb_ctf | gzio | zfs | zlib \ compile-with "${ZLIB_C}" contrib/zlib/uncompr.c optional crypto | geom_uzip | \ mxge | ddb_ctf | gzio | zfs | zlib \ compile-with "${ZLIB_C}" contrib/zlib/zutil.c optional crypto | geom_uzip | \ mxge | ddb_ctf | gzio | zfs | zlib \ compile-with "${ZLIB_C}" dev/zlib/zlib_mod.c optional crypto | geom_uzip | \ mxge | ddb_ctf | gzio | zfs | zlib dev/zlib/zcalloc.c optional crypto | geom_uzip | \ mxge | ddb_ctf | gzio | zfs | zlib net/altq/altq_cbq.c optional altq net/altq/altq_codel.c optional altq net/altq/altq_hfsc.c optional altq net/altq/altq_fairq.c optional altq net/altq/altq_priq.c optional altq net/altq/altq_red.c optional altq net/altq/altq_rio.c optional altq net/altq/altq_rmclass.c optional altq net/altq/altq_subr.c optional altq net/bpf.c standard net/bpf_buffer.c optional bpf net/bpf_jitter.c optional bpf_jitter net/bpf_filter.c optional bpf | netgraph_bpf net/bpf_zerocopy.c optional bpf net/bridgestp.c optional bridge | if_bridge net/ieee8023ad_lacp.c optional lagg net/if.c standard net/ifq.c standard net/if_bridge.c optional bridge inet | if_bridge inet net/if_clone.c standard net/if_dead.c standard net/if_disc.c optional disc net/if_edsc.c optional edsc net/if_enc.c optional enc inet | enc inet6 net/if_epair.c optional epair net/if_ethersubr.c optional ether net/if_fwsubr.c optional fwip net/if_gif.c optional gif inet | gif inet6 | \ netgraph_gif inet | netgraph_gif inet6 net/if_gre.c optional gre inet | gre inet6 net/if_ipsec.c optional inet ipsec | inet6 ipsec net/if_lagg.c optional lagg net/if_loop.c optional loop net/if_llatbl.c standard net/if_me.c optional me inet net/if_media.c standard net/if_mib.c standard net/if_ovpn.c optional ovpn inet | ovpn inet6 net/if_stf.c optional stf inet inet6 net/if_tuntap.c optional tuntap net/if_vlan.c optional vlan net/if_vxlan.c optional vxlan inet | vxlan inet6 net/ifdi_if.m optional ether pci iflib net/iflib.c optional ether pci iflib net/mp_ring.c optional ether iflib net/mppcc.c optional netgraph_mppc_compression net/mppcd.c optional netgraph_mppc_compression net/netisr.c standard net/debugnet.c optional inet debugnet net/debugnet_inet.c optional inet debugnet net/pfil.c optional ether | inet net/radix.c standard net/route.c standard net/route/nhgrp.c optional route_mpath net/route/nhgrp_ctl.c optional route_mpath net/route/nhop.c standard net/route/nhop_ctl.c standard net/route/nhop_utils.c standard net/route/fib_algo.c optional fib_algo net/route/route_ctl.c standard net/route/route_ddb.c optional ddb net/route/route_helpers.c standard net/route/route_ifaddrs.c standard net/route/route_rtentry.c standard net/route/route_subscription.c standard net/route/route_tables.c standard net/route/route_temporal.c standard net/rss_config.c optional inet rss | inet6 rss net/rtsock.c standard net/slcompress.c optional netgraph_vjc net/toeplitz.c optional inet rss | inet6 rss | route_mpath net/vnet.c optional vimage net80211/ieee80211.c optional wlan net80211/ieee80211_acl.c optional wlan wlan_acl net80211/ieee80211_action.c optional wlan net80211/ieee80211_adhoc.c optional wlan \ compile-with "${NORMAL_C} -Wno-unused-function" net80211/ieee80211_ageq.c optional wlan net80211/ieee80211_amrr.c optional wlan | wlan_amrr net80211/ieee80211_crypto.c optional wlan \ compile-with "${NORMAL_C} -Wno-unused-function" net80211/ieee80211_crypto_ccmp.c optional wlan wlan_ccmp net80211/ieee80211_crypto_none.c optional wlan net80211/ieee80211_crypto_tkip.c optional wlan wlan_tkip net80211/ieee80211_crypto_wep.c optional wlan wlan_wep net80211/ieee80211_ddb.c optional wlan ddb net80211/ieee80211_dfs.c optional wlan net80211/ieee80211_freebsd.c optional wlan net80211/ieee80211_hostap.c optional wlan \ compile-with "${NORMAL_C} -Wno-unused-function" net80211/ieee80211_ht.c optional wlan net80211/ieee80211_hwmp.c optional wlan ieee80211_support_mesh net80211/ieee80211_input.c optional wlan net80211/ieee80211_ioctl.c optional wlan net80211/ieee80211_mesh.c optional wlan ieee80211_support_mesh \ compile-with "${NORMAL_C} -Wno-unused-function" net80211/ieee80211_monitor.c optional wlan net80211/ieee80211_node.c optional wlan net80211/ieee80211_output.c optional wlan net80211/ieee80211_phy.c optional wlan net80211/ieee80211_power.c optional wlan net80211/ieee80211_proto.c optional wlan net80211/ieee80211_radiotap.c optional wlan net80211/ieee80211_ratectl.c optional wlan net80211/ieee80211_ratectl_none.c optional wlan net80211/ieee80211_regdomain.c optional wlan net80211/ieee80211_rssadapt.c optional wlan wlan_rssadapt net80211/ieee80211_scan.c optional wlan net80211/ieee80211_scan_sta.c optional wlan net80211/ieee80211_sta.c optional wlan \ compile-with "${NORMAL_C} -Wno-unused-function" net80211/ieee80211_superg.c optional wlan ieee80211_support_superg net80211/ieee80211_scan_sw.c optional wlan net80211/ieee80211_tdma.c optional wlan ieee80211_support_tdma net80211/ieee80211_vht.c optional wlan net80211/ieee80211_wds.c optional wlan net80211/ieee80211_xauth.c optional wlan wlan_xauth net80211/ieee80211_alq.c optional wlan ieee80211_alq netgraph/bluetooth/common/ng_bluetooth.c optional netgraph_bluetooth netgraph/bluetooth/drivers/ubt/ng_ubt.c optional netgraph_bluetooth_ubt usb netgraph/bluetooth/drivers/ubt/ng_ubt_intel.c optional netgraph_bluetooth_ubt usb netgraph/bluetooth/drivers/ubtbcmfw/ubtbcmfw.c optional netgraph_bluetooth_ubtbcmfw usb netgraph/bluetooth/hci/ng_hci_cmds.c optional netgraph_bluetooth_hci netgraph/bluetooth/hci/ng_hci_evnt.c optional netgraph_bluetooth_hci netgraph/bluetooth/hci/ng_hci_main.c optional netgraph_bluetooth_hci netgraph/bluetooth/hci/ng_hci_misc.c optional netgraph_bluetooth_hci netgraph/bluetooth/hci/ng_hci_ulpi.c optional netgraph_bluetooth_hci netgraph/bluetooth/l2cap/ng_l2cap_cmds.c optional netgraph_bluetooth_l2cap netgraph/bluetooth/l2cap/ng_l2cap_evnt.c optional netgraph_bluetooth_l2cap netgraph/bluetooth/l2cap/ng_l2cap_llpi.c optional netgraph_bluetooth_l2cap netgraph/bluetooth/l2cap/ng_l2cap_main.c optional netgraph_bluetooth_l2cap netgraph/bluetooth/l2cap/ng_l2cap_misc.c optional netgraph_bluetooth_l2cap netgraph/bluetooth/l2cap/ng_l2cap_ulpi.c optional netgraph_bluetooth_l2cap netgraph/bluetooth/socket/ng_btsocket.c optional netgraph_bluetooth_socket netgraph/bluetooth/socket/ng_btsocket_hci_raw.c optional netgraph_bluetooth_socket netgraph/bluetooth/socket/ng_btsocket_l2cap.c optional netgraph_bluetooth_socket netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c optional netgraph_bluetooth_socket netgraph/bluetooth/socket/ng_btsocket_rfcomm.c optional netgraph_bluetooth_socket netgraph/bluetooth/socket/ng_btsocket_sco.c optional netgraph_bluetooth_socket netgraph/netflow/netflow.c optional netgraph_netflow netgraph/netflow/netflow_v9.c optional netgraph_netflow netgraph/netflow/ng_netflow.c optional netgraph_netflow netgraph/ng_UI.c optional netgraph_UI netgraph/ng_async.c optional netgraph_async netgraph/ng_base.c optional netgraph netgraph/ng_bpf.c optional netgraph_bpf netgraph/ng_bridge.c optional netgraph_bridge netgraph/ng_car.c optional netgraph_car netgraph/ng_checksum.c optional netgraph_checksum netgraph/ng_cisco.c optional netgraph_cisco netgraph/ng_deflate.c optional netgraph_deflate netgraph/ng_device.c optional netgraph_device netgraph/ng_echo.c optional netgraph_echo netgraph/ng_eiface.c optional netgraph_eiface netgraph/ng_ether.c optional netgraph_ether netgraph/ng_ether_echo.c optional netgraph_ether_echo netgraph/ng_frame_relay.c optional netgraph_frame_relay netgraph/ng_gif.c optional netgraph_gif inet6 | netgraph_gif inet netgraph/ng_gif_demux.c optional netgraph_gif_demux netgraph/ng_hole.c optional netgraph_hole netgraph/ng_iface.c optional netgraph_iface netgraph/ng_ip_input.c optional netgraph_ip_input netgraph/ng_ipfw.c optional netgraph_ipfw inet ipfirewall netgraph/ng_ksocket.c optional netgraph_ksocket netgraph/ng_l2tp.c optional netgraph_l2tp netgraph/ng_lmi.c optional netgraph_lmi netgraph/ng_macfilter.c optional netgraph_macfilter netgraph/ng_mppc.c optional netgraph_mppc_compression | \ netgraph_mppc_encryption netgraph/ng_nat.c optional netgraph_nat inet libalias netgraph/ng_one2many.c optional netgraph_one2many netgraph/ng_parse.c optional netgraph netgraph/ng_patch.c optional netgraph_patch netgraph/ng_pipe.c optional netgraph_pipe netgraph/ng_ppp.c optional netgraph_ppp netgraph/ng_pppoe.c optional netgraph_pppoe netgraph/ng_pptpgre.c optional netgraph_pptpgre netgraph/ng_pred1.c optional netgraph_pred1 netgraph/ng_rfc1490.c optional netgraph_rfc1490 netgraph/ng_socket.c optional netgraph_socket netgraph/ng_split.c optional netgraph_split netgraph/ng_tag.c optional netgraph_tag netgraph/ng_tcpmss.c optional netgraph_tcpmss netgraph/ng_tee.c optional netgraph_tee netgraph/ng_tty.c optional netgraph_tty netgraph/ng_vjc.c optional netgraph_vjc netgraph/ng_vlan.c optional netgraph_vlan netgraph/ng_vlan_rotate.c optional netgraph_vlan_rotate netinet/accf_data.c optional accept_filter_data inet netinet/accf_dns.c optional accept_filter_dns inet netinet/accf_http.c optional accept_filter_http inet netinet/if_ether.c optional inet ether netinet/igmp.c optional inet netinet/in.c optional inet netinet/in_cksum.c optional inet | inet6 netinet/in_debug.c optional inet ddb netinet/in_kdtrace.c optional inet | inet6 netinet/ip_carp.c optional inet carp | inet6 carp netinet/in_fib.c optional inet netinet/in_fib_algo.c optional inet fib_algo netinet/in_gif.c optional gif inet | netgraph_gif inet netinet/ip_gre.c optional gre inet netinet/ip_id.c optional inet netinet/in_jail.c optional inet netinet/in_mcast.c optional inet netinet/in_pcb.c optional inet | inet6 netinet/in_prot.c optional inet | inet6 netinet/in_proto.c optional inet | inet6 netinet/in_rmx.c optional inet netinet/in_rss.c optional inet rss netinet/ip_divert.c optional ipdivert inet | ipdivert inet6 netinet/ip_ecn.c optional inet | inet6 netinet/ip_encap.c optional inet | inet6 netinet/ip_fastfwd.c optional inet netinet/ip_icmp.c optional inet | inet6 netinet/ip_input.c optional inet netinet/ip_mroute.c optional mrouting inet netinet/ip_options.c optional inet netinet/ip_output.c optional inet netinet/ip_reass.c optional inet netinet/raw_ip.c optional inet | inet6 netinet/cc/cc.c optional cc_newreno inet | cc_vegas inet | \ cc_htcp inet | cc_hd inet | cc_dctcp inet | cc_cubic inet | \ cc_chd inet | cc_cdg inet | cc_newreno inet6 | cc_vegas inet6 | \ cc_htcp inet6 | cc_hd inet6 |cc_dctcp inet6 | cc_cubic inet6 | \ cc_chd inet6 | cc_cdg inet6 netinet/cc/cc_cdg.c optional inet cc_cdg tcp_hhook netinet/cc/cc_chd.c optional inet cc_chd tcp_hhook netinet/cc/cc_cubic.c optional inet cc_cubic | inet6 cc_cubic netinet/cc/cc_dctcp.c optional inet cc_dctcp | inet6 cc_dctcp netinet/cc/cc_hd.c optional inet cc_hd tcp_hhook netinet/cc/cc_htcp.c optional inet cc_htcp | inet6 cc_htcp netinet/cc/cc_newreno.c optional inet cc_newreno | inet6 cc_newreno netinet/cc/cc_vegas.c optional inet cc_vegas tcp_hhook netinet/khelp/h_ertt.c optional inet tcp_hhook netinet/sctp_asconf.c optional inet sctp | inet6 sctp netinet/sctp_auth.c optional inet sctp | inet6 sctp netinet/sctp_bsd_addr.c optional inet sctp | inet6 sctp netinet/sctp_cc_functions.c optional inet sctp | inet6 sctp netinet/sctp_crc32.c optional inet | inet6 netinet/sctp_indata.c optional inet sctp | inet6 sctp netinet/sctp_input.c optional inet sctp | inet6 sctp netinet/sctp_kdtrace.c optional inet sctp | inet6 sctp netinet/sctp_module.c optional inet sctp | inet6 sctp netinet/sctp_output.c optional inet sctp | inet6 sctp netinet/sctp_pcb.c optional inet sctp | inet6 sctp netinet/sctp_peeloff.c optional inet sctp | inet6 sctp netinet/sctp_ss_functions.c optional inet sctp | inet6 sctp netinet/sctp_syscalls.c optional inet sctp | inet6 sctp netinet/sctp_sysctl.c optional inet sctp | inet6 sctp netinet/sctp_timer.c optional inet sctp | inet6 sctp netinet/sctp_usrreq.c optional inet sctp | inet6 sctp netinet/sctputil.c optional inet sctp | inet6 sctp netinet/siftr.c optional inet siftr alq | inet6 siftr alq netinet/tcp_ecn.c optional inet | inet6 netinet/tcp_fastopen.c optional inet tcp_rfc7413 | inet6 tcp_rfc7413 netinet/tcp_hostcache.c optional inet | inet6 netinet/tcp_input.c optional inet | inet6 netinet/tcp_log_buf.c optional tcp_blackbox inet | tcp_blackbox inet6 netinet/tcp_lro.c optional inet | inet6 netinet/tcp_lro_hpts.c optional tcphpts inet | tcphpts inet6 netinet/tcp_output.c optional inet | inet6 netinet/tcp_offload.c optional tcp_offload inet | tcp_offload inet6 netinet/tcp_hpts.c optional tcphpts inet | tcphpts inet6 netinet/tcp_ratelimit.c optional ratelimit inet | ratelimit inet6 netinet/tcp_pcap.c optional inet tcppcap | inet6 tcppcap \ compile-with "${NORMAL_C} ${NO_WNONNULL}" netinet/tcp_reass.c optional inet | inet6 netinet/tcp_sack.c optional inet | inet6 netinet/tcp_stacks/bbr.c optional inet tcphpts tcp_bbr | inet6 tcphpts tcp_bbr \ compile-with "${NORMAL_C} -DMODNAME=tcp_bbr -DSTACKNAME=bbr" netinet/tcp_stacks/rack.c optional inet tcphpts tcp_rack | inet6 tcphpts tcp_rack \ compile-with "${NORMAL_C} -DMODNAME=tcp_rack -DSTACKNAME=rack" netinet/tcp_stacks/rack_bbr_common.c optional inet tcphpts tcp_bbr | inet tcphpts tcp_rack | inet6 tcphpts tcp_bbr | inet6 tcphpts tcp_rack netinet/tcp_stacks/sack_filter.c optional inet tcphpts tcp_bbr | inet tcphpts tcp_rack | inet6 tcphpts tcp_bbr | inet6 tcphpts tcp_rack netinet/tcp_stacks/tailq_hash.c optional inet tcphpts tcp_bbr | inet tcphpts tcp_rack | inet6 tcphpts tcp_bbr | inet6 tcphpts tcp_rack netinet/tcp_stats.c optional stats inet | stats inet6 netinet/tcp_subr.c optional inet | inet6 netinet/tcp_syncache.c optional inet | inet6 netinet/tcp_timer.c optional inet | inet6 netinet/tcp_timewait.c optional inet | inet6 netinet/tcp_usrreq.c optional inet | inet6 netinet/udp_usrreq.c optional inet | inet6 netinet/libalias/alias.c optional libalias inet | netgraph_nat inet netinet/libalias/alias_db.c optional libalias inet | netgraph_nat inet netinet/libalias/alias_mod.c optional libalias | netgraph_nat netinet/libalias/alias_proxy.c optional libalias inet | netgraph_nat inet netinet/libalias/alias_util.c optional libalias inet | netgraph_nat inet netinet/libalias/alias_sctp.c optional libalias inet | netgraph_nat inet netinet/netdump/netdump_client.c optional inet debugnet netdump netinet6/dest6.c optional inet6 netinet6/frag6.c optional inet6 netinet6/icmp6.c optional inet6 netinet6/in6.c optional inet6 netinet6/in6_cksum.c optional inet6 netinet6/in6_fib.c optional inet6 netinet6/in6_fib_algo.c optional inet6 fib_algo netinet6/in6_gif.c optional gif inet6 | netgraph_gif inet6 netinet6/in6_ifattach.c optional inet6 netinet6/in6_jail.c optional inet6 netinet6/in6_mcast.c optional inet6 netinet6/in6_pcb.c optional inet6 netinet6/in6_proto.c optional inet6 netinet6/in6_rmx.c optional inet6 netinet6/in6_rss.c optional inet6 rss netinet6/in6_src.c optional inet6 netinet6/ip6_fastfwd.c optional inet6 netinet6/ip6_forward.c optional inet6 netinet6/ip6_gre.c optional gre inet6 netinet6/ip6_id.c optional inet6 netinet6/ip6_input.c optional inet6 netinet6/ip6_mroute.c optional mrouting inet6 netinet6/ip6_output.c optional inet6 netinet6/mld6.c optional inet6 netinet6/nd6.c optional inet6 netinet6/nd6_nbr.c optional inet6 netinet6/nd6_rtr.c optional inet6 netinet6/raw_ip6.c optional inet6 netinet6/route6.c optional inet6 netinet6/scope6.c optional inet6 netinet6/sctp6_usrreq.c optional inet6 sctp netinet6/udp6_usrreq.c optional inet6 netipsec/ipsec.c optional ipsec inet | ipsec inet6 netipsec/ipsec_input.c optional ipsec inet | ipsec inet6 netipsec/ipsec_mbuf.c optional ipsec inet | ipsec inet6 netipsec/ipsec_mod.c optional ipsec inet | ipsec inet6 netipsec/ipsec_output.c optional ipsec inet | ipsec inet6 netipsec/ipsec_pcb.c optional ipsec inet | ipsec inet6 | \ ipsec_support inet | ipsec_support inet6 netipsec/key.c optional ipsec inet | ipsec inet6 | \ ipsec_support inet | ipsec_support inet6 netipsec/key_debug.c optional ipsec inet | ipsec inet6 | \ ipsec_support inet | ipsec_support inet6 netipsec/keysock.c optional ipsec inet | ipsec inet6 | \ ipsec_support inet | ipsec_support inet6 netipsec/subr_ipsec.c optional ipsec inet | ipsec inet6 | \ ipsec_support inet | ipsec_support inet6 netipsec/udpencap.c optional ipsec inet netipsec/xform_ah.c optional ipsec inet | ipsec inet6 netipsec/xform_esp.c optional ipsec inet | ipsec inet6 netipsec/xform_ipcomp.c optional ipsec inet | ipsec inet6 netipsec/xform_tcp.c optional ipsec inet tcp_signature | \ ipsec inet6 tcp_signature | ipsec_support inet tcp_signature | \ ipsec_support inet6 tcp_signature netlink/netlink_generic_kpi.c standard netlink/netlink_glue.c standard netlink/netlink_message_parser.c standard netlink/netlink_domain.c optional netlink netlink/netlink_generic.c optional netlink netlink/netlink_io.c optional netlink netlink/netlink_message_writer.c optional netlink netlink/netlink_module.c optional netlink netlink/netlink_route.c optional netlink netlink/route/iface_drivers.c optional netlink netlink/route/iface.c optional netlink netlink/route/neigh.c optional netlink netlink/route/nexthop.c optional netlink netlink/route/rt.c optional netlink netpfil/ipfw/dn_aqm_codel.c optional inet dummynet netpfil/ipfw/dn_aqm_pie.c optional inet dummynet netpfil/ipfw/dn_heap.c optional inet dummynet netpfil/ipfw/dn_sched_fifo.c optional inet dummynet netpfil/ipfw/dn_sched_fq_codel.c optional inet dummynet netpfil/ipfw/dn_sched_fq_pie.c optional inet dummynet netpfil/ipfw/dn_sched_prio.c optional inet dummynet netpfil/ipfw/dn_sched_qfq.c optional inet dummynet netpfil/ipfw/dn_sched_rr.c optional inet dummynet netpfil/ipfw/dn_sched_wf2q.c optional inet dummynet netpfil/ipfw/ip_dummynet.c optional inet dummynet netpfil/ipfw/ip_dn_io.c optional inet dummynet netpfil/ipfw/ip_dn_glue.c optional inet dummynet netpfil/ipfw/ip_fw2.c optional inet ipfirewall netpfil/ipfw/ip_fw_bpf.c optional inet ipfirewall netpfil/ipfw/ip_fw_dynamic.c optional inet ipfirewall \ compile-with "${NORMAL_C} -I$S/contrib/ck/include" netpfil/ipfw/ip_fw_eaction.c optional inet ipfirewall netpfil/ipfw/ip_fw_log.c optional inet ipfirewall netpfil/ipfw/ip_fw_pfil.c optional inet ipfirewall netpfil/ipfw/ip_fw_sockopt.c optional inet ipfirewall netpfil/ipfw/ip_fw_table.c optional inet ipfirewall netpfil/ipfw/ip_fw_table_algo.c optional inet ipfirewall netpfil/ipfw/ip_fw_table_value.c optional inet ipfirewall netpfil/ipfw/ip_fw_iface.c optional inet ipfirewall netpfil/ipfw/ip_fw_nat.c optional inet ipfirewall_nat netpfil/ipfw/nat64/ip_fw_nat64.c optional inet inet6 ipfirewall \ ipfirewall_nat64 netpfil/ipfw/nat64/nat64clat.c optional inet inet6 ipfirewall \ ipfirewall_nat64 netpfil/ipfw/nat64/nat64clat_control.c optional inet inet6 ipfirewall \ ipfirewall_nat64 netpfil/ipfw/nat64/nat64lsn.c optional inet inet6 ipfirewall \ ipfirewall_nat64 compile-with "${NORMAL_C} -I$S/contrib/ck/include" netpfil/ipfw/nat64/nat64lsn_control.c optional inet inet6 ipfirewall \ ipfirewall_nat64 compile-with "${NORMAL_C} -I$S/contrib/ck/include" netpfil/ipfw/nat64/nat64stl.c optional inet inet6 ipfirewall \ ipfirewall_nat64 netpfil/ipfw/nat64/nat64stl_control.c optional inet inet6 ipfirewall \ ipfirewall_nat64 netpfil/ipfw/nat64/nat64_translate.c optional inet inet6 ipfirewall \ ipfirewall_nat64 netpfil/ipfw/nptv6/ip_fw_nptv6.c optional inet inet6 ipfirewall \ ipfirewall_nptv6 netpfil/ipfw/nptv6/nptv6.c optional inet inet6 ipfirewall \ ipfirewall_nptv6 netpfil/ipfw/pmod/ip_fw_pmod.c optional inet ipfirewall_pmod netpfil/ipfw/pmod/tcpmod.c optional inet ipfirewall_pmod netpfil/pf/if_pflog.c optional pflog pf inet netpfil/pf/if_pfsync.c optional pfsync pf inet netpfil/pf/pf.c optional pf inet netpfil/pf/pf_if.c optional pf inet netpfil/pf/pf_ioctl.c optional pf inet netpfil/pf/pf_lb.c optional pf inet netpfil/pf/pf_norm.c optional pf inet netpfil/pf/pf_nl.c optional pf inet netpfil/pf/pf_nv.c optional pf inet netpfil/pf/pf_osfp.c optional pf inet netpfil/pf/pf_ruleset.c optional pf inet netpfil/pf/pf_syncookies.c optional pf inet netpfil/pf/pf_table.c optional pf inet netpfil/pf/pfsync_nv.c optional pfsync pf inet netpfil/pf/in4_cksum.c optional pf inet netsmb/smb_conn.c optional netsmb netsmb/smb_crypt.c optional netsmb netsmb/smb_dev.c optional netsmb netsmb/smb_iod.c optional netsmb netsmb/smb_rq.c optional netsmb netsmb/smb_smb.c optional netsmb netsmb/smb_subr.c optional netsmb netsmb/smb_trantcp.c optional netsmb netsmb/smb_usr.c optional netsmb nfs/bootp_subr.c optional bootp nfscl nfs/krpc_subr.c optional bootp nfscl nfs/nfs_diskless.c optional nfscl nfs_root nfs/nfs_nfssvc.c optional nfscl | nfslockd | nfsd nlm/nlm_advlock.c optional nfslockd | nfsd nlm/nlm_prot_clnt.c optional nfslockd | nfsd nlm/nlm_prot_impl.c optional nfslockd | nfsd nlm/nlm_prot_server.c optional nfslockd | nfsd nlm/nlm_prot_svc.c optional nfslockd | nfsd nlm/nlm_prot_xdr.c optional nfslockd | nfsd nlm/sm_inter_xdr.c optional nfslockd | nfsd # Linux Kernel Programming Interface compat/linuxkpi/common/src/linux_80211.c optional compat_linuxkpi wlan \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_80211_macops.c optional compat_linuxkpi wlan \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_kmod.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_acpi.c optional compat_linuxkpi acpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_compat.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_current.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_devres.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_dmi.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_domain.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_firmware.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_fpu.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_hrtimer.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_i2c.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_i2cbb.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_interrupt.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_kobject.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_kthread.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_lock.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_mhi.c optional compat_linuxkpi wlan \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_netdev.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_page.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_pci.c optional compat_linuxkpi pci \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_tasklet.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_idr.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_radix.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_rcu.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C} -I$S/contrib/ck/include" compat/linuxkpi/common/src/linux_schedule.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_shmemfs.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_shrinker.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_skbuff.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_slab.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_usb.c optional compat_linuxkpi usb \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_work.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_xarray.c optional compat_linuxkpi \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/lkpi_iic_if.m optional compat_linuxkpi compat/linuxkpi/common/src/linux_seq_file.c optional compat_linuxkpi | lindebugfs \ compile-with "${LINUXKPI_C}" compat/linuxkpi/common/src/linux_simple_attr.c optional compat_linuxkpi | lindebugfs \ compile-with "${LINUXKPI_C}" compat/lindebugfs/lindebugfs.c optional lindebugfs \ compile-with "${LINUXKPI_C}" # OpenFabrics Enterprise Distribution (Infiniband) net/if_infiniband.c optional ofed | lagg ofed/drivers/infiniband/core/ib_addr.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_agent.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_cache.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_cm.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_cma.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_core_uverbs.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_cq.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_device.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_fmr_pool.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_iwcm.c optional ofed \ compile-with "${OFED_C} ${NO_WUNUSED_BUT_SET_VARIABLE}" ofed/drivers/infiniband/core/ib_iwpm_msg.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_iwpm_util.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_mad.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_mad_rmpp.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_multicast.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_packer.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_rdma_core.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_roce_gid_mgmt.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_sa_query.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_smi.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_sysfs.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_ucm.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_ucma.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_ud_header.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_umem.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_user_mad.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_uverbs_cmd.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_uverbs_ioctl.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_uverbs_main.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_uverbs_marshall.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_uverbs_std_types.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_uverbs_std_types_async_fd.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_uverbs_std_types_counters.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_uverbs_std_types_cq.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_uverbs_std_types_device.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_uverbs_std_types_dm.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_uverbs_std_types_flow_action.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_uverbs_std_types_mr.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_uverbs_uapi.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/core/ib_verbs.c optional ofed \ compile-with "${OFED_C}" ofed/drivers/infiniband/ulp/ipoib/ipoib_cm.c optional ipoib \ compile-with "${OFED_C} -I$S/ofed/drivers/infiniband/ulp/ipoib/" #ofed/drivers/infiniband/ulp/ipoib/ipoib_fs.c optional ipoib \ # compile-with "${OFED_C} -I$S/ofed/drivers/infiniband/ulp/ipoib/" ofed/drivers/infiniband/ulp/ipoib/ipoib_ib.c optional ipoib \ compile-with "${OFED_C} -I$S/ofed/drivers/infiniband/ulp/ipoib/" ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c optional ipoib \ compile-with "${OFED_C} -I$S/ofed/drivers/infiniband/ulp/ipoib/" ofed/drivers/infiniband/ulp/ipoib/ipoib_multicast.c optional ipoib \ compile-with "${OFED_C} -I$S/ofed/drivers/infiniband/ulp/ipoib/" ofed/drivers/infiniband/ulp/ipoib/ipoib_verbs.c optional ipoib \ compile-with "${OFED_C} -I$S/ofed/drivers/infiniband/ulp/ipoib/" #ofed/drivers/infiniband/ulp/ipoib/ipoib_vlan.c optional ipoib \ # compile-with "${OFED_C} -I$S/ofed/drivers/infiniband/ulp/ipoib/" ofed/drivers/infiniband/ulp/sdp/sdp_bcopy.c optional sdp inet \ compile-with "${OFED_C} -I$S/ofed/drivers/infiniband/ulp/sdp/" ofed/drivers/infiniband/ulp/sdp/sdp_main.c optional sdp inet \ compile-with "${OFED_C} -I$S/ofed/drivers/infiniband/ulp/sdp/" ofed/drivers/infiniband/ulp/sdp/sdp_rx.c optional sdp inet \ compile-with "${OFED_C} -I$S/ofed/drivers/infiniband/ulp/sdp/ ${NO_WUNUSED_BUT_SET_VARIABLE}" ofed/drivers/infiniband/ulp/sdp/sdp_cma.c optional sdp inet \ compile-with "${OFED_C} -I$S/ofed/drivers/infiniband/ulp/sdp/" ofed/drivers/infiniband/ulp/sdp/sdp_tx.c optional sdp inet \ compile-with "${OFED_C} -I$S/ofed/drivers/infiniband/ulp/sdp/ ${NO_WUNUSED_BUT_SET_VARIABLE}" dev/irdma/icrdma.c optional irdma ice inet inet6 pci ofed \ compile-with "${OFED_C} -I$S/dev/ice/" dev/irdma/irdma_cm.c optional irdma ice inet inet6 pci ofed \ compile-with "${OFED_C} -I$S/dev/ice/" dev/irdma/irdma_ctrl.c optional irdma ice inet inet6 pci ofed \ compile-with "${OFED_C} -I$S/dev/ice/" dev/irdma/irdma_hmc.c optional irdma ice inet inet6 pci ofed \ compile-with "${OFED_C} -I$S/dev/ice/" dev/irdma/irdma_hw.c optional irdma ice inet inet6 pci ofed \ compile-with "${OFED_C} -I$S/dev/ice/" dev/irdma/icrdma_hw.c optional irdma ice inet inet6 pci ofed \ compile-with "${OFED_C} -I$S/dev/ice/" dev/irdma/fbsd_kcompat.c optional irdma ice inet inet6 pci ofed \ compile-with "${OFED_C} -I$S/dev/ice/" dev/irdma/irdma_kcompat.c optional irdma ice inet inet6 pci ofed \ compile-with "${OFED_C} -I$S/dev/ice/" dev/irdma/irdma_pble.c optional irdma ice inet inet6 pci ofed \ compile-with "${OFED_C} -I$S/dev/ice/" dev/irdma/irdma_puda.c optional irdma ice inet inet6 pci ofed \ compile-with "${OFED_C} -I$S/dev/ice/" dev/irdma/irdma_uda.c optional irdma ice inet inet6 pci ofed \ compile-with "${OFED_C} -I$S/dev/ice/" dev/irdma/irdma_uk.c optional irdma ice inet inet6 pci ofed \ compile-with "${OFED_C} -I$S/dev/ice/" dev/irdma/irdma_utils.c optional irdma ice inet inet6 pci ofed \ compile-with "${OFED_C} -I$S/dev/ice/" dev/irdma/irdma_verbs.c optional irdma ice inet inet6 pci ofed \ compile-with "${OFED_C} -I$S/dev/ice/" dev/irdma/irdma_ws.c optional irdma ice inet inet6 pci ofed \ compile-with "${OFED_C} -I$S/dev/ice/" dev/mthca/mthca_allocator.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mthca/mthca_av.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mthca/mthca_catas.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mthca/mthca_cmd.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mthca/mthca_cq.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mthca/mthca_eq.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mthca/mthca_mad.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mthca/mthca_main.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mthca/mthca_mcg.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mthca/mthca_memfree.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mthca/mthca_mr.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mthca/mthca_pd.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mthca/mthca_profile.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mthca/mthca_provider.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mthca/mthca_qp.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mthca/mthca_reset.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mthca/mthca_srq.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mthca/mthca_uar.c optional mthca pci ofed \ compile-with "${OFED_C}" dev/mlx4/mlx4_ib/mlx4_ib_alias_GUID.c optional mlx4ib pci ofed \ compile-with "${OFED_C}" dev/mlx4/mlx4_ib/mlx4_ib_mcg.c optional mlx4ib pci ofed \ compile-with "${OFED_C}" dev/mlx4/mlx4_ib/mlx4_ib_sysfs.c optional mlx4ib pci ofed \ compile-with "${OFED_C}" dev/mlx4/mlx4_ib/mlx4_ib_cm.c optional mlx4ib pci ofed \ compile-with "${OFED_C}" dev/mlx4/mlx4_ib/mlx4_ib_ah.c optional mlx4ib pci ofed \ compile-with "${OFED_C}" dev/mlx4/mlx4_ib/mlx4_ib_cq.c optional mlx4ib pci ofed \ compile-with "${OFED_C}" dev/mlx4/mlx4_ib/mlx4_ib_doorbell.c optional mlx4ib pci ofed \ compile-with "${OFED_C}" dev/mlx4/mlx4_ib/mlx4_ib_mad.c optional mlx4ib pci ofed \ compile-with "${OFED_C}" dev/mlx4/mlx4_ib/mlx4_ib_main.c optional mlx4ib pci ofed \ compile-with "${OFED_C}" dev/mlx4/mlx4_ib/mlx4_ib_mr.c optional mlx4ib pci ofed \ compile-with "${OFED_C}" dev/mlx4/mlx4_ib/mlx4_ib_qp.c optional mlx4ib pci ofed \ compile-with "${OFED_C}" dev/mlx4/mlx4_ib/mlx4_ib_srq.c optional mlx4ib pci ofed \ compile-with "${OFED_C}" dev/mlx4/mlx4_ib/mlx4_ib_wc.c optional mlx4ib pci ofed \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_alloc.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_catas.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_cmd.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_cq.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_eq.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_fw.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_fw_qos.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_icm.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_intf.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_main.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_mcg.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_mr.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_pd.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_port.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_profile.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_qp.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_reset.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_sense.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_srq.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_core/mlx4_resource_tracker.c optional mlx4 pci \ compile-with "${OFED_C}" dev/mlx4/mlx4_en/mlx4_en_cq.c optional mlx4en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx4/mlx4_en/mlx4_en_main.c optional mlx4en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx4/mlx4_en/mlx4_en_netdev.c optional mlx4en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx4/mlx4_en/mlx4_en_port.c optional mlx4en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx4/mlx4_en/mlx4_en_resources.c optional mlx4en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx4/mlx4_en/mlx4_en_rx.c optional mlx4en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx4/mlx4_en/mlx4_en_tx.c optional mlx4en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx5/mlx5_ib/mlx5_ib_ah.c optional mlx5ib pci ofed \ compile-with "${OFED_C}" dev/mlx5/mlx5_ib/mlx5_ib_cong.c optional mlx5ib pci ofed \ compile-with "${OFED_C}" dev/mlx5/mlx5_ib/mlx5_ib_cq.c optional mlx5ib pci ofed \ compile-with "${OFED_C}" dev/mlx5/mlx5_ib/mlx5_ib_devx.c optional mlx5ib pci ofed \ compile-with "${OFED_C}" dev/mlx5/mlx5_ib/mlx5_ib_doorbell.c optional mlx5ib pci ofed \ compile-with "${OFED_C}" dev/mlx5/mlx5_ib/mlx5_ib_gsi.c optional mlx5ib pci ofed \ compile-with "${OFED_C}" dev/mlx5/mlx5_ib/mlx5_ib_mad.c optional mlx5ib pci ofed \ compile-with "${OFED_C}" dev/mlx5/mlx5_ib/mlx5_ib_main.c optional mlx5ib pci ofed \ compile-with "${OFED_C}" dev/mlx5/mlx5_ib/mlx5_ib_mem.c optional mlx5ib pci ofed \ compile-with "${OFED_C}" dev/mlx5/mlx5_ib/mlx5_ib_mr.c optional mlx5ib pci ofed \ compile-with "${OFED_C}" dev/mlx5/mlx5_ib/mlx5_ib_qp.c optional mlx5ib pci ofed \ compile-with "${OFED_C}" dev/mlx5/mlx5_ib/mlx5_ib_srq.c optional mlx5ib pci ofed \ compile-with "${OFED_C}" dev/mlx5/mlx5_ib/mlx5_ib_virt.c optional mlx5ib pci ofed \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_alloc.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_cmd.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_cq.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_diag_cnt.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_diagnostics.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_eq.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_eswitch.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_fc_cmd.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_fs_cmd.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_fs_counters.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_fs_tcp.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_fs_tree.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_fw.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_fwdump.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_health.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_mad.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_main.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_mcg.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_mpfs.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_mr.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_pagealloc.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_pd.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_port.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_qp.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_rl.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_srq.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_tls.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_transobj.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_uar.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_vport.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_vsc.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_core/mlx5_wq.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_lib/mlx5_gid.c optional mlx5 pci \ compile-with "${OFED_C}" dev/mlx5/mlx5_en/mlx5_en_dim.c optional mlx5en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx5/mlx5_en/mlx5_en_ethtool.c optional mlx5en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx5/mlx5_en/mlx5_en_main.c optional mlx5en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx5/mlx5_en/mlx5_en_tx.c optional mlx5en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx5/mlx5_en/mlx5_en_flow_table.c optional mlx5en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx5/mlx5_en/mlx5_en_hw_tls.c optional mlx5en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c optional mlx5en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx5/mlx5_en/mlx5_en_iq.c optional mlx5en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx5/mlx5_en/mlx5_en_rx.c optional mlx5en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx5/mlx5_en/mlx5_en_rl.c optional mlx5en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx5/mlx5_en/mlx5_en_txrx.c optional mlx5en pci inet inet6 \ compile-with "${OFED_C}" dev/mlx5/mlx5_en/mlx5_en_port_buffer.c optional mlx5en pci inet inet6 \ compile-with "${OFED_C}" # crypto support opencrypto/cbc_mac.c optional crypto opencrypto/criov.c optional crypto opencrypto/crypto.c optional crypto opencrypto/cryptodev.c optional cryptodev opencrypto/cryptodev_if.m optional crypto opencrypto/cryptosoft.c optional crypto opencrypto/cryptodeflate.c optional crypto opencrypto/gmac.c optional crypto opencrypto/gfmult.c optional crypto opencrypto/ktls_ocf.c optional kern_tls opencrypto/rmd160.c optional crypto opencrypto/xform_aes_cbc.c optional crypto opencrypto/xform_aes_icm.c optional crypto opencrypto/xform_aes_xts.c optional crypto opencrypto/xform_cbc_mac.c optional crypto opencrypto/xform_chacha20_poly1305.c optional crypto \ compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include -I$S/crypto/libsodium" opencrypto/xform_cml.c optional crypto opencrypto/xform_deflate.c optional crypto opencrypto/xform_gmac.c optional crypto opencrypto/xform_null.c optional crypto opencrypto/xform_poly1305.c optional crypto \ compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include -I$S/crypto/libsodium" opencrypto/xform_rmd160.c optional crypto opencrypto/xform_sha1.c optional crypto opencrypto/xform_sha2.c optional crypto contrib/libsodium/src/libsodium/crypto_core/ed25519/ref10/ed25519_ref10.c \ optional crypto \ compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include/sodium -I$S/crypto/libsodium -Wno-unused-function" contrib/libsodium/src/libsodium/crypto_core/hchacha20/core_hchacha20.c \ optional crypto \ compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include/sodium -I$S/crypto/libsodium" contrib/libsodium/src/libsodium/crypto_onetimeauth/poly1305/onetimeauth_poly1305.c \ optional crypto \ compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include/sodium -I$S/crypto/libsodium" contrib/libsodium/src/libsodium/crypto_onetimeauth/poly1305/donna/poly1305_donna.c \ optional crypto \ compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include/sodium -I$S/crypto/libsodium" contrib/libsodium/src/libsodium/crypto_scalarmult/curve25519/scalarmult_curve25519.c \ optional crypto \ compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include/sodium -I$S/crypto/libsodium" contrib/libsodium/src/libsodium/crypto_scalarmult/curve25519/ref10/x25519_ref10.c \ optional crypto \ compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include/sodium -I$S/crypto/libsodium -Wno-unused-function" contrib/libsodium/src/libsodium/crypto_stream/chacha20/stream_chacha20.c \ optional crypto \ compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include/sodium -I$S/crypto/libsodium" contrib/libsodium/src/libsodium/crypto_stream/chacha20/ref/chacha20_ref.c \ optional crypto \ compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include/sodium -I$S/crypto/libsodium" contrib/libsodium/src/libsodium/crypto_verify/sodium/verify.c \ optional crypto \ compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include/sodium -I$S/crypto/libsodium" crypto/libsodium/randombytes.c optional crypto \ compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include -I$S/crypto/libsodium" crypto/libsodium/utils.c optional crypto \ compile-with "${NORMAL_C} -I$S/contrib/libsodium/src/libsodium/include -I$S/crypto/libsodium" rpc/auth_none.c optional krpc | nfslockd | nfscl | nfsd rpc/auth_unix.c optional krpc | nfslockd | nfscl | nfsd rpc/authunix_prot.c optional krpc | nfslockd | nfscl | nfsd rpc/clnt_bck.c optional krpc | nfslockd | nfscl | nfsd rpc/clnt_dg.c optional krpc | nfslockd | nfscl | nfsd rpc/clnt_rc.c optional krpc | nfslockd | nfscl | nfsd rpc/clnt_vc.c optional krpc | nfslockd | nfscl | nfsd rpc/getnetconfig.c optional krpc | nfslockd | nfscl | nfsd rpc/replay.c optional krpc | nfslockd | nfscl | nfsd rpc/rpc_callmsg.c optional krpc | nfslockd | nfscl | nfsd rpc/rpc_generic.c optional krpc | nfslockd | nfscl | nfsd rpc/rpc_prot.c optional krpc | nfslockd | nfscl | nfsd rpc/rpcb_clnt.c optional krpc | nfslockd | nfscl | nfsd rpc/rpcb_prot.c optional krpc | nfslockd | nfscl | nfsd rpc/svc.c optional krpc | nfslockd | nfscl | nfsd rpc/svc_auth.c optional krpc | nfslockd | nfscl | nfsd rpc/svc_auth_unix.c optional krpc | nfslockd | nfscl | nfsd rpc/svc_dg.c optional krpc | nfslockd | nfscl | nfsd rpc/svc_generic.c optional krpc | nfslockd | nfscl | nfsd rpc/svc_vc.c optional krpc | nfslockd | nfscl | nfsd # # Kernel RPC-over-TLS # rpctlscd.h optional krpc | nfslockd | nfscl | nfsd \ dependency "$S/rpc/rpcsec_tls/rpctlscd.x" \ compile-with "RPCGEN_CPP='${CPP}' rpcgen -hM $S/rpc/rpcsec_tls/rpctlscd.x | grep -v pthread.h > rpctlscd.h" \ no-obj no-implicit-rule before-depend local \ clean "rpctlscd.h" rpctlscd_xdr.c optional krpc | nfslockd | nfscl | nfsd \ dependency "$S/rpc/rpcsec_tls/rpctlscd.x rpctlscd.h" \ compile-with "RPCGEN_CPP='${CPP}' rpcgen -c $S/rpc/rpcsec_tls/rpctlscd.x -o rpctlscd_xdr.c" no-ctfconvert \ no-implicit-rule before-depend local \ clean "rpctlscd_xdr.c" rpctlscd_clnt.c optional krpc | nfslockd | nfscl | nfsd \ dependency "$S/rpc/rpcsec_tls/rpctlscd.x rpctlscd.h" \ compile-with "RPCGEN_CPP='${CPP}' rpcgen -lM $S/rpc/rpcsec_tls/rpctlscd.x | grep -v string.h > rpctlscd_clnt.c" no-ctfconvert \ no-implicit-rule before-depend local \ clean "rpctlscd_clnt.c" rpctlssd.h optional krpc | nfslockd | nfscl | nfsd \ dependency "$S/rpc/rpcsec_tls/rpctlssd.x" \ compile-with "RPCGEN_CPP='${CPP}' rpcgen -hM $S/rpc/rpcsec_tls/rpctlssd.x | grep -v pthread.h > rpctlssd.h" \ no-obj no-implicit-rule before-depend local \ clean "rpctlssd.h" rpctlssd_xdr.c optional krpc | nfslockd | nfscl | nfsd \ dependency "$S/rpc/rpcsec_tls/rpctlssd.x rpctlssd.h" \ compile-with "RPCGEN_CPP='${CPP}' rpcgen -c $S/rpc/rpcsec_tls/rpctlssd.x -o rpctlssd_xdr.c" no-ctfconvert \ no-implicit-rule before-depend local \ clean "rpctlssd_xdr.c" rpctlssd_clnt.c optional krpc | nfslockd | nfscl | nfsd \ dependency "$S/rpc/rpcsec_tls/rpctlssd.x rpctlssd.h" \ compile-with "RPCGEN_CPP='${CPP}' rpcgen -lM $S/rpc/rpcsec_tls/rpctlssd.x | grep -v string.h > rpctlssd_clnt.c" no-ctfconvert \ no-implicit-rule before-depend local \ clean "rpctlssd_clnt.c" rpc/rpcsec_tls/rpctls_impl.c optional krpc | nfslockd | nfscl | nfsd rpc/rpcsec_tls/auth_tls.c optional krpc | nfslockd | nfscl | nfsd rpc/rpcsec_gss/rpcsec_gss.c optional krpc kgssapi | nfslockd kgssapi | nfscl kgssapi | nfsd kgssapi rpc/rpcsec_gss/rpcsec_gss_conf.c optional krpc kgssapi | nfslockd kgssapi | nfscl kgssapi | nfsd kgssapi rpc/rpcsec_gss/rpcsec_gss_misc.c optional krpc kgssapi | nfslockd kgssapi | nfscl kgssapi | nfsd kgssapi rpc/rpcsec_gss/rpcsec_gss_prot.c optional krpc kgssapi | nfslockd kgssapi | nfscl kgssapi | nfsd kgssapi rpc/rpcsec_gss/svc_rpcsec_gss.c optional krpc kgssapi | nfslockd kgssapi | nfscl kgssapi | nfsd kgssapi security/audit/audit.c optional audit security/audit/audit_arg.c optional audit security/audit/audit_bsm.c optional audit security/audit/audit_bsm_db.c optional audit security/audit/audit_bsm_klib.c optional audit security/audit/audit_dtrace.c optional dtaudit audit | dtraceall audit compile-with "${CDDL_C}" security/audit/audit_pipe.c optional audit security/audit/audit_syscalls.c standard security/audit/audit_trigger.c optional audit security/audit/audit_worker.c optional audit security/audit/bsm_domain.c optional audit security/audit/bsm_errno.c optional audit security/audit/bsm_fcntl.c optional audit security/audit/bsm_socket_type.c optional audit security/audit/bsm_token.c optional audit security/mac/mac_audit.c optional mac audit security/mac/mac_cred.c optional mac security/mac/mac_kdb.c optional mac security/mac/mac_framework.c optional mac security/mac/mac_inet.c optional mac inet | mac inet6 security/mac/mac_inet6.c optional mac inet6 security/mac/mac_label.c optional mac security/mac/mac_net.c optional mac security/mac/mac_pipe.c optional mac security/mac/mac_posix_sem.c optional mac security/mac/mac_posix_shm.c optional mac security/mac/mac_priv.c optional mac security/mac/mac_process.c optional mac security/mac/mac_socket.c optional mac security/mac/mac_syscalls.c standard security/mac/mac_system.c optional mac security/mac/mac_sysv_msg.c optional mac security/mac/mac_sysv_sem.c optional mac security/mac/mac_sysv_shm.c optional mac security/mac/mac_vfs.c optional mac security/mac_biba/mac_biba.c optional mac_biba security/mac_ddb/mac_ddb.c optional mac_ddb security/mac_bsdextended/mac_bsdextended.c optional mac_bsdextended security/mac_bsdextended/ugidfw_system.c optional mac_bsdextended security/mac_bsdextended/ugidfw_vnode.c optional mac_bsdextended security/mac_ifoff/mac_ifoff.c optional mac_ifoff security/mac_ipacl/mac_ipacl.c optional mac_ipacl security/mac_lomac/mac_lomac.c optional mac_lomac security/mac_mls/mac_mls.c optional mac_mls security/mac_none/mac_none.c optional mac_none security/mac_ntpd/mac_ntpd.c optional mac_ntpd security/mac_partition/mac_partition.c optional mac_partition security/mac_portacl/mac_portacl.c optional mac_portacl security/mac_priority/mac_priority.c optional mac_priority security/mac_seeotheruids/mac_seeotheruids.c optional mac_seeotheruids security/mac_stub/mac_stub.c optional mac_stub security/mac_test/mac_test.c optional mac_test security/mac_grantbylabel/mac_grantbylabel.c optional mac_grantbylabel security/mac_veriexec/mac_veriexec.c optional mac_veriexec security/mac_veriexec/veriexec_fingerprint.c optional mac_veriexec security/mac_veriexec/veriexec_metadata.c optional mac_veriexec security/mac_veriexec_parser/mac_veriexec_parser.c optional mac_veriexec mac_veriexec_parser security/mac_veriexec/mac_veriexec_rmd160.c optional mac_veriexec_rmd160 security/mac_veriexec/mac_veriexec_sha1.c optional mac_veriexec_sha1 security/mac_veriexec/mac_veriexec_sha256.c optional mac_veriexec_sha256 security/mac_veriexec/mac_veriexec_sha384.c optional mac_veriexec_sha384 security/mac_veriexec/mac_veriexec_sha512.c optional mac_veriexec_sha512 teken/teken.c optional sc !SC_NO_TERM_TEKEN | vt ufs/ffs/ffs_alloc.c optional ffs ufs/ffs/ffs_balloc.c optional ffs ufs/ffs/ffs_inode.c optional ffs ufs/ffs/ffs_snapshot.c optional ffs ufs/ffs/ffs_softdep.c optional ffs ufs/ffs/ffs_subr.c optional ffs | geom_label ufs/ffs/ffs_tables.c optional ffs | geom_label ufs/ffs/ffs_vfsops.c optional ffs ufs/ffs/ffs_vnops.c optional ffs ufs/ffs/ffs_rawread.c optional ffs directio ufs/ffs/ffs_suspend.c optional ffs ufs/ufs/ufs_acl.c optional ffs ufs/ufs/ufs_bmap.c optional ffs ufs/ufs/ufs_dirhash.c optional ffs ufs/ufs/ufs_extattr.c optional ffs ufs/ufs/ufs_gjournal.c optional ffs UFS_GJOURNAL ufs/ufs/ufs_inode.c optional ffs ufs/ufs/ufs_lookup.c optional ffs ufs/ufs/ufs_quota.c optional ffs ufs/ufs/ufs_vfsops.c optional ffs ufs/ufs/ufs_vnops.c optional ffs vm/device_pager.c standard vm/phys_pager.c standard vm/redzone.c optional DEBUG_REDZONE vm/sg_pager.c standard vm/swap_pager.c standard vm/uma_core.c standard vm/uma_dbg.c standard vm/memguard.c optional DEBUG_MEMGUARD vm/vm_domainset.c standard vm/vm_fault.c standard vm/vm_glue.c standard vm/vm_init.c standard vm/vm_kern.c standard vm/vm_map.c standard vm/vm_meter.c standard vm/vm_mmap.c standard vm/vm_object.c standard vm/vm_page.c standard vm/vm_pageout.c standard vm/vm_pager.c standard vm/vm_phys.c standard vm/vm_radix.c standard vm/vm_reserv.c standard vm/vm_swapout.c optional !NO_SWAPPING vm/vm_swapout_dummy.c optional NO_SWAPPING vm/vm_unix.c standard vm/vnode_pager.c standard xen/features.c optional xenhvm xen/xen_common.c optional xenhvm xen/xenbus/xenbus_if.m optional xenhvm xen/xenbus/xenbus.c optional xenhvm xen/xenbus/xenbusb_if.m optional xenhvm xen/xenbus/xenbusb.c optional xenhvm xen/xenbus/xenbusb_front.c optional xenhvm xen/xenbus/xenbusb_back.c optional xenhvm xen/xenmem/xenmem_if.m optional xenhvm xdr/xdr.c optional xdr | krpc | nfslockd | nfscl | nfsd xdr/xdr_array.c optional xdr | krpc | nfslockd | nfscl | nfsd xdr/xdr_mbuf.c optional xdr | krpc | nfslockd | nfscl | nfsd xdr/xdr_mem.c optional xdr | krpc | nfslockd | nfscl | nfsd xdr/xdr_reference.c optional xdr | krpc | nfslockd | nfscl | nfsd xdr/xdr_sizeof.c optional xdr | krpc | nfslockd | nfscl | nfsd diff --git a/sys/dev/cpufreq/cpufreq_dt.c b/sys/dev/cpufreq/cpufreq_dt.c index 4dae7142b380..929eebfe7dc5 100644 --- a/sys/dev/cpufreq/cpufreq_dt.c +++ b/sys/dev/cpufreq/cpufreq_dt.c @@ -1,627 +1,627 @@ /*- * Copyright (c) 2018 Emmanuel Vadot * Copyright (c) 2016 Jared McNeill * * 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. */ /* * Generic DT based cpufreq driver */ #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include "cpufreq_if.h" #if 0 #define DPRINTF(dev, msg...) device_printf(dev, "cpufreq_dt: " msg); #else #define DPRINTF(dev, msg...) #endif enum opp_version { OPP_V1 = 1, OPP_V2, }; struct cpufreq_dt_opp { uint64_t freq; uint32_t uvolt_target; uint32_t uvolt_min; uint32_t uvolt_max; uint32_t uamps; uint32_t clk_latency; bool turbo_mode; bool opp_suspend; }; #define CPUFREQ_DT_HAVE_REGULATOR(sc) ((sc)->reg != NULL) struct cpufreq_dt_softc { device_t dev; clk_t clk; regulator_t reg; struct cpufreq_dt_opp *opp; ssize_t nopp; int cpu; cpuset_t cpus; }; static void cpufreq_dt_notify(device_t dev, uint64_t freq) { struct cpufreq_dt_softc *sc; struct pcpu *pc; int cpu; sc = device_get_softc(dev); CPU_FOREACH(cpu) { if (CPU_ISSET(cpu, &sc->cpus)) { pc = pcpu_find(cpu); pc->pc_clock = freq; } } } static const struct cpufreq_dt_opp * cpufreq_dt_find_opp(device_t dev, uint64_t freq) { struct cpufreq_dt_softc *sc; uint64_t diff, best_diff; ssize_t n, best_n; sc = device_get_softc(dev); diff = 0; best_diff = ~0; DPRINTF(dev, "Looking for freq %ju\n", freq); for (n = 0; n < sc->nopp; n++) { diff = abs64((int64_t)sc->opp[n].freq - (int64_t)freq); DPRINTF(dev, "Testing %ju, diff is %ju\n", sc->opp[n].freq, diff); if (diff < best_diff) { best_diff = diff; best_n = n; DPRINTF(dev, "%ju is best for now\n", sc->opp[n].freq); } } DPRINTF(dev, "Will use %ju\n", sc->opp[best_n].freq); return (&sc->opp[best_n]); } static void cpufreq_dt_opp_to_setting(device_t dev, const struct cpufreq_dt_opp *opp, struct cf_setting *set) { memset(set, 0, sizeof(*set)); set->freq = opp->freq / 1000000; set->volts = opp->uvolt_target / 1000; set->power = CPUFREQ_VAL_UNKNOWN; set->lat = opp->clk_latency; set->dev = dev; } static int cpufreq_dt_get(device_t dev, struct cf_setting *set) { struct cpufreq_dt_softc *sc; const struct cpufreq_dt_opp *opp; uint64_t freq; sc = device_get_softc(dev); DPRINTF(dev, "cpufreq_dt_get\n"); if (clk_get_freq(sc->clk, &freq) != 0) return (ENXIO); opp = cpufreq_dt_find_opp(dev, freq); if (opp == NULL) { device_printf(dev, "Can't find the current freq in opp\n"); return (ENOENT); } cpufreq_dt_opp_to_setting(dev, opp, set); DPRINTF(dev, "Current freq %dMhz\n", set->freq); return (0); } static int cpufreq_dt_set(device_t dev, const struct cf_setting *set) { struct cpufreq_dt_softc *sc; const struct cpufreq_dt_opp *opp, *copp; uint64_t freq; int uvolt, error; sc = device_get_softc(dev); DPRINTF(dev, "Working on cpu %d\n", sc->cpu); DPRINTF(dev, "We have %d cpu on this dev\n", CPU_COUNT(&sc->cpus)); if (!CPU_ISSET(sc->cpu, &sc->cpus)) { DPRINTF(dev, "Not for this CPU\n"); return (0); } if (clk_get_freq(sc->clk, &freq) != 0) { device_printf(dev, "Can't get current clk freq\n"); return (ENXIO); } /* * Only do the regulator work if it's required. */ if (CPUFREQ_DT_HAVE_REGULATOR(sc)) { /* Try to get current valtage by using regulator first. */ error = regulator_get_voltage(sc->reg, &uvolt); if (error != 0) { /* * Try oppoints table as backup way. However, * this is insufficient because the actual processor * frequency may not be in the table. PLL frequency * granularity can be different that granularity of * oppoint table. */ copp = cpufreq_dt_find_opp(sc->dev, freq); if (copp == NULL) { device_printf(dev, "Can't find the current freq in opp\n"); return (ENOENT); } uvolt = copp->uvolt_target; } } else uvolt = 0; opp = cpufreq_dt_find_opp(sc->dev, set->freq * 1000000); if (opp == NULL) { device_printf(dev, "Couldn't find an opp for this freq\n"); return (EINVAL); } DPRINTF(sc->dev, "Current freq %ju, uvolt: %d\n", freq, uvolt); DPRINTF(sc->dev, "Target freq %ju, , uvolt: %d\n", opp->freq, opp->uvolt_target); if (CPUFREQ_DT_HAVE_REGULATOR(sc) && (uvolt < opp->uvolt_target)) { DPRINTF(dev, "Changing regulator from %u to %u\n", uvolt, opp->uvolt_target); error = regulator_set_voltage(sc->reg, opp->uvolt_min, opp->uvolt_max); if (error != 0) { DPRINTF(dev, "Failed, backout\n"); return (ENXIO); } } DPRINTF(dev, "Setting clk to %ju\n", opp->freq); error = clk_set_freq(sc->clk, opp->freq, CLK_SET_ROUND_DOWN); if (error != 0) { DPRINTF(dev, "Failed, backout\n"); /* Restore previous voltage (best effort) */ if (CPUFREQ_DT_HAVE_REGULATOR(sc)) error = regulator_set_voltage(sc->reg, copp->uvolt_min, copp->uvolt_max); return (ENXIO); } if (CPUFREQ_DT_HAVE_REGULATOR(sc) && (uvolt > opp->uvolt_target)) { DPRINTF(dev, "Changing regulator from %u to %u\n", uvolt, opp->uvolt_target); error = regulator_set_voltage(sc->reg, opp->uvolt_min, opp->uvolt_max); if (error != 0) { DPRINTF(dev, "Failed to switch regulator to %d\n", opp->uvolt_target); /* Restore previous CPU frequency (best effort) */ (void)clk_set_freq(sc->clk, copp->freq, 0); return (ENXIO); } } if (clk_get_freq(sc->clk, &freq) == 0) cpufreq_dt_notify(dev, freq); return (0); } static int cpufreq_dt_type(device_t dev, int *type) { if (type == NULL) return (EINVAL); *type = CPUFREQ_TYPE_ABSOLUTE; return (0); } static int cpufreq_dt_settings(device_t dev, struct cf_setting *sets, int *count) { struct cpufreq_dt_softc *sc; ssize_t n; DPRINTF(dev, "cpufreq_dt_settings\n"); if (sets == NULL || count == NULL) return (EINVAL); sc = device_get_softc(dev); if (*count < sc->nopp) { *count = (int)sc->nopp; return (E2BIG); } for (n = 0; n < sc->nopp; n++) cpufreq_dt_opp_to_setting(dev, &sc->opp[n], &sets[n]); *count = (int)sc->nopp; return (0); } static void cpufreq_dt_identify(driver_t *driver, device_t parent) { phandle_t node; /* Properties must be listed under node /cpus/cpu@0 */ node = ofw_bus_get_node(parent); /* The cpu@0 node must have the following properties */ if (!OF_hasprop(node, "clocks")) return; if (!OF_hasprop(node, "operating-points") && !OF_hasprop(node, "operating-points-v2")) return; if (device_find_child(parent, "cpufreq_dt", -1) != NULL) return; if (BUS_ADD_CHILD(parent, 0, "cpufreq_dt", device_get_unit(parent)) == NULL) device_printf(parent, "add cpufreq_dt child failed\n"); } static int cpufreq_dt_probe(device_t dev) { phandle_t node; node = ofw_bus_get_node(device_get_parent(dev)); /* * Note - supply isn't required here for probe; we'll check * it out in more detail during attach. */ if (!OF_hasprop(node, "clocks")) return (ENXIO); if (!OF_hasprop(node, "operating-points") && !OF_hasprop(node, "operating-points-v2")) return (ENXIO); device_set_desc(dev, "Generic cpufreq driver"); return (BUS_PROBE_GENERIC); } static int cpufreq_dt_oppv1_parse(struct cpufreq_dt_softc *sc, phandle_t node) { uint32_t *opp, lat; ssize_t n; sc->nopp = OF_getencprop_alloc_multi(node, "operating-points", sizeof(uint32_t) * 2, (void **)&opp); if (sc->nopp == -1) return (ENXIO); if (OF_getencprop(node, "clock-latency", &lat, sizeof(lat)) == -1) lat = CPUFREQ_VAL_UNKNOWN; sc->opp = malloc(sizeof(*sc->opp) * sc->nopp, M_DEVBUF, M_WAITOK); for (n = 0; n < sc->nopp; n++) { sc->opp[n].freq = opp[n * 2 + 0] * 1000; sc->opp[n].uvolt_min = opp[n * 2 + 1]; sc->opp[n].uvolt_max = sc->opp[n].uvolt_min; sc->opp[n].uvolt_target = sc->opp[n].uvolt_min; sc->opp[n].clk_latency = lat; if (bootverbose) device_printf(sc->dev, "%ju.%03ju MHz, %u uV\n", sc->opp[n].freq / 1000000, sc->opp[n].freq % 1000000, sc->opp[n].uvolt_target); } free(opp, M_OFWPROP); return (0); } static int cpufreq_dt_oppv2_parse(struct cpufreq_dt_softc *sc, phandle_t node) { phandle_t opp, opp_table, opp_xref; pcell_t cell[2]; uint32_t *volts, lat; int nvolt, i; /* * operating-points-v2 does not require the voltage entries * and a regulator. So, it's OK if they're not there. */ if (OF_getencprop(node, "operating-points-v2", &opp_xref, sizeof(opp_xref)) == -1) { device_printf(sc->dev, "Cannot get xref to oppv2 table\n"); return (ENXIO); } opp_table = OF_node_from_xref(opp_xref); if (opp_table == opp_xref) return (ENXIO); if (!OF_hasprop(opp_table, "opp-shared")) { device_printf(sc->dev, "Only opp-shared is supported\n"); return (ENXIO); } for (opp = OF_child(opp_table); opp > 0; opp = OF_peer(opp)) sc->nopp += 1; sc->opp = malloc(sizeof(*sc->opp) * sc->nopp, M_DEVBUF, M_WAITOK); for (i = 0, opp_table = OF_child(opp_table); opp_table > 0; opp_table = OF_peer(opp_table), i++) { /* opp-hz is a required property */ if (OF_getencprop(opp_table, "opp-hz", cell, sizeof(cell)) == -1) continue; sc->opp[i].freq = cell[0]; sc->opp[i].freq <<= 32; sc->opp[i].freq |= cell[1]; if (OF_getencprop(opp_table, "clock-latency", &lat, sizeof(lat)) == -1) sc->opp[i].clk_latency = CPUFREQ_VAL_UNKNOWN; else sc->opp[i].clk_latency = (int)lat; if (OF_hasprop(opp_table, "turbo-mode")) sc->opp[i].turbo_mode = true; if (OF_hasprop(opp_table, "opp-suspend")) sc->opp[i].opp_suspend = true; if (CPUFREQ_DT_HAVE_REGULATOR(sc)) { nvolt = OF_getencprop_alloc_multi(opp_table, "opp-microvolt", sizeof(*volts), (void **)&volts); if (nvolt == 1) { sc->opp[i].uvolt_target = volts[0]; sc->opp[i].uvolt_min = volts[0]; sc->opp[i].uvolt_max = volts[0]; } else if (nvolt == 3) { sc->opp[i].uvolt_target = volts[0]; sc->opp[i].uvolt_min = volts[1]; sc->opp[i].uvolt_max = volts[2]; } else { device_printf(sc->dev, "Wrong count of opp-microvolt property\n"); OF_prop_free(volts); free(sc->opp, M_DEVBUF); return (ENXIO); } OF_prop_free(volts); } else { /* No regulator required; don't add anything */ sc->opp[i].uvolt_target = 0; sc->opp[i].uvolt_min = 0; sc->opp[i].uvolt_max = 0; } if (bootverbose) device_printf(sc->dev, "%ju.%03ju Mhz (%u uV)\n", sc->opp[i].freq / 1000000, sc->opp[i].freq % 1000000, sc->opp[i].uvolt_target); } return (0); } static int cpufreq_dt_attach(device_t dev) { struct cpufreq_dt_softc *sc; phandle_t node; phandle_t cnode, opp, copp; int cpu; uint64_t freq; int rv = 0; char device_type[16]; enum opp_version version; sc = device_get_softc(dev); sc->dev = dev; node = ofw_bus_get_node(device_get_parent(dev)); sc->cpu = device_get_unit(device_get_parent(dev)); sc->reg = NULL; DPRINTF(dev, "cpu=%d\n", sc->cpu); if (sc->cpu >= mp_ncpus) { device_printf(dev, "Not attaching as cpu is not present\n"); rv = ENXIO; goto error; } /* * Cache if we have the regulator supply but don't error out * quite yet. If it's operating-points-v2 then regulator * and voltage entries are optional. */ if (regulator_get_by_ofw_property(dev, node, "cpu-supply", &sc->reg) == 0) device_printf(dev, "Found cpu-supply\n"); else if (regulator_get_by_ofw_property(dev, node, "cpu0-supply", &sc->reg) == 0) device_printf(dev, "Found cpu0-supply\n"); /* * Determine which operating mode we're in. Error out if we expect * a regulator but we're not getting it. */ if (OF_hasprop(node, "operating-points")) version = OPP_V1; else if (OF_hasprop(node, "operating-points-v2")) version = OPP_V2; else { device_printf(dev, "didn't find a valid operating-points or v2 node\n"); rv = ENXIO; goto error; } /* * Now, we only enforce needing a regulator for v1. */ if ((version == OPP_V1) && !CPUFREQ_DT_HAVE_REGULATOR(sc)) { device_printf(dev, "no regulator for %s\n", ofw_bus_get_name(device_get_parent(dev))); rv = ENXIO; goto error; } if (clk_get_by_ofw_index(dev, node, 0, &sc->clk) != 0) { device_printf(dev, "no clock for %s\n", ofw_bus_get_name(device_get_parent(dev))); rv = ENXIO; goto error; } if (version == OPP_V1) { rv = cpufreq_dt_oppv1_parse(sc, node); if (rv != 0) { device_printf(dev, "Failed to parse opp-v1 table\n"); goto error; } OF_getencprop(node, "operating-points", &opp, sizeof(opp)); } else if (version == OPP_V2) { rv = cpufreq_dt_oppv2_parse(sc, node); if (rv != 0) { device_printf(dev, "Failed to parse opp-v2 table\n"); goto error; } OF_getencprop(node, "operating-points-v2", &opp, sizeof(opp)); } else { device_printf(dev, "operating points version is incorrect\n"); goto error; } /* * Find all CPUs that share the same opp table */ CPU_ZERO(&sc->cpus); cnode = OF_parent(node); for (cpu = 0, cnode = OF_child(cnode); cnode > 0; cnode = OF_peer(cnode)) { if (OF_getprop(cnode, "device_type", device_type, sizeof(device_type)) <= 0) continue; if (strcmp(device_type, "cpu") != 0) continue; if (cpu == sc->cpu) { DPRINTF(dev, "Skipping our cpu\n"); CPU_SET(cpu, &sc->cpus); cpu++; continue; } DPRINTF(dev, "Testing CPU %d\n", cpu); copp = -1; if (version == OPP_V1) OF_getencprop(cnode, "operating-points", &copp, sizeof(copp)); else if (version == OPP_V2) OF_getencprop(cnode, "operating-points-v2", &copp, sizeof(copp)); if (opp == copp) { DPRINTF(dev, "CPU %d is using the same opp as this one (%d)\n", cpu, sc->cpu); CPU_SET(cpu, &sc->cpus); } cpu++; } if (clk_get_freq(sc->clk, &freq) == 0) cpufreq_dt_notify(dev, freq); cpufreq_register(dev); return (0); error: if (CPUFREQ_DT_HAVE_REGULATOR(sc)) regulator_release(sc->reg); return (rv); } static device_method_t cpufreq_dt_methods[] = { /* Device interface */ DEVMETHOD(device_identify, cpufreq_dt_identify), DEVMETHOD(device_probe, cpufreq_dt_probe), DEVMETHOD(device_attach, cpufreq_dt_attach), /* cpufreq interface */ DEVMETHOD(cpufreq_drv_get, cpufreq_dt_get), DEVMETHOD(cpufreq_drv_set, cpufreq_dt_set), DEVMETHOD(cpufreq_drv_type, cpufreq_dt_type), DEVMETHOD(cpufreq_drv_settings, cpufreq_dt_settings), DEVMETHOD_END }; static driver_t cpufreq_dt_driver = { "cpufreq_dt", cpufreq_dt_methods, sizeof(struct cpufreq_dt_softc), }; DRIVER_MODULE(cpufreq_dt, cpu, cpufreq_dt_driver, 0, 0); MODULE_VERSION(cpufreq_dt, 1); diff --git a/sys/dev/dwc/if_dwc_aw.c b/sys/dev/dwc/if_dwc_aw.c index 2a0dfaa33715..460b24b0401a 100644 --- a/sys/dev/dwc/if_dwc_aw.c +++ b/sys/dev/dwc/if_dwc_aw.c @@ -1,147 +1,147 @@ /*- * Copyright (c) 2015 Luiz Otavio O Souza * All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include "if_dwc_if.h" static int a20_if_dwc_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "allwinner,sun7i-a20-gmac")) return (ENXIO); device_set_desc(dev, "A20 Gigabit Ethernet Controller"); return (BUS_PROBE_DEFAULT); } static int a20_if_dwc_init(device_t dev) { struct dwc_softc *sc; const char *tx_parent_name; clk_t clk_tx, clk_tx_parent; regulator_t reg; int error; sc = device_get_softc(dev); /* Configure PHY for MII or RGMII mode */ switch(sc->phy_mode) { case MII_CONTYPE_RGMII: case MII_CONTYPE_RGMII_ID: case MII_CONTYPE_RGMII_RXID: case MII_CONTYPE_RGMII_TXID: tx_parent_name = "gmac_int_tx"; break; case MII_CONTYPE_MII: tx_parent_name = "mii_phy_tx"; break; default: device_printf(dev, "unsupported PHY connection type: %d", sc->phy_mode); return (ENXIO); } error = clk_get_by_ofw_name(dev, 0, "allwinner_gmac_tx", &clk_tx); if (error != 0) { device_printf(dev, "could not get tx clk\n"); return (error); } error = clk_get_by_name(dev, tx_parent_name, &clk_tx_parent); if (error != 0) { device_printf(dev, "could not get clock '%s'\n", tx_parent_name); return (error); } error = clk_set_parent_by_clk(clk_tx, clk_tx_parent); if (error != 0) { device_printf(dev, "could not set tx clk parent\n"); return (error); } /* Enable PHY regulator if applicable */ if (regulator_get_by_ofw_property(dev, 0, "phy-supply", ®) == 0) { error = regulator_enable(reg); if (error != 0) { device_printf(dev, "could not enable PHY regulator\n"); return (error); } } return (0); } static int a20_if_dwc_mii_clk(device_t dev) { return (GMAC_MII_CLK_150_250M_DIV102); } static device_method_t a20_dwc_methods[] = { DEVMETHOD(device_probe, a20_if_dwc_probe), DEVMETHOD(if_dwc_init, a20_if_dwc_init), DEVMETHOD(if_dwc_mii_clk, a20_if_dwc_mii_clk), DEVMETHOD_END }; extern driver_t dwc_driver; DEFINE_CLASS_1(dwc, a20_dwc_driver, a20_dwc_methods, sizeof(struct dwc_softc), dwc_driver); DRIVER_MODULE(a20_dwc, simplebus, a20_dwc_driver, 0, 0); MODULE_DEPEND(a20_dwc, dwc, 1, 1, 1); diff --git a/sys/dev/dwc/if_dwc_rk.c b/sys/dev/dwc/if_dwc_rk.c index c78fb447d6d3..fca9f879247b 100644 --- a/sys/dev/dwc/if_dwc_rk.c +++ b/sys/dev/dwc/if_dwc_rk.c @@ -1,636 +1,636 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018 Emmanuel Vadot * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include "if_dwc_if.h" #include "syscon_if.h" #define RK3328_GRF_MAC_CON0 0x0900 #define MAC_CON0_GMAC2IO_TX_DL_CFG_MASK 0x7F #define MAC_CON0_GMAC2IO_TX_DL_CFG_SHIFT 0 #define MAC_CON0_GMAC2IO_RX_DL_CFG_MASK 0x7F #define MAC_CON0_GMAC2IO_RX_DL_CFG_SHIFT 7 #define RK3328_GRF_MAC_CON1 0x0904 #define MAC_CON1_GMAC2IO_GMAC_TXCLK_DLY_ENA (1 << 0) #define MAC_CON1_GMAC2IO_GMAC_RXCLK_DLY_ENA (1 << 1) #define MAC_CON1_GMAC2IO_GMII_CLK_SEL_MASK (3 << 11) #define MAC_CON1_GMAC2IO_GMII_CLK_SEL_125 (0 << 11) #define MAC_CON1_GMAC2IO_GMII_CLK_SEL_25 (3 << 11) #define MAC_CON1_GMAC2IO_GMII_CLK_SEL_2_5 (2 << 11) #define MAC_CON1_GMAC2IO_RMII_MODE_MASK (1 << 9) #define MAC_CON1_GMAC2IO_RMII_MODE (1 << 9) #define MAC_CON1_GMAC2IO_INTF_SEL_MASK (7 << 4) #define MAC_CON1_GMAC2IO_INTF_RMII (4 << 4) #define MAC_CON1_GMAC2IO_INTF_RGMII (1 << 4) #define MAC_CON1_GMAC2IO_RMII_CLK_SEL_MASK (1 << 7) #define MAC_CON1_GMAC2IO_RMII_CLK_SEL_25 (1 << 7) #define MAC_CON1_GMAC2IO_RMII_CLK_SEL_2_5 (0 << 7) #define MAC_CON1_GMAC2IO_MAC_SPEED_MASK (1 << 2) #define MAC_CON1_GMAC2IO_MAC_SPEED_100 (1 << 2) #define MAC_CON1_GMAC2IO_MAC_SPEED_10 (0 << 2) #define RK3328_GRF_MAC_CON2 0x0908 #define RK3328_GRF_MACPHY_CON0 0x0B00 #define MACPHY_CON0_CLK_50M_MASK (1 << 14) #define MACPHY_CON0_CLK_50M (1 << 14) #define MACPHY_CON0_RMII_MODE_MASK (3 << 6) #define MACPHY_CON0_RMII_MODE (1 << 6) #define RK3328_GRF_MACPHY_CON1 0x0B04 #define MACPHY_CON1_RMII_MODE_MASK (1 << 9) #define MACPHY_CON1_RMII_MODE (1 << 9) #define RK3328_GRF_MACPHY_CON2 0x0B08 #define RK3328_GRF_MACPHY_CON3 0x0B0C #define RK3328_GRF_MACPHY_STATUS 0x0B10 #define RK3399_GRF_SOC_CON5 0xc214 #define SOC_CON5_GMAC_CLK_SEL_MASK (3 << 4) #define SOC_CON5_GMAC_CLK_SEL_125 (0 << 4) #define SOC_CON5_GMAC_CLK_SEL_25 (3 << 4) #define SOC_CON5_GMAC_CLK_SEL_2_5 (2 << 4) #define RK3399_GRF_SOC_CON6 0xc218 #define SOC_CON6_GMAC_TXCLK_DLY_ENA (1 << 7) #define SOC_CON6_TX_DL_CFG_MASK 0x7F #define SOC_CON6_TX_DL_CFG_SHIFT 0 #define SOC_CON6_RX_DL_CFG_MASK 0x7F #define SOC_CON6_GMAC_RXCLK_DLY_ENA (1 << 15) #define SOC_CON6_RX_DL_CFG_SHIFT 8 struct if_dwc_rk_softc; typedef void (*if_dwc_rk_set_delaysfn_t)(struct if_dwc_rk_softc *); typedef int (*if_dwc_rk_set_speedfn_t)(struct if_dwc_rk_softc *, int); typedef void (*if_dwc_rk_set_phy_modefn_t)(struct if_dwc_rk_softc *); typedef void (*if_dwc_rk_phy_powerupfn_t)(struct if_dwc_rk_softc *); struct if_dwc_rk_ops { if_dwc_rk_set_delaysfn_t set_delays; if_dwc_rk_set_speedfn_t set_speed; if_dwc_rk_set_phy_modefn_t set_phy_mode; if_dwc_rk_phy_powerupfn_t phy_powerup; }; struct if_dwc_rk_softc { struct dwc_softc base; uint32_t tx_delay; uint32_t rx_delay; bool integrated_phy; bool clock_in; phandle_t phy_node; struct syscon *grf; struct if_dwc_rk_ops *ops; /* Common clocks */ clk_t mac_clk_rx; clk_t mac_clk_tx; clk_t aclk_mac; clk_t pclk_mac; clk_t clk_stmmaceth; clk_t clk_mac_speed; /* RMII clocks */ clk_t clk_mac_ref; clk_t clk_mac_refout; /* PHY clock */ clk_t clk_phy; }; static void rk3328_set_delays(struct if_dwc_rk_softc *sc); static int rk3328_set_speed(struct if_dwc_rk_softc *sc, int speed); static void rk3328_set_phy_mode(struct if_dwc_rk_softc *sc); static void rk3328_phy_powerup(struct if_dwc_rk_softc *sc); static void rk3399_set_delays(struct if_dwc_rk_softc *sc); static int rk3399_set_speed(struct if_dwc_rk_softc *sc, int speed); static struct if_dwc_rk_ops rk3288_ops = { }; static struct if_dwc_rk_ops rk3328_ops = { .set_delays = rk3328_set_delays, .set_speed = rk3328_set_speed, .set_phy_mode = rk3328_set_phy_mode, .phy_powerup = rk3328_phy_powerup, }; static struct if_dwc_rk_ops rk3399_ops = { .set_delays = rk3399_set_delays, .set_speed = rk3399_set_speed, }; static struct ofw_compat_data compat_data[] = { {"rockchip,rk3288-gmac", (uintptr_t)&rk3288_ops}, {"rockchip,rk3328-gmac", (uintptr_t)&rk3328_ops}, {"rockchip,rk3399-gmac", (uintptr_t)&rk3399_ops}, {NULL, 0} }; static void rk3328_set_delays(struct if_dwc_rk_softc *sc) { uint32_t reg; uint32_t tx, rx; if (!mii_contype_is_rgmii(sc->base.phy_mode)) return; reg = SYSCON_READ_4(sc->grf, RK3328_GRF_MAC_CON0); tx = ((reg >> MAC_CON0_GMAC2IO_TX_DL_CFG_SHIFT) & MAC_CON0_GMAC2IO_TX_DL_CFG_MASK); rx = ((reg >> MAC_CON0_GMAC2IO_RX_DL_CFG_SHIFT) & MAC_CON0_GMAC2IO_RX_DL_CFG_MASK); reg = SYSCON_READ_4(sc->grf, RK3328_GRF_MAC_CON1); if (bootverbose) { device_printf(sc->base.dev, "current delays settings: tx=%u(%s) rx=%u(%s)\n", tx, ((reg & MAC_CON1_GMAC2IO_GMAC_TXCLK_DLY_ENA) ? "enabled" : "disabled"), rx, ((reg & MAC_CON1_GMAC2IO_GMAC_RXCLK_DLY_ENA) ? "enabled" : "disabled")); device_printf(sc->base.dev, "setting new RK3328 RX/TX delays: %d/%d\n", sc->tx_delay, sc->rx_delay); } reg = (MAC_CON1_GMAC2IO_GMAC_TXCLK_DLY_ENA | MAC_CON1_GMAC2IO_GMAC_RXCLK_DLY_ENA) << 16; reg |= (MAC_CON1_GMAC2IO_GMAC_TXCLK_DLY_ENA | MAC_CON1_GMAC2IO_GMAC_RXCLK_DLY_ENA); SYSCON_WRITE_4(sc->grf, RK3328_GRF_MAC_CON1, reg); reg = 0xffff << 16; reg |= ((sc->tx_delay & MAC_CON0_GMAC2IO_TX_DL_CFG_MASK) << MAC_CON0_GMAC2IO_TX_DL_CFG_SHIFT); reg |= ((sc->rx_delay & MAC_CON0_GMAC2IO_TX_DL_CFG_MASK) << MAC_CON0_GMAC2IO_RX_DL_CFG_SHIFT); SYSCON_WRITE_4(sc->grf, RK3328_GRF_MAC_CON0, reg); } static int rk3328_set_speed(struct if_dwc_rk_softc *sc, int speed) { uint32_t reg; switch (sc->base.phy_mode) { case MII_CONTYPE_RGMII: case MII_CONTYPE_RGMII_ID: case MII_CONTYPE_RGMII_RXID: case MII_CONTYPE_RGMII_TXID: switch (speed) { case IFM_1000_T: case IFM_1000_SX: reg = MAC_CON1_GMAC2IO_GMII_CLK_SEL_125; break; case IFM_100_TX: reg = MAC_CON1_GMAC2IO_GMII_CLK_SEL_25; break; case IFM_10_T: reg = MAC_CON1_GMAC2IO_GMII_CLK_SEL_2_5; break; default: device_printf(sc->base.dev, "unsupported RGMII media %u\n", speed); return (-1); } SYSCON_WRITE_4(sc->grf, RK3328_GRF_MAC_CON1, ((MAC_CON1_GMAC2IO_GMII_CLK_SEL_MASK << 16) | reg)); break; case MII_CONTYPE_RMII: switch (speed) { case IFM_100_TX: reg = MAC_CON1_GMAC2IO_RMII_CLK_SEL_25 | MAC_CON1_GMAC2IO_MAC_SPEED_100; break; case IFM_10_T: reg = MAC_CON1_GMAC2IO_RMII_CLK_SEL_2_5 | MAC_CON1_GMAC2IO_MAC_SPEED_10; break; default: device_printf(sc->base.dev, "unsupported RMII media %u\n", speed); return (-1); } SYSCON_WRITE_4(sc->grf, sc->integrated_phy ? RK3328_GRF_MAC_CON2 : RK3328_GRF_MAC_CON1, reg | ((MAC_CON1_GMAC2IO_RMII_CLK_SEL_MASK | MAC_CON1_GMAC2IO_MAC_SPEED_MASK) << 16)); break; } return (0); } static void rk3328_set_phy_mode(struct if_dwc_rk_softc *sc) { switch (sc->base.phy_mode) { case MII_CONTYPE_RGMII: case MII_CONTYPE_RGMII_ID: case MII_CONTYPE_RGMII_RXID: case MII_CONTYPE_RGMII_TXID: SYSCON_WRITE_4(sc->grf, RK3328_GRF_MAC_CON1, ((MAC_CON1_GMAC2IO_INTF_SEL_MASK | MAC_CON1_GMAC2IO_RMII_MODE_MASK) << 16) | MAC_CON1_GMAC2IO_INTF_RGMII); break; case MII_CONTYPE_RMII: SYSCON_WRITE_4(sc->grf, sc->integrated_phy ? RK3328_GRF_MAC_CON2 : RK3328_GRF_MAC_CON1, ((MAC_CON1_GMAC2IO_INTF_SEL_MASK | MAC_CON1_GMAC2IO_RMII_MODE_MASK) << 16) | MAC_CON1_GMAC2IO_INTF_RMII | MAC_CON1_GMAC2IO_RMII_MODE); break; } } static void rk3328_phy_powerup(struct if_dwc_rk_softc *sc) { SYSCON_WRITE_4(sc->grf, RK3328_GRF_MACPHY_CON1, (MACPHY_CON1_RMII_MODE_MASK << 16) | MACPHY_CON1_RMII_MODE); } static void rk3399_set_delays(struct if_dwc_rk_softc *sc) { uint32_t reg, tx, rx; if (!mii_contype_is_rgmii(sc->base.phy_mode)) return; reg = SYSCON_READ_4(sc->grf, RK3399_GRF_SOC_CON6); tx = ((reg >> SOC_CON6_TX_DL_CFG_SHIFT) & SOC_CON6_TX_DL_CFG_MASK); rx = ((reg >> SOC_CON6_RX_DL_CFG_SHIFT) & SOC_CON6_RX_DL_CFG_MASK); if (bootverbose) { device_printf(sc->base.dev, "current delays settings: tx=%u(%s) rx=%u(%s)\n", tx, ((reg & SOC_CON6_GMAC_TXCLK_DLY_ENA) ? "enabled" : "disabled"), rx, ((reg & SOC_CON6_GMAC_RXCLK_DLY_ENA) ? "enabled" : "disabled")); device_printf(sc->base.dev, "setting new RK3399 RX/TX delays: %d/%d\n", sc->rx_delay, sc->tx_delay); } reg = 0xFFFF << 16; reg |= ((sc->tx_delay & SOC_CON6_TX_DL_CFG_MASK) << SOC_CON6_TX_DL_CFG_SHIFT); reg |= ((sc->rx_delay & SOC_CON6_RX_DL_CFG_MASK) << SOC_CON6_RX_DL_CFG_SHIFT); reg |= SOC_CON6_GMAC_TXCLK_DLY_ENA | SOC_CON6_GMAC_RXCLK_DLY_ENA; SYSCON_WRITE_4(sc->grf, RK3399_GRF_SOC_CON6, reg); } static int rk3399_set_speed(struct if_dwc_rk_softc *sc, int speed) { uint32_t reg; switch (speed) { case IFM_1000_T: case IFM_1000_SX: reg = SOC_CON5_GMAC_CLK_SEL_125; break; case IFM_100_TX: reg = SOC_CON5_GMAC_CLK_SEL_25; break; case IFM_10_T: reg = SOC_CON5_GMAC_CLK_SEL_2_5; break; default: device_printf(sc->base.dev, "unsupported media %u\n", speed); return (-1); } SYSCON_WRITE_4(sc->grf, RK3399_GRF_SOC_CON5, ((SOC_CON5_GMAC_CLK_SEL_MASK << 16) | reg)); return (0); } static int if_dwc_rk_sysctl_delays(SYSCTL_HANDLER_ARGS) { struct if_dwc_rk_softc *sc; int rv; uint32_t rxtx; sc = arg1; rxtx = ((sc->rx_delay << 8) | sc->tx_delay); rv = sysctl_handle_int(oidp, &rxtx, 0, req); if (rv != 0 || req->newptr == NULL) return (rv); sc->tx_delay = rxtx & 0xff; sc->rx_delay = (rxtx >> 8) & 0xff; if (sc->ops->set_delays) sc->ops->set_delays(sc); return (0); } static int if_dwc_rk_init_sysctl(struct if_dwc_rk_softc *sc) { struct sysctl_oid *child; struct sysctl_ctx_list *ctx_list; ctx_list = device_get_sysctl_ctx(sc->base.dev); child = device_get_sysctl_tree(sc->base.dev); SYSCTL_ADD_PROC(ctx_list, SYSCTL_CHILDREN(child), OID_AUTO, "delays", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, sc, 0, if_dwc_rk_sysctl_delays, "", "RGMII RX/TX delays: ((rx << 8) | tx)"); return (0); } static int if_dwc_rk_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Rockchip Gigabit Ethernet Controller"); return (BUS_PROBE_DEFAULT); } static int if_dwc_rk_init_clocks(device_t dev) { struct if_dwc_rk_softc *sc; sc = device_get_softc(dev); /* Enable clocks */ if (clk_get_by_ofw_name(dev, 0, "mac_clk_tx", &sc->mac_clk_tx) != 0) { device_printf(sc->base.dev, "could not get mac_clk_tx clock\n"); sc->mac_clk_tx = NULL; } if (clk_get_by_ofw_name(dev, 0, "aclk_mac", &sc->aclk_mac) != 0) { device_printf(sc->base.dev, "could not get aclk_mac clock\n"); sc->aclk_mac = NULL; } if (clk_get_by_ofw_name(dev, 0, "pclk_mac", &sc->pclk_mac) != 0) { device_printf(sc->base.dev, "could not get pclk_mac clock\n"); sc->pclk_mac = NULL; } /* Optional clock */ clk_get_by_ofw_name(dev, 0, "clk_mac_speed", &sc->clk_mac_speed); if (sc->base.phy_mode == MII_CONTYPE_RMII) { if (clk_get_by_ofw_name(dev, 0, "mac_clk_rx", &sc->mac_clk_rx) != 0) { device_printf(sc->base.dev, "could not get mac_clk_rx clock\n"); sc->mac_clk_rx = NULL; } if (clk_get_by_ofw_name(dev, 0, "clk_mac_ref", &sc->clk_mac_ref) != 0) { device_printf(sc->base.dev, "could not get clk_mac_ref clock\n"); sc->clk_mac_ref = NULL; } if (!sc->clock_in) { if (clk_get_by_ofw_name(dev, 0, "clk_mac_refout", &sc->clk_mac_refout) != 0) { device_printf(sc->base.dev, "could not get clk_mac_refout clock\n"); sc->clk_mac_refout = NULL; } clk_set_freq(sc->clk_stmmaceth, 50000000, 0); } } if ((sc->phy_node != 0) && sc->integrated_phy) { if (clk_get_by_ofw_index(dev, sc->phy_node, 0, &sc->clk_phy) != 0) { device_printf(sc->base.dev, "could not get PHY clock\n"); sc->clk_phy = NULL; } if (sc->clk_phy) { clk_set_freq(sc->clk_phy, 50000000, 0); } } if (sc->base.phy_mode == MII_CONTYPE_RMII) { if (sc->mac_clk_rx) clk_enable(sc->mac_clk_rx); if (sc->clk_mac_ref) clk_enable(sc->clk_mac_ref); if (sc->clk_mac_refout) clk_enable(sc->clk_mac_refout); } if (sc->clk_phy) clk_enable(sc->clk_phy); if (sc->aclk_mac) clk_enable(sc->aclk_mac); if (sc->pclk_mac) clk_enable(sc->pclk_mac); if (sc->mac_clk_tx) clk_enable(sc->mac_clk_tx); if (sc->clk_mac_speed) clk_enable(sc->clk_mac_speed); DELAY(50); return (0); } static int if_dwc_rk_init(device_t dev) { struct if_dwc_rk_softc *sc; phandle_t node; uint32_t rx, tx; int err; pcell_t phy_handle; char *clock_in_out; hwreset_t phy_reset; regulator_t phy_supply; sc = device_get_softc(dev); node = ofw_bus_get_node(dev); sc->ops = (struct if_dwc_rk_ops *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; if (OF_hasprop(node, "rockchip,grf") && syscon_get_by_ofw_property(dev, node, "rockchip,grf", &sc->grf) != 0) { device_printf(dev, "cannot get grf driver handle\n"); return (ENXIO); } if (OF_getencprop(node, "tx_delay", &tx, sizeof(tx)) <= 0) tx = 0x30; if (OF_getencprop(node, "rx_delay", &rx, sizeof(rx)) <= 0) rx = 0x10; sc->tx_delay = tx; sc->rx_delay = rx; sc->clock_in = true; if (OF_getprop_alloc(node, "clock_in_out", (void **)&clock_in_out)) { if (strcmp(clock_in_out, "input") == 0) sc->clock_in = true; else sc->clock_in = false; OF_prop_free(clock_in_out); } if (OF_getencprop(node, "phy-handle", (void *)&phy_handle, sizeof(phy_handle)) > 0) sc->phy_node = OF_node_from_xref(phy_handle); if (sc->phy_node) sc->integrated_phy = OF_hasprop(sc->phy_node, "phy-is-integrated"); if (sc->integrated_phy) device_printf(sc->base.dev, "PHY is integrated\n"); if_dwc_rk_init_clocks(dev); if (sc->ops->set_phy_mode) sc->ops->set_phy_mode(sc); if (sc->ops->set_delays) sc->ops->set_delays(sc); /* * this also sets delays if tunable is defined */ err = if_dwc_rk_init_sysctl(sc); if (err != 0) return (err); if (regulator_get_by_ofw_property(sc->base.dev, 0, "phy-supply", &phy_supply) == 0) { if (regulator_enable(phy_supply)) { device_printf(sc->base.dev, "cannot enable 'phy' regulator\n"); } } else device_printf(sc->base.dev, "no phy-supply property\n"); /* Power up */ if (sc->integrated_phy) { if (sc->ops->phy_powerup) sc->ops->phy_powerup(sc); SYSCON_WRITE_4(sc->grf, RK3328_GRF_MACPHY_CON0, (MACPHY_CON0_CLK_50M_MASK << 16) | MACPHY_CON0_CLK_50M); SYSCON_WRITE_4(sc->grf, RK3328_GRF_MACPHY_CON0, (MACPHY_CON0_RMII_MODE_MASK << 16) | MACPHY_CON0_RMII_MODE); SYSCON_WRITE_4(sc->grf, RK3328_GRF_MACPHY_CON2, 0xffff1234); SYSCON_WRITE_4(sc->grf, RK3328_GRF_MACPHY_CON3, 0x003f0035); if (hwreset_get_by_ofw_idx(dev, sc->phy_node, 0, &phy_reset) == 0) { hwreset_assert(phy_reset); DELAY(20); hwreset_deassert(phy_reset); DELAY(20); } } return (0); } static int if_dwc_rk_mii_clk(device_t dev) { struct if_dwc_rk_softc *sc; uint64_t freq; int rv; sc = device_get_softc(dev); if ((rv = clk_get_freq(sc->pclk_mac, &freq)) != 0) return (-rv); freq = freq / 1000 / 1000; if (freq >= 60 && freq <= 100) return (GMAC_MII_CLK_60_100M_DIV42); else if (freq >= 100 && freq <= 150) return (GMAC_MII_CLK_100_150M_DIV62); else if (freq >= 20 && freq <= 35) return (GMAC_MII_CLK_25_35M_DIV16); else if (freq >= 35 && freq <= 60) return (GMAC_MII_CLK_35_60M_DIV26); else if (freq >= 150 && freq <= 250) return (GMAC_MII_CLK_150_250M_DIV102); else if (freq >= 250 && freq <= 300) return (GMAC_MII_CLK_250_300M_DIV124); return (-ERANGE); } static int if_dwc_rk_set_speed(device_t dev, int speed) { struct if_dwc_rk_softc *sc; sc = device_get_softc(dev); if (sc->ops->set_speed) return sc->ops->set_speed(sc, speed); return (0); } static device_method_t if_dwc_rk_methods[] = { DEVMETHOD(device_probe, if_dwc_rk_probe), DEVMETHOD(if_dwc_init, if_dwc_rk_init), DEVMETHOD(if_dwc_mii_clk, if_dwc_rk_mii_clk), DEVMETHOD(if_dwc_set_speed, if_dwc_rk_set_speed), DEVMETHOD_END }; extern driver_t dwc_driver; DEFINE_CLASS_1(dwc, dwc_rk_driver, if_dwc_rk_methods, sizeof(struct if_dwc_rk_softc), dwc_driver); DRIVER_MODULE(dwc_rk, simplebus, dwc_rk_driver, 0, 0); MODULE_DEPEND(dwc_rk, dwc, 1, 1, 1); diff --git a/sys/dev/eqos/if_eqos_fdt.c b/sys/dev/eqos/if_eqos_fdt.c index 5601c8b778e2..114f83f3bf37 100644 --- a/sys/dev/eqos/if_eqos_fdt.c +++ b/sys/dev/eqos/if_eqos_fdt.c @@ -1,307 +1,307 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2022 Soren Schmidt * All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. * * $Id: eqos_fdt.c 1049 2022-12-03 14:25:46Z sos $ */ #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include "if_eqos_if.h" #include "syscon_if.h" #include "gpio_if.h" #include "rk_otp_if.h" #define RK356XGMAC0 0xfe2a0000 #define RK356XGMAC1 0xfe010000 #define RK3588GMAC0 0xfe1b0000 #define RK3588GMAC1 0xfe1c0000 #define EQOS_GRF_GMAC0 0x0380 #define EQOS_GRF_GMAC1 0x0388 #define EQOS_CON0_OFFSET 0 #define EQOS_CON1_OFFSET 4 #define EQOS_GMAC_PHY_INTF_SEL_RGMII 0x00fc0010 #define EQOS_GMAC_PHY_INTF_SEL_RMII 0x00fc0040 #define EQOS_GMAC_RXCLK_DLY_ENABLE 0x00020002 #define EQOS_GMAC_RXCLK_DLY_DISABLE 0x00020000 #define EQOS_GMAC_TXCLK_DLY_ENABLE 0x00010001 #define EQOS_GMAC_TXCLK_DLY_DISABLE 0x00010000 #define EQOS_GMAC_CLK_RX_DL_CFG(val) (0x7f000000 | val << 8) #define EQOS_GMAC_CLK_TX_DL_CFG(val) (0x007f0000 | val) #define WR4(sc, o, v) bus_write_4(sc->res[EQOS_RES_MEM], (o), (v)) static const struct ofw_compat_data compat_data[] = { {"snps,dwmac-4.20a", 1}, { NULL, 0 } }; static int eqos_phy_reset(device_t dev) { pcell_t gpio_prop[4]; pcell_t delay_prop[3]; phandle_t node, gpio_node; device_t gpio; uint32_t pin, flags; uint32_t pin_value; node = ofw_bus_get_node(dev); if (OF_getencprop(node, "snps,reset-gpio", gpio_prop, sizeof(gpio_prop)) <= 0) return (0); if (OF_getencprop(node, "snps,reset-delays-us", delay_prop, sizeof(delay_prop)) <= 0) { device_printf(dev, "Wrong property for snps,reset-delays-us"); return (ENXIO); } gpio_node = OF_node_from_xref(gpio_prop[0]); if ((gpio = OF_device_from_xref(gpio_prop[0])) == NULL) { device_printf(dev, "Can't find gpio controller for phy reset\n"); return (ENXIO); } if (GPIO_MAP_GPIOS(gpio, node, gpio_node, nitems(gpio_prop) - 1, gpio_prop + 1, &pin, &flags) != 0) { device_printf(dev, "Can't map gpio for phy reset\n"); return (ENXIO); } pin_value = GPIO_PIN_LOW; if (OF_hasprop(node, "snps,reset-active-low")) pin_value = GPIO_PIN_HIGH; GPIO_PIN_SETFLAGS(gpio, pin, GPIO_PIN_OUTPUT); GPIO_PIN_SET(gpio, pin, pin_value); DELAY(delay_prop[0]); GPIO_PIN_SET(gpio, pin, !pin_value); DELAY(delay_prop[1]); GPIO_PIN_SET(gpio, pin, pin_value); DELAY(delay_prop[2]); return (0); } static int eqos_fdt_init(device_t dev) { struct eqos_softc *sc = device_get_softc(dev); phandle_t node = ofw_bus_get_node(dev); hwreset_t eqos_reset; regulator_t eqos_supply; uint32_t rx_delay, tx_delay; uint8_t buffer[16]; clk_t stmmaceth, mac_clk_rx, mac_clk_tx, aclk_mac, pclk_mac; uint64_t freq; int error; if (OF_hasprop(node, "rockchip,grf") && syscon_get_by_ofw_property(dev, node, "rockchip,grf", &sc->grf)) { device_printf(dev, "cannot get grf driver handle\n"); return (ENXIO); } /* figure out if gmac0 or gmac1 offset */ switch (rman_get_start(sc->res[EQOS_RES_MEM])) { case RK356XGMAC0: /* RK356X gmac0 */ sc->grf_offset = EQOS_GRF_GMAC0; break; case RK356XGMAC1: /* RK356X gmac1 */ sc->grf_offset = EQOS_GRF_GMAC1; break; case RK3588GMAC0: /* RK3588 gmac0 */ case RK3588GMAC1: /* RK3588 gmac1 */ default: device_printf(dev, "Unknown eqos address\n"); return (ENXIO); } if (hwreset_get_by_ofw_idx(dev, node, 0, &eqos_reset)) { device_printf(dev, "cannot get reset\n"); return (ENXIO); } hwreset_assert(eqos_reset); error = clk_set_assigned(dev, ofw_bus_get_node(dev)); if (error != 0) { device_printf(dev, "clk_set_assigned failed\n"); return (error); } if (clk_get_by_ofw_name(dev, 0, "stmmaceth", &stmmaceth) == 0) { error = clk_enable(stmmaceth); if (error != 0) { device_printf(dev, "could not enable main clock\n"); return (error); } if (bootverbose) { clk_get_freq(stmmaceth, &freq); device_printf(dev, "MAC clock(%s) freq: %jd\n", clk_get_name(stmmaceth), (intmax_t)freq); } } else { device_printf(dev, "could not find clock stmmaceth\n"); } if (clk_get_by_ofw_name(dev, 0, "mac_clk_rx", &mac_clk_rx) != 0) { device_printf(dev, "could not get mac_clk_rx clock\n"); mac_clk_rx = NULL; } if (clk_get_by_ofw_name(dev, 0, "mac_clk_tx", &mac_clk_tx) != 0) { device_printf(dev, "could not get mac_clk_tx clock\n"); mac_clk_tx = NULL; } if (clk_get_by_ofw_name(dev, 0, "aclk_mac", &aclk_mac) != 0) { device_printf(dev, "could not get aclk_mac clock\n"); aclk_mac = NULL; } if (clk_get_by_ofw_name(dev, 0, "pclk_mac", &pclk_mac) != 0) { device_printf(dev, "could not get pclk_mac clock\n"); pclk_mac = NULL; } if (aclk_mac) clk_enable(aclk_mac); if (pclk_mac) clk_enable(pclk_mac); if (mac_clk_tx) clk_enable(mac_clk_tx); sc->csr_clock = 125000000; sc->csr_clock_range = GMAC_MAC_MDIO_ADDRESS_CR_100_150; if (OF_getencprop(node, "tx_delay", &tx_delay, sizeof(tx_delay)) <= 0) tx_delay = 0x30; if (OF_getencprop(node, "rx_delay", &rx_delay, sizeof(rx_delay)) <= 0) rx_delay = 0x10; SYSCON_WRITE_4(sc->grf, sc->grf_offset + EQOS_CON0_OFFSET, EQOS_GMAC_CLK_RX_DL_CFG(rx_delay) | EQOS_GMAC_CLK_TX_DL_CFG(tx_delay)); SYSCON_WRITE_4(sc->grf, sc->grf_offset + EQOS_CON1_OFFSET, EQOS_GMAC_PHY_INTF_SEL_RGMII | EQOS_GMAC_RXCLK_DLY_ENABLE | EQOS_GMAC_TXCLK_DLY_ENABLE); if (!regulator_get_by_ofw_property(dev, 0, "phy-supply", &eqos_supply)) { if (regulator_enable(eqos_supply)) device_printf(dev, "cannot enable 'phy' regulator\n"); } else device_printf(dev, "no phy-supply property\n"); if (eqos_phy_reset(dev)) return (ENXIO); if (eqos_reset) hwreset_deassert(eqos_reset); /* set the MAC address if we have OTP data handy */ if (!RK_OTP_READ(dev, buffer, 0, sizeof(buffer))) { uint32_t mac; mac = hash32_buf(buffer, sizeof(buffer), HASHINIT); WR4(sc, GMAC_MAC_ADDRESS0_LOW, htobe32((mac & 0xffffff00) | 0x22)); mac = hash32_buf(buffer, sizeof(buffer), mac); WR4(sc, GMAC_MAC_ADDRESS0_HIGH, htobe16((mac & 0x0000ffff) + (device_get_unit(dev) << 8))); } return (0); } static int eqos_fdt_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "DesignWare EQOS Gigabit ethernet"); return (BUS_PROBE_DEFAULT); } static device_method_t eqos_fdt_methods[] = { /* Device interface */ DEVMETHOD(device_probe, eqos_fdt_probe), /* EQOS interface */ DEVMETHOD(if_eqos_init, eqos_fdt_init), DEVMETHOD_END }; DEFINE_CLASS_1(eqos, eqos_fdt_driver, eqos_fdt_methods, sizeof(struct eqos_softc), eqos_driver); DRIVER_MODULE(eqos, simplebus, eqos_fdt_driver, 0, 0); MODULE_DEPEND(eqos, ether, 1, 1, 1); MODULE_DEPEND(eqos, miibus, 1, 1, 1); diff --git a/sys/dev/gpio/gpioregulator.c b/sys/dev/gpio/gpioregulator.c index 1f18bd6fd709..1fddb7dedc10 100644 --- a/sys/dev/gpio/gpioregulator.c +++ b/sys/dev/gpio/gpioregulator.c @@ -1,340 +1,340 @@ /*- * Copyright (c) 2016 Jared McNeill * * 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. */ /* * GPIO controlled regulators */ #include #include #include #include #include #include #include #include #include #include -#include +#include #include "regdev_if.h" struct gpioregulator_state { int val; uint32_t mask; }; struct gpioregulator_init_def { struct regnode_init_def reg_init_def; struct gpiobus_pin *enable_pin; int enable_pin_valid; int startup_delay_us; int nstates; struct gpioregulator_state *states; int npins; struct gpiobus_pin **pins; }; struct gpioregulator_reg_sc { struct regnode *regnode; device_t base_dev; struct regnode_std_param *param; struct gpioregulator_init_def *def; }; struct gpioregulator_softc { device_t dev; struct gpioregulator_reg_sc *reg_sc; struct gpioregulator_init_def init_def; }; static int gpioregulator_regnode_init(struct regnode *regnode) { struct gpioregulator_reg_sc *sc; int error, n; sc = regnode_get_softc(regnode); if (sc->def->enable_pin_valid == 1) { error = gpio_pin_setflags(sc->def->enable_pin, GPIO_PIN_OUTPUT); if (error != 0) return (error); } for (n = 0; n < sc->def->npins; n++) { error = gpio_pin_setflags(sc->def->pins[n], GPIO_PIN_OUTPUT); if (error != 0) return (error); } return (0); } static int gpioregulator_regnode_enable(struct regnode *regnode, bool enable, int *udelay) { struct gpioregulator_reg_sc *sc; bool active; int error; sc = regnode_get_softc(regnode); if (sc->def->enable_pin_valid == 1) { active = enable; if (!sc->param->enable_active_high) active = !active; error = gpio_pin_set_active(sc->def->enable_pin, active); if (error != 0) return (error); } *udelay = sc->def->startup_delay_us; return (0); } static int gpioregulator_regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay) { struct gpioregulator_reg_sc *sc; const struct gpioregulator_state *state; int error, n; sc = regnode_get_softc(regnode); state = NULL; for (n = 0; n < sc->def->nstates; n++) { if (sc->def->states[n].val >= min_uvolt && sc->def->states[n].val <= max_uvolt) { state = &sc->def->states[n]; break; } } if (state == NULL) return (EINVAL); for (n = 0; n < sc->def->npins; n++) { error = gpio_pin_set_active(sc->def->pins[n], (state->mask >> n) & 1); if (error != 0) return (error); } *udelay = sc->def->startup_delay_us; return (0); } static int gpioregulator_regnode_get_voltage(struct regnode *regnode, int *uvolt) { struct gpioregulator_reg_sc *sc; uint32_t mask; int error, n; bool active; sc = regnode_get_softc(regnode); mask = 0; for (n = 0; n < sc->def->npins; n++) { error = gpio_pin_is_active(sc->def->pins[n], &active); if (error != 0) return (error); mask |= (active << n); } for (n = 0; n < sc->def->nstates; n++) { if (sc->def->states[n].mask == mask) { *uvolt = sc->def->states[n].val; return (0); } } return (EIO); } static regnode_method_t gpioregulator_regnode_methods[] = { /* Regulator interface */ REGNODEMETHOD(regnode_init, gpioregulator_regnode_init), REGNODEMETHOD(regnode_enable, gpioregulator_regnode_enable), REGNODEMETHOD(regnode_set_voltage, gpioregulator_regnode_set_voltage), REGNODEMETHOD(regnode_get_voltage, gpioregulator_regnode_get_voltage), REGNODEMETHOD_END }; DEFINE_CLASS_1(gpioregulator_regnode, gpioregulator_regnode_class, gpioregulator_regnode_methods, sizeof(struct gpioregulator_reg_sc), regnode_class); static int gpioregulator_parse_fdt(struct gpioregulator_softc *sc) { uint32_t *pstates, mask; phandle_t node; ssize_t len; int error, n; node = ofw_bus_get_node(sc->dev); pstates = NULL; mask = 0; error = regulator_parse_ofw_stdparam(sc->dev, node, &sc->init_def.reg_init_def); if (error != 0) return (error); /* "states" property (required) */ len = OF_getencprop_alloc_multi(node, "states", sizeof(*pstates), (void **)&pstates); if (len < 2) { device_printf(sc->dev, "invalid 'states' property\n"); error = EINVAL; goto done; } sc->init_def.nstates = len / 2; sc->init_def.states = malloc(sc->init_def.nstates * sizeof(*sc->init_def.states), M_DEVBUF, M_WAITOK); for (n = 0; n < sc->init_def.nstates; n++) { sc->init_def.states[n].val = pstates[n * 2 + 0]; sc->init_def.states[n].mask = pstates[n * 2 + 1]; mask |= sc->init_def.states[n].mask; } /* "startup-delay-us" property (optional) */ len = OF_getencprop(node, "startup-delay-us", &sc->init_def.startup_delay_us, sizeof(sc->init_def.startup_delay_us)); if (len <= 0) sc->init_def.startup_delay_us = 0; /* "enable-gpio" property (optional) */ error = gpio_pin_get_by_ofw_property(sc->dev, node, "enable-gpio", &sc->init_def.enable_pin); if (error == 0) sc->init_def.enable_pin_valid = 1; /* "gpios" property */ sc->init_def.npins = 32 - __builtin_clz(mask); sc->init_def.pins = malloc(sc->init_def.npins * sizeof(sc->init_def.pins), M_DEVBUF, M_WAITOK | M_ZERO); for (n = 0; n < sc->init_def.npins; n++) { error = gpio_pin_get_by_ofw_idx(sc->dev, node, n, &sc->init_def.pins[n]); if (error != 0) { device_printf(sc->dev, "cannot get pin %d\n", n); goto done; } } done: if (error != 0) { for (n = 0; n < sc->init_def.npins; n++) { if (sc->init_def.pins[n] != NULL) gpio_pin_release(sc->init_def.pins[n]); } free(sc->init_def.states, M_DEVBUF); free(sc->init_def.pins, M_DEVBUF); } OF_prop_free(pstates); return (error); } static int gpioregulator_probe(device_t dev) { if (!ofw_bus_is_compatible(dev, "regulator-gpio")) return (ENXIO); device_set_desc(dev, "GPIO controlled regulator"); return (BUS_PROBE_GENERIC); } static int gpioregulator_attach(device_t dev) { struct gpioregulator_softc *sc; struct regnode *regnode; phandle_t node; int error; sc = device_get_softc(dev); sc->dev = dev; node = ofw_bus_get_node(dev); error = gpioregulator_parse_fdt(sc); if (error != 0) { device_printf(dev, "cannot parse parameters\n"); return (ENXIO); } sc->init_def.reg_init_def.id = 1; sc->init_def.reg_init_def.ofw_node = node; regnode = regnode_create(dev, &gpioregulator_regnode_class, &sc->init_def.reg_init_def); if (regnode == NULL) { device_printf(dev, "cannot create regulator\n"); return (ENXIO); } sc->reg_sc = regnode_get_softc(regnode); sc->reg_sc->regnode = regnode; sc->reg_sc->base_dev = dev; sc->reg_sc->param = regnode_get_stdparam(regnode); sc->reg_sc->def = &sc->init_def; regnode_register(regnode); return (0); } static device_method_t gpioregulator_methods[] = { /* Device interface */ DEVMETHOD(device_probe, gpioregulator_probe), DEVMETHOD(device_attach, gpioregulator_attach), /* Regdev interface */ DEVMETHOD(regdev_map, regdev_default_ofw_map), DEVMETHOD_END }; static driver_t gpioregulator_driver = { "gpioregulator", gpioregulator_methods, sizeof(struct gpioregulator_softc), }; EARLY_DRIVER_MODULE(gpioregulator, simplebus, gpioregulator_driver, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); MODULE_VERSION(gpioregulator, 1); diff --git a/sys/dev/iicbus/pmic/act8846.c b/sys/dev/iicbus/pmic/act8846.c index af3ee0ede5e5..5e166247f79b 100644 --- a/sys/dev/iicbus/pmic/act8846.c +++ b/sys/dev/iicbus/pmic/act8846.c @@ -1,255 +1,255 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2019 Michal Meloun * * 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 AND CONTRIBUTORS ``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 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 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. */ #include /* * ACT8846 PMIC driver */ #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #include "regdev_if.h" static struct ofw_compat_data compat_data[] = { {"active-semi,act8846", 1}, {NULL, 0} }; #define LOCK(_sc) sx_xlock(&(_sc)->lock) #define UNLOCK(_sc) sx_xunlock(&(_sc)->lock) #define LOCK_INIT(_sc) sx_init(&(_sc)->lock, "act8846") #define LOCK_DESTROY(_sc) sx_destroy(&(_sc)->lock); #define ASSERT_LOCKED(_sc) sx_assert(&(_sc)->lock, SA_XLOCKED); #define ASSERT_UNLOCKED(_sc) sx_assert(&(_sc)->lock, SA_UNLOCKED); /* * Raw register access function. */ int act8846_read(struct act8846_softc *sc, uint8_t reg, uint8_t *val) { uint8_t addr; int rv; struct iic_msg msgs[2] = { {0, IIC_M_WR, 1, &addr}, {0, IIC_M_RD, 1, val}, }; msgs[0].slave = sc->bus_addr; msgs[1].slave = sc->bus_addr; addr = reg; rv = iicbus_transfer_excl(sc->dev, msgs, 2, IIC_INTRWAIT); if (rv != 0) { device_printf(sc->dev, "Error when reading reg 0x%02X, rv: %d\n", reg, rv); return (EIO); } return (0); } int act8846_read_buf(struct act8846_softc *sc, uint8_t reg, uint8_t *buf, size_t size) { uint8_t addr; int rv; struct iic_msg msgs[2] = { {0, IIC_M_WR, 1, &addr}, {0, IIC_M_RD, size, buf}, }; msgs[0].slave = sc->bus_addr; msgs[1].slave = sc->bus_addr; addr = reg; rv = iicbus_transfer_excl(sc->dev, msgs, 2, IIC_INTRWAIT); if (rv != 0) { device_printf(sc->dev, "Error when reading reg 0x%02X, rv: %d\n", reg, rv); return (EIO); } return (0); } int act8846_write(struct act8846_softc *sc, uint8_t reg, uint8_t val) { uint8_t data[2]; int rv; struct iic_msg msgs[1] = { {0, IIC_M_WR, 2, data}, }; msgs[0].slave = sc->bus_addr; data[0] = reg; data[1] = val; rv = iicbus_transfer_excl(sc->dev, msgs, 1, IIC_INTRWAIT); if (rv != 0) { device_printf(sc->dev, "Error when writing reg 0x%02X, rv: %d\n", reg, rv); return (EIO); } return (0); } int act8846_write_buf(struct act8846_softc *sc, uint8_t reg, uint8_t *buf, size_t size) { uint8_t data[1]; int rv; struct iic_msg msgs[2] = { {0, IIC_M_WR, 1, data}, {0, IIC_M_WR | IIC_M_NOSTART, size, buf}, }; msgs[0].slave = sc->bus_addr; msgs[1].slave = sc->bus_addr; data[0] = reg; rv = iicbus_transfer_excl(sc->dev, msgs, 2, IIC_INTRWAIT); if (rv != 0) { device_printf(sc->dev, "Error when writing reg 0x%02X, rv: %d\n", reg, rv); return (EIO); } return (0); } int act8846_modify(struct act8846_softc *sc, uint8_t reg, uint8_t clear, uint8_t set) { uint8_t val; int rv; rv = act8846_read(sc, reg, &val); if (rv != 0) return (rv); val &= ~clear; val |= set; rv = act8846_write(sc, reg, val); if (rv != 0) return (rv); return (0); } static int act8846_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "ACT8846 PMIC"); return (BUS_PROBE_DEFAULT); } static int act8846_attach(device_t dev) { struct act8846_softc *sc; int rv; phandle_t node; sc = device_get_softc(dev); sc->dev = dev; sc->bus_addr = iicbus_get_addr(dev); node = ofw_bus_get_node(sc->dev); rv = 0; LOCK_INIT(sc); rv = act8846_regulator_attach(sc, node); if (rv != 0) goto fail; return (bus_generic_attach(dev)); fail: LOCK_DESTROY(sc); return (rv); } static int act8846_detach(device_t dev) { struct act8846_softc *sc; sc = device_get_softc(dev); LOCK_DESTROY(sc); return (bus_generic_detach(dev)); } static device_method_t act8846_methods[] = { /* Device interface */ DEVMETHOD(device_probe, act8846_probe), DEVMETHOD(device_attach, act8846_attach), DEVMETHOD(device_detach, act8846_detach), /* Regdev interface */ DEVMETHOD(regdev_map, act8846_regulator_map), DEVMETHOD_END }; static DEFINE_CLASS_0(act8846_pmu, act8846_driver, act8846_methods, sizeof(struct act8846_softc)); EARLY_DRIVER_MODULE(act8846_pmic, iicbus, act8846_driver, NULL, NULL, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); MODULE_VERSION(act8846_pmic, 1); MODULE_DEPEND(act8846_pmic, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); IICBUS_FDT_PNP_INFO(compat_data); diff --git a/sys/dev/iicbus/pmic/act8846_regulator.c b/sys/dev/iicbus/pmic/act8846_regulator.c index 551b537bb64f..9a711db2fbef 100644 --- a/sys/dev/iicbus/pmic/act8846_regulator.c +++ b/sys/dev/iicbus/pmic/act8846_regulator.c @@ -1,503 +1,503 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2019 Michal Meloun * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include "regdev_if.h" MALLOC_DEFINE(M_ACT8846_REG, "ACT8846 regulator", "ACT8846 power regulator"); #if 0 #define dprintf(sc, format, arg...) device_printf(sc->base_sc->dev, "%s: " format, __func__, arg) */ #else #define dprintf(sc, format, arg...) #endif enum act8846_reg_id { ACT8846_REG_ID_REG1, ACT8846_REG_ID_REG2, ACT8846_REG_ID_REG3, ACT8846_REG_ID_REG4, ACT8846_REG_ID_REG5, ACT8846_REG_ID_REG6, ACT8846_REG_ID_REG7, ACT8846_REG_ID_REG8, ACT8846_REG_ID_REG9, ACT8846_REG_ID_REG10, ACT8846_REG_ID_REG11, ACT8846_REG_ID_REG12, ACT8846_REG_ID_REG13, }; struct act8846_regdef { intptr_t id; /* ID */ char *name; /* Regulator name */ char *supply_name; /* Source property name */ uint8_t enable_reg; uint8_t enable_mask; uint8_t voltage_reg; uint8_t voltage_mask; struct regulator_range *ranges; int nranges; }; struct act8846_softc; struct act8846_reg_sc { struct regnode *regnode; struct act8846_softc *base_sc; struct act8846_regdef *def; phandle_t xref; struct regnode_std_param *param; }; static struct regulator_range act8846_ranges[] = { REG_RANGE_INIT( 0, 23, 600000, 25000), REG_RANGE_INIT( 24, 47, 1200000, 50000), REG_RANGE_INIT( 48, 64, 2400000, 100000), }; static struct act8846_regdef act8846_regdefs[] = { { .id = ACT8846_REG_ID_REG1, .name = "REG1", .supply_name = "vp1", .enable_reg = ACT8846_REG1_CTRL, .enable_mask = ACT8846_CTRL_ENA, }, { .id = ACT8846_REG_ID_REG2, .name = "REG2", .supply_name = "vp2", .enable_reg = ACT8846_REG2_CTRL, .enable_mask = ACT8846_CTRL_ENA, .voltage_reg = ACT8846_REG2_VSET0, .voltage_mask = ACT8846_VSEL_MASK, .ranges = act8846_ranges, .nranges = nitems(act8846_ranges), }, { .id = ACT8846_REG_ID_REG3, .name = "REG3", .supply_name = "vp3", .enable_reg = ACT8846_REG3_CTRL, .enable_mask = ACT8846_CTRL_ENA, .voltage_reg = ACT8846_REG3_VSET0, .voltage_mask = ACT8846_VSEL_MASK, .ranges = act8846_ranges, .nranges = nitems(act8846_ranges), }, { .id = ACT8846_REG_ID_REG4, .name = "REG4", .supply_name = "vp4", .enable_reg = ACT8846_REG4_CTRL, .enable_mask = ACT8846_CTRL_ENA, .voltage_reg = ACT8846_REG4_VSET0, .voltage_mask = ACT8846_VSEL_MASK, .ranges = act8846_ranges, .nranges = nitems(act8846_ranges), }, { .id = ACT8846_REG_ID_REG5, .name = "REG5", .supply_name = "inl1", .enable_reg = ACT8846_REG5_CTRL, .enable_mask = ACT8846_CTRL_ENA, .voltage_reg = ACT8846_REG5_VSET, .voltage_mask = ACT8846_VSEL_MASK, .ranges = act8846_ranges, .nranges = nitems(act8846_ranges), }, { .id = ACT8846_REG_ID_REG6, .name = "REG6", .supply_name = "inl1", .enable_reg = ACT8846_REG6_CTRL, .enable_mask = ACT8846_CTRL_ENA, .voltage_reg = ACT8846_REG6_VSET, .voltage_mask = ACT8846_VSEL_MASK, .ranges = act8846_ranges, .nranges = nitems(act8846_ranges), }, { .id = ACT8846_REG_ID_REG7, .name = "REG7", .supply_name = "inl1", .enable_reg = ACT8846_REG7_CTRL, .enable_mask = ACT8846_CTRL_ENA, .voltage_reg = ACT8846_REG7_VSET, .voltage_mask = ACT8846_VSEL_MASK, .ranges = act8846_ranges, .nranges = nitems(act8846_ranges), }, { .id = ACT8846_REG_ID_REG8, .name = "REG8", .supply_name = "inl2", .enable_reg = ACT8846_REG8_CTRL, .enable_mask = ACT8846_CTRL_ENA, .voltage_reg = ACT8846_REG8_VSET, .voltage_mask = ACT8846_VSEL_MASK, .ranges = act8846_ranges, .nranges = nitems(act8846_ranges), }, { .id = ACT8846_REG_ID_REG9, .name = "REG9", .supply_name = "inl2", .enable_reg = ACT8846_REG9_CTRL, .enable_mask = ACT8846_CTRL_ENA, .voltage_reg = ACT8846_REG9_VSET, .voltage_mask = ACT8846_VSEL_MASK, .ranges = act8846_ranges, .nranges = nitems(act8846_ranges), }, { .id = ACT8846_REG_ID_REG10, .name = "REG10", .supply_name = "inl3", .enable_reg = ACT8846_REG10_CTRL, .enable_mask = ACT8846_CTRL_ENA, .voltage_reg = ACT8846_REG10_VSET, .voltage_mask = ACT8846_VSEL_MASK, .ranges = act8846_ranges, .nranges = nitems(act8846_ranges), }, { .id = ACT8846_REG_ID_REG11, .name = "REG11", .supply_name = "inl3", .enable_reg = ACT8846_REG11_CTRL, .enable_mask = ACT8846_CTRL_ENA, .voltage_reg = ACT8846_REG11_VSET, .voltage_mask = ACT8846_VSEL_MASK, .ranges = act8846_ranges, .nranges = nitems(act8846_ranges), }, { .id = ACT8846_REG_ID_REG12, .name = "REG12", .supply_name = "inl3", .enable_reg = ACT8846_REG12_CTRL, .enable_mask = ACT8846_CTRL_ENA, .voltage_reg = ACT8846_REG12_VSET, .voltage_mask = ACT8846_VSEL_MASK, .ranges = act8846_ranges, .nranges = nitems(act8846_ranges), }, { .id = ACT8846_REG_ID_REG13, .name = "REG13", .supply_name = "inl1", .enable_reg = ACT8846_REG13_CTRL, .enable_mask = ACT8846_CTRL_ENA, }, }; static int act8846_read_sel(struct act8846_reg_sc *sc, uint8_t *sel) { int rv; rv = RD1(sc->base_sc, sc->def->voltage_reg, sel); if (rv != 0) return (rv); *sel &= sc->def->voltage_mask; *sel >>= ffs(sc->def->voltage_mask) - 1; return (0); } static int act8846_write_sel(struct act8846_reg_sc *sc, uint8_t sel) { int rv; sel <<= ffs(sc->def->voltage_mask) - 1; sel &= sc->def->voltage_mask; rv = RM1(sc->base_sc, sc->def->voltage_reg, sc->def->voltage_mask, sel); if (rv != 0) return (rv); return (rv); } static int act8846_regnode_init(struct regnode *regnode) { return (0); } static int act8846_regnode_enable(struct regnode *regnode, bool enable, int *udelay) { struct act8846_reg_sc *sc; int rv; sc = regnode_get_softc(regnode); dprintf(sc, "%sabling regulator %s\n", enable ? "En" : "Dis", sc->def->name); rv = RM1(sc->base_sc, sc->def->enable_reg, sc->def->enable_mask, enable ? sc->def->enable_mask: 0); *udelay = sc->param->enable_delay; return (rv); } static int act8846_regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay) { struct act8846_reg_sc *sc; uint8_t sel; int uvolt, rv; sc = regnode_get_softc(regnode); if (sc->def->ranges == NULL) return (ENXIO); dprintf(sc, "Setting %s to %d<->%d uvolts\n", sc->def->name, min_uvolt, max_uvolt); rv = regulator_range_volt_to_sel8(sc->def->ranges, sc->def->nranges, min_uvolt, max_uvolt, &sel); if (rv != 0) return (rv); *udelay = sc->param->ramp_delay; rv = act8846_write_sel(sc, sel); act8846_read_sel(sc, &sel); regulator_range_sel8_to_volt(sc->def->ranges, sc->def->nranges, sel, &uvolt); dprintf(sc, "Regulator %s set to %d uvolt\n", sc->def->name, uvolt); return (rv); } static int act8846_regnode_get_voltage(struct regnode *regnode, int *uvolt) { struct act8846_reg_sc *sc; uint8_t sel; int rv; sc = regnode_get_softc(regnode); if (sc->def->ranges == NULL) { if (sc->def->id == ACT8846_REG_ID_REG13) { *uvolt = 1800000; return (0); } return (ENXIO); } rv = act8846_read_sel(sc, &sel); if (rv != 0) return (rv); rv = regulator_range_sel8_to_volt(sc->def->ranges, sc->def->nranges, sel, uvolt); dprintf(sc, "Regulator %s is at %d uvolt\n", sc->def->name, *uvolt); return (rv); } static regnode_method_t act8846_regnode_methods[] = { /* Regulator interface */ REGNODEMETHOD(regnode_init, act8846_regnode_init), REGNODEMETHOD(regnode_enable, act8846_regnode_enable), REGNODEMETHOD(regnode_set_voltage, act8846_regnode_set_voltage), REGNODEMETHOD(regnode_get_voltage, act8846_regnode_get_voltage), REGNODEMETHOD_END }; DEFINE_CLASS_1(act8846_regnode, act8846_regnode_class, act8846_regnode_methods, sizeof(struct act8846_reg_sc), regnode_class); static int act8846_fdt_parse(struct act8846_softc *sc, phandle_t pnode, phandle_t node, struct act8846_regdef *def, struct regnode_init_def *init_def) { int rv; phandle_t supply_node; char prop_name[64]; /* Maximum OFW property name length. */ rv = regulator_parse_ofw_stdparam(sc->dev, node, init_def); /* Get parent supply. */ if (def->supply_name == NULL) return (0); snprintf(prop_name, sizeof(prop_name), "%s-supply", def->supply_name); rv = OF_getencprop(pnode, prop_name, &supply_node, sizeof(supply_node)); if (rv <= 0) return (rv); supply_node = OF_node_from_xref(supply_node); rv = OF_getprop_alloc(supply_node, "regulator-name", (void **)&init_def->parent_name); if (rv <= 0) init_def->parent_name = NULL; return (0); } static struct act8846_reg_sc * act8846_attach(struct act8846_softc *sc, phandle_t pnode, phandle_t node, struct act8846_regdef *def) { struct act8846_reg_sc *reg_sc; struct regnode_init_def initdef; struct regnode *regnode; memset(&initdef, 0, sizeof(initdef)); if (act8846_fdt_parse(sc, pnode, node, def, &initdef) != 0) { device_printf(sc->dev, "cannot parse FDT data for regulator\n"); return (NULL); } initdef.id = def->id; initdef.ofw_node = node; regnode = regnode_create(sc->dev, &act8846_regnode_class, &initdef); if (regnode == NULL) { device_printf(sc->dev, "cannot create regulator\n"); return (NULL); } reg_sc = regnode_get_softc(regnode); reg_sc->base_sc = sc; reg_sc->def = def; reg_sc->xref = OF_xref_from_node(node); reg_sc->param = regnode_get_stdparam(regnode); regnode_register(regnode); if (bootverbose) { int volt, rv; regnode_topo_slock(); rv = regnode_get_voltage(regnode, &volt); if (rv == ENODEV) { device_printf(sc->dev, " Regulator %s: parent doesn't exist yet.\n", regnode_get_name(regnode)); } else if (rv != 0) { device_printf(sc->dev, " Regulator %s: voltage: INVALID!!!\n", regnode_get_name(regnode)); } else { device_printf(sc->dev, " Regulator %s: voltage: %d uV\n", regnode_get_name(regnode), volt); } regnode_topo_unlock(); } return (reg_sc); } int act8846_regulator_attach(struct act8846_softc *sc, phandle_t node) { struct act8846_reg_sc *reg; phandle_t child, rnode; int i; rnode = ofw_bus_find_child(node, "regulators"); if (rnode <= 0) { device_printf(sc->dev, " Cannot find regulators subnode\n"); return (ENXIO); } /* ACT8846 specific definitio. */ sc->nregs = nitems(act8846_regdefs); sc->regs = malloc(sizeof(struct act8846_reg_sc *) * sc->nregs, M_ACT8846_REG, M_WAITOK | M_ZERO); /* Attach all known regulators if exist in DT. */ for (i = 0; i < sc->nregs; i++) { child = ofw_bus_find_child(rnode, act8846_regdefs[i].name); if (child == 0) { if (bootverbose) device_printf(sc->dev, "Regulator %s missing in DT\n", act8846_regdefs[i].name); continue; } reg = act8846_attach(sc, node, child, act8846_regdefs + i); if (reg == NULL) { device_printf(sc->dev, "Cannot attach regulator: %s\n", act8846_regdefs[i].name); return (ENXIO); } sc->regs[i] = reg; } return (0); } int act8846_regulator_map(device_t dev, phandle_t xref, int ncells, pcell_t *cells, int *num) { struct act8846_softc *sc; int i; sc = device_get_softc(dev); for (i = 0; i < sc->nregs; i++) { if (sc->regs[i] == NULL) continue; if (sc->regs[i]->xref == xref) { *num = sc->regs[i]->def->id; return (0); } } return (ENXIO); } diff --git a/sys/dev/iicbus/pmic/fan53555.c b/sys/dev/iicbus/pmic/fan53555.c index 12940bad5c67..7693770428e2 100644 --- a/sys/dev/iicbus/pmic/fan53555.c +++ b/sys/dev/iicbus/pmic/fan53555.c @@ -1,509 +1,509 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2016 Jared McNeill * Copyright (c) 2018 Emmanuel Vadot * Copyright (c) 2019 Michal Meloun * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include "regdev_if.h" /* Registers */ #define FAN53555_VSEL0 0x00 #define FAN53555_VSEL1 0x01 #define FAN53555_VSEL_ENA (1 << 7) #define FAN53555_VSEL_MODE (1 << 6) #define FAN53555_VSEL_MASK 0x3f #define FAN53555_CTRL 0x02 #define FAN53555_ID1 0x03 #define FAN53555_ID1_DIE_ID(x) ((x) & 0x0F) #define FAN53555_ID2 0x04 #define FAN53555_ID2_DIE_REV(x) ((x) & 0x0F) #define FAN53555_MON 0x05 #define TCS4525_VSEL0 0x11 #define TCS4525_VSEL1 0x10 #define TCS4525_CHIP_ID_12 12 #if 0 #define dprintf(sc, format, arg...) \ device_printf(sc->base_dev, "%s: " format, __func__, arg) #else #define dprintf(sc, format, arg...) #endif enum fan53555_pmic_type { FAN53555 = 1, SYR827, SYR828, TCS4525, }; static struct ofw_compat_data compat_data[] = { {"fcs,fan53555", FAN53555}, {"silergy,syr827", SYR827}, {"silergy,syr828", SYR828}, {"tcs,tcs4525", TCS4525}, {NULL, 0} }; struct fan53555_reg_sc { struct regnode *regnode; char *name; device_t base_dev; uint8_t live_reg; uint8_t sleep_reg; struct regulator_range *range; struct regnode_std_param *param; }; struct fan53555_softc { device_t dev; uint8_t live_reg; uint8_t sleep_reg; }; static struct regulator_range syr_8_range = REG_RANGE_INIT( 0, 0x3F, 712500, 12500); static struct regulator_range fan_0_0_range = REG_RANGE_INIT( 0, 0x3F, 600000, 10000); static struct regulator_range fan_0_13_range = REG_RANGE_INIT( 0, 0x3F, 800000, 10000); static struct regulator_range fan_1_range = REG_RANGE_INIT( 0, 0x3F, 600000, 10000); static struct regulator_range fan_4_range = REG_RANGE_INIT( 0, 0x3F, 603000, 12826); static struct regulator_range tcs_12_range = REG_RANGE_INIT( 0, 0x3F, 800000, 6250); static int fan53555_read(device_t dev, uint8_t reg, uint8_t *val) { uint8_t addr; int rv; struct iic_msg msgs[2] = { {0, IIC_M_WR | IIC_M_NOSTOP, 1, &addr}, {0, IIC_M_RD, 1, val}, }; msgs[0].slave = iicbus_get_addr(dev); msgs[1].slave = iicbus_get_addr(dev); addr = reg; rv = iicbus_transfer_excl(dev, msgs, 2, IIC_INTRWAIT); if (rv != 0) { device_printf(dev, "Error when reading reg 0x%02X, rv: %d\n", reg, rv); return (EIO); } return (0); } static int fan53555_write(device_t dev, uint8_t reg, uint8_t val) { uint8_t data[2]; int rv; struct iic_msg msgs[1] = { {0, IIC_M_WR, 2, data}, }; msgs[0].slave = iicbus_get_addr(dev); data[0] = reg; data[1] = val; rv = iicbus_transfer_excl(dev, msgs, 1, IIC_INTRWAIT); if (rv != 0) { device_printf(dev, "Error when writing reg 0x%02X, rv: %d\n", reg, rv); return (EIO); } return (0); } static int fan53555_read_sel(struct fan53555_reg_sc *sc, uint8_t *sel) { int rv; rv = fan53555_read(sc->base_dev, sc->live_reg, sel); if (rv != 0) return (rv); *sel &= FAN53555_VSEL_MASK; return (0); } static int fan53555_write_sel(struct fan53555_reg_sc *sc, uint8_t sel) { int rv; uint8_t reg; rv = fan53555_read(sc->base_dev, sc->live_reg, ®); if (rv != 0) return (rv); reg &= ~FAN53555_VSEL_MASK; reg |= sel; rv = fan53555_write(sc->base_dev, sc->live_reg, reg); if (rv != 0) return (rv); return (rv); } static int fan53555_regnode_init(struct regnode *regnode) { return (0); } static int fan53555_regnode_enable(struct regnode *regnode, bool enable, int *udelay) { struct fan53555_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); dprintf(sc, "%sabling regulator %s\n", enable ? "En" : "Dis", sc->name); fan53555_read(sc->base_dev, sc->live_reg, &val); if (enable) val |=FAN53555_VSEL_ENA; else val &= ~FAN53555_VSEL_ENA; fan53555_write(sc->base_dev, sc->live_reg, val); *udelay = sc->param->enable_delay; return (0); } static int fan53555_regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay) { struct fan53555_reg_sc *sc; uint8_t sel; int uvolt, rv; sc = regnode_get_softc(regnode); dprintf(sc, "Setting %s to %d<->%d uvolts\n", sc->name, min_uvolt, max_uvolt); rv = regulator_range_volt_to_sel8(sc->range, 1, min_uvolt, max_uvolt, &sel); if (rv != 0) return (rv); *udelay = sc->param->ramp_delay; rv = fan53555_write_sel(sc, sel); dprintf(sc, "Regulator %s writing sel: 0x%02X\n", sc->name, sel); fan53555_read_sel(sc, &sel); regulator_range_sel8_to_volt(sc->range, 1, sel, &uvolt); dprintf(sc, "Regulator %s set to %d uvolt (sel: 0x%02X)\n", sc->name, uvolt, sel); return (rv); } static int fan53555_regnode_get_voltage(struct regnode *regnode, int *uvolt) { struct fan53555_reg_sc *sc; uint8_t sel; int rv; sc = regnode_get_softc(regnode); rv = fan53555_read_sel(sc, &sel); if (rv != 0) return (rv); rv = regulator_range_sel8_to_volt(sc->range, 1, sel, uvolt); dprintf(sc, "Regulator %s is at %d uvolt ((sel: 0x%02X)\n", sc->name, *uvolt, sel); return (rv); } static regnode_method_t fan53555_regnode_methods[] = { /* Regulator interface */ REGNODEMETHOD(regnode_init, fan53555_regnode_init), REGNODEMETHOD(regnode_enable, fan53555_regnode_enable), REGNODEMETHOD(regnode_set_voltage, fan53555_regnode_set_voltage), REGNODEMETHOD(regnode_get_voltage, fan53555_regnode_get_voltage), REGNODEMETHOD_END }; DEFINE_CLASS_1(fan53555_regnode, fan53555_regnode_class, fan53555_regnode_methods, sizeof(struct fan53555_reg_sc), regnode_class); static struct regulator_range * fan53555_get_range(struct fan53555_softc *sc, int type, uint8_t id, uint8_t rev) { if (type == SYR827 || type == SYR828) { switch (id) { case 8: return (&syr_8_range); default: return (NULL); } } if (type == FAN53555) { switch (id) { case 0: if (rev == 0) return (&fan_0_0_range); else if (rev == 13) return (&fan_0_13_range); else return (NULL); case 1: case 3: case 5: case 8: return (&fan_1_range); case 4: return (&fan_4_range); default: return (NULL); } } if (type == TCS4525) { switch (id) { case TCS4525_CHIP_ID_12: return (&tcs_12_range); default: return (NULL); } } return (NULL); } static struct fan53555_reg_sc * fan53555_reg_attach(struct fan53555_softc *sc, phandle_t node, int type) { struct fan53555_reg_sc *reg_sc; struct regnode_init_def initdef; struct regnode *regnode; static struct regulator_range *range; uint8_t id1, id2; memset(&initdef, 0, sizeof(initdef)); if (regulator_parse_ofw_stdparam(sc->dev, node, &initdef) != 0) { device_printf(sc->dev, "cannot parse regulator FDT data\n"); return (NULL); } if (fan53555_read(sc->dev, FAN53555_ID1, &id1) != 0) { device_printf(sc->dev, "cannot read ID1\n"); return (NULL); } if (fan53555_read(sc->dev, FAN53555_ID2, &id2) != 0) { device_printf(sc->dev, "cannot read ID2\n"); return (NULL); } dprintf(sc, "Device ID1: 0x%02X, ID2: 0x%02X\n", id1, id2); range = fan53555_get_range(sc, type, FAN53555_ID1_DIE_ID(id1), FAN53555_ID2_DIE_REV(id2)); if (range == NULL) { device_printf(sc->dev, "cannot determine chip type (ID1: 0x%02X, ID2: 0x%02X)\n", id1, id2); return (NULL); } initdef.id = 1; initdef.ofw_node = node; regnode = regnode_create(sc->dev, &fan53555_regnode_class, &initdef); if (regnode == NULL) { device_printf(sc->dev, "cannot create regulator\n"); return (NULL); } reg_sc = regnode_get_softc(regnode); reg_sc->name = "fan53555"; reg_sc->regnode = regnode; reg_sc->base_dev = sc->dev; reg_sc->param = regnode_get_stdparam(regnode); reg_sc->range = range; reg_sc->live_reg = sc->live_reg; reg_sc->sleep_reg = sc->sleep_reg; dprintf(sc->dev, "live_reg: %d, sleep_reg: %d\n", reg_sc->live_reg, reg_sc->sleep_reg); regnode_register(regnode); if (bootverbose) { int volt, rv; regnode_topo_slock(); rv = regnode_get_voltage(regnode, &volt); if (rv == ENODEV) { device_printf(sc->dev, " Regulator %s: parent doesn't exist yet.\n", regnode_get_name(regnode)); } else if (rv != 0) { device_printf(sc->dev, " Regulator %s: voltage: INVALID!!!\n", regnode_get_name(regnode)); } else { device_printf(sc->dev, " Regulator %s: voltage: %d uV\n", regnode_get_name(regnode), volt); } regnode_topo_unlock(); } return (reg_sc); } static int fan53555_probe(device_t dev) { int type; if (!ofw_bus_status_okay(dev)) return (ENXIO); type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; switch (type) { case FAN53555: device_set_desc(dev, "FAN53555 PMIC"); break; case SYR827: device_set_desc(dev, "SYR827 PMIC"); break; case SYR828: device_set_desc(dev, "SYR828 PMIC"); break; case TCS4525: device_set_desc(dev, "TCS4525 PMIC"); break; default: return (ENXIO); } return (BUS_PROBE_DEFAULT); } static int fan53555_attach(device_t dev) { struct fan53555_softc *sc; phandle_t node; int type, susp_sel, rv; sc = device_get_softc(dev); sc->dev = dev; node = ofw_bus_get_node(dev); type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; rv = OF_getencprop(node, "fcs,suspend-voltage-selector", &susp_sel, sizeof(susp_sel)); if (rv <= 0) susp_sel = 1; switch (type) { case FAN53555: case SYR827: case SYR828: if (susp_sel == 1) { sc->live_reg = FAN53555_VSEL0; sc->sleep_reg = FAN53555_VSEL1; } else { sc->live_reg = FAN53555_VSEL1; sc->sleep_reg = FAN53555_VSEL0; } break; case TCS4525: if (susp_sel == 1) { sc->live_reg = TCS4525_VSEL0; sc->sleep_reg = TCS4525_VSEL1; } else { sc->live_reg = TCS4525_VSEL1; sc->sleep_reg = TCS4525_VSEL0; } break; default: return (ENXIO); } if (fan53555_reg_attach(sc, node, type) == NULL) device_printf(dev, "cannot attach regulator.\n"); return (0); } static int fan53555_detach(device_t dev) { /* We cannot detach regulators */ return (EBUSY); } static device_method_t fan53555_methods[] = { DEVMETHOD(device_probe, fan53555_probe), DEVMETHOD(device_attach, fan53555_attach), DEVMETHOD(device_detach, fan53555_detach), /* Regdev interface */ DEVMETHOD(regdev_map, regdev_default_ofw_map), DEVMETHOD_END }; static DEFINE_CLASS_0(fan53555_pmic, fan53555_driver, fan53555_methods, sizeof(struct fan53555_softc)); EARLY_DRIVER_MODULE(fan53555, iicbus, fan53555_driver, 0, 0, BUS_PASS_RESOURCE); MODULE_VERSION(fan53555, 1); MODULE_DEPEND(fan53555, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); IICBUS_FDT_PNP_INFO(compat_data); diff --git a/sys/dev/iicbus/pmic/rockchip/rk8xx_regulators.c b/sys/dev/iicbus/pmic/rockchip/rk8xx_regulators.c index 7e637176531d..f640c6668376 100644 --- a/sys/dev/iicbus/pmic/rockchip/rk8xx_regulators.c +++ b/sys/dev/iicbus/pmic/rockchip/rk8xx_regulators.c @@ -1,367 +1,367 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018-2021 Emmanuel Vadot * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include -#include +#include #include #include "regdev_if.h" static int rk8xx_regnode_status(struct regnode *regnode, int *status); static int rk8xx_regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay); static int rk8xx_regnode_get_voltage(struct regnode *regnode, int *uvolt); /* #define dprintf(sc, format, arg...) device_printf(sc->base_dev, "%s: " format, __func__, arg) */ #define dprintf(sc, format, arg...) (sc = sc) static int rk8xx_regnode_init(struct regnode *regnode) { struct rk8xx_reg_sc *sc; struct regnode_std_param *param; int rv, udelay, uvolt, status; sc = regnode_get_softc(regnode); dprintf(sc, "Regulator %s init called\n", sc->def->name); param = regnode_get_stdparam(regnode); if (param->min_uvolt == 0) return (0); /* Check that the regulator is preset to the correct voltage */ rv = rk8xx_regnode_get_voltage(regnode, &uvolt); if (rv != 0) return(rv); if (uvolt >= param->min_uvolt && uvolt <= param->max_uvolt) return(0); /* * Set the regulator at the correct voltage if it is not enabled. * Do not enable it, this is will be done either by a * consumer or by regnode_set_constraint if boot_on is true */ rv = rk8xx_regnode_status(regnode, &status); if (rv != 0 || status == REGULATOR_STATUS_ENABLED) return (rv); rv = rk8xx_regnode_set_voltage(regnode, param->min_uvolt, param->max_uvolt, &udelay); if (udelay != 0) DELAY(udelay); return (rv); } static int rk8xx_regnode_enable(struct regnode *regnode, bool enable, int *udelay) { struct rk8xx_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); dprintf(sc, "%sabling regulator %s\n", enable ? "En" : "Dis", sc->def->name); rk8xx_read(sc->base_dev, sc->def->enable_reg, &val, 1); if (enable) val |= sc->def->enable_mask; else val &= ~sc->def->enable_mask; rk8xx_write(sc->base_dev, sc->def->enable_reg, &val, 1); *udelay = 0; return (0); } static void rk8xx_regnode_reg_to_voltage(struct rk8xx_reg_sc *sc, uint8_t val, int *uv) { struct rk8xx_softc *sc1; sc1 = device_get_softc(sc->base_dev); if (sc1->type == RK809 || sc1->type == RK817) { if (sc->def->voltage_step2) { int change; change = ((sc->def->voltage_min2 - sc->def->voltage_min) / sc->def->voltage_step); if (val > change) { if (val < sc->def->voltage_nstep) { *uv = sc->def->voltage_min2 + (val - change) * sc->def->voltage_step2; } else *uv = sc->def->voltage_max2; return; } } if (val < sc->def->voltage_nstep) *uv = sc->def->voltage_min + val * sc->def->voltage_step; else *uv = sc->def->voltage_max; } else { if (val < sc->def->voltage_nstep) *uv = sc->def->voltage_min + val * sc->def->voltage_step; else *uv = sc->def->voltage_min + (sc->def->voltage_nstep * sc->def->voltage_step); } } static int rk8xx_regnode_voltage_to_reg(struct rk8xx_reg_sc *sc, int min_uvolt, int max_uvolt, uint8_t *val) { uint8_t nval; int nstep, uvolt; struct rk8xx_softc *sc1; sc1 = device_get_softc(sc->base_dev); nval = 0; uvolt = sc->def->voltage_min; for (nstep = 0; nstep < sc->def->voltage_nstep && uvolt < min_uvolt; nstep++) { ++nval; if (sc1->type == RK809 || sc1->type == RK817) { if (sc->def->voltage_step2) { if (uvolt < sc->def->voltage_min2) uvolt += sc->def->voltage_step; else uvolt += sc->def->voltage_step2; } else uvolt += sc->def->voltage_step; } else uvolt += sc->def->voltage_step; } if (uvolt > max_uvolt) return (EINVAL); *val = nval; return (0); } static int rk8xx_regnode_status(struct regnode *regnode, int *status) { struct rk8xx_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); *status = 0; rk8xx_read(sc->base_dev, sc->def->enable_reg, &val, 1); if (val & sc->def->enable_mask) *status = REGULATOR_STATUS_ENABLED; return (0); } static int rk8xx_regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay) { struct rk8xx_reg_sc *sc; uint8_t val, old; int uvolt; struct rk8xx_softc *sc1; sc = regnode_get_softc(regnode); sc1 = device_get_softc(sc->base_dev); if (!sc->def->voltage_step) return (ENXIO); dprintf(sc, "Setting %s to %d<->%d uvolts\n", sc->def->name, min_uvolt, max_uvolt); rk8xx_read(sc->base_dev, sc->def->voltage_reg, &val, 1); old = val; if (rk8xx_regnode_voltage_to_reg(sc, min_uvolt, max_uvolt, &val) != 0) return (ERANGE); if (sc1->type == RK809 || sc1->type == RK817) val |= (old &= ~sc->def->voltage_mask); rk8xx_write(sc->base_dev, sc->def->voltage_reg, &val, 1); rk8xx_read(sc->base_dev, sc->def->voltage_reg, &val, 1); *udelay = 0; rk8xx_regnode_reg_to_voltage(sc, val, &uvolt); dprintf(sc, "Regulator %s set to %d uvolt\n", sc->def->name, uvolt); return (0); } static int rk8xx_regnode_get_voltage(struct regnode *regnode, int *uvolt) { struct rk8xx_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); if (sc->def->voltage_min == sc->def->voltage_max) { *uvolt = sc->def->voltage_min; return (0); } if (!sc->def->voltage_step) return (ENXIO); rk8xx_read(sc->base_dev, sc->def->voltage_reg, &val, 1); rk8xx_regnode_reg_to_voltage(sc, val & sc->def->voltage_mask, uvolt); dprintf(sc, "Regulator %s is at %d uvolt\n", sc->def->name, *uvolt); return (0); } static regnode_method_t rk8xx_regnode_methods[] = { /* Regulator interface */ REGNODEMETHOD(regnode_init, rk8xx_regnode_init), REGNODEMETHOD(regnode_enable, rk8xx_regnode_enable), REGNODEMETHOD(regnode_status, rk8xx_regnode_status), REGNODEMETHOD(regnode_set_voltage, rk8xx_regnode_set_voltage), REGNODEMETHOD(regnode_get_voltage, rk8xx_regnode_get_voltage), REGNODEMETHOD(regnode_check_voltage, regnode_method_check_voltage), REGNODEMETHOD_END }; DEFINE_CLASS_1(rk8xx_regnode, rk8xx_regnode_class, rk8xx_regnode_methods, sizeof(struct rk8xx_reg_sc), regnode_class); static struct rk8xx_reg_sc * rk8xx_reg_attach(device_t dev, phandle_t node, struct rk8xx_regdef *def) { struct rk8xx_reg_sc *reg_sc; struct regnode_init_def initdef; struct regnode *regnode; memset(&initdef, 0, sizeof(initdef)); if (regulator_parse_ofw_stdparam(dev, node, &initdef) != 0) { device_printf(dev, "cannot create regulator\n"); return (NULL); } if (initdef.std_param.min_uvolt == 0) initdef.std_param.min_uvolt = def->voltage_min; if (initdef.std_param.max_uvolt == 0) initdef.std_param.max_uvolt = def->voltage_max; initdef.id = def->id; initdef.ofw_node = node; regnode = regnode_create(dev, &rk8xx_regnode_class, &initdef); if (regnode == NULL) { device_printf(dev, "cannot create regulator\n"); return (NULL); } reg_sc = regnode_get_softc(regnode); reg_sc->regnode = regnode; reg_sc->base_dev = dev; reg_sc->def = def; reg_sc->xref = OF_xref_from_node(node); reg_sc->param = regnode_get_stdparam(regnode); regnode_register(regnode); return (reg_sc); } void rk8xx_attach_regulators(struct rk8xx_softc *sc) { struct rk8xx_reg_sc *reg; struct reg_list *regp; phandle_t rnode, child; int i; TAILQ_INIT(&sc->regs); rnode = ofw_bus_find_child(ofw_bus_get_node(sc->dev), "regulators"); if (rnode > 0) { for (i = 0; i < sc->nregs; i++) { child = ofw_bus_find_child(rnode, sc->regdefs[i].name); if (child == 0) continue; if (OF_hasprop(child, "regulator-name") != 1) continue; reg = rk8xx_reg_attach(sc->dev, child, &sc->regdefs[i]); if (reg == NULL) { device_printf(sc->dev, "cannot attach regulator %s\n", sc->regdefs[i].name); continue; } regp = malloc(sizeof(*regp), M_DEVBUF, M_WAITOK | M_ZERO); regp->reg = reg; TAILQ_INSERT_TAIL(&sc->regs, regp, next); if (bootverbose) device_printf(sc->dev, "Regulator %s attached\n", sc->regdefs[i].name); } } } int rk8xx_map(device_t dev, phandle_t xref, int ncells, pcell_t *cells, intptr_t *id) { struct rk8xx_softc *sc; struct reg_list *regp; sc = device_get_softc(dev); TAILQ_FOREACH(regp, &sc->regs, next) { if (regp->reg->xref == xref) { *id = regp->reg->def->id; return (0); } } return (ERANGE); } diff --git a/sys/dev/iicbus/pmic/silergy/sy8106a.c b/sys/dev/iicbus/pmic/silergy/sy8106a.c index 76a39415349d..7c00c67f38d9 100644 --- a/sys/dev/iicbus/pmic/silergy/sy8106a.c +++ b/sys/dev/iicbus/pmic/silergy/sy8106a.c @@ -1,294 +1,294 @@ /*- * Copyright (c) 2016 Jared McNeill * * 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. */ /* * Silergy Corp. SY8106A buck regulator */ #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include "iicbus_if.h" #include "regdev_if.h" #define VOUT1_SEL 0x01 #define SEL_GO (1 << 7) #define SEL_VOLTAGE_MASK 0x7f #define SEL_VOLTAGE_BASE 680000 /* uV */ #define SEL_VOLTAGE_STEP 10000 /* uV */ #define VOUT_COM 0x02 #define COM_DISABLE (1 << 0) #define SYS_STATUS 0x06 static struct ofw_compat_data compat_data[] = { { "silergy,sy8106a", 1 }, { NULL, 0 } }; struct sy8106a_reg_sc { struct regnode *regnode; device_t base_dev; phandle_t xref; struct regnode_std_param *param; }; struct sy8106a_softc { uint16_t addr; /* Regulator */ struct sy8106a_reg_sc *reg; }; static int sy8106a_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size) { struct sy8106a_softc *sc; struct iic_msg msg[2]; sc = device_get_softc(dev); msg[0].slave = sc->addr; msg[0].flags = IIC_M_WR; msg[0].len = 1; msg[0].buf = ® msg[1].slave = sc->addr; msg[1].flags = IIC_M_RD; msg[1].len = size; msg[1].buf = data; return (iicbus_transfer(dev, msg, 2)); } static int sy8106a_write(device_t dev, uint8_t reg, uint8_t val) { struct sy8106a_softc *sc; struct iic_msg msg; uint8_t buffer[2]; sc = device_get_softc(dev); buffer[0] = reg; buffer[1] = val; msg.slave = sc->addr; msg.flags = IIC_M_WR; msg.len = 2; msg.buf = buffer; return (iicbus_transfer(dev, &msg, 1)); } static int sy8106a_regnode_init(struct regnode *regnode) { return (0); } static int sy8106a_regnode_enable(struct regnode *regnode, bool enable, int *udelay) { struct sy8106a_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); sy8106a_read(sc->base_dev, VOUT_COM, &val, 1); if (enable) val &= ~COM_DISABLE; else val |= COM_DISABLE; sy8106a_write(sc->base_dev, VOUT_COM, val); *udelay = sc->param->ramp_delay; return (0); } static int sy8106a_regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay) { struct sy8106a_reg_sc *sc; int cur_uvolt; uint8_t val, oval; sc = regnode_get_softc(regnode); /* Get current voltage */ sy8106a_read(sc->base_dev, VOUT1_SEL, &oval, 1); cur_uvolt = (oval & SEL_VOLTAGE_MASK) * SEL_VOLTAGE_STEP + SEL_VOLTAGE_BASE; /* Set new voltage */ val = SEL_GO | ((min_uvolt - SEL_VOLTAGE_BASE) / SEL_VOLTAGE_STEP); sy8106a_write(sc->base_dev, VOUT1_SEL, val); /* Time to delay is based on the number of voltage steps */ *udelay = sc->param->ramp_delay * (abs(cur_uvolt - min_uvolt) / SEL_VOLTAGE_STEP); return (0); } static int sy8106a_regnode_get_voltage(struct regnode *regnode, int *uvolt) { struct sy8106a_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); sy8106a_read(sc->base_dev, VOUT1_SEL, &val, 1); *uvolt = (val & SEL_VOLTAGE_MASK) * SEL_VOLTAGE_STEP + SEL_VOLTAGE_BASE; return (0); } static regnode_method_t sy8106a_regnode_methods[] = { /* Regulator interface */ REGNODEMETHOD(regnode_init, sy8106a_regnode_init), REGNODEMETHOD(regnode_enable, sy8106a_regnode_enable), REGNODEMETHOD(regnode_set_voltage, sy8106a_regnode_set_voltage), REGNODEMETHOD(regnode_get_voltage, sy8106a_regnode_get_voltage), REGNODEMETHOD_END }; DEFINE_CLASS_1(sy8106a_regnode, sy8106a_regnode_class, sy8106a_regnode_methods, sizeof(struct sy8106a_reg_sc), regnode_class); static struct sy8106a_reg_sc * sy8106a_reg_attach(device_t dev, phandle_t node) { struct sy8106a_reg_sc *reg_sc; struct regnode_init_def initdef; struct regnode *regnode; memset(&initdef, 0, sizeof(initdef)); regulator_parse_ofw_stdparam(dev, node, &initdef); initdef.id = 0; initdef.ofw_node = node; regnode = regnode_create(dev, &sy8106a_regnode_class, &initdef); if (regnode == NULL) { device_printf(dev, "cannot create regulator\n"); return (NULL); } reg_sc = regnode_get_softc(regnode); reg_sc->regnode = regnode; reg_sc->base_dev = dev; reg_sc->xref = OF_xref_from_node(node); reg_sc->param = regnode_get_stdparam(regnode); regnode_register(regnode); return (reg_sc); } static int sy8106a_regdev_map(device_t dev, phandle_t xref, int ncells, pcell_t *cells, intptr_t *num) { struct sy8106a_softc *sc; sc = device_get_softc(dev); if (sc->reg->xref != xref) return (ENXIO); *num = 0; return (0); } static int sy8106a_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Silergy SY8106A regulator"); return (BUS_PROBE_DEFAULT); } static int sy8106a_attach(device_t dev) { struct sy8106a_softc *sc; phandle_t node; sc = device_get_softc(dev); node = ofw_bus_get_node(dev); sc->addr = iicbus_get_addr(dev); sc->reg = sy8106a_reg_attach(dev, node); if (sc->reg == NULL) { device_printf(dev, "cannot attach regulator\n"); return (ENXIO); } return (0); } static device_method_t sy8106a_methods[] = { /* Device interface */ DEVMETHOD(device_probe, sy8106a_probe), DEVMETHOD(device_attach, sy8106a_attach), /* Regdev interface */ DEVMETHOD(regdev_map, sy8106a_regdev_map), DEVMETHOD_END }; static driver_t sy8106a_driver = { "sy8106a", sy8106a_methods, sizeof(struct sy8106a_softc), }; EARLY_DRIVER_MODULE(sy8106a, iicbus, sy8106a_driver, 0, 0, BUS_PASS_RESOURCE); MODULE_VERSION(sy8106a, 1); MODULE_DEPEND(sy8106a, iicbus, 1, 1, 1); IICBUS_FDT_PNP_INFO(compat_data); diff --git a/sys/dev/iicbus/pmic/silergy/syr827.c b/sys/dev/iicbus/pmic/silergy/syr827.c index afc2bacfcd02..d48a3c92e665 100644 --- a/sys/dev/iicbus/pmic/silergy/syr827.c +++ b/sys/dev/iicbus/pmic/silergy/syr827.c @@ -1,320 +1,320 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2016 Jared McNeill * Copyright (c) 2018 Emmanuel Vadot * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include "iicbus_if.h" #include "regdev_if.h" #define VSEL0 0x00 #define VSEL1 0x01 #define VSEL_BUCK_EN (1 << 7) #define VSEL_NSEL_MASK 0x3F #define VSEL_VOLTAGE_BASE 712500 /* uV */ #define VSEL_VOLTAGE_STEP 12500 /* uV */ #define ID1 0x03 #define ID1_VENDOR_MASK 0xE0 #define ID1_VENDOR_SHIFT 5 #define ID1_DIE_MASK 0xF #define ID2 0x4 #define ID2_DIE_REV_MASK 0xF static struct ofw_compat_data compat_data[] = { { "silergy,syr827", 1 }, { NULL, 0 } }; struct syr827_reg_sc { struct regnode *regnode; device_t base_dev; phandle_t xref; struct regnode_std_param *param; int volt_reg; int suspend_reg; }; struct syr827_softc { uint16_t addr; struct intr_config_hook intr_hook; /* Regulator */ struct syr827_reg_sc *reg; }; static int syr827_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size) { return (iicdev_readfrom(dev, reg, data, size, IIC_INTRWAIT)); } static int syr827_write(device_t dev, uint8_t reg, uint8_t val) { return (iicdev_writeto(dev, reg, &val, 1, IIC_INTRWAIT)); } static int syr827_regnode_init(struct regnode *regnode) { return (0); } static int syr827_regnode_enable(struct regnode *regnode, bool enable, int *udelay) { struct syr827_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); syr827_read(sc->base_dev, sc->volt_reg, &val, 1); if (enable) val &= ~VSEL_BUCK_EN; else val |= VSEL_BUCK_EN; syr827_write(sc->base_dev, sc->volt_reg, val); *udelay = sc->param->ramp_delay; return (0); } static int syr827_regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay) { struct syr827_reg_sc *sc; int cur_uvolt; uint8_t val; sc = regnode_get_softc(regnode); /* Get current voltage */ syr827_read(sc->base_dev, sc->volt_reg, &val, 1); cur_uvolt = (val & VSEL_NSEL_MASK) * VSEL_VOLTAGE_STEP + VSEL_VOLTAGE_BASE; /* Set new voltage */ val &= ~VSEL_NSEL_MASK; val |= ((min_uvolt - VSEL_VOLTAGE_BASE) / VSEL_VOLTAGE_STEP); syr827_write(sc->base_dev, sc->volt_reg, val); /* Time to delay is based on the number of voltage steps */ *udelay = sc->param->ramp_delay * (abs(cur_uvolt - min_uvolt) / VSEL_VOLTAGE_STEP); return (0); } static int syr827_regnode_get_voltage(struct regnode *regnode, int *uvolt) { struct syr827_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); syr827_read(sc->base_dev, sc->volt_reg, &val, 1); *uvolt = (val & VSEL_NSEL_MASK) * VSEL_VOLTAGE_STEP + VSEL_VOLTAGE_BASE; return (0); } static regnode_method_t syr827_regnode_methods[] = { /* Regulator interface */ REGNODEMETHOD(regnode_init, syr827_regnode_init), REGNODEMETHOD(regnode_enable, syr827_regnode_enable), REGNODEMETHOD(regnode_set_voltage, syr827_regnode_set_voltage), REGNODEMETHOD(regnode_get_voltage, syr827_regnode_get_voltage), REGNODEMETHOD_END }; DEFINE_CLASS_1(syr827_regnode, syr827_regnode_class, syr827_regnode_methods, sizeof(struct syr827_reg_sc), regnode_class); static struct syr827_reg_sc * syr827_reg_attach(device_t dev, phandle_t node) { struct syr827_reg_sc *reg_sc; struct regnode_init_def initdef; struct regnode *regnode; int suspend_reg; memset(&initdef, 0, sizeof(initdef)); regulator_parse_ofw_stdparam(dev, node, &initdef); initdef.id = 0; initdef.ofw_node = node; regnode = regnode_create(dev, &syr827_regnode_class, &initdef); if (regnode == NULL) { device_printf(dev, "cannot create regulator\n"); return (NULL); } reg_sc = regnode_get_softc(regnode); reg_sc->regnode = regnode; reg_sc->base_dev = dev; reg_sc->xref = OF_xref_from_node(node); reg_sc->param = regnode_get_stdparam(regnode); if (OF_getencprop(node, "fcs,suspend-voltage-selector", &suspend_reg, sizeof(uint32_t)) <= 0) suspend_reg = 0; switch (suspend_reg) { case 0: reg_sc->suspend_reg = VSEL0; reg_sc->volt_reg = VSEL1; break; case 1: reg_sc->suspend_reg = VSEL1; reg_sc->volt_reg = VSEL0; break; } regnode_register(regnode); return (reg_sc); } static int syr827_regdev_map(device_t dev, phandle_t xref, int ncells, pcell_t *cells, intptr_t *num) { struct syr827_softc *sc; sc = device_get_softc(dev); if (sc->reg->xref != xref) return (ENXIO); *num = 0; return (0); } static int syr827_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Silergy SYR827 regulator"); return (BUS_PROBE_DEFAULT); } static void syr827_start(void *pdev) { struct syr827_softc *sc; device_t dev; uint8_t val; dev = pdev; sc = device_get_softc(dev); if (bootverbose) { syr827_read(dev, ID1, &val, 1); device_printf(dev, "Vendor ID: %x, DIE ID: %x\n", (val & ID1_VENDOR_MASK) >> ID1_VENDOR_SHIFT, val & ID1_DIE_MASK); syr827_read(dev, ID2, &val, 1); device_printf(dev, "DIE Rev: %x\n", val & ID2_DIE_REV_MASK); } config_intrhook_disestablish(&sc->intr_hook); } static int syr827_attach(device_t dev) { struct syr827_softc *sc; phandle_t node; sc = device_get_softc(dev); node = ofw_bus_get_node(dev); sc->addr = iicbus_get_addr(dev); sc->intr_hook.ich_func = syr827_start; sc->intr_hook.ich_arg = dev; if (config_intrhook_establish(&sc->intr_hook) != 0) return (ENOMEM); sc->reg = syr827_reg_attach(dev, node); if (sc->reg == NULL) { device_printf(dev, "cannot attach regulator\n"); return (ENXIO); } return (0); } static device_method_t syr827_methods[] = { /* Device interface */ DEVMETHOD(device_probe, syr827_probe), DEVMETHOD(device_attach, syr827_attach), /* Regdev interface */ DEVMETHOD(regdev_map, syr827_regdev_map), DEVMETHOD_END }; static driver_t syr827_driver = { "syr827", syr827_methods, sizeof(struct syr827_softc), }; EARLY_DRIVER_MODULE(syr827, iicbus, syr827_driver, 0, 0, BUS_PASS_RESOURCE); MODULE_VERSION(syr827, 1); MODULE_DEPEND(syr827, iicbus, 1, 1, 1); IICBUS_FDT_PNP_INFO(compat_data); diff --git a/sys/dev/mmc/host/dwmmc_var.h b/sys/dev/mmc/host/dwmmc_var.h index ebfc738eb8af..c524fd88f00a 100644 --- a/sys/dev/mmc/host/dwmmc_var.h +++ b/sys/dev/mmc/host/dwmmc_var.h @@ -1,103 +1,103 @@ /*- * Copyright (c) 2014 Ruslan Bukin * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) * ("CTSRD"), as part of the DARPA CRASH research programme. * * 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 AND CONTRIBUTORS ``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 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 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. */ #ifndef DEV_MMC_HOST_DWMMC_VAR_H #define DEV_MMC_HOST_DWMMC_VAR_H #include #include -#include +#include #include "opt_mmccam.h" #include enum { HWTYPE_NONE, HWTYPE_ALTERA, HWTYPE_EXYNOS, HWTYPE_HISILICON, HWTYPE_ROCKCHIP, }; struct dwmmc_softc { struct resource *res[2]; device_t dev; void *intr_cookie; struct mmc_host host; struct mmc_helper mmc_helper; struct mtx sc_mtx; #ifdef MMCCAM union ccb * ccb; struct mmc_sim mmc_sim; #else struct mmc_request *req; #endif struct mmc_command *curcmd; uint32_t flags; uint32_t hwtype; uint32_t use_auto_stop; uint32_t use_pio; device_t child; struct task card_task; /* Card presence check task */ struct timeout_task card_delayed_task;/* Card insert delayed task */ int (*update_ios)(struct dwmmc_softc *sc, struct mmc_ios *ios); bus_dma_tag_t desc_tag; bus_dmamap_t desc_map; struct idmac_desc *desc_ring; bus_addr_t desc_ring_paddr; bus_dma_tag_t buf_tag; bus_dmamap_t buf_map; uint32_t bus_busy; uint32_t dto_rcvd; uint32_t acd_rcvd; uint32_t cmd_done; uint64_t bus_hz; uint32_t fifo_depth; uint32_t num_slots; uint32_t sdr_timing; uint32_t ddr_timing; clk_t biu; clk_t ciu; hwreset_t hwreset; regulator_t vmmc; regulator_t vqmmc; }; DECLARE_CLASS(dwmmc_driver); int dwmmc_attach(device_t); int dwmmc_detach(device_t); #endif diff --git a/sys/dev/mmc/mmc_fdt_helpers.c b/sys/dev/mmc/mmc_fdt_helpers.c index 8742b90d4f9c..0fb76dbfe522 100644 --- a/sys/dev/mmc/mmc_fdt_helpers.c +++ b/sys/dev/mmc/mmc_fdt_helpers.c @@ -1,376 +1,376 @@ /* * Copyright 2019 Emmanuel Vadot * Copyright (c) 2017 Ian Lepore All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include "mmc_pwrseq_if.h" int mmc_fdt_parse(device_t dev, phandle_t node, struct mmc_helper *helper, struct mmc_host *host) { struct mmc_helper mmc_helper; phandle_t pwrseq_xref; memset(&mmc_helper, 0, sizeof(mmc_helper)); mmc_parse(dev, &mmc_helper, host); helper->props = mmc_helper.props; /* * Get the regulators if they are supported and * clean the non supported modes based on the available voltages. */ if (regulator_get_by_ofw_property(dev, 0, "vmmc-supply", &helper->vmmc_supply) == 0) { if (bootverbose) device_printf(dev, "vmmc-supply regulator found\n"); } if (regulator_get_by_ofw_property(dev, 0, "vqmmc-supply", &helper->vqmmc_supply) == 0 && bootverbose) { if (bootverbose) device_printf(dev, "vqmmc-supply regulator found\n"); } if (helper->vqmmc_supply != NULL) { if (regulator_check_voltage(helper->vqmmc_supply, 1200000) == 0) host->caps |= MMC_CAP_SIGNALING_120; else host->caps &= ~( MMC_CAP_MMC_HS400_120 | MMC_CAP_MMC_HS200_120 | MMC_CAP_MMC_DDR52_120); if (regulator_check_voltage(helper->vqmmc_supply, 1800000) == 0) host->caps |= MMC_CAP_SIGNALING_180; else host->caps &= ~(MMC_CAP_MMC_HS400_180 | MMC_CAP_MMC_HS200_180 | MMC_CAP_MMC_DDR52_180 | MMC_CAP_UHS_DDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25); if (regulator_check_voltage(helper->vqmmc_supply, 3300000) == 0) host->caps |= MMC_CAP_SIGNALING_330; } else host->caps |= MMC_CAP_SIGNALING_330; if (OF_hasprop(node, "mmc-pwrseq")) { if (OF_getencprop(node, "mmc-pwrseq", &pwrseq_xref, sizeof(pwrseq_xref)) == -1) { device_printf(dev, "Cannot get the pwrseq_xref property\n"); return (ENXIO); } helper->mmc_pwrseq = OF_device_from_xref(pwrseq_xref); } return (0); } /* * Card detect interrupt handler. */ static void cd_intr(void *arg) { struct mmc_helper *helper = arg; taskqueue_enqueue_timeout(taskqueue_swi_giant, &helper->cd_delayed_task, -(hz / 2)); } static void cd_card_task(void *arg, int pending __unused) { struct mmc_helper *helper = arg; bool cd_present; cd_present = mmc_fdt_gpio_get_present(helper); if(helper->cd_handler && cd_present != helper->cd_present) helper->cd_handler(helper->dev, cd_present); helper->cd_present = cd_present; /* If we're polling re-schedule the task */ if (helper->cd_ihandler == NULL) taskqueue_enqueue_timeout_sbt(taskqueue_swi_giant, &helper->cd_delayed_task, mstosbt(500), 0, C_PREL(2)); } /* * Card detect setup. */ static void cd_setup(struct mmc_helper *helper, phandle_t node) { int pincaps; device_t dev; const char *cd_mode_str; dev = helper->dev; TIMEOUT_TASK_INIT(taskqueue_swi_giant, &helper->cd_delayed_task, 0, cd_card_task, helper); /* * If the device is flagged as non-removable, set that slot option, and * set a flag to make sdhci_fdt_gpio_get_present() always return true. */ if (helper->props & MMC_PROP_NON_REMOVABLE) { helper->cd_disabled = true; if (bootverbose) device_printf(dev, "Non-removable media\n"); return; } /* * If there is no cd-gpios property, then presumably the hardware * PRESENT_STATE register and interrupts will reflect card state * properly, and there's nothing more for us to do. Our get_present() * will return sdhci_generic_get_card_present() because cd_pin is NULL. * * If there is a property, make sure we can read the pin. */ if (gpio_pin_get_by_ofw_property(dev, node, "cd-gpios", &helper->cd_pin)) return; if (gpio_pin_getcaps(helper->cd_pin, &pincaps) != 0 || !(pincaps & GPIO_PIN_INPUT)) { device_printf(dev, "Cannot read card-detect gpio pin; " "setting card-always-present flag.\n"); helper->cd_disabled = true; return; } /* * If the pin can trigger an interrupt on both rising and falling edges, * we can use it to detect card presence changes. If not, we'll request * card presence polling instead of using interrupts. */ if (!(pincaps & GPIO_INTR_EDGE_BOTH)) { if (bootverbose) device_printf(dev, "Cannot configure " "GPIO_INTR_EDGE_BOTH for card detect\n"); goto without_interrupts; } if (helper->cd_handler == NULL) { if (bootverbose) device_printf(dev, "Cannot configure " "interrupts as no cd_handler is set\n"); goto without_interrupts; } /* * Create an interrupt resource from the pin and set up the interrupt. */ if ((helper->cd_ires = gpio_alloc_intr_resource(dev, &helper->cd_irid, RF_ACTIVE, helper->cd_pin, GPIO_INTR_EDGE_BOTH)) == NULL) { if (bootverbose) device_printf(dev, "Cannot allocate an IRQ for card " "detect GPIO\n"); goto without_interrupts; } if (bus_setup_intr(dev, helper->cd_ires, INTR_TYPE_BIO | INTR_MPSAFE, NULL, cd_intr, helper, &helper->cd_ihandler) != 0) { device_printf(dev, "Unable to setup card-detect irq handler\n"); helper->cd_ihandler = NULL; goto without_interrupts; } without_interrupts: /* * If we have a readable gpio pin, but didn't successfully configure * gpio interrupts, setup a timeout task to poll the pin */ if (helper->cd_ihandler == NULL) { cd_mode_str = "polling"; } else { cd_mode_str = "interrupts"; } if (bootverbose) { device_printf(dev, "Card presence detect on %s pin %u, " "configured for %s.\n", device_get_nameunit(helper->cd_pin->dev), helper->cd_pin->pin, cd_mode_str); } } /* * Write protect setup. */ static void wp_setup(struct mmc_helper *helper, phandle_t node) { device_t dev; dev = helper->dev; if (OF_hasprop(node, "disable-wp")) { helper->wp_disabled = true; if (bootverbose) device_printf(dev, "Write protect disabled\n"); return; } if (gpio_pin_get_by_ofw_property(dev, node, "wp-gpios", &helper->wp_pin)) return; if (bootverbose) device_printf(dev, "Write protect switch on %s pin %u\n", device_get_nameunit(helper->wp_pin->dev), helper->wp_pin->pin); } int mmc_fdt_gpio_setup(device_t dev, phandle_t node, struct mmc_helper *helper, mmc_fdt_cd_handler handler) { if (node <= 0) node = ofw_bus_get_node(dev); if (node <= 0) { device_printf(dev, "Cannot get node for device\n"); return (ENXIO); } helper->dev = dev; helper->cd_handler = handler; cd_setup(helper, node); wp_setup(helper, node); /* * Schedule a card detection */ taskqueue_enqueue_timeout_sbt(taskqueue_swi_giant, &helper->cd_delayed_task, mstosbt(500), 0, C_PREL(2)); return (0); } void mmc_fdt_gpio_teardown(struct mmc_helper *helper) { if (helper == NULL) return; if (helper->cd_ihandler != NULL) bus_teardown_intr(helper->dev, helper->cd_ires, helper->cd_ihandler); if (helper->wp_pin != NULL) gpio_pin_release(helper->wp_pin); if (helper->cd_pin != NULL) gpio_pin_release(helper->cd_pin); if (helper->cd_ires != NULL) bus_release_resource(helper->dev, SYS_RES_IRQ, 0, helper->cd_ires); taskqueue_drain_timeout(taskqueue_swi_giant, &helper->cd_delayed_task); } bool mmc_fdt_gpio_get_present(struct mmc_helper *helper) { bool pinstate; if (helper->cd_disabled) return (true); if (helper->cd_pin == NULL) return (false); gpio_pin_is_active(helper->cd_pin, &pinstate); return (pinstate ^ (bool)(helper->props & MMC_PROP_CD_INVERTED)); } bool mmc_fdt_gpio_get_readonly(struct mmc_helper *helper) { bool pinstate; if (helper->wp_disabled) return (false); if (helper->wp_pin == NULL) return (false); gpio_pin_is_active(helper->wp_pin, &pinstate); return (pinstate ^ (bool)(helper->props & MMC_PROP_WP_INVERTED)); } void mmc_fdt_set_power(struct mmc_helper *helper, enum mmc_power_mode power_mode) { int reg_status; int rv; switch (power_mode) { case power_on: break; case power_off: if (helper->vmmc_supply) { rv = regulator_status(helper->vmmc_supply, ®_status); if (rv == 0 && reg_status == REGULATOR_STATUS_ENABLED) regulator_disable(helper->vmmc_supply); } if (helper->vqmmc_supply) { rv = regulator_status(helper->vqmmc_supply, ®_status); if (rv == 0 && reg_status == REGULATOR_STATUS_ENABLED) regulator_disable(helper->vqmmc_supply); } if (helper->mmc_pwrseq) MMC_PWRSEQ_SET_POWER(helper->mmc_pwrseq, false); break; case power_up: if (helper->vmmc_supply) { rv = regulator_status(helper->vmmc_supply, ®_status); if (rv == 0 && reg_status != REGULATOR_STATUS_ENABLED) regulator_enable(helper->vmmc_supply); } if (helper->vqmmc_supply) { rv = regulator_status(helper->vqmmc_supply, ®_status); if (rv == 0 && reg_status != REGULATOR_STATUS_ENABLED) regulator_enable(helper->vqmmc_supply); } if (helper->mmc_pwrseq) MMC_PWRSEQ_SET_POWER(helper->mmc_pwrseq, true); break; } } diff --git a/sys/dev/mmc/mmc_fdt_helpers.h b/sys/dev/mmc/mmc_fdt_helpers.h index 8b14138d882d..f22ce65b10ea 100644 --- a/sys/dev/mmc/mmc_fdt_helpers.h +++ b/sys/dev/mmc/mmc_fdt_helpers.h @@ -1,49 +1,49 @@ /* * Copyright 2019 Emmanuel Vadot * Copyright (c) 2017 Ian Lepore All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ #ifndef _MMC_FDT_HELPERS_H_ #define _MMC_FDT_HELPERS_H_ #include #include -#include +#include #include #define mmc_fdt_helper mmc_helper /* For backwards compatibility */ typedef void (*mmc_fdt_cd_handler)(device_t dev, bool present); int mmc_fdt_parse(device_t dev, phandle_t node, struct mmc_helper *helper, struct mmc_host *host); int mmc_fdt_gpio_setup(device_t dev, phandle_t node, struct mmc_helper *helper, mmc_fdt_cd_handler handler); void mmc_fdt_gpio_teardown(struct mmc_helper *helper); bool mmc_fdt_gpio_get_present(struct mmc_helper *helper); bool mmc_fdt_gpio_get_readonly(struct mmc_helper *helper); void mmc_fdt_set_power(struct mmc_helper *helper, enum mmc_power_mode power_mode); #endif diff --git a/sys/dev/mmc/mmc_helpers.h b/sys/dev/mmc/mmc_helpers.h index 2788d1eb0ecc..db2ed0a3959a 100644 --- a/sys/dev/mmc/mmc_helpers.h +++ b/sys/dev/mmc/mmc_helpers.h @@ -1,66 +1,66 @@ /* * Copyright 2019 Emmanuel Vadot * Copyright (c) 2017 Ian Lepore All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ #ifndef _MMC_HELPERS_H_ #define _MMC_HELPERS_H_ #include -#include +#include struct mmc_helper { device_t dev; gpio_pin_t wp_pin; gpio_pin_t cd_pin; void * cd_ihandler; struct resource * cd_ires; int cd_irid; void (*cd_handler)(device_t, bool); struct timeout_task cd_delayed_task; bool cd_disabled; bool wp_disabled; bool cd_present; uint32_t props; #define MMC_PROP_BROKEN_CD (1 << 0) #define MMC_PROP_NON_REMOVABLE (1 << 1) #define MMC_PROP_WP_INVERTED (1 << 2) #define MMC_PROP_CD_INVERTED (1 << 3) #define MMC_PROP_DISABLE_WP (1 << 4) #define MMC_PROP_NO_SDIO (1 << 5) #define MMC_PROP_NO_SD (1 << 6) #define MMC_PROP_NO_MMC (1 << 7) regulator_t vmmc_supply; regulator_t vqmmc_supply; device_t mmc_pwrseq; }; int mmc_parse(device_t dev, struct mmc_helper *helper, struct mmc_host *host); #endif diff --git a/sys/dev/pwm/pwm_backlight.c b/sys/dev/pwm/pwm_backlight.c index 0a5cf4c34d6f..ce3c0a6e1bd9 100644 --- a/sys/dev/pwm/pwm_backlight.c +++ b/sys/dev/pwm/pwm_backlight.c @@ -1,304 +1,304 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2020 Emmanuel Vadot * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include "backlight_if.h" #include "pwmbus_if.h" struct pwm_backlight_softc { device_t pwmdev; struct cdev *cdev; pwm_channel_t channel; uint32_t *levels; ssize_t nlevels; int default_level; ssize_t current_level; regulator_t power_supply; uint64_t period; uint64_t duty; bool enabled; }; static int pwm_backlight_find_level_per_percent(struct pwm_backlight_softc *sc, int percent); static struct ofw_compat_data compat_data[] = { { "pwm-backlight", 1 }, { NULL, 0 } }; static int pwm_backlight_probe(device_t dev) { if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "PWM Backlight"); return (BUS_PROBE_DEFAULT); } static int pwm_backlight_attach(device_t dev) { struct pwm_backlight_softc *sc; phandle_t node; int rv; sc = device_get_softc(dev); node = ofw_bus_get_node(dev); rv = pwm_get_by_ofw_propidx(dev, node, "pwms", 0, &sc->channel); if (rv != 0) { device_printf(dev, "Cannot map pwm channel %d\n", rv); return (ENXIO); } if (regulator_get_by_ofw_property(dev, 0, "power-supply", &sc->power_supply) != 0) { device_printf(dev, "No power-supply property\n"); return (ENXIO); } if (OF_hasprop(node, "brightness-levels")) { sc->nlevels = OF_getencprop_alloc(node, "brightness-levels", (void **)&sc->levels); if (sc->nlevels <= 0) { device_printf(dev, "Cannot parse brightness levels\n"); return (ENXIO); } sc->nlevels /= sizeof(uint32_t); if (OF_getencprop(node, "default-brightness-level", &sc->default_level, sizeof(uint32_t)) <= 0) { device_printf(dev, "No default-brightness-level while brightness-levels is specified\n"); return (ENXIO); } else { if (sc->default_level > sc->nlevels) { device_printf(dev, "default-brightness-level isn't present in brightness-levels range\n"); return (ENXIO); } sc->channel->duty = sc->channel->period * sc->levels[sc->default_level] / 100; } if (bootverbose) { device_printf(dev, "Number of levels: %zd\n", sc->nlevels); device_printf(dev, "Configured period time: %ju\n", (uintmax_t)sc->channel->period); device_printf(dev, "Default duty cycle: %ju\n", (uintmax_t)sc->channel->duty); } } else { /* Get the current backlight level */ PWMBUS_CHANNEL_GET_CONFIG(sc->channel->dev, sc->channel->channel, (unsigned int *)&sc->channel->period, (unsigned int *)&sc->channel->duty); if (sc->channel->duty > sc->channel->period) sc->channel->duty = sc->channel->period; if (bootverbose) { device_printf(dev, "Configured period time: %ju\n", (uintmax_t)sc->channel->period); device_printf(dev, "Default duty cycle: %ju\n", (uintmax_t)sc->channel->duty); } } regulator_enable(sc->power_supply); sc->channel->enabled = true; PWMBUS_CHANNEL_CONFIG(sc->channel->dev, sc->channel->channel, sc->channel->period, sc->channel->duty); PWMBUS_CHANNEL_ENABLE(sc->channel->dev, sc->channel->channel, sc->channel->enabled); sc->current_level = pwm_backlight_find_level_per_percent(sc, sc->channel->period / sc->channel->duty); sc->cdev = backlight_register("pwm_backlight", dev); if (sc->cdev == NULL) device_printf(dev, "Cannot register as a backlight\n"); return (0); } static int pwm_backlight_detach(device_t dev) { struct pwm_backlight_softc *sc; sc = device_get_softc(dev); if (sc->nlevels > 0) OF_prop_free(sc->levels); regulator_disable(sc->power_supply); backlight_destroy(sc->cdev); return (0); } static int pwm_backlight_find_level_per_percent(struct pwm_backlight_softc *sc, int percent) { int i; int diff; if (percent < 0 || percent > 100) return (-1); for (i = 0, diff = 0; i < sc->nlevels; i++) { if (sc->levels[i] == percent) return (i); else if (sc->levels[i] < percent) diff = percent - sc->levels[i]; else { if (diff < abs((percent - sc->levels[i]))) return (i - 1); else return (i); } } return (-1); } static int pwm_backlight_update_status(device_t dev, struct backlight_props *props) { struct pwm_backlight_softc *sc; int reg_status; int error; sc = device_get_softc(dev); if (sc->nlevels != 0) { error = pwm_backlight_find_level_per_percent(sc, props->brightness); if (error < 0) return (ERANGE); sc->current_level = error; sc->channel->duty = sc->channel->period * sc->levels[sc->current_level] / 100; } else { if (props->brightness > 100 || props->brightness < 0) return (ERANGE); sc->channel->duty = sc->channel->period * props->brightness / 100; } sc->channel->enabled = true; PWMBUS_CHANNEL_CONFIG(sc->channel->dev, sc->channel->channel, sc->channel->period, sc->channel->duty); PWMBUS_CHANNEL_ENABLE(sc->channel->dev, sc->channel->channel, sc->channel->enabled); error = regulator_status(sc->power_supply, ®_status); if (error != 0) device_printf(dev, "Cannot get power-supply status: %d\n", error); else { if (props->brightness > 0) { if (reg_status != REGULATOR_STATUS_ENABLED) regulator_enable(sc->power_supply); } else { if (reg_status == REGULATOR_STATUS_ENABLED) regulator_disable(sc->power_supply); } } return (0); } static int pwm_backlight_get_status(device_t dev, struct backlight_props *props) { struct pwm_backlight_softc *sc; int i; sc = device_get_softc(dev); if (sc->nlevels != 0) { props->brightness = sc->levels[sc->current_level]; props->nlevels = sc->nlevels; for (i = 0; i < sc->nlevels; i++) props->levels[i] = sc->levels[i]; } else { props->brightness = sc->channel->duty * 100 / sc->channel->period; props->nlevels = 0; } return (0); } static int pwm_backlight_get_info(device_t dev, struct backlight_info *info) { info->type = BACKLIGHT_TYPE_PANEL; strlcpy(info->name, "pwm-backlight", BACKLIGHTMAXNAMELENGTH); return (0); } static device_method_t pwm_backlight_methods[] = { /* device_if */ DEVMETHOD(device_probe, pwm_backlight_probe), DEVMETHOD(device_attach, pwm_backlight_attach), DEVMETHOD(device_detach, pwm_backlight_detach), /* backlight interface */ DEVMETHOD(backlight_update_status, pwm_backlight_update_status), DEVMETHOD(backlight_get_status, pwm_backlight_get_status), DEVMETHOD(backlight_get_info, pwm_backlight_get_info), DEVMETHOD_END }; driver_t pwm_backlight_driver = { "pwm_backlight", pwm_backlight_methods, sizeof(struct pwm_backlight_softc), }; DRIVER_MODULE(pwm_backlight, simplebus, pwm_backlight_driver, 0, 0); MODULE_DEPEND(pwm_backlight, backlight, 1, 1, 1); OFWBUS_PNP_INFO(compat_data); diff --git a/sys/dev/extres/regulator/regdev_if.m b/sys/dev/regulator/regdev_if.m similarity index 100% rename from sys/dev/extres/regulator/regdev_if.m rename to sys/dev/regulator/regdev_if.m diff --git a/sys/dev/extres/regulator/regnode_if.m b/sys/dev/regulator/regnode_if.m similarity index 100% rename from sys/dev/extres/regulator/regnode_if.m rename to sys/dev/regulator/regnode_if.m diff --git a/sys/dev/extres/regulator/regulator.c b/sys/dev/regulator/regulator.c similarity index 99% rename from sys/dev/extres/regulator/regulator.c rename to sys/dev/regulator/regulator.c index 68e76f09a05e..6b49c6e93aae 100644 --- a/sys/dev/extres/regulator/regulator.c +++ b/sys/dev/regulator/regulator.c @@ -1,1325 +1,1325 @@ /*- * Copyright 2016 Michal Meloun * All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef FDT #include #include #include #endif -#include +#include #ifdef FDT #include "regdev_if.h" #endif SYSCTL_NODE(_hw, OID_AUTO, regulator, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Regulators"); MALLOC_DEFINE(M_REGULATOR, "regulator", "Regulator framework"); #define DIV_ROUND_UP(n,d) howmany(n, d) /* Forward declarations. */ struct regulator; struct regnode; typedef TAILQ_HEAD(regnode_list, regnode) regnode_list_t; typedef TAILQ_HEAD(regulator_list, regulator) regulator_list_t; /* Default regulator methods. */ static int regnode_method_init(struct regnode *regnode); static int regnode_method_enable(struct regnode *regnode, bool enable, int *udelay); static int regnode_method_status(struct regnode *regnode, int *status); static int regnode_method_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay); static int regnode_method_get_voltage(struct regnode *regnode, int *uvolt); static void regulator_constraint(void *dummy); static void regulator_shutdown(void *dummy); /* * Regulator controller methods. */ static regnode_method_t regnode_methods[] = { REGNODEMETHOD(regnode_init, regnode_method_init), REGNODEMETHOD(regnode_enable, regnode_method_enable), REGNODEMETHOD(regnode_status, regnode_method_status), REGNODEMETHOD(regnode_set_voltage, regnode_method_set_voltage), REGNODEMETHOD(regnode_get_voltage, regnode_method_get_voltage), REGNODEMETHOD(regnode_check_voltage, regnode_method_check_voltage), REGNODEMETHOD_END }; DEFINE_CLASS_0(regnode, regnode_class, regnode_methods, 0); /* * Regulator node - basic element for modelling SOC and bard power supply * chains. Its contains producer data. */ struct regnode { KOBJ_FIELDS; TAILQ_ENTRY(regnode) reglist_link; /* Global list entry */ regulator_list_t consumers_list; /* Consumers list */ /* Cache for already resolved names */ struct regnode *parent; /* Resolved parent */ /* Details of this device. */ const char *name; /* Globally unique name */ const char *parent_name; /* Parent name */ device_t pdev; /* Producer device_t */ void *softc; /* Producer softc */ intptr_t id; /* Per producer unique id */ #ifdef FDT phandle_t ofw_node; /* OFW node of regulator */ #endif int flags; /* REGULATOR_FLAGS_ */ struct sx lock; /* Lock for this regulator */ int ref_cnt; /* Reference counter */ int enable_cnt; /* Enabled counter */ struct regnode_std_param std_param; /* Standard parameters */ struct sysctl_ctx_list sysctl_ctx; }; /* * Per consumer data, information about how a consumer is using a regulator * node. * A pointer to this structure is used as a handle in the consumer interface. */ struct regulator { device_t cdev; /* Consumer device */ struct regnode *regnode; TAILQ_ENTRY(regulator) link; /* Consumers list entry */ int enable_cnt; int min_uvolt; /* Requested uvolt range */ int max_uvolt; }; /* * Regulator names must be system wide unique. */ static regnode_list_t regnode_list = TAILQ_HEAD_INITIALIZER(regnode_list); static struct sx regnode_topo_lock; SX_SYSINIT(regulator_topology, ®node_topo_lock, "Regulator topology lock"); #define REG_TOPO_SLOCK() sx_slock(®node_topo_lock) #define REG_TOPO_XLOCK() sx_xlock(®node_topo_lock) #define REG_TOPO_UNLOCK() sx_unlock(®node_topo_lock) #define REG_TOPO_ASSERT() sx_assert(®node_topo_lock, SA_LOCKED) #define REG_TOPO_XASSERT() sx_assert(®node_topo_lock, SA_XLOCKED) #define REGNODE_SLOCK(_sc) sx_slock(&((_sc)->lock)) #define REGNODE_XLOCK(_sc) sx_xlock(&((_sc)->lock)) #define REGNODE_UNLOCK(_sc) sx_unlock(&((_sc)->lock)) SYSINIT(regulator_constraint, SI_SUB_LAST, SI_ORDER_ANY, regulator_constraint, NULL); SYSINIT(regulator_shutdown, SI_SUB_LAST, SI_ORDER_ANY, regulator_shutdown, NULL); static void regulator_constraint(void *dummy) { struct regnode *entry; int rv; REG_TOPO_SLOCK(); TAILQ_FOREACH(entry, ®node_list, reglist_link) { rv = regnode_set_constraint(entry); if (rv != 0 && bootverbose) printf("regulator: setting constraint on %s failed (%d)\n", entry->name, rv); } REG_TOPO_UNLOCK(); } /* * Disable unused regulator * We run this function at SI_SUB_LAST which mean that every driver that needs * regulator should have already enable them. * All the remaining regulators should be those left enabled by the bootloader * or enable by default by the PMIC. */ static void regulator_shutdown(void *dummy) { struct regnode *entry; int status, ret; int disable = 1; TUNABLE_INT_FETCH("hw.regulator.disable_unused", &disable); if (!disable) return; REG_TOPO_SLOCK(); if (bootverbose) printf("regulator: shutting down unused regulators\n"); TAILQ_FOREACH(entry, ®node_list, reglist_link) { if (!entry->std_param.always_on) { ret = regnode_status(entry, &status); if (ret == 0 && status == REGULATOR_STATUS_ENABLED) { if (bootverbose) printf("regulator: shutting down %s... ", entry->name); ret = regnode_stop(entry, 0); if (bootverbose) { /* * Call out busy in particular, here, * because it's not unexpected to fail * shutdown if the regulator is simply * in-use. */ if (ret == EBUSY) printf("busy\n"); else if (ret != 0) printf("error (%d)\n", ret); else printf("ok\n"); } } } } REG_TOPO_UNLOCK(); } /* * sysctl handler */ static int regnode_uvolt_sysctl(SYSCTL_HANDLER_ARGS) { struct regnode *regnode = arg1; int rv, uvolt; if (regnode->std_param.min_uvolt == regnode->std_param.max_uvolt) { uvolt = regnode->std_param.min_uvolt; } else { REG_TOPO_SLOCK(); if ((rv = regnode_get_voltage(regnode, &uvolt)) != 0) { REG_TOPO_UNLOCK(); return (rv); } REG_TOPO_UNLOCK(); } return sysctl_handle_int(oidp, &uvolt, sizeof(uvolt), req); } /* ---------------------------------------------------------------------------- * * Default regulator methods for base class. * */ static int regnode_method_init(struct regnode *regnode) { return (0); } static int regnode_method_enable(struct regnode *regnode, bool enable, int *udelay) { if (!enable) return (ENXIO); *udelay = 0; return (0); } static int regnode_method_status(struct regnode *regnode, int *status) { *status = REGULATOR_STATUS_ENABLED; return (0); } static int regnode_method_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay) { if ((min_uvolt > regnode->std_param.max_uvolt) || (max_uvolt < regnode->std_param.min_uvolt)) return (ERANGE); *udelay = 0; return (0); } static int regnode_method_get_voltage(struct regnode *regnode, int *uvolt) { *uvolt = regnode->std_param.min_uvolt + (regnode->std_param.max_uvolt - regnode->std_param.min_uvolt) / 2; return (0); } int regnode_method_check_voltage(struct regnode *regnode, int uvolt) { if ((uvolt > regnode->std_param.max_uvolt) || (uvolt < regnode->std_param.min_uvolt)) return (ERANGE); return (0); } /* ---------------------------------------------------------------------------- * * Internal functions. * */ static struct regnode * regnode_find_by_name(const char *name) { struct regnode *entry; REG_TOPO_ASSERT(); TAILQ_FOREACH(entry, ®node_list, reglist_link) { if (strcmp(entry->name, name) == 0) return (entry); } return (NULL); } static struct regnode * regnode_find_by_id(device_t dev, intptr_t id) { struct regnode *entry; REG_TOPO_ASSERT(); TAILQ_FOREACH(entry, ®node_list, reglist_link) { if ((entry->pdev == dev) && (entry->id == id)) return (entry); } return (NULL); } /* * Create and initialize regulator object, but do not register it. */ struct regnode * regnode_create(device_t pdev, regnode_class_t regnode_class, struct regnode_init_def *def) { struct regnode *regnode; struct sysctl_oid *regnode_oid; KASSERT(def->name != NULL, ("regulator name is NULL")); KASSERT(def->name[0] != '\0', ("regulator name is empty")); REG_TOPO_SLOCK(); if (regnode_find_by_name(def->name) != NULL) panic("Duplicated regulator registration: %s\n", def->name); REG_TOPO_UNLOCK(); /* Create object and initialize it. */ regnode = malloc(sizeof(struct regnode), M_REGULATOR, M_WAITOK | M_ZERO); kobj_init((kobj_t)regnode, (kobj_class_t)regnode_class); sx_init(®node->lock, "Regulator node lock"); /* Allocate softc if required. */ if (regnode_class->size > 0) { regnode->softc = malloc(regnode_class->size, M_REGULATOR, M_WAITOK | M_ZERO); } /* Copy all strings unless they're flagged as static. */ if (def->flags & REGULATOR_FLAGS_STATIC) { regnode->name = def->name; regnode->parent_name = def->parent_name; } else { regnode->name = strdup(def->name, M_REGULATOR); if (def->parent_name != NULL) regnode->parent_name = strdup(def->parent_name, M_REGULATOR); } /* Rest of init. */ TAILQ_INIT(®node->consumers_list); regnode->id = def->id; regnode->pdev = pdev; regnode->flags = def->flags; regnode->parent = NULL; regnode->std_param = def->std_param; #ifdef FDT regnode->ofw_node = def->ofw_node; #endif sysctl_ctx_init(®node->sysctl_ctx); regnode_oid = SYSCTL_ADD_NODE(®node->sysctl_ctx, SYSCTL_STATIC_CHILDREN(_hw_regulator), OID_AUTO, regnode->name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "A regulator node"); SYSCTL_ADD_INT(®node->sysctl_ctx, SYSCTL_CHILDREN(regnode_oid), OID_AUTO, "min_uvolt", CTLFLAG_RD, ®node->std_param.min_uvolt, 0, "Minimal voltage (in uV)"); SYSCTL_ADD_INT(®node->sysctl_ctx, SYSCTL_CHILDREN(regnode_oid), OID_AUTO, "max_uvolt", CTLFLAG_RD, ®node->std_param.max_uvolt, 0, "Maximal voltage (in uV)"); SYSCTL_ADD_INT(®node->sysctl_ctx, SYSCTL_CHILDREN(regnode_oid), OID_AUTO, "min_uamp", CTLFLAG_RD, ®node->std_param.min_uamp, 0, "Minimal amperage (in uA)"); SYSCTL_ADD_INT(®node->sysctl_ctx, SYSCTL_CHILDREN(regnode_oid), OID_AUTO, "max_uamp", CTLFLAG_RD, ®node->std_param.max_uamp, 0, "Maximal amperage (in uA)"); SYSCTL_ADD_INT(®node->sysctl_ctx, SYSCTL_CHILDREN(regnode_oid), OID_AUTO, "ramp_delay", CTLFLAG_RD, ®node->std_param.ramp_delay, 0, "Ramp delay (in uV/us)"); SYSCTL_ADD_INT(®node->sysctl_ctx, SYSCTL_CHILDREN(regnode_oid), OID_AUTO, "enable_delay", CTLFLAG_RD, ®node->std_param.enable_delay, 0, "Enable delay (in us)"); SYSCTL_ADD_INT(®node->sysctl_ctx, SYSCTL_CHILDREN(regnode_oid), OID_AUTO, "enable_cnt", CTLFLAG_RD, ®node->enable_cnt, 0, "The regulator enable counter"); SYSCTL_ADD_U8(®node->sysctl_ctx, SYSCTL_CHILDREN(regnode_oid), OID_AUTO, "boot_on", CTLFLAG_RD, (uint8_t *) ®node->std_param.boot_on, 0, "Is enabled on boot"); SYSCTL_ADD_U8(®node->sysctl_ctx, SYSCTL_CHILDREN(regnode_oid), OID_AUTO, "always_on", CTLFLAG_RD, (uint8_t *)®node->std_param.always_on, 0, "Is always enabled"); SYSCTL_ADD_PROC(®node->sysctl_ctx, SYSCTL_CHILDREN(regnode_oid), OID_AUTO, "uvolt", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, regnode, 0, regnode_uvolt_sysctl, "I", "Current voltage (in uV)"); return (regnode); } /* Register regulator object. */ struct regnode * regnode_register(struct regnode *regnode) { int rv; #ifdef FDT if (regnode->ofw_node <= 0) regnode->ofw_node = ofw_bus_get_node(regnode->pdev); if (regnode->ofw_node <= 0) return (NULL); #endif rv = REGNODE_INIT(regnode); if (rv != 0) { printf("REGNODE_INIT failed: %d\n", rv); return (NULL); } REG_TOPO_XLOCK(); TAILQ_INSERT_TAIL(®node_list, regnode, reglist_link); REG_TOPO_UNLOCK(); #ifdef FDT OF_device_register_xref(OF_xref_from_node(regnode->ofw_node), regnode->pdev); #endif return (regnode); } static int regnode_resolve_parent(struct regnode *regnode) { /* All ready resolved or no parent? */ if ((regnode->parent != NULL) || (regnode->parent_name == NULL)) return (0); regnode->parent = regnode_find_by_name(regnode->parent_name); if (regnode->parent == NULL) return (ENODEV); return (0); } static void regnode_delay(int usec) { int ticks; if (usec == 0) return; ticks = (usec * hz + 999999) / 1000000; if (cold || ticks < 2) DELAY(usec); else pause("REGULATOR", ticks); } /* -------------------------------------------------------------------------- * * Regulator providers interface * */ const char * regnode_get_name(struct regnode *regnode) { return (regnode->name); } const char * regnode_get_parent_name(struct regnode *regnode) { return (regnode->parent_name); } int regnode_get_flags(struct regnode *regnode) { return (regnode->flags); } void * regnode_get_softc(struct regnode *regnode) { return (regnode->softc); } device_t regnode_get_device(struct regnode *regnode) { return (regnode->pdev); } struct regnode_std_param *regnode_get_stdparam(struct regnode *regnode) { return (®node->std_param); } void regnode_topo_unlock(void) { REG_TOPO_UNLOCK(); } void regnode_topo_xlock(void) { REG_TOPO_XLOCK(); } void regnode_topo_slock(void) { REG_TOPO_SLOCK(); } /* -------------------------------------------------------------------------- * * Real consumers executive * */ struct regnode * regnode_get_parent(struct regnode *regnode) { int rv; REG_TOPO_ASSERT(); rv = regnode_resolve_parent(regnode); if (rv != 0) return (NULL); return (regnode->parent); } /* * Enable regulator. */ int regnode_enable(struct regnode *regnode) { int udelay; int rv; REG_TOPO_ASSERT(); /* Enable regulator for each node in chain, starting from source. */ rv = regnode_resolve_parent(regnode); if (rv != 0) return (rv); if (regnode->parent != NULL) { rv = regnode_enable(regnode->parent); if (rv != 0) return (rv); } /* Handle this node. */ REGNODE_XLOCK(regnode); if (regnode->enable_cnt == 0) { rv = REGNODE_ENABLE(regnode, true, &udelay); if (rv != 0) { REGNODE_UNLOCK(regnode); return (rv); } regnode_delay(udelay); } regnode->enable_cnt++; REGNODE_UNLOCK(regnode); return (0); } /* * Disable regulator. */ int regnode_disable(struct regnode *regnode) { int udelay; int rv; REG_TOPO_ASSERT(); rv = 0; REGNODE_XLOCK(regnode); /* Disable regulator for each node in chain, starting from consumer. */ if (regnode->enable_cnt == 1 && (regnode->flags & REGULATOR_FLAGS_NOT_DISABLE) == 0 && !regnode->std_param.always_on) { rv = REGNODE_ENABLE(regnode, false, &udelay); if (rv != 0) { REGNODE_UNLOCK(regnode); return (rv); } regnode_delay(udelay); } regnode->enable_cnt--; REGNODE_UNLOCK(regnode); rv = regnode_resolve_parent(regnode); if (rv != 0) return (rv); if (regnode->parent != NULL) rv = regnode_disable(regnode->parent); return (rv); } /* * Stop regulator. */ int regnode_stop(struct regnode *regnode, int depth) { int udelay; int rv; REG_TOPO_ASSERT(); rv = 0; REGNODE_XLOCK(regnode); /* The first node must not be enabled. */ if ((regnode->enable_cnt != 0) && (depth == 0)) { REGNODE_UNLOCK(regnode); return (EBUSY); } /* Disable regulator for each node in chain, starting from consumer */ if ((regnode->enable_cnt == 0) && ((regnode->flags & REGULATOR_FLAGS_NOT_DISABLE) == 0)) { rv = REGNODE_STOP(regnode, &udelay); if (rv != 0) { REGNODE_UNLOCK(regnode); return (rv); } regnode_delay(udelay); } REGNODE_UNLOCK(regnode); rv = regnode_resolve_parent(regnode); if (rv != 0) return (rv); if (regnode->parent != NULL && regnode->parent->enable_cnt == 0) rv = regnode_stop(regnode->parent, depth + 1); return (rv); } /* * Get regulator status. (REGULATOR_STATUS_*) */ int regnode_status(struct regnode *regnode, int *status) { int rv; REG_TOPO_ASSERT(); REGNODE_XLOCK(regnode); rv = REGNODE_STATUS(regnode, status); REGNODE_UNLOCK(regnode); return (rv); } /* * Get actual regulator voltage. */ int regnode_get_voltage(struct regnode *regnode, int *uvolt) { int rv; REG_TOPO_ASSERT(); REGNODE_XLOCK(regnode); rv = REGNODE_GET_VOLTAGE(regnode, uvolt); REGNODE_UNLOCK(regnode); /* Pass call into parent, if regulator is in bypass mode. */ if (rv == ENOENT) { rv = regnode_resolve_parent(regnode); if (rv != 0) return (rv); if (regnode->parent != NULL) rv = regnode_get_voltage(regnode->parent, uvolt); } return (rv); } /* * Set regulator voltage. */ int regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt) { int udelay; int rv; REG_TOPO_ASSERT(); REGNODE_XLOCK(regnode); rv = REGNODE_SET_VOLTAGE(regnode, min_uvolt, max_uvolt, &udelay); if (rv == 0) regnode_delay(udelay); REGNODE_UNLOCK(regnode); return (rv); } /* * Consumer variant of regnode_set_voltage(). */ static int regnode_set_voltage_checked(struct regnode *regnode, struct regulator *reg, int min_uvolt, int max_uvolt) { int udelay; int all_max_uvolt; int all_min_uvolt; struct regulator *tmp; int rv; REG_TOPO_ASSERT(); REGNODE_XLOCK(regnode); /* Return error if requested range is outside of regulator range. */ if ((min_uvolt > regnode->std_param.max_uvolt) || (max_uvolt < regnode->std_param.min_uvolt)) { REGNODE_UNLOCK(regnode); return (ERANGE); } /* Get actual voltage range for all consumers. */ all_min_uvolt = regnode->std_param.min_uvolt; all_max_uvolt = regnode->std_param.max_uvolt; TAILQ_FOREACH(tmp, ®node->consumers_list, link) { /* Don't take requestor in account. */ if (tmp == reg) continue; if (all_min_uvolt < tmp->min_uvolt) all_min_uvolt = tmp->min_uvolt; if (all_max_uvolt > tmp->max_uvolt) all_max_uvolt = tmp->max_uvolt; } /* Test if request fits to actual contract. */ if ((min_uvolt > all_max_uvolt) || (max_uvolt < all_min_uvolt)) { REGNODE_UNLOCK(regnode); return (ERANGE); } /* Adjust new range.*/ if (min_uvolt < all_min_uvolt) min_uvolt = all_min_uvolt; if (max_uvolt > all_max_uvolt) max_uvolt = all_max_uvolt; rv = REGNODE_SET_VOLTAGE(regnode, min_uvolt, max_uvolt, &udelay); regnode_delay(udelay); REGNODE_UNLOCK(regnode); return (rv); } int regnode_set_constraint(struct regnode *regnode) { int status, rv, uvolt; if (regnode->std_param.boot_on != true && regnode->std_param.always_on != true) return (0); rv = regnode_status(regnode, &status); if (rv != 0) { if (bootverbose) printf("Cannot get regulator status for %s\n", regnode_get_name(regnode)); return (rv); } if (status == REGULATOR_STATUS_ENABLED) return (0); rv = regnode_get_voltage(regnode, &uvolt); if (rv != 0) { if (bootverbose) printf("Cannot get regulator voltage for %s\n", regnode_get_name(regnode)); return (rv); } if (uvolt < regnode->std_param.min_uvolt || uvolt > regnode->std_param.max_uvolt) { if (bootverbose) printf("Regulator %s current voltage %d is not in the" " acceptable range : %d<->%d\n", regnode_get_name(regnode), uvolt, regnode->std_param.min_uvolt, regnode->std_param.max_uvolt); return (ERANGE); } rv = regnode_enable(regnode); if (rv != 0) { if (bootverbose) printf("Cannot enable regulator %s\n", regnode_get_name(regnode)); return (rv); } return (0); } #ifdef FDT phandle_t regnode_get_ofw_node(struct regnode *regnode) { return (regnode->ofw_node); } #endif /* -------------------------------------------------------------------------- * * Regulator consumers interface. * */ /* Helper function for regulator_get*() */ static regulator_t regulator_create(struct regnode *regnode, device_t cdev) { struct regulator *reg; REG_TOPO_ASSERT(); reg = malloc(sizeof(struct regulator), M_REGULATOR, M_WAITOK | M_ZERO); reg->cdev = cdev; reg->regnode = regnode; reg->enable_cnt = 0; REGNODE_XLOCK(regnode); regnode->ref_cnt++; TAILQ_INSERT_TAIL(®node->consumers_list, reg, link); reg ->min_uvolt = regnode->std_param.min_uvolt; reg ->max_uvolt = regnode->std_param.max_uvolt; REGNODE_UNLOCK(regnode); return (reg); } int regulator_enable(regulator_t reg) { int rv; struct regnode *regnode; regnode = reg->regnode; KASSERT(regnode->ref_cnt > 0, ("Attempt to access unreferenced regulator: %s\n", regnode->name)); REG_TOPO_SLOCK(); rv = regnode_enable(regnode); if (rv == 0) reg->enable_cnt++; REG_TOPO_UNLOCK(); return (rv); } int regulator_disable(regulator_t reg) { int rv; struct regnode *regnode; regnode = reg->regnode; KASSERT(regnode->ref_cnt > 0, ("Attempt to access unreferenced regulator: %s\n", regnode->name)); KASSERT(reg->enable_cnt > 0, ("Attempt to disable already disabled regulator: %s\n", regnode->name)); REG_TOPO_SLOCK(); rv = regnode_disable(regnode); if (rv == 0) reg->enable_cnt--; REG_TOPO_UNLOCK(); return (rv); } int regulator_stop(regulator_t reg) { int rv; struct regnode *regnode; regnode = reg->regnode; KASSERT(regnode->ref_cnt > 0, ("Attempt to access unreferenced regulator: %s\n", regnode->name)); KASSERT(reg->enable_cnt == 0, ("Attempt to stop already enabled regulator: %s\n", regnode->name)); REG_TOPO_SLOCK(); rv = regnode_stop(regnode, 0); REG_TOPO_UNLOCK(); return (rv); } int regulator_status(regulator_t reg, int *status) { int rv; struct regnode *regnode; regnode = reg->regnode; KASSERT(regnode->ref_cnt > 0, ("Attempt to access unreferenced regulator: %s\n", regnode->name)); if (reg->enable_cnt == 0) { *status = 0; return (0); } REG_TOPO_SLOCK(); rv = regnode_status(regnode, status); REG_TOPO_UNLOCK(); return (rv); } int regulator_get_voltage(regulator_t reg, int *uvolt) { int rv; struct regnode *regnode; regnode = reg->regnode; KASSERT(regnode->ref_cnt > 0, ("Attempt to access unreferenced regulator: %s\n", regnode->name)); REG_TOPO_SLOCK(); rv = regnode_get_voltage(regnode, uvolt); REG_TOPO_UNLOCK(); return (rv); } int regulator_set_voltage(regulator_t reg, int min_uvolt, int max_uvolt) { struct regnode *regnode; int rv; regnode = reg->regnode; KASSERT(regnode->ref_cnt > 0, ("Attempt to access unreferenced regulator: %s\n", regnode->name)); REG_TOPO_SLOCK(); rv = regnode_set_voltage_checked(regnode, reg, min_uvolt, max_uvolt); if (rv == 0) { reg->min_uvolt = min_uvolt; reg->max_uvolt = max_uvolt; } REG_TOPO_UNLOCK(); return (rv); } int regulator_check_voltage(regulator_t reg, int uvolt) { int rv; struct regnode *regnode; regnode = reg->regnode; KASSERT(regnode->ref_cnt > 0, ("Attempt to access unreferenced regulator: %s\n", regnode->name)); REG_TOPO_SLOCK(); rv = REGNODE_CHECK_VOLTAGE(regnode, uvolt); REG_TOPO_UNLOCK(); return (rv); } const char * regulator_get_name(regulator_t reg) { struct regnode *regnode; regnode = reg->regnode; KASSERT(regnode->ref_cnt > 0, ("Attempt to access unreferenced regulator: %s\n", regnode->name)); return (regnode->name); } int regulator_get_by_name(device_t cdev, const char *name, regulator_t *reg) { struct regnode *regnode; REG_TOPO_SLOCK(); regnode = regnode_find_by_name(name); if (regnode == NULL) { REG_TOPO_UNLOCK(); return (ENODEV); } *reg = regulator_create(regnode, cdev); REG_TOPO_UNLOCK(); return (0); } int regulator_get_by_id(device_t cdev, device_t pdev, intptr_t id, regulator_t *reg) { struct regnode *regnode; REG_TOPO_SLOCK(); regnode = regnode_find_by_id(pdev, id); if (regnode == NULL) { REG_TOPO_UNLOCK(); return (ENODEV); } *reg = regulator_create(regnode, cdev); REG_TOPO_UNLOCK(); return (0); } int regulator_release(regulator_t reg) { struct regnode *regnode; regnode = reg->regnode; KASSERT(regnode->ref_cnt > 0, ("Attempt to access unreferenced regulator: %s\n", regnode->name)); REG_TOPO_SLOCK(); while (reg->enable_cnt > 0) { regnode_disable(regnode); reg->enable_cnt--; } REGNODE_XLOCK(regnode); TAILQ_REMOVE(®node->consumers_list, reg, link); regnode->ref_cnt--; REGNODE_UNLOCK(regnode); REG_TOPO_UNLOCK(); free(reg, M_REGULATOR); return (0); } #ifdef FDT /* Default DT mapper. */ int regdev_default_ofw_map(device_t dev, phandle_t xref, int ncells, pcell_t *cells, intptr_t *id) { if (ncells == 0) *id = 1; else if (ncells == 1) *id = cells[0]; else return (ERANGE); return (0); } int regulator_parse_ofw_stdparam(device_t pdev, phandle_t node, struct regnode_init_def *def) { phandle_t supply_xref; struct regnode_std_param *par; int rv; par = &def->std_param; rv = OF_getprop_alloc(node, "regulator-name", (void **)&def->name); if (rv <= 0) { device_printf(pdev, "%s: Missing regulator name\n", __func__); return (ENXIO); } rv = OF_getencprop(node, "regulator-min-microvolt", &par->min_uvolt, sizeof(par->min_uvolt)); if (rv <= 0) par->min_uvolt = 0; rv = OF_getencprop(node, "regulator-max-microvolt", &par->max_uvolt, sizeof(par->max_uvolt)); if (rv <= 0) par->max_uvolt = 0; rv = OF_getencprop(node, "regulator-min-microamp", &par->min_uamp, sizeof(par->min_uamp)); if (rv <= 0) par->min_uamp = 0; rv = OF_getencprop(node, "regulator-max-microamp", &par->max_uamp, sizeof(par->max_uamp)); if (rv <= 0) par->max_uamp = 0; rv = OF_getencprop(node, "regulator-ramp-delay", &par->ramp_delay, sizeof(par->ramp_delay)); if (rv <= 0) par->ramp_delay = 0; rv = OF_getencprop(node, "regulator-enable-ramp-delay", &par->enable_delay, sizeof(par->enable_delay)); if (rv <= 0) par->enable_delay = 0; if (OF_hasprop(node, "regulator-boot-on")) par->boot_on = true; if (OF_hasprop(node, "regulator-always-on")) par->always_on = true; if (OF_hasprop(node, "enable-active-high")) par->enable_active_high = 1; rv = OF_getencprop(node, "vin-supply", &supply_xref, sizeof(supply_xref)); if (rv >= 0) { rv = OF_getprop_alloc(supply_xref, "regulator-name", (void **)&def->parent_name); if (rv <= 0) def->parent_name = NULL; } return (0); } int regulator_get_by_ofw_property(device_t cdev, phandle_t cnode, char *name, regulator_t *reg) { phandle_t *cells; device_t regdev; int ncells, rv; intptr_t id; *reg = NULL; if (cnode <= 0) cnode = ofw_bus_get_node(cdev); if (cnode <= 0) { device_printf(cdev, "%s called on not ofw based device\n", __func__); return (ENXIO); } cells = NULL; ncells = OF_getencprop_alloc_multi(cnode, name, sizeof(*cells), (void **)&cells); if (ncells <= 0) return (ENOENT); /* Translate xref to device */ regdev = OF_device_from_xref(cells[0]); if (regdev == NULL) { OF_prop_free(cells); return (ENODEV); } /* Map regulator to number */ rv = REGDEV_MAP(regdev, cells[0], ncells - 1, cells + 1, &id); OF_prop_free(cells); if (rv != 0) return (rv); return (regulator_get_by_id(cdev, regdev, id, reg)); } #endif /* -------------------------------------------------------------------------- * * Regulator utility functions. * */ /* Convert raw selector value to real voltage */ int regulator_range_sel8_to_volt(struct regulator_range *ranges, int nranges, uint8_t sel, int *volt) { struct regulator_range *range; int i; if (nranges == 0) panic("Voltage regulator have zero ranges\n"); for (i = 0; i < nranges ; i++) { range = ranges + i; if (!(sel >= range->min_sel && sel <= range->max_sel)) continue; sel -= range->min_sel; *volt = range->min_uvolt + sel * range->step_uvolt; return (0); } return (ERANGE); } int regulator_range_volt_to_sel8(struct regulator_range *ranges, int nranges, int min_uvolt, int max_uvolt, uint8_t *out_sel) { struct regulator_range *range; uint8_t sel; int uvolt; int rv, i; if (nranges == 0) panic("Voltage regulator have zero ranges\n"); for (i = 0; i < nranges; i++) { range = ranges + i; uvolt = range->min_uvolt + (range->max_sel - range->min_sel) * range->step_uvolt; if ((min_uvolt > uvolt) || (max_uvolt < range->min_uvolt)) continue; if (min_uvolt <= range->min_uvolt) min_uvolt = range->min_uvolt; /* if step == 0 -> fixed voltage range. */ if (range->step_uvolt == 0) sel = 0; else sel = DIV_ROUND_UP(min_uvolt - range->min_uvolt, range->step_uvolt); sel += range->min_sel; break; } if (i >= nranges) return (ERANGE); /* Verify new settings. */ rv = regulator_range_sel8_to_volt(ranges, nranges, sel, &uvolt); if (rv != 0) return (rv); if ((uvolt < min_uvolt) || (uvolt > max_uvolt)) return (ERANGE); *out_sel = sel; return (0); } diff --git a/sys/dev/extres/regulator/regulator.h b/sys/dev/regulator/regulator.h similarity index 98% rename from sys/dev/extres/regulator/regulator.h rename to sys/dev/regulator/regulator.h index 4ef07f9acf12..e11dec515019 100644 --- a/sys/dev/extres/regulator/regulator.h +++ b/sys/dev/regulator/regulator.h @@ -1,154 +1,155 @@ /*- * Copyright 2016 Michal Meloun * All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ -#ifndef _DEV_EXTRES_REGULATOR_H_ -#define _DEV_EXTRES_REGULATOR_H_ +#ifndef _DEV_REGULATOR_H_ +#define _DEV_REGULATOR_H_ + #include "opt_platform.h" #include #include #ifdef FDT #include #endif #include "regnode_if.h" SYSCTL_DECL(_hw_regulator); #define REGULATOR_FLAGS_STATIC 0x00000001 /* Static strings */ #define REGULATOR_FLAGS_NOT_DISABLE 0x00000002 /* Cannot be disabled */ #define REGULATOR_STATUS_ENABLED 0x00000001 #define REGULATOR_STATUS_OVERCURRENT 0x00000002 typedef struct regulator *regulator_t; /* Standard regulator parameters. */ struct regnode_std_param { int min_uvolt; /* In uV */ int max_uvolt; /* In uV */ int min_uamp; /* In uA */ int max_uamp; /* In uA */ int ramp_delay; /* In uV/usec */ int enable_delay; /* In usec */ bool boot_on; /* Is enabled on boot */ bool always_on; /* Must be enabled */ int enable_active_high; }; /* Initialization parameters. */ struct regnode_init_def { char *name; /* Regulator name */ char *parent_name; /* Name of parent regulator */ struct regnode_std_param std_param; /* Standard parameters */ intptr_t id; /* Regulator ID */ int flags; /* Flags */ #ifdef FDT phandle_t ofw_node; /* OFW node of regulator */ #endif }; struct regulator_range { int min_uvolt; int step_uvolt; uint8_t min_sel; uint8_t max_sel; }; #define REG_RANGE_INIT(_min_sel, _max_sel, _min_uvolt, _step_uvolt) { \ .min_sel = _min_sel, \ .max_sel = _max_sel, \ .min_uvolt = _min_uvolt, \ .step_uvolt = _step_uvolt, \ } /* * Shorthands for constructing method tables. */ #define REGNODEMETHOD KOBJMETHOD #define REGNODEMETHOD_END KOBJMETHOD_END #define regnode_method_t kobj_method_t #define regnode_class_t kobj_class_t DECLARE_CLASS(regnode_class); /* Providers interface. */ struct regnode *regnode_create(device_t pdev, regnode_class_t regnode_class, struct regnode_init_def *def); struct regnode *regnode_register(struct regnode *regnode); const char *regnode_get_name(struct regnode *regnode); const char *regnode_get_parent_name(struct regnode *regnode); struct regnode *regnode_get_parent(struct regnode *regnode); int regnode_get_flags(struct regnode *regnode); void *regnode_get_softc(struct regnode *regnode); device_t regnode_get_device(struct regnode *regnode); struct regnode_std_param *regnode_get_stdparam(struct regnode *regnode); void regnode_topo_unlock(void); void regnode_topo_xlock(void); void regnode_topo_slock(void); int regnode_enable(struct regnode *regnode); int regnode_disable(struct regnode *regnode); int regnode_stop(struct regnode *regnode, int depth); int regnode_status(struct regnode *regnode, int *status); int regnode_get_voltage(struct regnode *regnode, int *uvolt); int regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt); int regnode_set_constraint(struct regnode *regnode); /* Standard method that aren't default */ int regnode_method_check_voltage(struct regnode *regnode, int uvolt); #ifdef FDT phandle_t regnode_get_ofw_node(struct regnode *regnode); #endif /* Consumers interface. */ int regulator_get_by_name(device_t cdev, const char *name, regulator_t *regulator); int regulator_get_by_id(device_t cdev, device_t pdev, intptr_t id, regulator_t *regulator); int regulator_release(regulator_t regulator); const char *regulator_get_name(regulator_t regulator); int regulator_enable(regulator_t reg); int regulator_disable(regulator_t reg); int regulator_stop(regulator_t reg); int regulator_status(regulator_t reg, int *status); int regulator_get_voltage(regulator_t reg, int *uvolt); int regulator_set_voltage(regulator_t reg, int min_uvolt, int max_uvolt); int regulator_check_voltage(regulator_t reg, int uvolt); #ifdef FDT int regulator_get_by_ofw_property(device_t dev, phandle_t node, char *name, regulator_t *reg); int regulator_parse_ofw_stdparam(device_t dev, phandle_t node, struct regnode_init_def *def); #endif /* Utility functions */ int regulator_range_volt_to_sel8(struct regulator_range *ranges, int nranges, int min_uvolt, int max_uvolt, uint8_t *out_sel); int regulator_range_sel8_to_volt(struct regulator_range *ranges, int nranges, uint8_t sel, int *volt); -#endif /* _DEV_EXTRES_REGULATOR_H_ */ +#endif /* _DEV_REGULATOR_H_ */ diff --git a/sys/dev/extres/regulator/regulator_bus.c b/sys/dev/regulator/regulator_bus.c similarity index 100% rename from sys/dev/extres/regulator/regulator_bus.c rename to sys/dev/regulator/regulator_bus.c diff --git a/sys/dev/extres/regulator/regulator_fixed.c b/sys/dev/regulator/regulator_fixed.c similarity index 99% rename from sys/dev/extres/regulator/regulator_fixed.c rename to sys/dev/regulator/regulator_fixed.c index d39e83c93037..d9ebbe017e11 100644 --- a/sys/dev/extres/regulator/regulator_fixed.c +++ b/sys/dev/regulator/regulator_fixed.c @@ -1,515 +1,515 @@ /*- * Copyright 2016 Michal Meloun * All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ #include #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #ifdef FDT #include #include #include #endif #include -#include +#include #ifdef FDT #include "regdev_if.h" #endif MALLOC_DEFINE(M_FIXEDREGULATOR, "fixedregulator", "Fixed regulator"); /* GPIO list for shared pins. */ typedef TAILQ_HEAD(gpio_list, gpio_entry) gpio_list_t; struct gpio_entry { TAILQ_ENTRY(gpio_entry) link; struct gpiobus_pin gpio_pin; int use_cnt; int enable_cnt; bool always_on; }; static gpio_list_t gpio_list = TAILQ_HEAD_INITIALIZER(gpio_list); static struct mtx gpio_list_mtx; MTX_SYSINIT(gpio_list_lock, &gpio_list_mtx, "Regulator GPIO lock", MTX_DEF); struct regnode_fixed_sc { struct regnode_std_param *param; bool gpio_open_drain; struct gpio_entry *gpio_entry; }; static int regnode_fixed_init(struct regnode *regnode); static int regnode_fixed_enable(struct regnode *regnode, bool enable, int *udelay); static int regnode_fixed_status(struct regnode *regnode, int *status); static int regnode_fixed_stop(struct regnode *regnode, int *udelay); static int regnode_fixed_get_voltage(struct regnode *regnode, int *uvolt); static regnode_method_t regnode_fixed_methods[] = { /* Regulator interface */ REGNODEMETHOD(regnode_init, regnode_fixed_init), REGNODEMETHOD(regnode_enable, regnode_fixed_enable), REGNODEMETHOD(regnode_status, regnode_fixed_status), REGNODEMETHOD(regnode_stop, regnode_fixed_stop), REGNODEMETHOD(regnode_get_voltage, regnode_fixed_get_voltage), REGNODEMETHOD(regnode_check_voltage, regnode_method_check_voltage), REGNODEMETHOD_END }; DEFINE_CLASS_1(regnode_fixed, regnode_fixed_class, regnode_fixed_methods, sizeof(struct regnode_fixed_sc), regnode_class); /* * GPIO list functions. * Two or more regulators can share single GPIO pins, so we must track all * GPIOs in gpio_list. * The GPIO pin is registerd and reseved for first consumer, all others share * gpio_entry with it. */ static struct gpio_entry * regnode_get_gpio_entry(struct gpiobus_pin *gpio_pin) { struct gpio_entry *entry, *tmp; device_t busdev; int rv; busdev = GPIO_GET_BUS(gpio_pin->dev); if (busdev == NULL) return (NULL); entry = malloc(sizeof(struct gpio_entry), M_FIXEDREGULATOR, M_WAITOK | M_ZERO); mtx_lock(&gpio_list_mtx); TAILQ_FOREACH(tmp, &gpio_list, link) { if (tmp->gpio_pin.dev == gpio_pin->dev && tmp->gpio_pin.pin == gpio_pin->pin) { tmp->use_cnt++; mtx_unlock(&gpio_list_mtx); free(entry, M_FIXEDREGULATOR); return (tmp); } } /* Reserve pin. */ /* XXX Can we call gpiobus_acquire_pin() with gpio_list_mtx held? */ rv = gpiobus_acquire_pin(busdev, gpio_pin->pin); if (rv != 0) { mtx_unlock(&gpio_list_mtx); free(entry, M_FIXEDREGULATOR); return (NULL); } /* Everything is OK, build new entry and insert it to list. */ entry->gpio_pin = *gpio_pin; entry->use_cnt = 1; TAILQ_INSERT_TAIL(&gpio_list, entry, link); mtx_unlock(&gpio_list_mtx); return (entry); } /* * Regulator class implementation. */ static int regnode_fixed_init(struct regnode *regnode) { device_t dev; struct regnode_fixed_sc *sc; struct gpiobus_pin *pin; uint32_t flags; int rv; sc = regnode_get_softc(regnode); dev = regnode_get_device(regnode); sc->param = regnode_get_stdparam(regnode); if (sc->gpio_entry == NULL) return (0); pin = &sc->gpio_entry->gpio_pin; flags = GPIO_PIN_OUTPUT; if (sc->gpio_open_drain) flags |= GPIO_PIN_OPENDRAIN; if (sc->param->boot_on || sc->param->always_on) { rv = GPIO_PIN_SET(pin->dev, pin->pin, sc->param->enable_active_high); if (rv != 0) { device_printf(dev, "Cannot set GPIO pin: %d\n", pin->pin); return (rv); } } rv = GPIO_PIN_SETFLAGS(pin->dev, pin->pin, flags); if (rv != 0) { device_printf(dev, "Cannot configure GPIO pin: %d\n", pin->pin); return (rv); } return (0); } /* * Enable/disable regulator. * Take shared GPIO pins in account */ static int regnode_fixed_enable(struct regnode *regnode, bool enable, int *udelay) { device_t dev; struct regnode_fixed_sc *sc; struct gpiobus_pin *pin; int rv; sc = regnode_get_softc(regnode); dev = regnode_get_device(regnode); *udelay = 0; if (sc->gpio_entry == NULL) return (0); pin = &sc->gpio_entry->gpio_pin; if (enable) { sc->gpio_entry->enable_cnt++; if (sc->gpio_entry->enable_cnt > 1) return (0); } else { KASSERT(sc->gpio_entry->enable_cnt > 0, ("Invalid enable count")); sc->gpio_entry->enable_cnt--; if (sc->gpio_entry->enable_cnt >= 1) return (0); } if (sc->gpio_entry->always_on && !enable) return (0); if (!sc->param->enable_active_high) enable = !enable; rv = GPIO_PIN_SET(pin->dev, pin->pin, enable); if (rv != 0) { device_printf(dev, "Cannot set GPIO pin: %d\n", pin->pin); return (rv); } *udelay = sc->param->enable_delay; return (0); } /* * Stop (physicaly shutdown) regulator. * Take shared GPIO pins in account */ static int regnode_fixed_stop(struct regnode *regnode, int *udelay) { device_t dev; struct regnode_fixed_sc *sc; struct gpiobus_pin *pin; int rv; sc = regnode_get_softc(regnode); dev = regnode_get_device(regnode); *udelay = 0; if (sc->gpio_entry == NULL) return (0); if (sc->gpio_entry->always_on) return (0); pin = &sc->gpio_entry->gpio_pin; if (sc->gpio_entry->enable_cnt > 0) { /* Other regulator(s) are enabled. */ /* XXXX Any diagnostic message? Or error? */ return (0); } rv = GPIO_PIN_SET(pin->dev, pin->pin, sc->param->enable_active_high ? false: true); if (rv != 0) { device_printf(dev, "Cannot set GPIO pin: %d\n", pin->pin); return (rv); } *udelay = sc->param->enable_delay; return (0); } static int regnode_fixed_status(struct regnode *regnode, int *status) { struct regnode_fixed_sc *sc; struct gpiobus_pin *pin; uint32_t val; int rv; sc = regnode_get_softc(regnode); *status = 0; if (sc->gpio_entry == NULL) { *status = REGULATOR_STATUS_ENABLED; return (0); } pin = &sc->gpio_entry->gpio_pin; rv = GPIO_PIN_GET(pin->dev, pin->pin, &val); if (rv == 0) { if (!sc->param->enable_active_high ^ (val != 0)) *status = REGULATOR_STATUS_ENABLED; } return (rv); } static int regnode_fixed_get_voltage(struct regnode *regnode, int *uvolt) { struct regnode_fixed_sc *sc; sc = regnode_get_softc(regnode); *uvolt = sc->param->min_uvolt; return (0); } int regnode_fixed_register(device_t dev, struct regnode_fixed_init_def *init_def) { struct regnode *regnode; struct regnode_fixed_sc *sc; regnode = regnode_create(dev, ®node_fixed_class, &init_def->reg_init_def); if (regnode == NULL) { device_printf(dev, "Cannot create regulator.\n"); return(ENXIO); } sc = regnode_get_softc(regnode); sc->gpio_open_drain = init_def->gpio_open_drain; if (init_def->gpio_pin != NULL) { sc->gpio_entry = regnode_get_gpio_entry(init_def->gpio_pin); if (sc->gpio_entry == NULL) return(ENXIO); } regnode = regnode_register(regnode); if (regnode == NULL) { device_printf(dev, "Cannot register regulator.\n"); return(ENXIO); } if (sc->gpio_entry != NULL) sc->gpio_entry->always_on |= sc->param->always_on; return (0); } /* * OFW Driver implementation. */ #ifdef FDT struct regfix_softc { device_t dev; bool attach_done; struct regnode_fixed_init_def init_def; phandle_t gpio_prodxref; pcell_t *gpio_cells; int gpio_ncells; struct gpiobus_pin gpio_pin; }; static struct ofw_compat_data compat_data[] = { {"regulator-fixed", 1}, {NULL, 0}, }; static int regfix_get_gpio(struct regfix_softc * sc) { device_t busdev; phandle_t node; int rv; if (sc->gpio_prodxref == 0) return (0); node = ofw_bus_get_node(sc->dev); /* Test if controller exist. */ sc->gpio_pin.dev = OF_device_from_xref(sc->gpio_prodxref); if (sc->gpio_pin.dev == NULL) return (ENODEV); /* Test if GPIO bus already exist. */ busdev = GPIO_GET_BUS(sc->gpio_pin.dev); if (busdev == NULL) return (ENODEV); rv = gpio_map_gpios(sc->gpio_pin.dev, node, OF_node_from_xref(sc->gpio_prodxref), sc->gpio_ncells, sc->gpio_cells, &(sc->gpio_pin.pin), &(sc->gpio_pin.flags)); if (rv != 0) { device_printf(sc->dev, "Cannot map the gpio property.\n"); return (ENXIO); } sc->init_def.gpio_pin = &sc->gpio_pin; return (0); } static int regfix_parse_fdt(struct regfix_softc * sc) { phandle_t node; int rv; struct regnode_init_def *init_def; node = ofw_bus_get_node(sc->dev); init_def = &sc->init_def.reg_init_def; rv = regulator_parse_ofw_stdparam(sc->dev, node, init_def); if (rv != 0) { device_printf(sc->dev, "Cannot parse standard parameters.\n"); return(rv); } if (init_def->std_param.min_uvolt != init_def->std_param.max_uvolt) { device_printf(sc->dev, "min_uvolt != max_uvolt\n"); return (ENXIO); } /* Fixed regulator uses 'startup-delay-us' property for enable_delay */ rv = OF_getencprop(node, "startup-delay-us", &init_def->std_param.enable_delay, sizeof(init_def->std_param.enable_delay)); if (rv <= 0) init_def->std_param.enable_delay = 0; /* GPIO pin */ if (OF_hasprop(node, "gpio-open-drain")) sc->init_def.gpio_open_drain = true; if (!OF_hasprop(node, "gpio")) return (0); rv = ofw_bus_parse_xref_list_alloc(node, "gpio", "#gpio-cells", 0, &sc->gpio_prodxref, &sc->gpio_ncells, &sc->gpio_cells); if (rv != 0) { sc->gpio_prodxref = 0; device_printf(sc->dev, "Malformed gpio property\n"); return (ENXIO); } return (0); } static void regfix_new_pass(device_t dev) { struct regfix_softc * sc; int rv; sc = device_get_softc(dev); bus_generic_new_pass(dev); if (sc->attach_done) return; /* Try to get and configure GPIO. */ rv = regfix_get_gpio(sc); if (rv != 0) return; /* Register regulator. */ regnode_fixed_register(sc->dev, &sc->init_def); sc->attach_done = true; } static int regfix_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "Fixed Regulator"); return (BUS_PROBE_DEFAULT); } static int regfix_detach(device_t dev) { /* This device is always present. */ return (EBUSY); } static int regfix_attach(device_t dev) { struct regfix_softc * sc; int rv; sc = device_get_softc(dev); sc->dev = dev; /* Parse FDT data. */ rv = regfix_parse_fdt(sc); if (rv != 0) return(ENXIO); /* Fill reset of init. */ sc->init_def.reg_init_def.id = 1; sc->init_def.reg_init_def.flags = REGULATOR_FLAGS_STATIC; /* Try to get and configure GPIO. */ rv = regfix_get_gpio(sc); if (rv != 0) return (bus_generic_attach(dev)); /* Register regulator. */ regnode_fixed_register(sc->dev, &sc->init_def); sc->attach_done = true; return (bus_generic_attach(dev)); } static device_method_t regfix_methods[] = { /* Device interface */ DEVMETHOD(device_probe, regfix_probe), DEVMETHOD(device_attach, regfix_attach), DEVMETHOD(device_detach, regfix_detach), /* Bus interface */ DEVMETHOD(bus_new_pass, regfix_new_pass), /* Regdev interface */ DEVMETHOD(regdev_map, regdev_default_ofw_map), DEVMETHOD_END }; DEFINE_CLASS_0(regfix, regfix_driver, regfix_methods, sizeof(struct regfix_softc)); EARLY_DRIVER_MODULE(regfix, simplebus, regfix_driver, 0, 0, BUS_PASS_BUS); #endif /* FDT */ diff --git a/sys/dev/extres/regulator/regulator_fixed.h b/sys/dev/regulator/regulator_fixed.h similarity index 90% rename from sys/dev/extres/regulator/regulator_fixed.h rename to sys/dev/regulator/regulator_fixed.h index 2d1abe01b9af..33213252d653 100644 --- a/sys/dev/extres/regulator/regulator_fixed.h +++ b/sys/dev/regulator/regulator_fixed.h @@ -1,42 +1,42 @@ /*- * Copyright 2016 Michal Meloun * All rights reserved. * * 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 AND CONTRIBUTORS ``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 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 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. */ -#ifndef _DEV_EXTRES_REGULATOR_FIXED_H_ -#define _DEV_EXTRES_REGULATOR_FIXED_H_ +#ifndef _DEV_REGULATOR_FIXED_H_ +#define _DEV_REGULATOR_FIXED_H_ #include -#include +#include struct regnode_fixed_init_def { struct regnode_init_def reg_init_def; bool gpio_open_drain; struct gpiobus_pin *gpio_pin; }; int regnode_fixed_register(device_t dev, struct regnode_fixed_init_def *init_def); -#endif /*_DEV_EXTRES_REGULATOR_FIXED_H_*/ +#endif /*_DEV_REGULATOR_FIXED_H_*/ diff --git a/sys/dev/sdhci/sdhci_xenon.c b/sys/dev/sdhci/sdhci_xenon.c index d8f66e655e50..4a823b896ca8 100644 --- a/sys/dev/sdhci/sdhci_xenon.c +++ b/sys/dev/sdhci/sdhci_xenon.c @@ -1,643 +1,643 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2018 Rubicon Communications, LLC (Netgate) * All rights reserved. * * 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. */ /* * Marvell Xenon SDHCI controller driver. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include "mmcbr_if.h" #include "sdhci_if.h" #include "opt_mmccam.h" #include "opt_soc.h" #define MAX_SLOTS 6 static uint8_t sdhci_xenon_read_1(device_t dev, struct sdhci_slot *slot __unused, bus_size_t off) { struct sdhci_xenon_softc *sc = device_get_softc(dev); return (bus_read_1(sc->mem_res, off)); } static void sdhci_xenon_write_1(device_t dev, struct sdhci_slot *slot __unused, bus_size_t off, uint8_t val) { struct sdhci_xenon_softc *sc = device_get_softc(dev); bus_write_1(sc->mem_res, off, val); } static uint16_t sdhci_xenon_read_2(device_t dev, struct sdhci_slot *slot __unused, bus_size_t off) { struct sdhci_xenon_softc *sc = device_get_softc(dev); return (bus_read_2(sc->mem_res, off)); } static void sdhci_xenon_write_2(device_t dev, struct sdhci_slot *slot __unused, bus_size_t off, uint16_t val) { struct sdhci_xenon_softc *sc = device_get_softc(dev); bus_write_2(sc->mem_res, off, val); } static uint32_t sdhci_xenon_read_4(device_t dev, struct sdhci_slot *slot __unused, bus_size_t off) { struct sdhci_xenon_softc *sc = device_get_softc(dev); return bus_read_4(sc->mem_res, off); } static void sdhci_xenon_write_4(device_t dev, struct sdhci_slot *slot __unused, bus_size_t off, uint32_t val) { struct sdhci_xenon_softc *sc = device_get_softc(dev); bus_write_4(sc->mem_res, off, val); } static void sdhci_xenon_read_multi_4(device_t dev, struct sdhci_slot *slot __unused, bus_size_t off, uint32_t *data, bus_size_t count) { struct sdhci_xenon_softc *sc = device_get_softc(dev); bus_read_multi_4(sc->mem_res, off, data, count); } static void sdhci_xenon_write_multi_4(device_t dev, struct sdhci_slot *slot __unused, bus_size_t off, uint32_t *data, bus_size_t count) { struct sdhci_xenon_softc *sc = device_get_softc(dev); bus_write_multi_4(sc->mem_res, off, data, count); } static void sdhci_xenon_intr(void *arg) { struct sdhci_xenon_softc *sc = (struct sdhci_xenon_softc *)arg; sdhci_generic_intr(sc->slot); } static int sdhci_xenon_get_ro(device_t bus, device_t dev) { struct sdhci_xenon_softc *sc = device_get_softc(bus); return (sdhci_generic_get_ro(bus, dev) ^ sc->wp_inverted); } static void sdhci_xenon_set_uhs_timing(device_t brdev, struct sdhci_slot *slot) { const struct mmc_ios *ios; uint16_t hostctrl2; if (slot->version < SDHCI_SPEC_300) return; mtx_assert(&slot->mtx, MA_OWNED); ios = &slot->host.ios; /* Update timing parameteres in SDHCI_HOST_CONTROL2 register. */ hostctrl2 = sdhci_xenon_read_2(brdev, slot, SDHCI_HOST_CONTROL2); hostctrl2 &= ~SDHCI_CTRL2_UHS_MASK; if (ios->clock > SD_SDR50_MAX) { if (ios->timing == bus_timing_mmc_hs400 || ios->timing == bus_timing_mmc_hs400es) hostctrl2 |= XENON_CTRL2_MMC_HS400; else if (ios->timing == bus_timing_mmc_hs200) hostctrl2 |= XENON_CTRL2_MMC_HS200; else hostctrl2 |= SDHCI_CTRL2_UHS_SDR104; } else if (ios->clock > SD_SDR25_MAX) hostctrl2 |= SDHCI_CTRL2_UHS_SDR50; else if (ios->clock > SD_SDR12_MAX) { if (ios->timing == bus_timing_uhs_ddr50 || ios->timing == bus_timing_mmc_ddr52) hostctrl2 |= SDHCI_CTRL2_UHS_DDR50; else hostctrl2 |= SDHCI_CTRL2_UHS_SDR25; } else if (ios->clock > SD_MMC_CARD_ID_FREQUENCY) hostctrl2 |= SDHCI_CTRL2_UHS_SDR12; sdhci_xenon_write_2(brdev, slot, SDHCI_HOST_CONTROL2, hostctrl2); } static int sdhci_xenon_phy_init(device_t brdev, struct mmc_ios *ios) { int i; struct sdhci_xenon_softc *sc; uint32_t reg; sc = device_get_softc(brdev); reg = bus_read_4(sc->mem_res, XENON_EMMC_PHY_TIMING_ADJUST); reg |= XENON_SAMPL_INV_QSP_PHASE_SELECT; switch (ios->timing) { case bus_timing_normal: case bus_timing_hs: case bus_timing_uhs_sdr12: case bus_timing_uhs_sdr25: case bus_timing_uhs_sdr50: reg |= XENON_TIMING_ADJUST_SLOW_MODE; break; default: reg &= ~XENON_TIMING_ADJUST_SLOW_MODE; } if (sc->slow_mode) reg |= XENON_TIMING_ADJUST_SLOW_MODE; bus_write_4(sc->mem_res, XENON_EMMC_PHY_TIMING_ADJUST, reg); reg = bus_read_4(sc->mem_res, XENON_EMMC_PHY_TIMING_ADJUST); reg |= XENON_PHY_INITIALIZATION; bus_write_4(sc->mem_res, XENON_EMMC_PHY_TIMING_ADJUST, reg); /* Wait for the eMMC PHY init. */ for (i = 100; i > 0; i--) { DELAY(100); reg = bus_read_4(sc->mem_res, XENON_EMMC_PHY_TIMING_ADJUST); if ((reg & XENON_PHY_INITIALIZATION) == 0) break; } if (i == 0) { device_printf(brdev, "eMMC PHY failed to initialize\n"); return (ETIMEDOUT); } return (0); } static int sdhci_xenon_phy_set(device_t brdev, struct mmc_ios *ios) { struct sdhci_xenon_softc *sc; uint32_t reg; sc = device_get_softc(brdev); /* Setup pad, set bit[28] and bits[26:24] */ reg = bus_read_4(sc->mem_res, XENON_EMMC_PHY_PAD_CONTROL); reg |= (XENON_FC_DQ_RECEN | XENON_FC_CMD_RECEN | XENON_FC_QSP_RECEN | XENON_OEN_QSN); /* All FC_XX_RECEIVCE should be set as CMOS Type */ reg |= XENON_FC_ALL_CMOS_RECEIVER; bus_write_4(sc->mem_res, XENON_EMMC_PHY_PAD_CONTROL, reg); /* Set CMD and DQ Pull Up */ reg = bus_read_4(sc->mem_res, XENON_EMMC_PHY_PAD_CONTROL1); reg |= (XENON_EMMC_FC_CMD_PU | XENON_EMMC_FC_DQ_PU); reg &= ~(XENON_EMMC_FC_CMD_PD | XENON_EMMC_FC_DQ_PD); bus_write_4(sc->mem_res, XENON_EMMC_PHY_PAD_CONTROL1, reg); if (ios->timing == bus_timing_normal) return (sdhci_xenon_phy_init(brdev, ios)); /* Clear SDIO mode, no SDIO support for now. */ reg = bus_read_4(sc->mem_res, XENON_EMMC_PHY_TIMING_ADJUST); reg &= ~XENON_TIMING_ADJUST_SDIO_MODE; bus_write_4(sc->mem_res, XENON_EMMC_PHY_TIMING_ADJUST, reg); /* * Set preferred ZNR and ZPR value. * The ZNR and ZPR value vary between different boards. * Define them both in the DTS for the board! */ reg = bus_read_4(sc->mem_res, XENON_EMMC_PHY_PAD_CONTROL2); reg &= ~((XENON_ZNR_MASK << XENON_ZNR_SHIFT) | XENON_ZPR_MASK); reg |= ((sc->znr << XENON_ZNR_SHIFT) | sc->zpr); bus_write_4(sc->mem_res, XENON_EMMC_PHY_PAD_CONTROL2, reg); /* Disable the SD clock to set EMMC_PHY_FUNC_CONTROL. */ reg = bus_read_4(sc->mem_res, SDHCI_CLOCK_CONTROL); reg &= ~SDHCI_CLOCK_CARD_EN; bus_write_4(sc->mem_res, SDHCI_CLOCK_CONTROL, reg); reg = bus_read_4(sc->mem_res, XENON_EMMC_PHY_FUNC_CONTROL); switch (ios->timing) { case bus_timing_mmc_hs400: reg |= (XENON_DQ_DDR_MODE_MASK << XENON_DQ_DDR_MODE_SHIFT) | XENON_CMD_DDR_MODE; reg &= ~XENON_DQ_ASYNC_MODE; break; case bus_timing_uhs_ddr50: case bus_timing_mmc_ddr52: reg |= (XENON_DQ_DDR_MODE_MASK << XENON_DQ_DDR_MODE_SHIFT) | XENON_CMD_DDR_MODE | XENON_DQ_ASYNC_MODE; break; default: reg &= ~((XENON_DQ_DDR_MODE_MASK << XENON_DQ_DDR_MODE_SHIFT) | XENON_CMD_DDR_MODE); reg |= XENON_DQ_ASYNC_MODE; } bus_write_4(sc->mem_res, XENON_EMMC_PHY_FUNC_CONTROL, reg); /* Enable SD clock. */ reg = bus_read_4(sc->mem_res, SDHCI_CLOCK_CONTROL); reg |= SDHCI_CLOCK_CARD_EN; bus_write_4(sc->mem_res, SDHCI_CLOCK_CONTROL, reg); if (ios->timing == bus_timing_mmc_hs400) bus_write_4(sc->mem_res, XENON_EMMC_PHY_LOGIC_TIMING_ADJUST, XENON_LOGIC_TIMING_VALUE); else { /* Disable both SDHC Data Strobe and Enhanced Strobe. */ reg = bus_read_4(sc->mem_res, XENON_SLOT_EMMC_CTRL); reg &= ~(XENON_ENABLE_DATA_STROBE | XENON_ENABLE_RESP_STROBE); bus_write_4(sc->mem_res, XENON_SLOT_EMMC_CTRL, reg); /* Clear Strobe line Pull down or Pull up. */ reg = bus_read_4(sc->mem_res, XENON_EMMC_PHY_PAD_CONTROL1); reg &= ~(XENON_EMMC_FC_QSP_PD | XENON_EMMC_FC_QSP_PU); bus_write_4(sc->mem_res, XENON_EMMC_PHY_PAD_CONTROL1, reg); } return (sdhci_xenon_phy_init(brdev, ios)); } static int sdhci_xenon_update_ios(device_t brdev, device_t reqdev) { int err; struct sdhci_xenon_softc *sc; struct mmc_ios *ios; struct sdhci_slot *slot; uint32_t reg; err = sdhci_generic_update_ios(brdev, reqdev); if (err != 0) return (err); sc = device_get_softc(brdev); slot = device_get_ivars(reqdev); ios = &slot->host.ios; switch (ios->power_mode) { case power_on: break; case power_off: if (bootverbose) device_printf(sc->dev, "Powering down sd/mmc\n"); if (sc->vmmc_supply) regulator_disable(sc->vmmc_supply); if (sc->vqmmc_supply) regulator_disable(sc->vqmmc_supply); break; case power_up: if (bootverbose) device_printf(sc->dev, "Powering up sd/mmc\n"); if (sc->vmmc_supply) regulator_enable(sc->vmmc_supply); if (sc->vqmmc_supply) regulator_enable(sc->vqmmc_supply); break; }; /* Update the PHY settings. */ if (ios->clock != 0) sdhci_xenon_phy_set(brdev, ios); if (ios->clock > SD_MMC_CARD_ID_FREQUENCY) { /* Enable SDCLK_IDLEOFF. */ reg = bus_read_4(sc->mem_res, XENON_SYS_OP_CTRL); reg |= 1 << (XENON_SDCLK_IDLEOFF_ENABLE_SHIFT + sc->slot_id); bus_write_4(sc->mem_res, XENON_SYS_OP_CTRL, reg); } return (0); } static int sdhci_xenon_switch_vccq(device_t brdev, device_t reqdev) { struct sdhci_xenon_softc *sc; struct sdhci_slot *slot; uint16_t hostctrl2; int uvolt, err; slot = device_get_ivars(reqdev); if (slot->version < SDHCI_SPEC_300) return (0); sc = device_get_softc(brdev); if (sc->vqmmc_supply == NULL && !sc->skip_regulators) return (EOPNOTSUPP); err = 0; hostctrl2 = bus_read_2(sc->mem_res, SDHCI_HOST_CONTROL2); switch (slot->host.ios.vccq) { case vccq_330: if (!(hostctrl2 & SDHCI_CTRL2_S18_ENABLE)) return (0); hostctrl2 &= ~SDHCI_CTRL2_S18_ENABLE; bus_write_2(sc->mem_res, SDHCI_HOST_CONTROL2, hostctrl2); if (!sc->skip_regulators) { uvolt = 3300000; err = regulator_set_voltage(sc->vqmmc_supply, uvolt, uvolt); if (err != 0) { device_printf(sc->dev, "Cannot set vqmmc to %d<->%d\n", uvolt, uvolt); return (err); } } /* * According to the 'SD Host Controller Simplified * Specification 4.20 the host driver should take more * than 5ms for stable time of host voltage regulator * from changing 1.8V Signaling Enable. */ DELAY(5000); hostctrl2 = bus_read_2(sc->mem_res, SDHCI_HOST_CONTROL2); if (!(hostctrl2 & SDHCI_CTRL2_S18_ENABLE)) return (0); return (EAGAIN); case vccq_180: if (!(slot->host.caps & MMC_CAP_SIGNALING_180)) { return (EINVAL); } if (hostctrl2 & SDHCI_CTRL2_S18_ENABLE) return (0); hostctrl2 |= SDHCI_CTRL2_S18_ENABLE; bus_write_2(sc->mem_res, SDHCI_HOST_CONTROL2, hostctrl2); if (!sc->skip_regulators) { uvolt = 1800000; err = regulator_set_voltage(sc->vqmmc_supply, uvolt, uvolt); if (err != 0) { device_printf(sc->dev, "Cannot set vqmmc to %d<->%d\n", uvolt, uvolt); return (err); } } /* * According to the 'SD Host Controller Simplified * Specification 4.20 the host driver should take more * than 5ms for stable time of host voltage regulator * from changing 1.8V Signaling Enable. */ DELAY(5000); hostctrl2 = bus_read_2(sc->mem_res, SDHCI_HOST_CONTROL2); if (hostctrl2 & SDHCI_CTRL2_S18_ENABLE) return (0); return (EAGAIN); default: device_printf(brdev, "Attempt to set unsupported signaling voltage\n"); return (EINVAL); } } static void sdhci_xenon_parse_prop(device_t dev) { struct sdhci_xenon_softc *sc; uint32_t val; sc = device_get_softc(dev); val = 0; if (device_get_property(dev, "quirks", &val, sizeof(val), DEVICE_PROP_UINT32) > 0) sc->slot->quirks = val; sc->znr = XENON_ZNR_DEF_VALUE; if (device_get_property(dev, "marvell,xenon-phy-znr", &val, sizeof(val), DEVICE_PROP_UINT32) > 0) sc->znr = val & XENON_ZNR_MASK; sc->zpr = XENON_ZPR_DEF_VALUE; if (device_get_property(dev, "marvell,xenon-phy-zpr", &val, sizeof(val), DEVICE_PROP_UINT32) > 0) sc->zpr = val & XENON_ZPR_MASK; if (device_has_property(dev, "marvell,xenon-phy-slow-mode")) sc->slow_mode = true; } int sdhci_xenon_attach(device_t dev) { struct sdhci_xenon_softc *sc = device_get_softc(dev); int err, rid; uint32_t reg; sc->dev = dev; sc->slot_id = 0; /* Allocate IRQ. */ rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->irq_res == NULL) { device_printf(dev, "Can't allocate IRQ\n"); return (ENOMEM); } /* Allocate memory. */ rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) { bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res), sc->irq_res); device_printf(dev, "Can't allocate memory for slot\n"); return (ENOMEM); } sdhci_xenon_parse_prop(dev); sc->slot->max_clk = XENON_MMC_MAX_CLK; if (sc->slot->host.f_max > 0) sc->slot->max_clk = sc->slot->host.f_max; if (sdhci_init_slot(dev, sc->slot, 0)) goto fail; /* 1.2V signaling is not supported. */ sc->slot->host.caps &= ~MMC_CAP_SIGNALING_120; /* Disable UHS in case of the PHY slow mode. */ if (sc->slow_mode) sc->slot->host.caps &= ~MMC_CAP_SIGNALING_180; /* Activate the interrupt */ err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, sdhci_xenon_intr, sc, &sc->intrhand); if (err) { device_printf(dev, "Cannot setup IRQ\n"); goto fail; } /* Disable Auto Clock Gating. */ reg = bus_read_4(sc->mem_res, XENON_SYS_OP_CTRL); reg |= XENON_AUTO_CLKGATE_DISABLE; bus_write_4(sc->mem_res, XENON_SYS_OP_CTRL, reg); /* Enable this SD controller. */ reg |= (1 << sc->slot_id); bus_write_4(sc->mem_res, XENON_SYS_OP_CTRL, reg); /* Enable Parallel Transfer. */ reg = bus_read_4(sc->mem_res, XENON_SYS_EXT_OP_CTRL); reg |= (1 << sc->slot_id); bus_write_4(sc->mem_res, XENON_SYS_EXT_OP_CTRL, reg); /* Enable Auto Clock Gating. */ reg &= ~XENON_AUTO_CLKGATE_DISABLE; bus_write_4(sc->mem_res, XENON_SYS_OP_CTRL, reg); /* Disable SDCLK_IDLEOFF before the card initialization. */ reg = bus_read_4(sc->mem_res, XENON_SYS_OP_CTRL); reg &= ~(1 << (XENON_SDCLK_IDLEOFF_ENABLE_SHIFT + sc->slot_id)); bus_write_4(sc->mem_res, XENON_SYS_OP_CTRL, reg); /* Mask command conflict errors. */ reg = bus_read_4(sc->mem_res, XENON_SYS_EXT_OP_CTRL); reg |= XENON_MASK_CMD_CONFLICT_ERR; bus_write_4(sc->mem_res, XENON_SYS_EXT_OP_CTRL, reg); /* Process cards detection. */ sdhci_start_slot(sc->slot); return (0); fail: bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res), sc->irq_res); bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem_res), sc->mem_res); free(sc->slot, M_DEVBUF); sc->slot = NULL; return (ENXIO); } int sdhci_xenon_detach(device_t dev) { struct sdhci_xenon_softc *sc = device_get_softc(dev); bus_generic_detach(dev); bus_teardown_intr(dev, sc->irq_res, sc->intrhand); bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res), sc->irq_res); sdhci_cleanup_slot(sc->slot); bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem_res), sc->mem_res); free(sc->slot, M_DEVBUF); sc->slot = NULL; return (0); } static device_method_t sdhci_xenon_methods[] = { /* Bus interface */ DEVMETHOD(bus_read_ivar, sdhci_generic_read_ivar), DEVMETHOD(bus_write_ivar, sdhci_generic_write_ivar), /* mmcbr_if */ DEVMETHOD(mmcbr_update_ios, sdhci_xenon_update_ios), DEVMETHOD(mmcbr_request, sdhci_generic_request), DEVMETHOD(mmcbr_get_ro, sdhci_xenon_get_ro), DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host), DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host), DEVMETHOD(mmcbr_switch_vccq, sdhci_xenon_switch_vccq), DEVMETHOD(mmcbr_tune, sdhci_generic_tune), DEVMETHOD(mmcbr_retune, sdhci_generic_retune), /* SDHCI registers accessors */ DEVMETHOD(sdhci_read_1, sdhci_xenon_read_1), DEVMETHOD(sdhci_read_2, sdhci_xenon_read_2), DEVMETHOD(sdhci_read_4, sdhci_xenon_read_4), DEVMETHOD(sdhci_read_multi_4, sdhci_xenon_read_multi_4), DEVMETHOD(sdhci_write_1, sdhci_xenon_write_1), DEVMETHOD(sdhci_write_2, sdhci_xenon_write_2), DEVMETHOD(sdhci_write_4, sdhci_xenon_write_4), DEVMETHOD(sdhci_write_multi_4, sdhci_xenon_write_multi_4), DEVMETHOD(sdhci_set_uhs_timing, sdhci_xenon_set_uhs_timing), DEVMETHOD_END }; DEFINE_CLASS_0(sdhci_xenon, sdhci_xenon_driver, sdhci_xenon_methods, sizeof(struct sdhci_xenon_softc)); SDHCI_DEPEND(sdhci_xenon); #ifndef MMCCAM MMC_DECLARE_BRIDGE(sdhci_xenon); #endif diff --git a/sys/dev/sdhci/sdhci_xenon_acpi.c b/sys/dev/sdhci/sdhci_xenon_acpi.c index c792e3cf2e48..01b6c14dc5f2 100644 --- a/sys/dev/sdhci/sdhci_xenon_acpi.c +++ b/sys/dev/sdhci/sdhci_xenon_acpi.c @@ -1,131 +1,131 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2021 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 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. */ #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include "mmcbr_if.h" #include "sdhci_if.h" #include "opt_mmccam.h" #include "opt_soc.h" static char *sdhci_xenon_hids[] = { "MRVL0002", "MRVL0003", "MRVL0004", NULL }; static int sdhci_xenon_acpi_probe(device_t dev) { device_t bus; int err; bus = device_get_parent(dev); err = ACPI_ID_PROBE(bus, dev, sdhci_xenon_hids, NULL); if (err <= 0) { device_set_desc(dev, "Armada Xenon SDHCI controller"); return (err); } return (ENXIO); } static int sdhci_xenon_acpi_attach(device_t dev) { struct sdhci_xenon_softc *sc; struct sdhci_slot *slot; struct mmc_helper mmc_helper; sc = device_get_softc(dev); memset(&mmc_helper, 0, sizeof(mmc_helper)); slot = malloc(sizeof(*slot), M_DEVBUF, M_ZERO | M_WAITOK); if (!slot) return (ENOMEM); /* * Don't use regularators. * In ACPI mode the firmware takes care of them for us */ sc->skip_regulators = true; sc->slot = slot; if (mmc_parse(dev, &mmc_helper, &slot->host) != 0) return (ENXIO); if (mmc_helper.props & MMC_PROP_NON_REMOVABLE) { slot->opt |= SDHCI_NON_REMOVABLE; if (bootverbose) device_printf(dev, "Non-removable media\n"); } sc->wp_inverted = mmc_helper.props & MMC_PROP_WP_INVERTED; return (sdhci_xenon_attach(dev)); } static device_method_t sdhci_xenon_acpi_methods[] = { /* device_if */ DEVMETHOD(device_probe, sdhci_xenon_acpi_probe), DEVMETHOD(device_attach, sdhci_xenon_acpi_attach), DEVMETHOD(device_detach, sdhci_xenon_detach), DEVMETHOD(sdhci_get_card_present, sdhci_generic_get_card_present), DEVMETHOD_END }; DEFINE_CLASS_1(sdhci_xenon, sdhci_xenon_acpi_driver, sdhci_xenon_acpi_methods, sizeof(struct sdhci_xenon_softc), sdhci_xenon_driver); DRIVER_MODULE(sdhci_xenon, acpi, sdhci_xenon_acpi_driver, NULL, NULL); #ifndef MMCCAM MMC_DECLARE_BRIDGE(sdhci_xenon_acpi); #endif diff --git a/sys/dev/sound/fdt/simple_amplifier.c b/sys/dev/sound/fdt/simple_amplifier.c index 45505be4d3e3..c6379dd08450 100644 --- a/sys/dev/sound/fdt/simple_amplifier.c +++ b/sys/dev/sound/fdt/simple_amplifier.c @@ -1,199 +1,199 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2020 Oleksandr Tymoshenko * * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include "opt_snd.h" #include #include #include "audio_dai_if.h" static struct ofw_compat_data compat_data[] = { { "simple-audio-amplifier", 1}, { NULL, 0} }; struct simple_amp_softc { device_t dev; regulator_t supply_vcc; gpio_pin_t gpio_enable; bool gpio_is_valid; }; static int simple_amp_probe(device_t dev); static int simple_amp_attach(device_t dev); static int simple_amp_detach(device_t dev); static int simple_amp_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "Simple Amplifier"); return (BUS_PROBE_DEFAULT); } static int simple_amp_attach(device_t dev) { struct simple_amp_softc *sc; phandle_t node; int error; sc = device_get_softc(dev); sc->dev = dev; node = ofw_bus_get_node(dev); error = gpio_pin_get_by_ofw_property(dev, node, "enable-gpios", &sc->gpio_enable); if (error != 0) sc->gpio_is_valid = false; else sc->gpio_is_valid = true; error = regulator_get_by_ofw_property(dev, 0, "VCC-supply", &sc->supply_vcc); if (error != 0) device_printf(dev, "no VCC supply"); OF_device_register_xref(OF_xref_from_node(node), dev); return (0); } static int simple_amp_detach(device_t dev) { return (0); } static int simple_amp_dai_init(device_t dev, uint32_t format) { return (0); } static int simple_amp_dai_trigger(device_t dev, int go, int pcm_dir) { struct simple_amp_softc *sc; int error; if ((pcm_dir != PCMDIR_PLAY) && (pcm_dir != PCMDIR_REC)) return (EINVAL); sc = device_get_softc(dev); error = 0; switch (go) { case PCMTRIG_START: if (sc->supply_vcc != NULL) { error = regulator_enable(sc->supply_vcc); if (error != 0) { device_printf(sc->dev, "could not enable 'VCC' regulator\n"); break; } } if (sc->gpio_is_valid) { error = gpio_pin_set_active(sc->gpio_enable, 1); if (error != 0) { device_printf(sc->dev, "could not set 'gpio-enable' gpio\n"); break; } } break; case PCMTRIG_STOP: case PCMTRIG_ABORT: if (sc->gpio_is_valid) { error = gpio_pin_set_active(sc->gpio_enable, 0); if (error != 0) { device_printf(sc->dev, "could not clear 'gpio-enable' gpio\n"); break; } } if (sc->supply_vcc != NULL) { error = regulator_disable(sc->supply_vcc); if (error != 0) { device_printf(sc->dev, "could not disable 'VCC' regulator\n"); break; } } break; } return (error); } static device_method_t simple_amp_methods[] = { /* Device interface */ DEVMETHOD(device_probe, simple_amp_probe), DEVMETHOD(device_attach, simple_amp_attach), DEVMETHOD(device_detach, simple_amp_detach), DEVMETHOD(audio_dai_init, simple_amp_dai_init), DEVMETHOD(audio_dai_trigger, simple_amp_dai_trigger), DEVMETHOD_END }; static driver_t simple_amp_driver = { "simpleamp", simple_amp_methods, sizeof(struct simple_amp_softc), }; DRIVER_MODULE(simple_amp, simplebus, simple_amp_driver, 0, 0); SIMPLEBUS_PNP_INFO(compat_data); diff --git a/sys/dev/usb/controller/usb_nop_xceiv.c b/sys/dev/usb/controller/usb_nop_xceiv.c index 25fc13cb0020..e9503a35531a 100644 --- a/sys/dev/usb/controller/usb_nop_xceiv.c +++ b/sys/dev/usb/controller/usb_nop_xceiv.c @@ -1,206 +1,206 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2019 Rubicon Communications, LLC (Netgate) * * 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 AND CONTRIBUTORS ``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 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 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include "phynode_if.h" struct usb_nop_xceiv_softc { device_t dev; regulator_t vcc_supply; clk_t clk; uint32_t clk_freq; }; static struct ofw_compat_data compat_data[] = { {"usb-nop-xceiv", 1}, {NULL, 0} }; /* Phy class and methods. */ static int usb_nop_xceiv_phy_enable(struct phynode *phy, bool enable); static phynode_usb_method_t usb_nop_xceiv_phynode_methods[] = { PHYNODEMETHOD(phynode_enable, usb_nop_xceiv_phy_enable), PHYNODEMETHOD_END }; DEFINE_CLASS_1(usb_nop_xceiv_phynode, usb_nop_xceiv_phynode_class, usb_nop_xceiv_phynode_methods, sizeof(struct phynode_usb_sc), phynode_usb_class); static int usb_nop_xceiv_phy_enable(struct phynode *phynode, bool enable) { struct usb_nop_xceiv_softc *sc; device_t dev; intptr_t phy; int error; dev = phynode_get_device(phynode); phy = phynode_get_id(phynode); sc = device_get_softc(dev); if (phy != 0) return (ERANGE); /* Enable the phy clock */ if (sc->clk_freq != 0) { if (enable) { error = clk_set_freq(sc->clk, sc->clk_freq, CLK_SET_ROUND_ANY); if (error != 0) { device_printf(dev, "Cannot set clock to %dMhz\n", sc->clk_freq); goto fail; } error = clk_enable(sc->clk); } else error = clk_disable(sc->clk); if (error != 0) { device_printf(dev, "Cannot %sable the clock\n", enable ? "En" : "Dis"); goto fail; } } if (sc->vcc_supply) { if (enable) error = regulator_enable(sc->vcc_supply); else error = regulator_disable(sc->vcc_supply); if (error != 0) { device_printf(dev, "Cannot %sable the regulator\n", enable ? "En" : "Dis"); goto fail; } } return (0); fail: return (ENXIO); } static int usb_nop_xceiv_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "USB NOP PHY"); return (BUS_PROBE_DEFAULT); } static int usb_nop_xceiv_attach(device_t dev) { struct usb_nop_xceiv_softc *sc; struct phynode *phynode; struct phynode_init_def phy_init; phandle_t node; int error; sc = device_get_softc(dev); sc->dev = dev; node = ofw_bus_get_node(dev); /* Parse the optional properties */ OF_getencprop(node, "clock-frequency", &sc->clk_freq, sizeof(uint32_t)); error = clk_get_by_ofw_name(dev, node, "main_clk", &sc->clk); if (error != 0 && sc->clk_freq != 0) { device_printf(dev, "clock property is mandatory if clock-frequency is present\n"); return (ENXIO); } regulator_get_by_ofw_property(dev, node, "vcc-supply", &sc->vcc_supply); phy_init.id = 0; phy_init.ofw_node = node; phynode = phynode_create(dev, &usb_nop_xceiv_phynode_class, &phy_init); if (phynode == NULL) { device_printf(dev, "failed to create USB NOP PHY\n"); return (ENXIO); } if (phynode_register(phynode) == NULL) { device_printf(dev, "failed to create USB NOP PHY\n"); return (ENXIO); } OF_device_register_xref(OF_xref_from_node(node), dev); return (0); } static int usb_nop_xceiv_detach(device_t dev) { return (EBUSY); } static device_method_t usb_nop_xceiv_methods[] = { /* Device interface */ DEVMETHOD(device_probe, usb_nop_xceiv_probe), DEVMETHOD(device_attach, usb_nop_xceiv_attach), DEVMETHOD(device_detach, usb_nop_xceiv_detach), DEVMETHOD_END }; static driver_t usb_nop_xceiv_driver = { "usb_nop_xceiv", usb_nop_xceiv_methods, sizeof(struct usb_nop_xceiv_softc), }; EARLY_DRIVER_MODULE(usb_nop_xceiv, simplebus, usb_nop_xceiv_driver, 0, 0, BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE);