Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F105798315
D20156.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D20156.diff
View Options
Index: head/sys/dev/sdhci/sdhci_fdt.c
===================================================================
--- head/sys/dev/sdhci/sdhci_fdt.c
+++ head/sys/dev/sdhci/sdhci_fdt.c
@@ -52,6 +52,14 @@
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#ifdef EXT_RESOURCES
+#include <dev/ofw/ofw_subr.h>
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/clk/clk_fixed.h>
+#include <dev/extres/syscon/syscon.h>
+#include <dev/extres/phy/phy.h>
+#endif
+
#include <dev/mmc/bridge.h>
#include <dev/sdhci/sdhci.h>
@@ -61,16 +69,37 @@
#include "opt_mmccam.h"
+#ifdef EXT_RESOURCES
+#include "clkdev_if.h"
+#include "syscon_if.h"
+#endif
+
#define MAX_SLOTS 6
#define SDHCI_FDT_ARMADA38X 1
#define SDHCI_FDT_GENERIC 2
#define SDHCI_FDT_XLNX_ZY7 3
#define SDHCI_FDT_QUALCOMM 4
+#define SDHCI_FDT_RK3399 5
+#ifdef EXT_RESOURCES
+#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 LOWEST_SET_BIT(mask) ((((mask) - 1) & (mask)) ^ (mask))
+#define SHIFTIN(x, mask) ((x) * LOWEST_SET_BIT(mask))
+
+#define EMMCCARDCLK_ID 1000
+#endif
+
static struct ofw_compat_data compat_data[] = {
{ "marvell,armada-380-sdhci", SDHCI_FDT_ARMADA38X },
{ "sdhci_generic", SDHCI_FDT_GENERIC },
{ "qcom,sdhci-msm-v4", SDHCI_FDT_QUALCOMM },
+ { "rockchip,rk3399-sdhci-5.1", SDHCI_FDT_RK3399 },
{ "xlnx,zy7_sdhci", SDHCI_FDT_XLNX_ZY7 },
{ NULL, 0 }
};
@@ -90,8 +119,209 @@
bool wp_inverted; /* WP pin is inverted */
bool no_18v; /* No 1.8V support */
+
+#ifdef EXT_RESOURCES
+ clk_t clk_xin; /* xin24m fixed clock */
+ clk_t clk_ahb; /* ahb clock */
+ phy_t phy; /* phy to be used */
+#endif
};
+#ifdef EXT_RESOURCES
+struct rk3399_emmccardclk_sc {
+ device_t clkdev;
+ bus_addr_t reg;
+};
+
+static int
+rk3399_emmccardclk_init(struct clknode *clk, device_t dev)
+{
+
+ clknode_init_parent_idx(clk, 0);
+ return (0);
+}
+
+static clknode_method_t rk3399_emmccardclk_clknode_methods[] = {
+ /* Device interface */
+ CLKNODEMETHOD(clknode_init, rk3399_emmccardclk_init),
+ CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(rk3399_emmccardclk_clknode, rk3399_emmccardclk_clknode_class,
+ rk3399_emmccardclk_clknode_methods, sizeof(struct rk3399_emmccardclk_sc),
+ clknode_class);
+
+static int
+rk3399_ofw_map(struct clkdom *clkdom, uint32_t ncells,
+ phandle_t *cells, struct clknode **clk)
+{
+
+ if (ncells == 0)
+ *clk = clknode_find_by_id(clkdom, EMMCCARDCLK_ID);
+ else
+ return (ERANGE);
+
+ if (*clk == NULL)
+ return (ENXIO);
+ return (0);
+}
+
+static void
+sdhci_init_rk3399_emmccardclk(device_t dev)
+{
+ struct clknode_init_def def;
+ struct rk3399_emmccardclk_sc *sc;
+ struct clkdom *clkdom;
+ struct clknode *clk;
+ clk_t clk_parent;
+ bus_addr_t paddr;
+ bus_size_t psize;
+ const char **clknames;
+ phandle_t node;
+ int i, nclocks, ncells, error;
+
+ node = ofw_bus_get_node(dev);
+
+ if (ofw_reg_to_paddr(node, 0, &paddr, &psize, NULL) != 0) {
+ device_printf(dev, "cannot parse 'reg' property\n");
+ return;
+ }
+
+ error = ofw_bus_parse_xref_list_get_length(node, "clocks",
+ "#clock-cells", &ncells);
+ if (error != 0 || ncells != 2) {
+ device_printf(dev, "couldn't find parent clocks\n");
+ return;
+ }
+
+ nclocks = ofw_bus_string_list_to_array(node, "clock-output-names",
+ &clknames);
+ /* No clocks to export */
+ if (nclocks <= 0)
+ return;
+
+ if (nclocks != 1) {
+ device_printf(dev, "Having %d clock instead of 1, aborting\n",
+ nclocks);
+ return;
+ }
+
+ clkdom = clkdom_create(dev);
+ clkdom_set_ofw_mapper(clkdom, rk3399_ofw_map);
+
+ memset(&def, 0, sizeof(def));
+ def.id = EMMCCARDCLK_ID;
+ 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(dev, 0, i, &clk_parent);
+ if (error != 0) {
+ device_printf(dev, "cannot get clock %d\n", error);
+ return;
+ }
+ def.parent_names[i] = clk_get_name(clk_parent);
+ if (bootverbose)
+ device_printf(dev, "clk parent: %s\n",
+ def.parent_names[i]);
+ clk_release(clk_parent);
+ }
+ def.parent_cnt = ncells;
+
+ clk = clknode_create(clkdom, &rk3399_emmccardclk_clknode_class, &def);
+ if (clk == NULL) {
+ device_printf(dev, "cannot create clknode\n");
+ return;
+ }
+
+ sc = clknode_get_softc(clk);
+ sc->reg = paddr;
+ sc->clkdev = device_get_parent(dev);
+
+ clknode_register(clkdom, clk);
+
+ if (clkdom_finit(clkdom) != 0) {
+ device_printf(dev, "cannot finalize clkdom initialization\n");
+ return;
+ }
+
+ if (bootverbose)
+ clkdom_dump(clkdom);
+}
+
+static int
+sdhci_init_rk3399(device_t dev)
+{
+ struct sdhci_fdt_softc *sc = device_get_softc(dev);
+ struct syscon *grf = NULL;
+ phandle_t node;
+ uint64_t freq;
+ uint32_t mask, val;
+ int error;
+
+ /* Get and activate clocks */
+ error = clk_get_by_ofw_name(dev, 0, "clk_xin", &sc->clk_xin);
+ if (error != 0) {
+ device_printf(dev, "cannot get xin clock\n");
+ return (ENXIO);
+ }
+ error = clk_enable(sc->clk_xin);
+ if (error != 0) {
+ device_printf(dev, "cannot enable xin clock\n");
+ return (ENXIO);
+ }
+ error = clk_get_freq(sc->clk_xin, &freq);
+ if (error != 0) {
+ device_printf(dev, "cannot get xin clock frequency\n");
+ return (ENXIO);
+ }
+ error = clk_get_by_ofw_name(dev, 0, "clk_ahb", &sc->clk_ahb);
+ if (error != 0) {
+ device_printf(dev, "cannot get ahb clock\n");
+ return (ENXIO);
+ }
+ error = clk_enable(sc->clk_ahb);
+ if (error != 0) {
+ device_printf(dev, "cannot enable ahb clock\n");
+ return (ENXIO);
+ }
+
+ /* Register clock */
+ sdhci_init_rk3399_emmccardclk(dev);
+
+ /* Enable PHY */
+ error = phy_get_by_ofw_name(dev, 0, "phy_arasan", &sc->phy);
+ if (error != 0) {
+ device_printf(dev, "Could not get phy\n");
+ return (ENXIO);
+ }
+ error = phy_enable(sc->phy);
+ if (error != 0) {
+ device_printf(dev, "Could not enable phy\n");
+ return (ENXIO);
+ }
+ /* Get syscon */
+ node = ofw_bus_get_node(dev);
+ if (OF_hasprop(node, "arasan,soc-ctl-syscon") &&
+ syscon_get_by_ofw_property(dev, node,
+ "arasan,soc-ctl-syscon", &grf) != 0) {
+ device_printf(dev, "cannot get grf driver handle\n");
+ return (ENXIO);
+ }
+
+ /* Disable clock multiplier */
+ mask = RK3399_CORECFG_CLOCKMULTIPLIER;
+ val = 0;
+ SYSCON_WRITE_4(grf, 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(grf, RK3399_GRF_EMMCCORE_CON0, (mask << 16) | val);
+
+ return (0);
+}
+#endif
+
static uint8_t
sdhci_fdt_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off)
{
@@ -212,6 +442,9 @@
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");
@@ -254,6 +487,18 @@
device_printf(dev, "Can't allocate IRQ\n");
return (ENOMEM);
}
+
+#ifdef EXT_RESOURCES
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data ==
+ SDHCI_FDT_RK3399) {
+ /* Initialize SDHCI */
+ err = sdhci_init_rk3399(dev);
+ if (err != 0) {
+ device_printf(dev, "Cannot init RK3399 SDHCI\n");
+ return (err);
+ }
+ }
+#endif
/* Scan all slots. */
slots = sc->num_slots; /* number of slots determined in probe(). */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Dec 21, 8:39 PM (20 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15546487
Default Alt Text
D20156.diff (7 KB)
Attached To
Mode
D20156: Add support for RK3399 emmc
Attached
Detach File
Event Timeline
Log In to Comment