Date: Fri, 7 Feb 2025 09:07:07 GMT From: Bojan =?utf-8?Q?Novkovi=C4=87?= <bnovkov@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: e17e33f997d6 - main - sdhci: Refactor the generic FDT driver Message-ID: <202502070907.517977xk067660@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by bnovkov: URL: https://cgit.FreeBSD.org/src/commit/?id=e17e33f997d63107e3a6859cfe3c19eba041b424 commit e17e33f997d63107e3a6859cfe3c19eba041b424 Author: Bojan Novković <bnovkov@FreeBSD.org> AuthorDate: 2025-01-18 19:02:51 +0000 Commit: Bojan Novković <bnovkov@FreeBSD.org> CommitDate: 2025-02-07 09:06:07 +0000 sdhci: Refactor the generic FDT driver This patch refactors the 'sdhci_fdt.c' driver by moving all vendor specific routines into separate files and making the base 'sdhci_fdt' driver subclassable. The goal is to make adding new FDT-based drivers easier and more maintainable. No functional change intended. Reviewed by: manu, imp Differential Revision: https://reviews.freebsd.org/D48527 --- sys/arm/rockchip/files.rk32xx | 1 + sys/arm64/conf/std.xilinx | 1 + sys/conf/files.arm64 | 3 + sys/dev/sdhci/sdhci_fdt.c | 273 +++++------------------------------ sys/dev/sdhci/sdhci_fdt.h | 66 +++++++++ sys/dev/sdhci/sdhci_fdt_rockchip.c | 283 +++++++++++++++++++++++++++++++++++++ sys/dev/sdhci/sdhci_fdt_xilinx.c | 115 +++++++++++++++ 7 files changed, 507 insertions(+), 235 deletions(-) diff --git a/sys/arm/rockchip/files.rk32xx b/sys/arm/rockchip/files.rk32xx index a9ca6cb1b5ae..7331b12a06ed 100644 --- a/sys/arm/rockchip/files.rk32xx +++ b/sys/arm/rockchip/files.rk32xx @@ -27,3 +27,4 @@ dev/iicbus/pmic/act8846_regulator.c standard dev/iicbus/pmic/fan53555.c standard dev/iicbus/rtc/hym8563.c standard dev/mmc/host/dwmmc_rockchip.c optional dwmmc +dev/sdhci/sdhci_fdt_rockchip.c optional sdhci diff --git a/sys/arm64/conf/std.xilinx b/sys/arm64/conf/std.xilinx index 50ebf5ade53b..2283616e8cdf 100644 --- a/sys/arm64/conf/std.xilinx +++ b/sys/arm64/conf/std.xilinx @@ -15,6 +15,7 @@ device cgem # Cadence GEM Gigabit Ethernet device # MMC/SD/SDIO Card slot support device sdhci +device sdhci_xilinx # IICBUS device cdnc_i2c diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 index 4b73ebd1e6db..43da6e757b1c 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -436,6 +436,9 @@ dev/sdhci/sdhci_xenon.c optional sdhci_xenon sdhci dev/sdhci/sdhci_xenon_acpi.c optional sdhci_xenon sdhci acpi dev/sdhci/sdhci_xenon_fdt.c optional sdhci_xenon sdhci fdt +dev/sdhci/sdhci_fdt_xilinx.c optional sdhci_xilinx sdhci fdt +dev/sdhci/sdhci_fdt_rockchip.c optional sdhci fdt soc_rockchip + dev/sram/mmio_sram.c optional fdt mmio_sram dev/sram/mmio_sram_if.m optional fdt mmio_sram diff --git a/sys/dev/sdhci/sdhci_fdt.c b/sys/dev/sdhci/sdhci_fdt.c index 1d8013ee7088..efc12b54e10f 100644 --- a/sys/dev/sdhci/sdhci_fdt.c +++ b/sys/dev/sdhci/sdhci_fdt.c @@ -47,106 +47,37 @@ #include <dev/fdt/fdt_common.h> #include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> -#include <dev/ofw/ofw_subr.h> #include <dev/clk/clk.h> #include <dev/clk/clk_fixed.h> +#include <dev/ofw/ofw_bus_subr.h> + +#include <dev/ofw/ofw_subr.h> +#include <dev/ofw/openfirm.h> #include <dev/syscon/syscon.h> #include <dev/phy/phy.h> #include <dev/mmc/bridge.h> #include <dev/sdhci/sdhci.h> +#include <dev/sdhci/sdhci_fdt.h> #include "mmcbr_if.h" #include "sdhci_if.h" #include "opt_mmccam.h" -#include "clkdev_if.h" -#include "syscon_if.h" - -#define MAX_SLOTS 6 #define SDHCI_FDT_ARMADA38X 1 #define SDHCI_FDT_XLNX_ZY7 2 #define SDHCI_FDT_QUALCOMM 3 -#define SDHCI_FDT_RK3399 4 -#define SDHCI_FDT_RK3568 5 -#define SDHCI_FDT_XLNX_ZMP 6 - -#define RK3399_GRF_EMMCCORE_CON0 0xf000 -#define RK3399_CORECFG_BASECLKFREQ 0xff00 -#define RK3399_CORECFG_TIMEOUTCLKUNIT (1 << 7) -#define RK3399_CORECFG_TUNINGCOUNT 0x3f -#define RK3399_GRF_EMMCCORE_CON11 0xf02c -#define RK3399_CORECFG_CLOCKMULTIPLIER 0xff - -#define RK3568_EMMC_HOST_CTRL 0x0508 -#define RK3568_EMMC_EMMC_CTRL 0x052c -#define RK3568_EMMC_ATCTRL 0x0540 -#define RK3568_EMMC_DLL_CTRL 0x0800 -#define DLL_CTRL_SRST 0x00000001 -#define DLL_CTRL_START 0x00000002 -#define DLL_CTRL_START_POINT_DEFAULT 0x00050000 -#define DLL_CTRL_INCREMENT_DEFAULT 0x00000200 - -#define RK3568_EMMC_DLL_RXCLK 0x0804 -#define DLL_RXCLK_DELAY_ENABLE 0x08000000 -#define DLL_RXCLK_NO_INV 0x20000000 - -#define RK3568_EMMC_DLL_TXCLK 0x0808 -#define DLL_TXCLK_DELAY_ENABLE 0x08000000 -#define DLL_TXCLK_TAPNUM_DEFAULT 0x00000008 -#define DLL_TXCLK_TAPNUM_FROM_SW 0x01000000 - -#define RK3568_EMMC_DLL_STRBIN 0x080c -#define DLL_STRBIN_DELAY_ENABLE 0x08000000 -#define DLL_STRBIN_TAPNUM_DEFAULT 0x00000008 -#define DLL_STRBIN_TAPNUM_FROM_SW 0x01000000 - -#define RK3568_EMMC_DLL_STATUS0 0x0840 -#define DLL_STATUS0_DLL_LOCK 0x00000100 -#define DLL_STATUS0_DLL_TIMEOUT 0x00000200 - -#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[] = { { "marvell,armada-380-sdhci", SDHCI_FDT_ARMADA38X }, { "qcom,sdhci-msm-v4", SDHCI_FDT_QUALCOMM }, - { "rockchip,rk3399-sdhci-5.1", SDHCI_FDT_RK3399 }, { "xlnx,zy7_sdhci", SDHCI_FDT_XLNX_ZY7 }, - { "rockchip,rk3568-dwcmshc", SDHCI_FDT_RK3568 }, - { "xlnx,zynqmp-8.9a", SDHCI_FDT_XLNX_ZMP }, { NULL, 0 } }; -struct sdhci_fdt_softc { - device_t dev; /* Controller device */ - u_int quirks; /* Chip specific quirks */ - u_int caps; /* If we override SDHCI_CAPABILITIES */ - uint32_t max_clk; /* Max possible freq */ - uint8_t sdma_boundary; /* If we override the SDMA boundary */ - struct resource *irq_res; /* IRQ resource */ - void *intrhand; /* Interrupt handle */ - - int num_slots; /* Number of slots on this controller*/ - struct sdhci_slot slots[MAX_SLOTS]; - struct resource *mem_res[MAX_SLOTS]; /* Memory resource */ - - bool wp_inverted; /* WP pin is inverted */ - bool wp_disabled; /* WP pin is not supported */ - bool no_18v; /* No 1.8V support */ - - clk_t clk_xin; /* xin24m fixed clock */ - clk_t clk_ahb; /* ahb clock */ - clk_t clk_core; /* core clock */ - phy_t phy; /* phy to be used */ - - struct syscon *syscon; /* Handle to the syscon */ -}; - struct sdhci_exported_clocks_sc { device_t clkdev; }; @@ -168,7 +99,7 @@ DEFINE_CLASS_1(sdhci_exported_clocks_clknode, sdhci_exported_clocks_clknode_clas sdhci_exported_clocks_clknode_methods, sizeof(struct sdhci_exported_clocks_sc), clknode_class); -static int +int sdhci_clock_ofw_map(struct clkdom *clkdom, uint32_t ncells, phandle_t *cells, struct clknode **clk) { @@ -183,7 +114,7 @@ sdhci_clock_ofw_map(struct clkdom *clkdom, uint32_t ncells, return (0); } -static void +void sdhci_export_clocks(struct sdhci_fdt_softc *sc) { struct clknode_init_def def; @@ -248,7 +179,7 @@ sdhci_export_clocks(struct sdhci_fdt_softc *sc) clkdom_dump(clkdom); } -static int +int sdhci_init_clocks(device_t dev) { struct sdhci_fdt_softc *sc = device_get_softc(dev); @@ -279,7 +210,7 @@ sdhci_init_clocks(device_t dev) return (0); } -static int +int sdhci_init_phy(struct sdhci_fdt_softc *sc) { int error; @@ -301,7 +232,7 @@ sdhci_init_phy(struct sdhci_fdt_softc *sc) return (0); } -static int +int sdhci_get_syscon(struct sdhci_fdt_softc *sc) { phandle_t node; @@ -318,34 +249,6 @@ sdhci_get_syscon(struct sdhci_fdt_softc *sc) return (0); } -static int -sdhci_init_rk3399(device_t dev) -{ - struct sdhci_fdt_softc *sc = device_get_softc(dev); - uint64_t freq; - uint32_t mask, val; - int error; - - error = clk_get_freq(sc->clk_xin, &freq); - if (error != 0) { - device_printf(dev, "cannot get xin clock frequency\n"); - return (ENXIO); - } - - /* Disable clock multiplier */ - mask = RK3399_CORECFG_CLOCKMULTIPLIER; - val = 0; - SYSCON_WRITE_4(sc->syscon, RK3399_GRF_EMMCCORE_CON11, (mask << 16) | val); - - /* Set base clock frequency */ - mask = RK3399_CORECFG_BASECLKFREQ; - val = SHIFTIN((freq + (1000000 / 2)) / 1000000, - RK3399_CORECFG_BASECLKFREQ); - SYSCON_WRITE_4(sc->syscon, RK3399_GRF_EMMCCORE_CON0, (mask << 16) | val); - - return (0); -} - static uint8_t sdhci_fdt_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off) { @@ -440,80 +343,15 @@ sdhci_fdt_get_ro(device_t bus, device_t dev) return (sdhci_generic_get_ro(bus, dev) ^ sc->wp_inverted); } -static int -sdhci_fdt_set_clock(device_t dev, struct sdhci_slot *slot, int clock) -{ - struct sdhci_fdt_softc *sc = device_get_softc(dev); - int32_t val; - int i; - - if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == - SDHCI_FDT_RK3568) { - if (clock == 400000) - clock = 375000; - - if (clock) { - clk_set_freq(sc->clk_core, clock, 0); - - if (clock <= 52000000) { - bus_write_4(sc->mem_res[slot->num], - RK3568_EMMC_DLL_CTRL, 0x0); - bus_write_4(sc->mem_res[slot->num], - RK3568_EMMC_DLL_RXCLK, DLL_RXCLK_NO_INV); - bus_write_4(sc->mem_res[slot->num], - RK3568_EMMC_DLL_TXCLK, 0x0); - bus_write_4(sc->mem_res[slot->num], - RK3568_EMMC_DLL_STRBIN, 0x0); - return (clock); - } - - bus_write_4(sc->mem_res[slot->num], - RK3568_EMMC_DLL_CTRL, DLL_CTRL_START); - DELAY(1000); - bus_write_4(sc->mem_res[slot->num], - RK3568_EMMC_DLL_CTRL, 0); - bus_write_4(sc->mem_res[slot->num], - RK3568_EMMC_DLL_CTRL, DLL_CTRL_START_POINT_DEFAULT | - DLL_CTRL_INCREMENT_DEFAULT | DLL_CTRL_START); - for (i = 0; i < 500; i++) { - val = bus_read_4(sc->mem_res[slot->num], - RK3568_EMMC_DLL_STATUS0); - if (val & DLL_STATUS0_DLL_LOCK && - !(val & DLL_STATUS0_DLL_TIMEOUT)) - break; - DELAY(1000); - } - bus_write_4(sc->mem_res[slot->num], RK3568_EMMC_ATCTRL, - (0x1 << 16 | 0x2 << 17 | 0x3 << 19)); - bus_write_4(sc->mem_res[slot->num], - RK3568_EMMC_DLL_RXCLK, - DLL_RXCLK_DELAY_ENABLE | DLL_RXCLK_NO_INV); - bus_write_4(sc->mem_res[slot->num], - RK3568_EMMC_DLL_TXCLK, DLL_TXCLK_DELAY_ENABLE | - DLL_TXCLK_TAPNUM_DEFAULT|DLL_TXCLK_TAPNUM_FROM_SW); - bus_write_4(sc->mem_res[slot->num], - RK3568_EMMC_DLL_STRBIN, DLL_STRBIN_DELAY_ENABLE | - DLL_STRBIN_TAPNUM_DEFAULT | - DLL_STRBIN_TAPNUM_FROM_SW); - } - } - return (clock); -} - static int sdhci_fdt_probe(device_t dev) { struct sdhci_fdt_softc *sc = device_get_softc(dev); - phandle_t node; - pcell_t cid; - - sc->quirks = 0; - sc->num_slots = 1; - sc->max_clk = 0; if (!ofw_bus_status_okay(dev)) return (ENXIO); + sc->quirks = 0; switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) { case SDHCI_FDT_ARMADA38X: sc->quirks = SDHCI_QUIRK_BROKEN_AUTO_STOP; @@ -525,25 +363,33 @@ sdhci_fdt_probe(device_t dev) sc->sdma_boundary = SDHCI_BLKSZ_SDMA_BNDRY_4K; device_set_desc(dev, "Qualcomm FDT SDHCI controller"); break; - case SDHCI_FDT_RK3399: - device_set_desc(dev, "Rockchip RK3399 fdt SDHCI controller"); - break; case SDHCI_FDT_XLNX_ZY7: sc->quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; device_set_desc(dev, "Zynq-7000 generic fdt SDHCI controller"); break; - case SDHCI_FDT_RK3568: - device_set_desc(dev, "Rockchip RK3568 fdt SDHCI controller"); - break; - case SDHCI_FDT_XLNX_ZMP: - device_set_desc(dev, "ZynqMP generic fdt SDHCI controller"); - break; default: return (ENXIO); } + return (0); +} + +int +sdhci_fdt_attach(device_t dev) +{ + struct sdhci_fdt_softc *sc = device_get_softc(dev); + struct sdhci_slot *slot; + int err, slots, rid, i; + phandle_t node; + pcell_t cid; + + sc->dev = dev; + node = ofw_bus_get_node(dev); + sc->num_slots = 1; + sc->max_clk = 0; + /* Allow dts to patch quirks, slots, and max-frequency. */ if ((OF_getencprop(node, "quirks", &cid, sizeof(cid))) > 0) sc->quirks = cid; @@ -558,18 +404,6 @@ sdhci_fdt_probe(device_t dev) if (OF_hasprop(node, "disable-wp")) sc->wp_disabled = true; - return (0); -} - -static int -sdhci_fdt_attach(device_t dev) -{ - struct sdhci_fdt_softc *sc = device_get_softc(dev); - struct sdhci_slot *slot; - int err, slots, rid, i, compat; - - sc->dev = dev; - /* Allocate IRQ. */ rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, @@ -579,44 +413,6 @@ sdhci_fdt_attach(device_t dev) return (ENOMEM); } - compat = ofw_bus_search_compatible(dev, compat_data)->ocd_data; - switch (compat) { - case SDHCI_FDT_RK3399: - case SDHCI_FDT_XLNX_ZMP: - err = sdhci_init_clocks(dev); - if (err != 0) { - device_printf(dev, "Cannot init clocks\n"); - return (err); - } - sdhci_export_clocks(sc); - if ((err = sdhci_init_phy(sc)) != 0) { - device_printf(dev, "Cannot init phy\n"); - return (err); - } - if ((err = sdhci_get_syscon(sc)) != 0) { - device_printf(dev, "Cannot get syscon handle\n"); - return (err); - } - if (compat == SDHCI_FDT_RK3399) { - err = sdhci_init_rk3399(dev); - if (err != 0) { - device_printf(dev, "Cannot init RK3399 SDHCI\n"); - return (err); - } - } - break; - case SDHCI_FDT_RK3568: - /* setup & enable clocks */ - if (clk_get_by_ofw_name(dev, 0, "core", &sc->clk_core)) { - device_printf(dev, "cannot get core clock\n"); - return (ENXIO); - } - clk_enable(sc->clk_core); - break; - default: - break; - } - /* Scan all slots. */ slots = sc->num_slots; /* number of slots determined in probe(). */ sc->num_slots = 0; @@ -640,7 +436,6 @@ sdhci_fdt_attach(device_t dev) if (sdhci_init_slot(dev, slot, i) != 0) continue; - sc->num_slots++; } device_printf(dev, "%d slot(s) allocated\n", sc->num_slots); @@ -660,7 +455,7 @@ sdhci_fdt_attach(device_t dev) return (0); } -static int +int sdhci_fdt_detach(device_t dev) { struct sdhci_fdt_softc *sc = device_get_softc(dev); @@ -680,6 +475,14 @@ sdhci_fdt_detach(device_t dev) return (0); } +int +sdhci_fdt_set_clock(device_t dev, struct sdhci_slot *slot, int clock) +{ + + return (clock); +} + + static device_method_t sdhci_fdt_methods[] = { /* device_if */ DEVMETHOD(device_probe, sdhci_fdt_probe), @@ -711,7 +514,7 @@ static device_method_t sdhci_fdt_methods[] = { DEVMETHOD_END }; -static driver_t sdhci_fdt_driver = { +driver_t sdhci_fdt_driver = { "sdhci_fdt", sdhci_fdt_methods, sizeof(struct sdhci_fdt_softc), diff --git a/sys/dev/sdhci/sdhci_fdt.h b/sys/dev/sdhci/sdhci_fdt.h new file mode 100644 index 000000000000..740fd375edd9 --- /dev/null +++ b/sys/dev/sdhci/sdhci_fdt.h @@ -0,0 +1,66 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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. + */ + + +#ifndef _SDHCI_FDT_H_ +#define _SDHCI_FDT_H_ + +#define SDHCI_FDT_MAX_SLOTS 6 + +struct sdhci_fdt_softc { + device_t dev; /* Controller device */ + u_int quirks; /* Chip specific quirks */ + u_int caps; /* If we override SDHCI_CAPABILITIES */ + uint32_t max_clk; /* Max possible freq */ + uint8_t sdma_boundary; /* If we override the SDMA boundary */ + struct resource *irq_res; /* IRQ resource */ + void *intrhand; /* Interrupt handle */ + + int num_slots; /* Number of slots on this controller*/ + struct sdhci_slot slots[SDHCI_FDT_MAX_SLOTS]; + struct resource *mem_res[SDHCI_FDT_MAX_SLOTS]; /* Memory resource */ + + bool wp_inverted; /* WP pin is inverted */ + bool wp_disabled; /* WP pin is not supported */ + bool no_18v; /* No 1.8V support */ + + clk_t clk_xin; /* xin24m fixed clock */ + clk_t clk_ahb; /* ahb clock */ + clk_t clk_core; /* core clock */ + phy_t phy; /* phy to be used */ + + struct syscon *syscon; /* Handle to the syscon */ +}; + +int sdhci_fdt_attach(device_t dev); +int sdhci_fdt_detach(device_t dev); +int sdhci_get_syscon(struct sdhci_fdt_softc *sc); +int sdhci_init_phy(struct sdhci_fdt_softc *sc); +void sdhci_export_clocks(struct sdhci_fdt_softc *sc); +int sdhci_clock_ofw_map(struct clkdom *clkdom, uint32_t ncells, + phandle_t *cells, struct clknode **clk); +int sdhci_init_clocks(device_t dev); +int sdhci_fdt_set_clock(device_t dev, struct sdhci_slot *slot, + int clock); +#endif diff --git a/sys/dev/sdhci/sdhci_fdt_rockchip.c b/sys/dev/sdhci/sdhci_fdt_rockchip.c new file mode 100644 index 000000000000..b3311d3e8a48 --- /dev/null +++ b/sys/dev/sdhci/sdhci_fdt_rockchip.c @@ -0,0 +1,283 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2019 Ganbold Tsagaankhuu <ganbold@freebsd.org> + * Copyright (c) 2022 Søren Schmidt <sos@FreeBSD.org> + * + * 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 <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/resource.h> +#include <sys/rman.h> +#include <sys/sysctl.h> +#include <sys/taskqueue.h> + +#include <machine/bus.h> +#include <machine/resource.h> + +#include <dev/fdt/fdt_common.h> +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> + +#include <dev/ofw/ofw_subr.h> +#include <dev/clk/clk.h> +#include <dev/clk/clk_fixed.h> +#include <dev/ofw/openfirm.h> +#include <dev/syscon/syscon.h> +#include <dev/phy/phy.h> + +#include <dev/mmc/bridge.h> + +#include <dev/sdhci/sdhci.h> +#include <dev/sdhci/sdhci_fdt.h> + +#include "mmcbr_if.h" +#include "sdhci_if.h" + +#include "opt_mmccam.h" + +#include "clkdev_if.h" +#include "syscon_if.h" + +#define SDHCI_FDT_RK3399 1 +#define SDHCI_FDT_RK3568 2 + +#define RK3399_GRF_EMMCCORE_CON0 0xf000 +#define RK3399_CORECFG_BASECLKFREQ 0xff00 +#define RK3399_CORECFG_TIMEOUTCLKUNIT (1 << 7) +#define RK3399_CORECFG_TUNINGCOUNT 0x3f +#define RK3399_GRF_EMMCCORE_CON11 0xf02c +#define RK3399_CORECFG_CLOCKMULTIPLIER 0xff + +#define RK3568_EMMC_HOST_CTRL 0x0508 +#define RK3568_EMMC_EMMC_CTRL 0x052c +#define RK3568_EMMC_ATCTRL 0x0540 +#define RK3568_EMMC_DLL_CTRL 0x0800 +#define DLL_CTRL_SRST 0x00000001 +#define DLL_CTRL_START 0x00000002 +#define DLL_CTRL_START_POINT_DEFAULT 0x00050000 +#define DLL_CTRL_INCREMENT_DEFAULT 0x00000200 + +#define RK3568_EMMC_DLL_RXCLK 0x0804 +#define DLL_RXCLK_DELAY_ENABLE 0x08000000 +#define DLL_RXCLK_NO_INV 0x20000000 + +#define RK3568_EMMC_DLL_TXCLK 0x0808 +#define DLL_TXCLK_DELAY_ENABLE 0x08000000 +#define DLL_TXCLK_TAPNUM_DEFAULT 0x00000008 +#define DLL_TXCLK_TAPNUM_FROM_SW 0x01000000 + +#define RK3568_EMMC_DLL_STRBIN 0x080c +#define DLL_STRBIN_DELAY_ENABLE 0x08000000 +#define DLL_STRBIN_TAPNUM_DEFAULT 0x00000008 +#define DLL_STRBIN_TAPNUM_FROM_SW 0x01000000 + +#define RK3568_EMMC_DLL_STATUS0 0x0840 +#define DLL_STATUS0_DLL_LOCK 0x00000100 +#define DLL_STATUS0_DLL_TIMEOUT 0x00000200 + +#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[] = { + { "rockchip,rk3399-sdhci-5.1", SDHCI_FDT_RK3399 }, + { "rockchip,rk3568-dwcmshc", SDHCI_FDT_RK3568 }, + { NULL, 0 } +}; + +static int +sdhci_fdt_rockchip_probe(device_t dev) +{ + struct sdhci_fdt_softc *sc = device_get_softc(dev); + + sc->quirks = 0; + switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) { + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + case SDHCI_FDT_RK3399: + device_set_desc(dev, "Rockchip RK3399 fdt SDHCI controller"); + break; + case SDHCI_FDT_RK3568: + device_set_desc(dev, "Rockchip RK3568 fdt SDHCI controller"); + break; + default: + return (ENXIO); + } + + return (0); +} + +static int +sdhci_init_rk3399(device_t dev) +{ + struct sdhci_fdt_softc *sc = device_get_softc(dev); + uint64_t freq; + uint32_t mask, val; + int error; + + error = clk_get_freq(sc->clk_xin, &freq); + if (error != 0) { + device_printf(dev, "cannot get xin clock frequency\n"); + return (ENXIO); + } + + /* Disable clock multiplier */ + mask = RK3399_CORECFG_CLOCKMULTIPLIER; + val = 0; + SYSCON_WRITE_4(sc->syscon, RK3399_GRF_EMMCCORE_CON11, (mask << 16) | val); + + /* Set base clock frequency */ + mask = RK3399_CORECFG_BASECLKFREQ; + val = SHIFTIN((freq + (1000000 / 2)) / 1000000, + RK3399_CORECFG_BASECLKFREQ); + SYSCON_WRITE_4(sc->syscon, RK3399_GRF_EMMCCORE_CON0, (mask << 16) | val); + + return (0); +} + +static int +sdhci_fdt_rockchip_set_clock(device_t dev, struct sdhci_slot *slot, int clock) +{ + struct sdhci_fdt_softc *sc = device_get_softc(dev); + int32_t val; + int i; + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == + SDHCI_FDT_RK3568) { + if (clock == 400000) + clock = 375000; + + if (clock) { + clk_set_freq(sc->clk_core, clock, 0); + + if (clock <= 52000000) { + bus_write_4(sc->mem_res[slot->num], + RK3568_EMMC_DLL_CTRL, 0x0); + bus_write_4(sc->mem_res[slot->num], + RK3568_EMMC_DLL_RXCLK, DLL_RXCLK_NO_INV); + bus_write_4(sc->mem_res[slot->num], + RK3568_EMMC_DLL_TXCLK, 0x0); + bus_write_4(sc->mem_res[slot->num], + RK3568_EMMC_DLL_STRBIN, 0x0); + return (clock); + } + + bus_write_4(sc->mem_res[slot->num], + RK3568_EMMC_DLL_CTRL, DLL_CTRL_START); + DELAY(1000); + bus_write_4(sc->mem_res[slot->num], + RK3568_EMMC_DLL_CTRL, 0); + bus_write_4(sc->mem_res[slot->num], + RK3568_EMMC_DLL_CTRL, DLL_CTRL_START_POINT_DEFAULT | + DLL_CTRL_INCREMENT_DEFAULT | DLL_CTRL_START); + for (i = 0; i < 500; i++) { + val = bus_read_4(sc->mem_res[slot->num], + RK3568_EMMC_DLL_STATUS0); + if (val & DLL_STATUS0_DLL_LOCK && + !(val & DLL_STATUS0_DLL_TIMEOUT)) + break; + DELAY(1000); + } + bus_write_4(sc->mem_res[slot->num], RK3568_EMMC_ATCTRL, + (0x1 << 16 | 0x2 << 17 | 0x3 << 19)); + bus_write_4(sc->mem_res[slot->num], + RK3568_EMMC_DLL_RXCLK, + DLL_RXCLK_DELAY_ENABLE | DLL_RXCLK_NO_INV); + bus_write_4(sc->mem_res[slot->num], + RK3568_EMMC_DLL_TXCLK, DLL_TXCLK_DELAY_ENABLE | + DLL_TXCLK_TAPNUM_DEFAULT|DLL_TXCLK_TAPNUM_FROM_SW); + bus_write_4(sc->mem_res[slot->num], + RK3568_EMMC_DLL_STRBIN, DLL_STRBIN_DELAY_ENABLE | + DLL_STRBIN_TAPNUM_DEFAULT | + DLL_STRBIN_TAPNUM_FROM_SW); + } + } + return (sdhci_fdt_rockchip_set_clock(dev, slot, clock)); +} + +static int +sdhci_fdt_rockchip_attach(device_t dev) +{ + struct sdhci_fdt_softc *sc = device_get_softc(dev); + int err, compat; + + compat = ofw_bus_search_compatible(dev, compat_data)->ocd_data; + switch (compat) { + case SDHCI_FDT_RK3399: + err = sdhci_init_clocks(dev); + if (err != 0) { + device_printf(dev, "Cannot init clocks\n"); + return (err); + } + sdhci_export_clocks(sc); + if ((err = sdhci_init_phy(sc)) != 0) { + device_printf(dev, "Cannot init phy\n"); + return (err); + } + if ((err = sdhci_get_syscon(sc)) != 0) { + device_printf(dev, "Cannot get syscon handle\n"); + return (err); + } + if (compat == SDHCI_FDT_RK3399) { + err = sdhci_init_rk3399(dev); + if (err != 0) { + device_printf(dev, "Cannot init RK3399 SDHCI\n"); + return (err); + } + } + break; + case SDHCI_FDT_RK3568: + /* setup & enable clocks */ + if (clk_get_by_ofw_name(dev, 0, "core", &sc->clk_core)) { + device_printf(dev, "cannot get core clock\n"); + return (ENXIO); + } + clk_enable(sc->clk_core); + break; + default: + break; + } + + return (sdhci_fdt_attach(dev)); +} + +static device_method_t sdhci_fdt_rockchip_methods[] = { + /* device_if */ + DEVMETHOD(device_probe, sdhci_fdt_rockchip_probe), + DEVMETHOD(device_attach, sdhci_fdt_rockchip_attach), + + /* SDHCI methods */ + DEVMETHOD(sdhci_set_clock, sdhci_fdt_rockchip_set_clock), + + DEVMETHOD_END +}; +extern driver_t sdhci_fdt_driver; + +DEFINE_CLASS_1(sdhci_rockchip, sdhci_fdt_rockchip_driver, sdhci_fdt_rockchip_methods, + sizeof(struct sdhci_fdt_softc), sdhci_fdt_driver); +DRIVER_MODULE(sdhci_rockchip, simplebus, sdhci_fdt_rockchip_driver, NULL, NULL); diff --git a/sys/dev/sdhci/sdhci_fdt_xilinx.c b/sys/dev/sdhci/sdhci_fdt_xilinx.c new file mode 100644 index 000000000000..1800e756dd33 --- /dev/null +++ b/sys/dev/sdhci/sdhci_fdt_xilinx.c @@ -0,0 +1,115 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Emmanuel Vadot <manu@freebsd.org> + * + * 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 <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/resource.h> +#include <sys/rman.h> +#include <sys/sysctl.h> +#include <sys/taskqueue.h> + +#include <machine/bus.h> +#include <machine/resource.h> + +#include <dev/fdt/fdt_common.h> +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> + +#include <dev/ofw/ofw_subr.h> +#include <dev/clk/clk.h> +#include <dev/clk/clk_fixed.h> +#include <dev/ofw/openfirm.h> +#include <dev/syscon/syscon.h> +#include <dev/phy/phy.h> + +#include <dev/mmc/bridge.h> + +#include <dev/sdhci/sdhci.h> +#include <dev/sdhci/sdhci_fdt.h> + +#include "mmcbr_if.h" +#include "sdhci_if.h" + +#include "opt_mmccam.h" + +#include "clkdev_if.h" +#include "syscon_if.h" + +static int +sdhci_fdt_xilinx_probe(device_t dev) +{ + struct sdhci_fdt_softc *sc = device_get_softc(dev); + + if (!ofw_bus_is_compatible(dev, "xlnx,zynqmp-8.9a")) + return (ENXIO); + + sc->quirks = 0; + device_set_desc(dev, "ZynqMP generic fdt SDHCI controller"); + + return (0); +} + +static int +sdhci_fdt_xilinx_attach(device_t dev) +{ + struct sdhci_fdt_softc *sc = device_get_softc(dev); + int err; + + err = sdhci_init_clocks(dev); + if (err != 0) { + device_printf(dev, "Cannot init clocks\n"); + return (err); + } + sdhci_export_clocks(sc); + if ((err = sdhci_init_phy(sc)) != 0) { + device_printf(dev, "Cannot init phy\n"); + return (err); + } + if ((err = sdhci_get_syscon(sc)) != 0) { + device_printf(dev, "Cannot get syscon handle\n"); + return (err); + } + + return (sdhci_fdt_attach(dev)); +} + +static device_method_t sdhci_fdt_xilinx_methods[] = { + /* device_if */ + DEVMETHOD(device_probe, sdhci_fdt_xilinx_probe), + DEVMETHOD(device_attach, sdhci_fdt_xilinx_attach), + + DEVMETHOD_END +}; +extern driver_t sdhci_fdt_driver; + +DEFINE_CLASS_1(sdhci_xilinx, sdhci_fdt_xilinx_driver, sdhci_fdt_xilinx_methods, + sizeof(struct sdhci_fdt_softc), sdhci_fdt_driver); +DRIVER_MODULE(sdhci_xilinx, simplebus, sdhci_fdt_xilinx_driver, NULL, NULL);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202502070907.517977xk067660>