Index: sys/riscv/eswin/eswin_ahci.c =================================================================== --- /dev/null +++ sys/riscv/eswin/eswin_ahci.c @@ -0,0 +1,215 @@ +/*- + * Copyright (c) 2024 Ruslan Bukin + * + * This software was developed by the University of Cambridge Computer + * Laboratory (Department of Computer Science and Technology) under Innovate + * UK project 105694, "Digital Security by Design (DSbD) Technology Platform + * Prototype". + * + * 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 "opt_acpi.h" +#include "opt_platform.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include "syscon_if.h" + +#define SATA_REF_CTRL1 0x338 +#define SATA_PHY_CTRL0 0x328 +#define SATA_PHY_CTRL1 0x32c +#define SATA_LOS_IDEN 0x33c +#define SATA_AXI_LP_CTRL 0x308 +#define SATA_REG_CTRL 0x334 +#define SATA_MPLL_CTRL 0x320 +#define SATA_RESET_CTRL 0x340 +#define SATA_RESET_CTRL_ASSERT 0x3 +#define SATA_RESET_CTRL_DEASSERT 0x0 +#define SATA_PHY_RESET (1 << 0) +#define SATA_P0_RESET (1 << 1) +#define SATA_LOS_LEVEL 0x9 +#define SATA_LOS_BIAS (0x02 << 16) +#define SATA_REF_REPEATCLK_EN (1 << 0) +#define SATA_REF_USE_PAD (1 << 20) +#define SATA_P0_AMPLITUDE_GEN1 0x42 +#define SATA_P0_AMPLITUDE_GEN2 (0x46 << 8) +#define SATA_P0_AMPLITUDE_GEN3 (0x73 << 16) +#define SATA_P0_PHY_TX_PREEMPH_GEN1 0x05 +#define SATA_P0_PHY_TX_PREEMPH_GEN2 (0x05 << 8) +#define SATA_P0_PHY_TX_PREEMPH_GEN3 (0x23 << 16) +#define SATA_MPLL_MULTIPLIER (0x3c << 16) +#define SATA_M_CSYSREQ (1 << 0) +#define SATA_S_CSYSREQ (1 << 16) +#define HSPDME_RST_CTRL 0x41C +#define SW_HSP_SATA_ARSTN (1 << 27) +#define SW_SATA_RSTN (0xf << 9) + +static struct ofw_compat_data compat_data[] = { + {"snps,eswin-ahci", 1}, + {NULL, 0} +}; + +struct eswin_ahci_softc { + struct ahci_controller ctlr; /* Must be the first field. */ + device_t dev; + struct syscon *hsp; +}; + +static int +eswin_ahci_probe(device_t dev) +{ + struct ahci_controller *ctlr; + struct eswin_ahci_softc *sc; + phandle_t node; + + sc = device_get_softc(dev); + + ctlr = &sc->ctlr; + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) + return (ENXIO); + + device_set_desc(dev, "Eswin EIC7700 AHCI SATA controller"); + + node = ofw_bus_get_node(dev); + ctlr->dma_coherent = OF_hasprop(node, "dma-coherent"); + + return (BUS_PROBE_DEFAULT); +} + +static void +eswin_syscon_sata_init(struct eswin_ahci_softc *sc) +{ + + SYSCON_WRITE_4(sc->hsp, SATA_REF_CTRL1, 0x1); + SYSCON_WRITE_4(sc->hsp, SATA_PHY_CTRL0, + (SATA_P0_AMPLITUDE_GEN1 | + SATA_P0_AMPLITUDE_GEN2 | + SATA_P0_AMPLITUDE_GEN3)); + SYSCON_WRITE_4(sc->hsp, SATA_PHY_CTRL1, + (SATA_P0_PHY_TX_PREEMPH_GEN1 | + SATA_P0_PHY_TX_PREEMPH_GEN2 | + SATA_P0_PHY_TX_PREEMPH_GEN3)); + SYSCON_WRITE_4(sc->hsp, SATA_LOS_IDEN, SATA_LOS_LEVEL | SATA_LOS_BIAS); + SYSCON_WRITE_4(sc->hsp, SATA_AXI_LP_CTRL, + (SATA_M_CSYSREQ | SATA_S_CSYSREQ)); + SYSCON_WRITE_4(sc->hsp, SATA_REG_CTRL, + (SATA_REF_REPEATCLK_EN | SATA_REF_USE_PAD)); + SYSCON_WRITE_4(sc->hsp, SATA_MPLL_CTRL, SATA_MPLL_MULTIPLIER); + SYSCON_WRITE_4(sc->hsp, SATA_RESET_CTRL, 0x0); +} + +static int +eswin_ahci_attach(device_t dev) +{ + struct ahci_controller *ctlr; + struct eswin_ahci_softc *sc; + phandle_t node; + int error; + + sc = device_get_softc(dev); + + ctlr = &sc->ctlr; + 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); + + /* Setup controller defaults. */ + ctlr->numirqs = 1; + + node = ofw_bus_get_node(dev); + + if (syscon_get_by_ofw_property(dev, node, "eswin,hsp_sp_csr", + &sc->hsp)) { + device_printf(dev, "Can't get syscon handle.\n"); + return (ENXIO); + } + + eswin_syscon_sata_init(sc); + + /* Reset controller. */ + if ((error = ahci_ctlr_reset(dev)) == 0) + error = ahci_attach(dev); + + if (error != 0) { + if (ctlr->r_mem != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, + ctlr->r_mem); + } + + return (error); +} + +static int +eswin_ahci_detach(device_t dev) +{ + + return (ahci_detach(dev)); +} + +static device_method_t ahci_fdt_methods[] = { + DEVMETHOD(device_probe, eswin_ahci_probe), + DEVMETHOD(device_attach, eswin_ahci_attach), + DEVMETHOD(device_detach, eswin_ahci_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(bus_get_dma_tag, ahci_get_dma_tag), + DEVMETHOD_END +}; + +static driver_t ahci_fdt_driver = { + "ahci", + ahci_fdt_methods, + sizeof(struct eswin_ahci_softc) +}; + +DRIVER_MODULE(ahci_fdt, simplebus, ahci_fdt_driver, NULL, NULL);