Changeset View
Changeset View
Standalone View
Standalone View
head/sys/riscv/sifive/fu540_prci.c
Show First 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
#include <machine/cpu.h> | #include <machine/cpu.h> | ||||
#include <dev/extres/clk/clk.h> | #include <dev/extres/clk/clk.h> | ||||
#include <dev/ofw/ofw_bus.h> | #include <dev/ofw/ofw_bus.h> | ||||
#include <dev/ofw/ofw_bus_subr.h> | #include <dev/ofw/ofw_bus_subr.h> | ||||
#include <dev/ofw/openfirm.h> | #include <dev/ofw/openfirm.h> | ||||
#include <gnu/dts/include/dt-bindings/clock/sifive-fu540-prci.h> | |||||
static struct resource_spec prci_spec[] = { | static struct resource_spec prci_spec[] = { | ||||
{ SYS_RES_MEMORY, 0, RF_ACTIVE }, | { SYS_RES_MEMORY, 0, RF_ACTIVE }, | ||||
RESOURCE_SPEC_END | RESOURCE_SPEC_END | ||||
}; | }; | ||||
struct prci_softc { | struct prci_softc { | ||||
device_t dev; | device_t dev; | ||||
struct mtx mtx; | struct mtx mtx; | ||||
struct clkdom *clkdom; | struct clkdom *clkdom; | ||||
struct resource *res; | struct resource *res; | ||||
bus_space_tag_t bst; | bus_space_tag_t bst; | ||||
bus_space_handle_t bsh; | bus_space_handle_t bsh; | ||||
}; | }; | ||||
struct prci_clk_pll_sc { | struct prci_clk_pll_sc { | ||||
struct prci_softc *parent_sc; | struct prci_softc *parent_sc; | ||||
uint32_t reg; | |||||
}; | }; | ||||
#define PRCI_LOCK(sc) mtx_lock(&(sc)->mtx) | #define PRCI_LOCK(sc) mtx_lock(&(sc)->mtx) | ||||
#define PRCI_UNLOCK(sc) mtx_unlock(&(sc)->mtx) | #define PRCI_UNLOCK(sc) mtx_unlock(&(sc)->mtx) | ||||
#define PRCI_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED); | #define PRCI_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED); | ||||
#define PRCI_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED); | #define PRCI_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED); | ||||
#define PRCI_COREPLL 0x4 | #define PRCI_COREPLL_CFG0 0x4 | ||||
#define PRCI_COREPLL_DIVR_MASK 0x3f | #define PRCI_DDRPLL_CFG0 0xC | ||||
#define PRCI_COREPLL_DIVR_SHIFT 0 | #define PRCI_GEMGXLPLL_CFG0 0x1C | ||||
#define PRCI_COREPLL_DIVF_MASK 0x7fc0 | |||||
#define PRCI_COREPLL_DIVF_SHIFT 6 | |||||
#define PRCI_COREPLL_DIVQ_MASK 0x38000 | |||||
#define PRCI_COREPLL_DIVQ_SHIFT 15 | |||||
#define PRCI_PLL_DIVR_MASK 0x3f | |||||
#define PRCI_PLL_DIVR_SHIFT 0 | |||||
#define PRCI_PLL_DIVF_MASK 0x7fc0 | |||||
#define PRCI_PLL_DIVF_SHIFT 6 | |||||
#define PRCI_PLL_DIVQ_MASK 0x38000 | |||||
#define PRCI_PLL_DIVQ_SHIFT 15 | |||||
#define PRCI_READ(_sc, _reg) \ | #define PRCI_READ(_sc, _reg) \ | ||||
bus_space_read_4((_sc)->bst, (_sc)->bsh, (_reg)) | bus_space_read_4((_sc)->bst, (_sc)->bsh, (_reg)) | ||||
struct prci_pll_def { | |||||
uint32_t id; | |||||
const char *name; | |||||
uint32_t reg; | |||||
}; | |||||
#define PLL(_id, _name, _base) \ | |||||
{ \ | |||||
.id = (_id), \ | |||||
.name = (_name), \ | |||||
.reg = (_base), \ | |||||
} | |||||
/* PLL Clocks */ | |||||
struct prci_pll_def pll_clks[] = { | |||||
PLL(PRCI_CLK_COREPLL, "coreclk", PRCI_COREPLL_CFG0), | |||||
PLL(PRCI_CLK_DDRPLL, "ddrclk", PRCI_DDRPLL_CFG0), | |||||
PLL(PRCI_CLK_GEMGXLPLL, "gemgxclk", PRCI_GEMGXLPLL_CFG0), | |||||
}; | |||||
static int | static int | ||||
prci_clk_pll_init(struct clknode *clk, device_t dev) | prci_clk_pll_init(struct clknode *clk, device_t dev) | ||||
{ | { | ||||
clknode_init_parent_idx(clk, 0); | clknode_init_parent_idx(clk, 0); | ||||
return (0); | return (0); | ||||
} | } | ||||
Show All 19 Lines | prci_clk_pll_recalc(struct clknode *clk, uint64_t *freq) | ||||
if (err) { | if (err) { | ||||
device_printf(sc->parent_sc->dev, | device_printf(sc->parent_sc->dev, | ||||
"Failed to get refclk frequency\n"); | "Failed to get refclk frequency\n"); | ||||
PRCI_UNLOCK(sc->parent_sc); | PRCI_UNLOCK(sc->parent_sc); | ||||
return (err); | return (err); | ||||
} | } | ||||
/* Calculate the PLL output */ | /* Calculate the PLL output */ | ||||
val = PRCI_READ(sc->parent_sc, PRCI_COREPLL); | val = PRCI_READ(sc->parent_sc, sc->reg); | ||||
divf = (val & PRCI_COREPLL_DIVF_MASK) >> PRCI_COREPLL_DIVF_SHIFT; | divf = (val & PRCI_PLL_DIVF_MASK) >> PRCI_PLL_DIVF_SHIFT; | ||||
divq = (val & PRCI_COREPLL_DIVQ_MASK) >> PRCI_COREPLL_DIVQ_SHIFT; | divq = (val & PRCI_PLL_DIVQ_MASK) >> PRCI_PLL_DIVQ_SHIFT; | ||||
divr = (val & PRCI_COREPLL_DIVR_MASK) >> PRCI_COREPLL_DIVR_SHIFT; | divr = (val & PRCI_PLL_DIVR_MASK) >> PRCI_PLL_DIVR_SHIFT; | ||||
*freq = refclk / (divr + 1) * (2 * (divf + 1)) / (1 << divq); | *freq = refclk / (divr + 1) * (2 * (divf + 1)) / (1 << divq); | ||||
PRCI_UNLOCK(sc->parent_sc); | PRCI_UNLOCK(sc->parent_sc); | ||||
return (0); | return (0); | ||||
} | } | ||||
Show All 18 Lines | if (!ofw_bus_is_compatible(dev, "sifive,aloeprci0")) | ||||
return (ENXIO); | return (ENXIO); | ||||
device_set_desc(dev, "SiFive FU540 Power Reset Clocking Interrupt"); | device_set_desc(dev, "SiFive FU540 Power Reset Clocking Interrupt"); | ||||
return (BUS_PROBE_DEFAULT); | return (BUS_PROBE_DEFAULT); | ||||
} | } | ||||
static void | static void | ||||
prci_pll_register(struct prci_softc *parent_sc, struct clknode_init_def *clkdef) | prci_pll_register(struct prci_softc *parent_sc, struct clknode_init_def *clkdef, | ||||
uint32_t reg) | |||||
{ | { | ||||
struct clknode *clk; | struct clknode *clk; | ||||
struct prci_clk_pll_sc *sc; | struct prci_clk_pll_sc *sc; | ||||
clk = clknode_create(parent_sc->clkdom, &prci_clk_pll_clknode_class, | clk = clknode_create(parent_sc->clkdom, &prci_clk_pll_clknode_class, | ||||
clkdef); | clkdef); | ||||
if (clk == NULL) | if (clk == NULL) | ||||
panic("Failed to create clknode"); | panic("Failed to create clknode"); | ||||
sc = clknode_get_softc(clk); | sc = clknode_get_softc(clk); | ||||
sc->parent_sc = parent_sc; | sc->parent_sc = parent_sc; | ||||
sc->reg = reg; | |||||
clknode_register(parent_sc->clkdom, clk); | clknode_register(parent_sc->clkdom, clk); | ||||
} | } | ||||
static int | static int | ||||
prci_attach(device_t dev) | prci_attach(device_t dev) | ||||
{ | { | ||||
struct clknode_init_def clkdef; | struct clknode_init_def clkdef; | ||||
Show All 19 Lines | prci_attach(device_t dev) | ||||
error = ofw_bus_parse_xref_list_get_length(node, "clocks", | error = ofw_bus_parse_xref_list_get_length(node, "clocks", | ||||
"#clock-cells", &ncells); | "#clock-cells", &ncells); | ||||
if (error != 0 || ncells != 1) { | if (error != 0 || ncells != 1) { | ||||
device_printf(dev, "couldn't find parent clock\n"); | device_printf(dev, "couldn't find parent clock\n"); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
bzero(&clkdef, sizeof(clkdef)); | bzero(&clkdef, sizeof(clkdef)); | ||||
clkdef.id = 0; | |||||
clkdef.name = "coreclk"; | |||||
clkdef.parent_names = mallocarray(ncells, sizeof(char *), M_OFWPROP, | clkdef.parent_names = mallocarray(ncells, sizeof(char *), M_OFWPROP, | ||||
M_WAITOK); | M_WAITOK); | ||||
for (i = 0; i < ncells; i++) { | for (i = 0; i < ncells; i++) { | ||||
error = clk_get_by_ofw_index(dev, 0, i, &clk_parent); | error = clk_get_by_ofw_index(dev, 0, i, &clk_parent); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(dev, "cannot get clock %d\n", error); | device_printf(dev, "cannot get clock %d\n", error); | ||||
goto fail1; | goto fail1; | ||||
} | } | ||||
clkdef.parent_names[i] = clk_get_name(clk_parent); | clkdef.parent_names[i] = clk_get_name(clk_parent); | ||||
if (bootverbose) | if (bootverbose) | ||||
device_printf(dev, "clk parent: %s\n", | device_printf(dev, "clk parent: %s\n", | ||||
clkdef.parent_names[i]); | clkdef.parent_names[i]); | ||||
clk_release(clk_parent); | clk_release(clk_parent); | ||||
} | } | ||||
clkdef.parent_cnt = ncells; | clkdef.parent_cnt = ncells; | ||||
sc->clkdom = clkdom_create(dev); | sc->clkdom = clkdom_create(dev); | ||||
if (sc->clkdom == NULL) { | if (sc->clkdom == NULL) { | ||||
device_printf(dev, "Couldn't create clock domain\n"); | device_printf(dev, "Couldn't create clock domain\n"); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
/* We can't free a clkdom, so from now on we cannot fail. */ | /* We can't free a clkdom, so from now on we cannot fail. */ | ||||
prci_pll_register(sc, &clkdef); | for (i = 0; i < nitems(pll_clks); i++) { | ||||
clkdef.id = pll_clks[i].id; | |||||
clkdef.name = pll_clks[i].name; | |||||
prci_pll_register(sc, &clkdef, pll_clks[i].reg); | |||||
} | |||||
error = clkdom_finit(sc->clkdom); | error = clkdom_finit(sc->clkdom); | ||||
if (error) | if (error) | ||||
panic("Couldn't finalise clock domain"); | panic("Couldn't finalise clock domain"); | ||||
return (0); | return (0); | ||||
fail1: | fail1: | ||||
Show All 25 Lines |