Add support for Rockchip RK3568 SDHCI controller.
This commit is contained in:
parent
571e5792f9
commit
e00774a917
@ -419,6 +419,7 @@ sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock)
|
||||
|
||||
if (clock == slot->clock)
|
||||
return;
|
||||
clock = SDHCI_SET_CLOCK(slot->bus, slot, clock);
|
||||
slot->clock = clock;
|
||||
|
||||
/* Turn off the clock. */
|
||||
|
@ -76,6 +76,7 @@ __FBSDID("$FreeBSD$");
|
||||
#define SDHCI_FDT_XLNX_ZY7 3
|
||||
#define SDHCI_FDT_QUALCOMM 4
|
||||
#define SDHCI_FDT_RK3399 5
|
||||
#define SDHCI_FDT_RK3568 6
|
||||
|
||||
#define RK3399_GRF_EMMCCORE_CON0 0xf000
|
||||
#define RK3399_CORECFG_BASECLKFREQ 0xff00
|
||||
@ -84,6 +85,33 @@ __FBSDID("$FreeBSD$");
|
||||
#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))
|
||||
|
||||
@ -95,6 +123,7 @@ static struct ofw_compat_data compat_data[] = {
|
||||
{ "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 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
@ -116,6 +145,7 @@ struct sdhci_fdt_softc {
|
||||
|
||||
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 */
|
||||
};
|
||||
|
||||
@ -404,6 +434,66 @@ 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)
|
||||
{
|
||||
@ -439,6 +529,9 @@ sdhci_fdt_probe(device_t dev)
|
||||
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;
|
||||
default:
|
||||
return (ENXIO);
|
||||
}
|
||||
@ -488,6 +581,16 @@ sdhci_fdt_attach(device_t dev)
|
||||
}
|
||||
}
|
||||
|
||||
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data ==
|
||||
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);
|
||||
}
|
||||
|
||||
/* Scan all slots. */
|
||||
slots = sc->num_slots; /* number of slots determined in probe(). */
|
||||
sc->num_slots = 0;
|
||||
@ -577,6 +680,7 @@ static device_method_t sdhci_fdt_methods[] = {
|
||||
DEVMETHOD(sdhci_write_2, sdhci_fdt_write_2),
|
||||
DEVMETHOD(sdhci_write_4, sdhci_fdt_write_4),
|
||||
DEVMETHOD(sdhci_write_multi_4, sdhci_fdt_write_multi_4),
|
||||
DEVMETHOD(sdhci_set_clock, sdhci_fdt_set_clock),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
@ -69,6 +69,14 @@
|
||||
#include <dev/sdhci/sdhci.h>
|
||||
|
||||
CODE {
|
||||
static int
|
||||
null_set_clock(device_t brdev __unused,
|
||||
struct sdhci_slot *slot __unused,
|
||||
int clock)
|
||||
{
|
||||
return (clock);
|
||||
}
|
||||
|
||||
static void
|
||||
null_set_uhs_timing(device_t brdev __unused,
|
||||
struct sdhci_slot *slot __unused)
|
||||
@ -165,6 +173,12 @@ METHOD void set_uhs_timing {
|
||||
struct sdhci_slot *slot;
|
||||
} DEFAULT null_set_uhs_timing;
|
||||
|
||||
METHOD int set_clock {
|
||||
device_t brdev;
|
||||
struct sdhci_slot *slot;
|
||||
int clock;
|
||||
} DEFAULT null_set_clock;
|
||||
|
||||
METHOD void reset {
|
||||
device_t brdev;
|
||||
struct sdhci_slot *slot;
|
||||
|
Loading…
x
Reference in New Issue
Block a user